aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
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 */