aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2009-01-13 09:03:29 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:00:35 -0500
commit9aed3cc124343d92be6697e9af3928bdfe8eb03e (patch)
tree6a49a68422656790f944f37e3f34379b753d1dab
parent0c1aa495961f03c964b3287cf5800217cf6f2cee (diff)
nl80211: New command for adding extra IE(s) into management frames
A new nl80211 command, NL80211_CMD_SET_MGMT_EXTRA_IE, can be used to add arbitrary IE data into the end of management frames. The interface allows extra IEs to be configured for each management frame subtype, but only some of them (ProbeReq, ProbeResp, Auth, (Re)AssocReq, Deauth, Disassoc) are currently accepted in mac80211 implementation. This makes it easier to implement IEEE 802.11 extensions like WPS and FT that add IE(s) into some management frames. In addition, this can be useful for testing and experimentation purposes. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/nl80211.h22
-rw-r--r--include/net/cfg80211.h26
-rw-r--r--net/mac80211/cfg.c82
-rw-r--r--net/mac80211/ieee80211_i.h16
-rw-r--r--net/mac80211/iface.c7
-rw-r--r--net/mac80211/mlme.c52
-rw-r--r--net/wireless/nl80211.c47
7 files changed, 246 insertions, 6 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 4e7a7986a521..76aae3d8e97e 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -133,6 +133,14 @@
133 * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the 133 * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
134 * interface identified by %NL80211_ATTR_IFINDEX 134 * interface identified by %NL80211_ATTR_IFINDEX
135 * 135 *
136 * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
137 * interface is identified with %NL80211_ATTR_IFINDEX and the management
138 * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
139 * added to the end of the specified management frame is specified with
140 * %NL80211_ATTR_IE. If the command succeeds, the requested data will be
141 * added to all specified management frames generated by
142 * kernel/firmware/driver.
143 *
136 * @NL80211_CMD_MAX: highest used command number 144 * @NL80211_CMD_MAX: highest used command number
137 * @__NL80211_CMD_AFTER_LAST: internal use 145 * @__NL80211_CMD_AFTER_LAST: internal use
138 */ 146 */
@@ -178,6 +186,8 @@ enum nl80211_commands {
178 NL80211_CMD_GET_MESH_PARAMS, 186 NL80211_CMD_GET_MESH_PARAMS,
179 NL80211_CMD_SET_MESH_PARAMS, 187 NL80211_CMD_SET_MESH_PARAMS,
180 188
189 NL80211_CMD_SET_MGMT_EXTRA_IE,
190
181 /* add new commands above here */ 191 /* add new commands above here */
182 192
183 /* used to define NL80211_CMD_MAX below */ 193 /* used to define NL80211_CMD_MAX below */
@@ -190,6 +200,7 @@ enum nl80211_commands {
190 * here 200 * here
191 */ 201 */
192#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS 202#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
203#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
193 204
194/** 205/**
195 * enum nl80211_attrs - nl80211 netlink attributes 206 * enum nl80211_attrs - nl80211 netlink attributes
@@ -284,6 +295,12 @@ enum nl80211_commands {
284 * supported interface types, each a flag attribute with the number 295 * supported interface types, each a flag attribute with the number
285 * of the interface mode. 296 * of the interface mode.
286 * 297 *
298 * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for
299 * %NL80211_CMD_SET_MGMT_EXTRA_IE.
300 *
301 * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
302 * %NL80211_CMD_SET_MGMT_EXTRA_IE).
303 *
287 * @NL80211_ATTR_MAX: highest attribute number currently defined 304 * @NL80211_ATTR_MAX: highest attribute number currently defined
288 * @__NL80211_ATTR_AFTER_LAST: internal use 305 * @__NL80211_ATTR_AFTER_LAST: internal use
289 */ 306 */
@@ -348,6 +365,9 @@ enum nl80211_attrs {
348 365
349 NL80211_ATTR_KEY_DEFAULT_MGMT, 366 NL80211_ATTR_KEY_DEFAULT_MGMT,
350 367
368 NL80211_ATTR_MGMT_SUBTYPE,
369 NL80211_ATTR_IE,
370
351 /* add attributes here, update the policy in nl80211.c */ 371 /* add attributes here, update the policy in nl80211.c */
352 372
353 __NL80211_ATTR_AFTER_LAST, 373 __NL80211_ATTR_AFTER_LAST,
@@ -363,6 +383,8 @@ enum nl80211_attrs {
363#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS 383#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
364#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ 384#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
365#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE 385#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
386#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
387#define NL80211_ATTR_IE NL80211_ATTR_IE
366 388
367#define NL80211_MAX_SUPP_RATES 32 389#define NL80211_MAX_SUPP_RATES 32
368#define NL80211_MAX_SUPP_REG_RULES 32 390#define NL80211_MAX_SUPP_REG_RULES 32
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index df78abc496f1..c7da88fb15b7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -433,6 +433,26 @@ struct ieee80211_txq_params {
433 u8 aifs; 433 u8 aifs;
434}; 434};
435 435
436/**
437 * struct mgmt_extra_ie_params - Extra management frame IE parameters
438 *
439 * Used to add extra IE(s) into management frames. If the driver cannot add the
440 * requested data into all management frames of the specified subtype that are
441 * generated in kernel or firmware/hardware, it must reject the configuration
442 * call. The IE data buffer is added to the end of the specified management
443 * frame body after all other IEs. This addition is not applied to frames that
444 * are injected through a monitor interface.
445 *
446 * @subtype: Management frame subtype
447 * @ies: IE data buffer or %NULL to remove previous data
448 * @ies_len: Length of @ies in octets
449 */
450struct mgmt_extra_ie_params {
451 u8 subtype;
452 u8 *ies;
453 int ies_len;
454};
455
436/* from net/wireless.h */ 456/* from net/wireless.h */
437struct wiphy; 457struct wiphy;
438 458
@@ -501,6 +521,8 @@ struct ieee80211_channel;
501 * @set_txq_params: Set TX queue parameters 521 * @set_txq_params: Set TX queue parameters
502 * 522 *
503 * @set_channel: Set channel 523 * @set_channel: Set channel
524 *
525 * @set_mgmt_extra_ie: Set extra IE data for management frames
504 */ 526 */
505struct cfg80211_ops { 527struct cfg80211_ops {
506 int (*add_virtual_intf)(struct wiphy *wiphy, char *name, 528 int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -571,6 +593,10 @@ struct cfg80211_ops {
571 int (*set_channel)(struct wiphy *wiphy, 593 int (*set_channel)(struct wiphy *wiphy,
572 struct ieee80211_channel *chan, 594 struct ieee80211_channel *chan,
573 enum nl80211_channel_type channel_type); 595 enum nl80211_channel_type channel_type);
596
597 int (*set_mgmt_extra_ie)(struct wiphy *wiphy,
598 struct net_device *dev,
599 struct mgmt_extra_ie_params *params);
574}; 600};
575 601
576/* temporary wext handlers */ 602/* temporary wext handlers */
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
1178static 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
1222static 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
1178struct cfg80211_ops mac80211_config_ops = { 1259struct 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
336struct ieee80211_if_mesh { 352struct 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
134static 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 */
135void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 141void 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
2156static 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(&params, 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, &params);
2184 rtnl_unlock();
2185 } else
2186 err = -EOPNOTSUPP;
2187
2188 cfg80211_put_dev(drv);
2189 dev_put(dev);
2190 return err;
2191}
2192
2152static struct genl_ops nl80211_ops[] = { 2193static 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 */