diff options
author | John W. Linville <linville@tuxdriver.com> | 2011-11-28 14:11:18 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-11-28 14:11:18 -0500 |
commit | 39338b56382ac640614851a80e0bd71994cc664d (patch) | |
tree | c319e23181be286b1d320c29f755a81e5ef61172 /net/wireless | |
parent | 8b7ff200010600ef7cd9d002f9f8f97edfc7578e (diff) | |
parent | eb1852b10593dc3ca73e02bf9ac4753a5a464905 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.h | 10 | ||||
-rw-r--r-- | net/wireless/mlme.c | 37 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 133 | ||||
-rw-r--r-- | net/wireless/reg.c | 39 | ||||
-rw-r--r-- | net/wireless/reg.h | 1 | ||||
-rw-r--r-- | net/wireless/sme.c | 7 | ||||
-rw-r--r-- | net/wireless/util.c | 186 |
7 files changed, 201 insertions, 212 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h index 1c7d4df5418c..fb08c28fc90a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -341,13 +341,17 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
341 | const u8 *bssid, const u8 *prev_bssid, | 341 | const u8 *bssid, const u8 *prev_bssid, |
342 | const u8 *ssid, int ssid_len, | 342 | const u8 *ssid, int ssid_len, |
343 | const u8 *ie, int ie_len, bool use_mfp, | 343 | const u8 *ie, int ie_len, bool use_mfp, |
344 | struct cfg80211_crypto_settings *crypt); | 344 | struct cfg80211_crypto_settings *crypt, |
345 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
346 | struct ieee80211_ht_cap *ht_capa_mask); | ||
345 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 347 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
346 | struct net_device *dev, struct ieee80211_channel *chan, | 348 | struct net_device *dev, struct ieee80211_channel *chan, |
347 | const u8 *bssid, const u8 *prev_bssid, | 349 | const u8 *bssid, const u8 *prev_bssid, |
348 | const u8 *ssid, int ssid_len, | 350 | const u8 *ssid, int ssid_len, |
349 | const u8 *ie, int ie_len, bool use_mfp, | 351 | const u8 *ie, int ie_len, bool use_mfp, |
350 | struct cfg80211_crypto_settings *crypt); | 352 | struct cfg80211_crypto_settings *crypt, |
353 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
354 | struct ieee80211_ht_cap *ht_capa_mask); | ||
351 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | 355 | int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, |
352 | struct net_device *dev, const u8 *bssid, | 356 | struct net_device *dev, const u8 *bssid, |
353 | const u8 *ie, int ie_len, u16 reason, | 357 | const u8 *ie, int ie_len, u16 reason, |
@@ -379,6 +383,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, | |||
379 | bool channel_type_valid, unsigned int wait, | 383 | bool channel_type_valid, unsigned int wait, |
380 | const u8 *buf, size_t len, bool no_cck, | 384 | const u8 *buf, size_t len, bool no_cck, |
381 | bool dont_wait_for_ack, u64 *cookie); | 385 | bool dont_wait_for_ack, u64 *cookie); |
386 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | ||
387 | const struct ieee80211_ht_cap *ht_capa_mask); | ||
382 | 388 | ||
383 | /* SME */ | 389 | /* SME */ |
384 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 390 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 6c1bafd508c8..438dfc105b4a 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -501,13 +501,32 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | |||
501 | return err; | 501 | return err; |
502 | } | 502 | } |
503 | 503 | ||
504 | /* Do a logical ht_capa &= ht_capa_mask. */ | ||
505 | void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa, | ||
506 | const struct ieee80211_ht_cap *ht_capa_mask) | ||
507 | { | ||
508 | int i; | ||
509 | u8 *p1, *p2; | ||
510 | if (!ht_capa_mask) { | ||
511 | memset(ht_capa, 0, sizeof(*ht_capa)); | ||
512 | return; | ||
513 | } | ||
514 | |||
515 | p1 = (u8*)(ht_capa); | ||
516 | p2 = (u8*)(ht_capa_mask); | ||
517 | for (i = 0; i<sizeof(*ht_capa); i++) | ||
518 | p1[i] &= p2[i]; | ||
519 | } | ||
520 | |||
504 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 521 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, |
505 | struct net_device *dev, | 522 | struct net_device *dev, |
506 | struct ieee80211_channel *chan, | 523 | struct ieee80211_channel *chan, |
507 | const u8 *bssid, const u8 *prev_bssid, | 524 | const u8 *bssid, const u8 *prev_bssid, |
508 | const u8 *ssid, int ssid_len, | 525 | const u8 *ssid, int ssid_len, |
509 | const u8 *ie, int ie_len, bool use_mfp, | 526 | const u8 *ie, int ie_len, bool use_mfp, |
510 | struct cfg80211_crypto_settings *crypt) | 527 | struct cfg80211_crypto_settings *crypt, |
528 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
529 | struct ieee80211_ht_cap *ht_capa_mask) | ||
511 | { | 530 | { |
512 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 531 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
513 | struct cfg80211_assoc_request req; | 532 | struct cfg80211_assoc_request req; |
@@ -537,6 +556,15 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
537 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); | 556 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); |
538 | req.use_mfp = use_mfp; | 557 | req.use_mfp = use_mfp; |
539 | req.prev_bssid = prev_bssid; | 558 | req.prev_bssid = prev_bssid; |
559 | req.flags = assoc_flags; | ||
560 | if (ht_capa) | ||
561 | memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa)); | ||
562 | if (ht_capa_mask) | ||
563 | memcpy(&req.ht_capa_mask, ht_capa_mask, | ||
564 | sizeof(req.ht_capa_mask)); | ||
565 | cfg80211_oper_and_ht_capa(&req.ht_capa_mask, | ||
566 | rdev->wiphy.ht_capa_mod_mask); | ||
567 | |||
540 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | 568 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
541 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | 569 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); |
542 | if (!req.bss) { | 570 | if (!req.bss) { |
@@ -574,14 +602,17 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |||
574 | const u8 *bssid, const u8 *prev_bssid, | 602 | const u8 *bssid, const u8 *prev_bssid, |
575 | const u8 *ssid, int ssid_len, | 603 | const u8 *ssid, int ssid_len, |
576 | const u8 *ie, int ie_len, bool use_mfp, | 604 | const u8 *ie, int ie_len, bool use_mfp, |
577 | struct cfg80211_crypto_settings *crypt) | 605 | struct cfg80211_crypto_settings *crypt, |
606 | u32 assoc_flags, struct ieee80211_ht_cap *ht_capa, | ||
607 | struct ieee80211_ht_cap *ht_capa_mask) | ||
578 | { | 608 | { |
579 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 609 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
580 | int err; | 610 | int err; |
581 | 611 | ||
582 | wdev_lock(wdev); | 612 | wdev_lock(wdev); |
583 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 613 | err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
584 | ssid, ssid_len, ie, ie_len, use_mfp, crypt); | 614 | ssid, ssid_len, ie, ie_len, use_mfp, crypt, |
615 | assoc_flags, ht_capa, ht_capa_mask); | ||
585 | wdev_unlock(wdev); | 616 | wdev_unlock(wdev); |
586 | 617 | ||
587 | return err; | 618 | return err; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6bc7c4b32fa5..a1cabde7cb5f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -199,6 +199,11 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
199 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, | 199 | [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG }, |
200 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, | 200 | [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY, |
201 | .len = IEEE80211_MAX_DATA_LEN }, | 201 | .len = IEEE80211_MAX_DATA_LEN }, |
202 | [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 }, | ||
203 | [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG }, | ||
204 | [NL80211_ATTR_HT_CAPABILITY_MASK] = { | ||
205 | .len = NL80211_HT_CAPABILITY_LEN | ||
206 | }, | ||
202 | }; | 207 | }; |
203 | 208 | ||
204 | /* policy for the key attributes */ | 209 | /* policy for the key attributes */ |
@@ -881,7 +886,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
881 | CMD(set_pmksa, SET_PMKSA); | 886 | CMD(set_pmksa, SET_PMKSA); |
882 | CMD(del_pmksa, DEL_PMKSA); | 887 | CMD(del_pmksa, DEL_PMKSA); |
883 | CMD(flush_pmksa, FLUSH_PMKSA); | 888 | CMD(flush_pmksa, FLUSH_PMKSA); |
884 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 889 | if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) |
890 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | ||
885 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | 891 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); |
886 | CMD(mgmt_tx, FRAME); | 892 | CMD(mgmt_tx, FRAME); |
887 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); | 893 | CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL); |
@@ -903,6 +909,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
903 | NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS); | 909 | NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS); |
904 | } | 910 | } |
905 | 911 | ||
912 | #ifdef CONFIG_NL80211_TESTMODE | ||
913 | CMD(testmode_cmd, TESTMODE); | ||
914 | #endif | ||
915 | |||
906 | #undef CMD | 916 | #undef CMD |
907 | 917 | ||
908 | if (dev->ops->connect || dev->ops->auth) { | 918 | if (dev->ops->connect || dev->ops->auth) { |
@@ -917,11 +927,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
917 | 927 | ||
918 | nla_nest_end(msg, nl_cmds); | 928 | nla_nest_end(msg, nl_cmds); |
919 | 929 | ||
920 | if (dev->ops->remain_on_channel) | 930 | if (dev->ops->remain_on_channel && |
931 | dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) | ||
921 | NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | 932 | NLA_PUT_U32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, |
922 | dev->wiphy.max_remain_on_channel_duration); | 933 | dev->wiphy.max_remain_on_channel_duration); |
923 | 934 | ||
924 | if (dev->ops->mgmt_tx_cancel_wait) | 935 | if (dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) |
925 | NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); | 936 | NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK); |
926 | 937 | ||
927 | if (mgmt_stypes) { | 938 | if (mgmt_stypes) { |
@@ -1025,6 +1036,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1025 | 1036 | ||
1026 | NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features); | 1037 | NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features); |
1027 | 1038 | ||
1039 | if (dev->wiphy.ht_capa_mod_mask) | ||
1040 | NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, | ||
1041 | sizeof(*dev->wiphy.ht_capa_mod_mask), | ||
1042 | dev->wiphy.ht_capa_mod_mask); | ||
1043 | |||
1028 | return genlmsg_end(msg, hdr); | 1044 | return genlmsg_end(msg, hdr); |
1029 | 1045 | ||
1030 | nla_put_failure: | 1046 | nla_put_failure: |
@@ -2478,26 +2494,34 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
2478 | /* | 2494 | /* |
2479 | * Get vlan interface making sure it is running and on the right wiphy. | 2495 | * Get vlan interface making sure it is running and on the right wiphy. |
2480 | */ | 2496 | */ |
2481 | static int get_vlan(struct genl_info *info, | 2497 | static struct net_device *get_vlan(struct genl_info *info, |
2482 | struct cfg80211_registered_device *rdev, | 2498 | struct cfg80211_registered_device *rdev) |
2483 | struct net_device **vlan) | ||
2484 | { | 2499 | { |
2485 | struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; | 2500 | struct nlattr *vlanattr = info->attrs[NL80211_ATTR_STA_VLAN]; |
2486 | *vlan = NULL; | 2501 | struct net_device *v; |
2487 | 2502 | int ret; | |
2488 | if (vlanattr) { | 2503 | |
2489 | *vlan = dev_get_by_index(genl_info_net(info), | 2504 | if (!vlanattr) |
2490 | nla_get_u32(vlanattr)); | 2505 | return NULL; |
2491 | if (!*vlan) | 2506 | |
2492 | return -ENODEV; | 2507 | v = dev_get_by_index(genl_info_net(info), nla_get_u32(vlanattr)); |
2493 | if (!(*vlan)->ieee80211_ptr) | 2508 | if (!v) |
2494 | return -EINVAL; | 2509 | return ERR_PTR(-ENODEV); |
2495 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) | 2510 | |
2496 | return -EINVAL; | 2511 | if (!v->ieee80211_ptr || v->ieee80211_ptr->wiphy != &rdev->wiphy) { |
2497 | if (!netif_running(*vlan)) | 2512 | ret = -EINVAL; |
2498 | return -ENETDOWN; | 2513 | goto error; |
2499 | } | 2514 | } |
2500 | return 0; | 2515 | |
2516 | if (!netif_running(v)) { | ||
2517 | ret = -ENETDOWN; | ||
2518 | goto error; | ||
2519 | } | ||
2520 | |||
2521 | return v; | ||
2522 | error: | ||
2523 | dev_put(v); | ||
2524 | return ERR_PTR(ret); | ||
2501 | } | 2525 | } |
2502 | 2526 | ||
2503 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 2527 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
@@ -2547,9 +2571,9 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2547 | params.plink_state = | 2571 | params.plink_state = |
2548 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); | 2572 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); |
2549 | 2573 | ||
2550 | err = get_vlan(info, rdev, ¶ms.vlan); | 2574 | params.vlan = get_vlan(info, rdev); |
2551 | if (err) | 2575 | if (IS_ERR(params.vlan)) |
2552 | goto out; | 2576 | return PTR_ERR(params.vlan); |
2553 | 2577 | ||
2554 | /* validate settings */ | 2578 | /* validate settings */ |
2555 | err = 0; | 2579 | err = 0; |
@@ -2717,9 +2741,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2717 | (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))) | 2741 | (rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))) |
2718 | return -EINVAL; | 2742 | return -EINVAL; |
2719 | 2743 | ||
2720 | err = get_vlan(info, rdev, ¶ms.vlan); | 2744 | params.vlan = get_vlan(info, rdev); |
2721 | if (err) | 2745 | if (IS_ERR(params.vlan)) |
2722 | goto out; | 2746 | return PTR_ERR(params.vlan); |
2723 | 2747 | ||
2724 | /* validate settings */ | 2748 | /* validate settings */ |
2725 | err = 0; | 2749 | err = 0; |
@@ -3382,6 +3406,9 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
3382 | 3406 | ||
3383 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, | 3407 | NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, |
3384 | cfg80211_regdomain->alpha2); | 3408 | cfg80211_regdomain->alpha2); |
3409 | if (cfg80211_regdomain->dfs_region) | ||
3410 | NLA_PUT_U8(msg, NL80211_ATTR_DFS_REGION, | ||
3411 | cfg80211_regdomain->dfs_region); | ||
3385 | 3412 | ||
3386 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 3413 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
3387 | if (!nl_reg_rules) | 3414 | if (!nl_reg_rules) |
@@ -3440,6 +3467,7 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3440 | char *alpha2 = NULL; | 3467 | char *alpha2 = NULL; |
3441 | int rem_reg_rules = 0, r = 0; | 3468 | int rem_reg_rules = 0, r = 0; |
3442 | u32 num_rules = 0, rule_idx = 0, size_of_regd; | 3469 | u32 num_rules = 0, rule_idx = 0, size_of_regd; |
3470 | u8 dfs_region = 0; | ||
3443 | struct ieee80211_regdomain *rd = NULL; | 3471 | struct ieee80211_regdomain *rd = NULL; |
3444 | 3472 | ||
3445 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 3473 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
@@ -3450,6 +3478,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3450 | 3478 | ||
3451 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 3479 | alpha2 = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
3452 | 3480 | ||
3481 | if (info->attrs[NL80211_ATTR_DFS_REGION]) | ||
3482 | dfs_region = nla_get_u8(info->attrs[NL80211_ATTR_DFS_REGION]); | ||
3483 | |||
3453 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 3484 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
3454 | rem_reg_rules) { | 3485 | rem_reg_rules) { |
3455 | num_rules++; | 3486 | num_rules++; |
@@ -3477,6 +3508,13 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3477 | rd->alpha2[0] = alpha2[0]; | 3508 | rd->alpha2[0] = alpha2[0]; |
3478 | rd->alpha2[1] = alpha2[1]; | 3509 | rd->alpha2[1] = alpha2[1]; |
3479 | 3510 | ||
3511 | /* | ||
3512 | * Disable DFS master mode if the DFS region was | ||
3513 | * not supported or known on this kernel. | ||
3514 | */ | ||
3515 | if (reg_supported_dfs_region(dfs_region)) | ||
3516 | rd->dfs_region = dfs_region; | ||
3517 | |||
3480 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], | 3518 | nla_for_each_nested(nl_reg_rule, info->attrs[NL80211_ATTR_REG_RULES], |
3481 | rem_reg_rules) { | 3519 | rem_reg_rules) { |
3482 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, | 3520 | nla_parse(tb, NL80211_REG_RULE_ATTR_MAX, |
@@ -4384,6 +4422,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
4384 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 4422 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
4385 | int err, ssid_len, ie_len = 0; | 4423 | int err, ssid_len, ie_len = 0; |
4386 | bool use_mfp = false; | 4424 | bool use_mfp = false; |
4425 | u32 flags = 0; | ||
4426 | struct ieee80211_ht_cap *ht_capa = NULL; | ||
4427 | struct ieee80211_ht_cap *ht_capa_mask = NULL; | ||
4387 | 4428 | ||
4388 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 4429 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
4389 | return -EINVAL; | 4430 | return -EINVAL; |
@@ -4427,11 +4468,25 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
4427 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) | 4468 | if (info->attrs[NL80211_ATTR_PREV_BSSID]) |
4428 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); | 4469 | prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]); |
4429 | 4470 | ||
4471 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) | ||
4472 | flags |= ASSOC_REQ_DISABLE_HT; | ||
4473 | |||
4474 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
4475 | ht_capa_mask = | ||
4476 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]); | ||
4477 | |||
4478 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | ||
4479 | if (!ht_capa_mask) | ||
4480 | return -EINVAL; | ||
4481 | ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
4482 | } | ||
4483 | |||
4430 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); | 4484 | err = nl80211_crypto_settings(rdev, info, &crypto, 1); |
4431 | if (!err) | 4485 | if (!err) |
4432 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, | 4486 | err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, |
4433 | ssid, ssid_len, ie, ie_len, use_mfp, | 4487 | ssid, ssid_len, ie, ie_len, use_mfp, |
4434 | &crypto); | 4488 | &crypto, flags, ht_capa, |
4489 | ht_capa_mask); | ||
4435 | 4490 | ||
4436 | return err; | 4491 | return err; |
4437 | } | 4492 | } |
@@ -4921,6 +4976,22 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | |||
4921 | return PTR_ERR(connkeys); | 4976 | return PTR_ERR(connkeys); |
4922 | } | 4977 | } |
4923 | 4978 | ||
4979 | if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT])) | ||
4980 | connect.flags |= ASSOC_REQ_DISABLE_HT; | ||
4981 | |||
4982 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
4983 | memcpy(&connect.ht_capa_mask, | ||
4984 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]), | ||
4985 | sizeof(connect.ht_capa_mask)); | ||
4986 | |||
4987 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) { | ||
4988 | if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) | ||
4989 | return -EINVAL; | ||
4990 | memcpy(&connect.ht_capa, | ||
4991 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]), | ||
4992 | sizeof(connect.ht_capa)); | ||
4993 | } | ||
4994 | |||
4924 | err = cfg80211_connect(rdev, dev, &connect, connkeys); | 4995 | err = cfg80211_connect(rdev, dev, &connect, connkeys); |
4925 | if (err) | 4996 | if (err) |
4926 | kfree(connkeys); | 4997 | kfree(connkeys); |
@@ -5108,7 +5179,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5108 | duration > rdev->wiphy.max_remain_on_channel_duration) | 5179 | duration > rdev->wiphy.max_remain_on_channel_duration) |
5109 | return -EINVAL; | 5180 | return -EINVAL; |
5110 | 5181 | ||
5111 | if (!rdev->ops->remain_on_channel) | 5182 | if (!rdev->ops->remain_on_channel || |
5183 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) | ||
5112 | return -EOPNOTSUPP; | 5184 | return -EOPNOTSUPP; |
5113 | 5185 | ||
5114 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 5186 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
@@ -5321,7 +5393,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5321 | return -EOPNOTSUPP; | 5393 | return -EOPNOTSUPP; |
5322 | 5394 | ||
5323 | if (info->attrs[NL80211_ATTR_DURATION]) { | 5395 | if (info->attrs[NL80211_ATTR_DURATION]) { |
5324 | if (!rdev->ops->mgmt_tx_cancel_wait) | 5396 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
5325 | return -EINVAL; | 5397 | return -EINVAL; |
5326 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 5398 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
5327 | } | 5399 | } |
@@ -5339,6 +5411,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5339 | 5411 | ||
5340 | offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; | 5412 | offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK]; |
5341 | 5413 | ||
5414 | if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | ||
5415 | return -EINVAL; | ||
5416 | |||
5342 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 5417 | no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
5343 | 5418 | ||
5344 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 5419 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 77e926738014..76b35df39623 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1123,6 +1123,8 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, | |||
1123 | if (ignore_reg_update(wiphy, initiator)) | 1123 | if (ignore_reg_update(wiphy, initiator)) |
1124 | return; | 1124 | return; |
1125 | 1125 | ||
1126 | last_request->dfs_region = cfg80211_regdomain->dfs_region; | ||
1127 | |||
1126 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1128 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1127 | if (wiphy->bands[band]) | 1129 | if (wiphy->bands[band]) |
1128 | handle_band(wiphy, band, initiator); | 1130 | handle_band(wiphy, band, initiator); |
@@ -1948,6 +1950,42 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
1948 | } | 1950 | } |
1949 | } | 1951 | } |
1950 | 1952 | ||
1953 | bool reg_supported_dfs_region(u8 dfs_region) | ||
1954 | { | ||
1955 | switch (dfs_region) { | ||
1956 | case NL80211_DFS_UNSET: | ||
1957 | case NL80211_DFS_FCC: | ||
1958 | case NL80211_DFS_ETSI: | ||
1959 | case NL80211_DFS_JP: | ||
1960 | return true; | ||
1961 | default: | ||
1962 | REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n", | ||
1963 | dfs_region); | ||
1964 | return false; | ||
1965 | } | ||
1966 | } | ||
1967 | |||
1968 | static void print_dfs_region(u8 dfs_region) | ||
1969 | { | ||
1970 | if (!dfs_region) | ||
1971 | return; | ||
1972 | |||
1973 | switch (dfs_region) { | ||
1974 | case NL80211_DFS_FCC: | ||
1975 | pr_info(" DFS Master region FCC"); | ||
1976 | break; | ||
1977 | case NL80211_DFS_ETSI: | ||
1978 | pr_info(" DFS Master region ETSI"); | ||
1979 | break; | ||
1980 | case NL80211_DFS_JP: | ||
1981 | pr_info(" DFS Master region JP"); | ||
1982 | break; | ||
1983 | default: | ||
1984 | pr_info(" DFS Master region Uknown"); | ||
1985 | break; | ||
1986 | } | ||
1987 | } | ||
1988 | |||
1951 | static void print_regdomain(const struct ieee80211_regdomain *rd) | 1989 | static void print_regdomain(const struct ieee80211_regdomain *rd) |
1952 | { | 1990 | { |
1953 | 1991 | ||
@@ -1975,6 +2013,7 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
1975 | pr_info("Regulatory domain changed to country: %c%c\n", | 2013 | pr_info("Regulatory domain changed to country: %c%c\n", |
1976 | rd->alpha2[0], rd->alpha2[1]); | 2014 | rd->alpha2[0], rd->alpha2[1]); |
1977 | } | 2015 | } |
2016 | print_dfs_region(rd->dfs_region); | ||
1978 | print_rd_rules(rd); | 2017 | print_rd_rules(rd); |
1979 | } | 2018 | } |
1980 | 2019 | ||
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 4a56799d868d..786e414afd91 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -5,6 +5,7 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain; | |||
5 | 5 | ||
6 | bool is_world_regdom(const char *alpha2); | 6 | bool is_world_regdom(const char *alpha2); |
7 | bool reg_is_valid_request(const char *alpha2); | 7 | bool reg_is_valid_request(const char *alpha2); |
8 | bool reg_supported_dfs_region(u8 dfs_region); | ||
8 | 9 | ||
9 | int regulatory_hint_user(const char *alpha2); | 10 | int regulatory_hint_user(const char *alpha2); |
10 | 11 | ||
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 0acfdc9beacf..f0c900ce2fb9 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -190,7 +190,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) | |||
190 | prev_bssid, | 190 | prev_bssid, |
191 | params->ssid, params->ssid_len, | 191 | params->ssid, params->ssid_len, |
192 | params->ie, params->ie_len, | 192 | params->ie, params->ie_len, |
193 | false, ¶ms->crypto); | 193 | false, ¶ms->crypto, |
194 | params->flags, ¶ms->ht_capa, | ||
195 | ¶ms->ht_capa_mask); | ||
194 | if (err) | 196 | if (err) |
195 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, | 197 | __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, |
196 | NULL, 0, | 198 | NULL, 0, |
@@ -774,6 +776,9 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, | |||
774 | wdev->connect_keys = NULL; | 776 | wdev->connect_keys = NULL; |
775 | } | 777 | } |
776 | 778 | ||
779 | cfg80211_oper_and_ht_capa(&connect->ht_capa_mask, | ||
780 | rdev->wiphy.ht_capa_mod_mask); | ||
781 | |||
777 | if (connkeys && connkeys->def >= 0) { | 782 | if (connkeys && connkeys->def >= 0) { |
778 | int idx; | 783 | int idx; |
779 | u32 cipher; | 784 | u32 cipher; |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 4dde429441d2..9c601d59b77a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/bitops.h> | 7 | #include <linux/bitops.h> |
8 | #include <linux/etherdevice.h> | 8 | #include <linux/etherdevice.h> |
9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
10 | #include <linux/crc32.h> | ||
11 | #include <net/cfg80211.h> | 10 | #include <net/cfg80211.h> |
12 | #include <net/ip.h> | 11 | #include <net/ip.h> |
13 | #include "core.h" | 12 | #include "core.h" |
@@ -240,17 +239,6 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
240 | return 0; | 239 | return 0; |
241 | } | 240 | } |
242 | 241 | ||
243 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | ||
244 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | ||
245 | const unsigned char rfc1042_header[] __aligned(2) = | ||
246 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
247 | EXPORT_SYMBOL(rfc1042_header); | ||
248 | |||
249 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | ||
250 | const unsigned char bridge_tunnel_header[] __aligned(2) = | ||
251 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | ||
252 | EXPORT_SYMBOL(bridge_tunnel_header); | ||
253 | |||
254 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) | 242 | unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc) |
255 | { | 243 | { |
256 | unsigned int hdrlen = 24; | 244 | unsigned int hdrlen = 24; |
@@ -1051,169 +1039,13 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | |||
1051 | return 0; | 1039 | return 0; |
1052 | } | 1040 | } |
1053 | 1041 | ||
1054 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | 1042 | /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ |
1055 | struct ieee802_11_elems *elems, | 1043 | /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ |
1056 | u64 filter, u32 crc) | 1044 | const unsigned char rfc1042_header[] __aligned(2) = |
1057 | { | 1045 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; |
1058 | size_t left = len; | 1046 | EXPORT_SYMBOL(rfc1042_header); |
1059 | u8 *pos = start; | ||
1060 | bool calc_crc = filter != 0; | ||
1061 | |||
1062 | memset(elems, 0, sizeof(*elems)); | ||
1063 | elems->ie_start = start; | ||
1064 | elems->total_len = len; | ||
1065 | |||
1066 | while (left >= 2) { | ||
1067 | u8 id, elen; | ||
1068 | |||
1069 | id = *pos++; | ||
1070 | elen = *pos++; | ||
1071 | left -= 2; | ||
1072 | |||
1073 | if (elen > left) | ||
1074 | break; | ||
1075 | |||
1076 | if (calc_crc && id < 64 && (filter & (1ULL << id))) | ||
1077 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
1078 | |||
1079 | switch (id) { | ||
1080 | case WLAN_EID_SSID: | ||
1081 | elems->ssid = pos; | ||
1082 | elems->ssid_len = elen; | ||
1083 | break; | ||
1084 | case WLAN_EID_SUPP_RATES: | ||
1085 | elems->supp_rates = pos; | ||
1086 | elems->supp_rates_len = elen; | ||
1087 | break; | ||
1088 | case WLAN_EID_FH_PARAMS: | ||
1089 | elems->fh_params = pos; | ||
1090 | elems->fh_params_len = elen; | ||
1091 | break; | ||
1092 | case WLAN_EID_DS_PARAMS: | ||
1093 | elems->ds_params = pos; | ||
1094 | elems->ds_params_len = elen; | ||
1095 | break; | ||
1096 | case WLAN_EID_CF_PARAMS: | ||
1097 | elems->cf_params = pos; | ||
1098 | elems->cf_params_len = elen; | ||
1099 | break; | ||
1100 | case WLAN_EID_TIM: | ||
1101 | if (elen >= sizeof(struct ieee80211_tim_ie)) { | ||
1102 | elems->tim = (void *)pos; | ||
1103 | elems->tim_len = elen; | ||
1104 | } | ||
1105 | break; | ||
1106 | case WLAN_EID_IBSS_PARAMS: | ||
1107 | elems->ibss_params = pos; | ||
1108 | elems->ibss_params_len = elen; | ||
1109 | break; | ||
1110 | case WLAN_EID_CHALLENGE: | ||
1111 | elems->challenge = pos; | ||
1112 | elems->challenge_len = elen; | ||
1113 | break; | ||
1114 | case WLAN_EID_VENDOR_SPECIFIC: | ||
1115 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && | ||
1116 | pos[2] == 0xf2) { | ||
1117 | /* Microsoft OUI (00:50:F2) */ | ||
1118 | |||
1119 | if (calc_crc) | ||
1120 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
1121 | |||
1122 | if (pos[3] == 1) { | ||
1123 | /* OUI Type 1 - WPA IE */ | ||
1124 | elems->wpa = pos; | ||
1125 | elems->wpa_len = elen; | ||
1126 | } else if (elen >= 5 && pos[3] == 2) { | ||
1127 | /* OUI Type 2 - WMM IE */ | ||
1128 | if (pos[4] == 0) { | ||
1129 | elems->wmm_info = pos; | ||
1130 | elems->wmm_info_len = elen; | ||
1131 | } else if (pos[4] == 1) { | ||
1132 | elems->wmm_param = pos; | ||
1133 | elems->wmm_param_len = elen; | ||
1134 | } | ||
1135 | } | ||
1136 | } | ||
1137 | break; | ||
1138 | case WLAN_EID_RSN: | ||
1139 | elems->rsn = pos; | ||
1140 | elems->rsn_len = elen; | ||
1141 | break; | ||
1142 | case WLAN_EID_ERP_INFO: | ||
1143 | elems->erp_info = pos; | ||
1144 | elems->erp_info_len = elen; | ||
1145 | break; | ||
1146 | case WLAN_EID_EXT_SUPP_RATES: | ||
1147 | elems->ext_supp_rates = pos; | ||
1148 | elems->ext_supp_rates_len = elen; | ||
1149 | break; | ||
1150 | case WLAN_EID_HT_CAPABILITY: | ||
1151 | if (elen >= sizeof(struct ieee80211_ht_cap)) | ||
1152 | elems->ht_cap_elem = (void *)pos; | ||
1153 | break; | ||
1154 | case WLAN_EID_HT_INFORMATION: | ||
1155 | if (elen >= sizeof(struct ieee80211_ht_info)) | ||
1156 | elems->ht_info_elem = (void *)pos; | ||
1157 | break; | ||
1158 | case WLAN_EID_MESH_ID: | ||
1159 | elems->mesh_id = pos; | ||
1160 | elems->mesh_id_len = elen; | ||
1161 | break; | ||
1162 | case WLAN_EID_MESH_CONFIG: | ||
1163 | if (elen >= sizeof(struct ieee80211_meshconf_ie)) | ||
1164 | elems->mesh_config = (void *)pos; | ||
1165 | break; | ||
1166 | case WLAN_EID_PEER_MGMT: | ||
1167 | elems->peering = pos; | ||
1168 | elems->peering_len = elen; | ||
1169 | break; | ||
1170 | case WLAN_EID_PREQ: | ||
1171 | elems->preq = pos; | ||
1172 | elems->preq_len = elen; | ||
1173 | break; | ||
1174 | case WLAN_EID_PREP: | ||
1175 | elems->prep = pos; | ||
1176 | elems->prep_len = elen; | ||
1177 | break; | ||
1178 | case WLAN_EID_PERR: | ||
1179 | elems->perr = pos; | ||
1180 | elems->perr_len = elen; | ||
1181 | break; | ||
1182 | case WLAN_EID_RANN: | ||
1183 | if (elen >= sizeof(struct ieee80211_rann_ie)) | ||
1184 | elems->rann = (void *)pos; | ||
1185 | break; | ||
1186 | case WLAN_EID_CHANNEL_SWITCH: | ||
1187 | elems->ch_switch_elem = pos; | ||
1188 | elems->ch_switch_elem_len = elen; | ||
1189 | break; | ||
1190 | case WLAN_EID_QUIET: | ||
1191 | if (!elems->quiet_elem) { | ||
1192 | elems->quiet_elem = pos; | ||
1193 | elems->quiet_elem_len = elen; | ||
1194 | } | ||
1195 | elems->num_of_quiet_elem++; | ||
1196 | break; | ||
1197 | case WLAN_EID_COUNTRY: | ||
1198 | elems->country_elem = pos; | ||
1199 | elems->country_elem_len = elen; | ||
1200 | break; | ||
1201 | case WLAN_EID_PWR_CONSTRAINT: | ||
1202 | elems->pwr_constr_elem = pos; | ||
1203 | elems->pwr_constr_elem_len = elen; | ||
1204 | break; | ||
1205 | case WLAN_EID_TIMEOUT_INTERVAL: | ||
1206 | elems->timeout_int = pos; | ||
1207 | elems->timeout_int_len = elen; | ||
1208 | break; | ||
1209 | default: | ||
1210 | break; | ||
1211 | } | ||
1212 | |||
1213 | left -= elen; | ||
1214 | pos += elen; | ||
1215 | } | ||
1216 | 1047 | ||
1217 | return crc; | 1048 | /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ |
1218 | } | 1049 | const unsigned char bridge_tunnel_header[] __aligned(2) = |
1219 | EXPORT_SYMBOL(ieee802_11_parse_elems_crc); | 1050 | { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; |
1051 | EXPORT_SYMBOL(bridge_tunnel_header); | ||