diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 82 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 16 | ||||
-rw-r--r-- | net/mac80211/iface.c | 7 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 52 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 47 |
5 files changed, 198 insertions, 6 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 72c106915433..d1ac3ab2c515 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1175,6 +1175,87 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1175 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1175 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
1176 | } | 1176 | } |
1177 | 1177 | ||
1178 | static int set_mgmt_extra_ie_sta(struct ieee80211_if_sta *ifsta, u8 subtype, | ||
1179 | u8 *ies, size_t ies_len) | ||
1180 | { | ||
1181 | switch (subtype) { | ||
1182 | case IEEE80211_STYPE_PROBE_REQ >> 4: | ||
1183 | kfree(ifsta->ie_probereq); | ||
1184 | ifsta->ie_probereq = ies; | ||
1185 | ifsta->ie_probereq_len = ies_len; | ||
1186 | return 0; | ||
1187 | case IEEE80211_STYPE_PROBE_RESP >> 4: | ||
1188 | kfree(ifsta->ie_proberesp); | ||
1189 | ifsta->ie_proberesp = ies; | ||
1190 | ifsta->ie_proberesp_len = ies_len; | ||
1191 | return 0; | ||
1192 | case IEEE80211_STYPE_AUTH >> 4: | ||
1193 | kfree(ifsta->ie_auth); | ||
1194 | ifsta->ie_auth = ies; | ||
1195 | ifsta->ie_auth_len = ies_len; | ||
1196 | return 0; | ||
1197 | case IEEE80211_STYPE_ASSOC_REQ >> 4: | ||
1198 | kfree(ifsta->ie_assocreq); | ||
1199 | ifsta->ie_assocreq = ies; | ||
1200 | ifsta->ie_assocreq_len = ies_len; | ||
1201 | return 0; | ||
1202 | case IEEE80211_STYPE_REASSOC_REQ >> 4: | ||
1203 | kfree(ifsta->ie_reassocreq); | ||
1204 | ifsta->ie_reassocreq = ies; | ||
1205 | ifsta->ie_reassocreq_len = ies_len; | ||
1206 | return 0; | ||
1207 | case IEEE80211_STYPE_DEAUTH >> 4: | ||
1208 | kfree(ifsta->ie_deauth); | ||
1209 | ifsta->ie_deauth = ies; | ||
1210 | ifsta->ie_deauth_len = ies_len; | ||
1211 | return 0; | ||
1212 | case IEEE80211_STYPE_DISASSOC >> 4: | ||
1213 | kfree(ifsta->ie_disassoc); | ||
1214 | ifsta->ie_disassoc = ies; | ||
1215 | ifsta->ie_disassoc_len = ies_len; | ||
1216 | return 0; | ||
1217 | } | ||
1218 | |||
1219 | return -EOPNOTSUPP; | ||
1220 | } | ||
1221 | |||
1222 | static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy, | ||
1223 | struct net_device *dev, | ||
1224 | struct mgmt_extra_ie_params *params) | ||
1225 | { | ||
1226 | struct ieee80211_sub_if_data *sdata; | ||
1227 | u8 *ies; | ||
1228 | size_t ies_len; | ||
1229 | int ret = -EOPNOTSUPP; | ||
1230 | |||
1231 | if (params->ies) { | ||
1232 | ies = kmemdup(params->ies, params->ies_len, GFP_KERNEL); | ||
1233 | if (ies == NULL) | ||
1234 | return -ENOMEM; | ||
1235 | ies_len = params->ies_len; | ||
1236 | } else { | ||
1237 | ies = NULL; | ||
1238 | ies_len = 0; | ||
1239 | } | ||
1240 | |||
1241 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1242 | |||
1243 | switch (sdata->vif.type) { | ||
1244 | case NL80211_IFTYPE_STATION: | ||
1245 | case NL80211_IFTYPE_ADHOC: | ||
1246 | ret = set_mgmt_extra_ie_sta(&sdata->u.sta, params->subtype, | ||
1247 | ies, ies_len); | ||
1248 | break; | ||
1249 | default: | ||
1250 | ret = -EOPNOTSUPP; | ||
1251 | break; | ||
1252 | } | ||
1253 | |||
1254 | if (ret) | ||
1255 | kfree(ies); | ||
1256 | return ret; | ||
1257 | } | ||
1258 | |||
1178 | struct cfg80211_ops mac80211_config_ops = { | 1259 | struct cfg80211_ops mac80211_config_ops = { |
1179 | .add_virtual_intf = ieee80211_add_iface, | 1260 | .add_virtual_intf = ieee80211_add_iface, |
1180 | .del_virtual_intf = ieee80211_del_iface, | 1261 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1204,4 +1285,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1204 | .change_bss = ieee80211_change_bss, | 1285 | .change_bss = ieee80211_change_bss, |
1205 | .set_txq_params = ieee80211_set_txq_params, | 1286 | .set_txq_params = ieee80211_set_txq_params, |
1206 | .set_channel = ieee80211_set_channel, | 1287 | .set_channel = ieee80211_set_channel, |
1288 | .set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie, | ||
1207 | }; | 1289 | }; |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c9ffadb55d36..5eafd3affe27 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -331,6 +331,22 @@ struct ieee80211_if_sta { | |||
331 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; | 331 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; |
332 | 332 | ||
333 | int wmm_last_param_set; | 333 | int wmm_last_param_set; |
334 | |||
335 | /* Extra IE data for management frames */ | ||
336 | u8 *ie_probereq; | ||
337 | size_t ie_probereq_len; | ||
338 | u8 *ie_proberesp; | ||
339 | size_t ie_proberesp_len; | ||
340 | u8 *ie_auth; | ||
341 | size_t ie_auth_len; | ||
342 | u8 *ie_assocreq; | ||
343 | size_t ie_assocreq_len; | ||
344 | u8 *ie_reassocreq; | ||
345 | size_t ie_reassocreq_len; | ||
346 | u8 *ie_deauth; | ||
347 | size_t ie_deauth_len; | ||
348 | u8 *ie_disassoc; | ||
349 | size_t ie_disassoc_len; | ||
334 | }; | 350 | }; |
335 | 351 | ||
336 | struct ieee80211_if_mesh { | 352 | struct ieee80211_if_mesh { |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 5d5a029228be..8dc2c2188d92 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -632,6 +632,13 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
632 | kfree(sdata->u.sta.assocreq_ies); | 632 | kfree(sdata->u.sta.assocreq_ies); |
633 | kfree(sdata->u.sta.assocresp_ies); | 633 | kfree(sdata->u.sta.assocresp_ies); |
634 | kfree_skb(sdata->u.sta.probe_resp); | 634 | kfree_skb(sdata->u.sta.probe_resp); |
635 | kfree(sdata->u.sta.ie_probereq); | ||
636 | kfree(sdata->u.sta.ie_proberesp); | ||
637 | kfree(sdata->u.sta.ie_auth); | ||
638 | kfree(sdata->u.sta.ie_assocreq); | ||
639 | kfree(sdata->u.sta.ie_reassocreq); | ||
640 | kfree(sdata->u.sta.ie_deauth); | ||
641 | kfree(sdata->u.sta.ie_disassoc); | ||
635 | break; | 642 | break; |
636 | case NL80211_IFTYPE_WDS: | 643 | case NL80211_IFTYPE_WDS: |
637 | case NL80211_IFTYPE_AP_VLAN: | 644 | case NL80211_IFTYPE_AP_VLAN: |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f0d42498c257..43da6227b37c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -131,6 +131,12 @@ u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | |||
131 | 131 | ||
132 | /* frame sending functions */ | 132 | /* frame sending functions */ |
133 | 133 | ||
134 | static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) | ||
135 | { | ||
136 | if (ies) | ||
137 | memcpy(skb_put(skb, ies_len), ies, ies_len); | ||
138 | } | ||
139 | |||
134 | /* also used by scanning code */ | 140 | /* also used by scanning code */ |
135 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 141 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
136 | u8 *ssid, size_t ssid_len) | 142 | u8 *ssid, size_t ssid_len) |
@@ -142,7 +148,8 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
142 | u8 *pos, *supp_rates, *esupp_rates = NULL; | 148 | u8 *pos, *supp_rates, *esupp_rates = NULL; |
143 | int i; | 149 | int i; |
144 | 150 | ||
145 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); | 151 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + |
152 | sdata->u.sta.ie_probereq_len); | ||
146 | if (!skb) { | 153 | if (!skb) { |
147 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 154 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " |
148 | "request\n", sdata->dev->name); | 155 | "request\n", sdata->dev->name); |
@@ -189,6 +196,9 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
189 | *pos = rate->bitrate / 5; | 196 | *pos = rate->bitrate / 5; |
190 | } | 197 | } |
191 | 198 | ||
199 | add_extra_ies(skb, sdata->u.sta.ie_probereq, | ||
200 | sdata->u.sta.ie_probereq_len); | ||
201 | |||
192 | ieee80211_tx_skb(sdata, skb, 0); | 202 | ieee80211_tx_skb(sdata, skb, 0); |
193 | } | 203 | } |
194 | 204 | ||
@@ -202,7 +212,8 @@ static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
202 | struct ieee80211_mgmt *mgmt; | 212 | struct ieee80211_mgmt *mgmt; |
203 | 213 | ||
204 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 214 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
205 | sizeof(*mgmt) + 6 + extra_len); | 215 | sizeof(*mgmt) + 6 + extra_len + |
216 | sdata->u.sta.ie_auth_len); | ||
206 | if (!skb) { | 217 | if (!skb) { |
207 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | 218 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " |
208 | "frame\n", sdata->dev->name); | 219 | "frame\n", sdata->dev->name); |
@@ -225,6 +236,7 @@ static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
225 | mgmt->u.auth.status_code = cpu_to_le16(0); | 236 | mgmt->u.auth.status_code = cpu_to_le16(0); |
226 | if (extra) | 237 | if (extra) |
227 | memcpy(skb_put(skb, extra_len), extra, extra_len); | 238 | memcpy(skb_put(skb, extra_len), extra, extra_len); |
239 | add_extra_ies(skb, sdata->u.sta.ie_auth, sdata->u.sta.ie_auth_len); | ||
228 | 240 | ||
229 | ieee80211_tx_skb(sdata, skb, encrypt); | 241 | ieee80211_tx_skb(sdata, skb, encrypt); |
230 | } | 242 | } |
@@ -235,17 +247,26 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
235 | struct ieee80211_local *local = sdata->local; | 247 | struct ieee80211_local *local = sdata->local; |
236 | struct sk_buff *skb; | 248 | struct sk_buff *skb; |
237 | struct ieee80211_mgmt *mgmt; | 249 | struct ieee80211_mgmt *mgmt; |
238 | u8 *pos, *ies, *ht_ie; | 250 | u8 *pos, *ies, *ht_ie, *e_ies; |
239 | int i, len, count, rates_len, supp_rates_len; | 251 | int i, len, count, rates_len, supp_rates_len; |
240 | u16 capab; | 252 | u16 capab; |
241 | struct ieee80211_bss *bss; | 253 | struct ieee80211_bss *bss; |
242 | int wmm = 0; | 254 | int wmm = 0; |
243 | struct ieee80211_supported_band *sband; | 255 | struct ieee80211_supported_band *sband; |
244 | u64 rates = 0; | 256 | u64 rates = 0; |
257 | size_t e_ies_len; | ||
258 | |||
259 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | ||
260 | e_ies = sdata->u.sta.ie_reassocreq; | ||
261 | e_ies_len = sdata->u.sta.ie_reassocreq_len; | ||
262 | } else { | ||
263 | e_ies = sdata->u.sta.ie_assocreq; | ||
264 | e_ies_len = sdata->u.sta.ie_assocreq_len; | ||
265 | } | ||
245 | 266 | ||
246 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 267 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
247 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | 268 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + |
248 | ifsta->ssid_len); | 269 | ifsta->ssid_len + e_ies_len); |
249 | if (!skb) { | 270 | if (!skb) { |
250 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 271 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
251 | "frame\n", sdata->dev->name); | 272 | "frame\n", sdata->dev->name); |
@@ -436,6 +457,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
436 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 457 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
437 | } | 458 | } |
438 | 459 | ||
460 | add_extra_ies(skb, e_ies, e_ies_len); | ||
461 | |||
439 | kfree(ifsta->assocreq_ies); | 462 | kfree(ifsta->assocreq_ies); |
440 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | 463 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; |
441 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | 464 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); |
@@ -453,8 +476,19 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
453 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 476 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; |
454 | struct sk_buff *skb; | 477 | struct sk_buff *skb; |
455 | struct ieee80211_mgmt *mgmt; | 478 | struct ieee80211_mgmt *mgmt; |
479 | u8 *ies; | ||
480 | size_t ies_len; | ||
456 | 481 | ||
457 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); | 482 | if (stype == IEEE80211_STYPE_DEAUTH) { |
483 | ies = sdata->u.sta.ie_deauth; | ||
484 | ies_len = sdata->u.sta.ie_deauth_len; | ||
485 | } else { | ||
486 | ies = sdata->u.sta.ie_disassoc; | ||
487 | ies_len = sdata->u.sta.ie_disassoc_len; | ||
488 | } | ||
489 | |||
490 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + | ||
491 | ies_len); | ||
458 | if (!skb) { | 492 | if (!skb) { |
459 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | 493 | printk(KERN_DEBUG "%s: failed to allocate buffer for " |
460 | "deauth/disassoc frame\n", sdata->dev->name); | 494 | "deauth/disassoc frame\n", sdata->dev->name); |
@@ -472,6 +506,8 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
472 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 506 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
473 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | 507 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); |
474 | 508 | ||
509 | add_extra_ies(skb, ies, ies_len); | ||
510 | |||
475 | ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED); | 511 | ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED); |
476 | } | 512 | } |
477 | 513 | ||
@@ -1473,7 +1509,8 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1473 | struct ieee80211_supported_band *sband; | 1509 | struct ieee80211_supported_band *sband; |
1474 | union iwreq_data wrqu; | 1510 | union iwreq_data wrqu; |
1475 | 1511 | ||
1476 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 1512 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + |
1513 | sdata->u.sta.ie_proberesp_len); | ||
1477 | if (!skb) { | 1514 | if (!skb) { |
1478 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 1515 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " |
1479 | "response\n", sdata->dev->name); | 1516 | "response\n", sdata->dev->name); |
@@ -1556,6 +1593,9 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1556 | memcpy(pos, &bss->supp_rates[8], rates); | 1593 | memcpy(pos, &bss->supp_rates[8], rates); |
1557 | } | 1594 | } |
1558 | 1595 | ||
1596 | add_extra_ies(skb, sdata->u.sta.ie_proberesp, | ||
1597 | sdata->u.sta.ie_proberesp_len); | ||
1598 | |||
1559 | ifsta->probe_resp = skb; | 1599 | ifsta->probe_resp = skb; |
1560 | 1600 | ||
1561 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 1601 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 123d3b160fad..09a5d0f1d6dc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -105,6 +105,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
105 | 105 | ||
106 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 106 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, |
107 | .len = NL80211_HT_CAPABILITY_LEN }, | 107 | .len = NL80211_HT_CAPABILITY_LEN }, |
108 | |||
109 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, | ||
110 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, | ||
111 | .len = IEEE80211_MAX_DATA_LEN }, | ||
108 | }; | 112 | }; |
109 | 113 | ||
110 | /* message building helper */ | 114 | /* message building helper */ |
@@ -2149,6 +2153,43 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2149 | return -EINVAL; | 2153 | return -EINVAL; |
2150 | } | 2154 | } |
2151 | 2155 | ||
2156 | static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb, | ||
2157 | struct genl_info *info) | ||
2158 | { | ||
2159 | struct cfg80211_registered_device *drv; | ||
2160 | int err; | ||
2161 | struct net_device *dev; | ||
2162 | struct mgmt_extra_ie_params params; | ||
2163 | |||
2164 | memset(¶ms, 0, sizeof(params)); | ||
2165 | |||
2166 | if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) | ||
2167 | return -EINVAL; | ||
2168 | params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]); | ||
2169 | if (params.subtype > 15) | ||
2170 | return -EINVAL; /* FC Subtype field is 4 bits (0..15) */ | ||
2171 | |||
2172 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2173 | params.ies = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2174 | params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2175 | } | ||
2176 | |||
2177 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2178 | if (err) | ||
2179 | return err; | ||
2180 | |||
2181 | if (drv->ops->set_mgmt_extra_ie) { | ||
2182 | rtnl_lock(); | ||
2183 | err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, ¶ms); | ||
2184 | rtnl_unlock(); | ||
2185 | } else | ||
2186 | err = -EOPNOTSUPP; | ||
2187 | |||
2188 | cfg80211_put_dev(drv); | ||
2189 | dev_put(dev); | ||
2190 | return err; | ||
2191 | } | ||
2192 | |||
2152 | static struct genl_ops nl80211_ops[] = { | 2193 | static struct genl_ops nl80211_ops[] = { |
2153 | { | 2194 | { |
2154 | .cmd = NL80211_CMD_GET_WIPHY, | 2195 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -2310,6 +2351,12 @@ static struct genl_ops nl80211_ops[] = { | |||
2310 | .policy = nl80211_policy, | 2351 | .policy = nl80211_policy, |
2311 | .flags = GENL_ADMIN_PERM, | 2352 | .flags = GENL_ADMIN_PERM, |
2312 | }, | 2353 | }, |
2354 | { | ||
2355 | .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE, | ||
2356 | .doit = nl80211_set_mgmt_extra_ie, | ||
2357 | .policy = nl80211_policy, | ||
2358 | .flags = GENL_ADMIN_PERM, | ||
2359 | }, | ||
2313 | }; | 2360 | }; |
2314 | 2361 | ||
2315 | /* multicast groups */ | 2362 | /* multicast groups */ |