I am learning linux wifi drivers, and was exploring the code in cfg80211
subsytem for a scan request.
I can't understand why the following struct
is allocated more memory than required.
Or, I can't understand the way the size of memory to be allocated is calculated in this way.
The struct
is defined in include/net/cfg80211.h
:
struct cfg80211_scan_request {
struct cfg80211_ssid *ssids;
int n_ssids;
u32 n_channels;
enum nl80211_bss_scan_width scan_width;
const u8 *ie;
size_t ie_len;
u16 duration;
bool duration_mandatory;
u32 flags;
u32 rates[NUM_NL80211_BANDS];
struct wireless_dev *wdev;
u8 mac_addr[ETH_ALEN] __aligned(2);
u8 mac_addr_mask[ETH_ALEN] __aligned(2);
u8 bssid[ETH_ALEN] __aligned(2);
/* internal */
struct wiphy *wiphy;
unsigned long scan_start;
struct cfg80211_scan_info info;
bool notified;
bool no_cck;
/* keep last */
struct ieee80211_channel *channels[0];
};
In file /net/wireless/nl80211.c
, memory is being allocated to the struct
as follows:
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
// ...
struct cfg80211_scan_request *request;
// ...
request = kzalloc(sizeof(*request)
+ sizeof(*request->ssids) * n_ssids
+ sizeof(*request->channels) * n_channels
+ ie_len, GFP_KERNEL);
// ...
}
I have a doubt that more memory is being allocated than required. Or, the way size is calculated in kzalloc
doesn't make sense to me.
This is what I expect the code to be like:
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
// ...
struct cfg80211_scan_request *request;
// ...
request = kzalloc(sizeof(*request)
+ sizeof(*request->channels) * n_channels,
GFP_KERNEL);
// ...
}
Why that much size of memory is allocated then?
What I'm understanding is kzalloc(struct + flexible_array_member + extra_len_but_why)
.
Presumably the code after the kzalloc
sets the values of the pointers requests->ssids
and requests->ie
so that they point into the newly allocated memory, just after the struct.
That way, only one block of memory needs to be allocated for the three arrays.
EDIT: I found the function in question, and indeed, just after the kzalloc call shown in the OP, we find the following, which sets up the ssids
and ie
pointers:
if (n_ssids)
request->ssids = (void *)&request->channels[n_channels];
request->n_ssids = n_ssids;
if (ie_len) {
if (n_ssids)
request->ie = (void *)(request->ssids + n_ssids);
else
request->ie = (void *)(request->channels + n_channels);
}