aboutsummaryrefslogtreecommitdiffstats
path: root/net
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 /net
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>
Diffstat (limited to 'net')
-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
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
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 */