diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 358 |
1 files changed, 324 insertions, 34 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index cea338150d0..fb18bb4dea7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -83,8 +83,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
83 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 83 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
84 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, | 84 | [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, |
85 | 85 | ||
86 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 86 | [NL80211_ATTR_MAC] = { .len = ETH_ALEN }, |
87 | [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 87 | [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN }, |
88 | 88 | ||
89 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, | 89 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, |
90 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, | 90 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, |
@@ -126,8 +126,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
126 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, | 126 | [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, |
127 | [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, | 127 | [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, |
128 | 128 | ||
129 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 129 | [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN }, |
130 | .len = NL80211_HT_CAPABILITY_LEN }, | ||
131 | 130 | ||
132 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, | 131 | [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, |
133 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, | 132 | [NL80211_ATTR_IE] = { .type = NLA_BINARY, |
@@ -176,6 +175,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
176 | [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, | 175 | [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, |
177 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, | 176 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, |
178 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, | 177 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, |
178 | [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, | ||
179 | [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED }, | ||
179 | }; | 180 | }; |
180 | 181 | ||
181 | /* policy for the key attributes */ | 182 | /* policy for the key attributes */ |
@@ -204,6 +205,18 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
204 | [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, | 205 | [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, |
205 | [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, | 206 | [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, |
206 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, | 207 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, |
208 | [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG }, | ||
209 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, | ||
210 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, | ||
211 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, | ||
212 | }; | ||
213 | |||
214 | /* policy for GTK rekey offload attributes */ | ||
215 | static const struct nla_policy | ||
216 | nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { | ||
217 | [NL80211_REKEY_DATA_KEK] = { .len = NL80211_KEK_LEN }, | ||
218 | [NL80211_REKEY_DATA_KCK] = { .len = NL80211_KCK_LEN }, | ||
219 | [NL80211_REKEY_DATA_REPLAY_CTR] = { .len = NL80211_REPLAY_CTR_LEN }, | ||
207 | }; | 220 | }; |
208 | 221 | ||
209 | /* ifidx get helper */ | 222 | /* ifidx get helper */ |
@@ -683,8 +696,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
683 | dev->wiphy.coverage_class); | 696 | dev->wiphy.coverage_class); |
684 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 697 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
685 | dev->wiphy.max_scan_ssids); | 698 | dev->wiphy.max_scan_ssids); |
699 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, | ||
700 | dev->wiphy.max_sched_scan_ssids); | ||
686 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | 701 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, |
687 | dev->wiphy.max_scan_ie_len); | 702 | dev->wiphy.max_scan_ie_len); |
703 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, | ||
704 | dev->wiphy.max_sched_scan_ie_len); | ||
688 | 705 | ||
689 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) | 706 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) |
690 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); | 707 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); |
@@ -920,6 +937,16 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
920 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | 937 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); |
921 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) | 938 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) |
922 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | 939 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); |
940 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) | ||
941 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED); | ||
942 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) | ||
943 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); | ||
944 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) | ||
945 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); | ||
946 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) | ||
947 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); | ||
948 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) | ||
949 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); | ||
923 | if (dev->wiphy.wowlan.n_patterns) { | 950 | if (dev->wiphy.wowlan.n_patterns) { |
924 | struct nl80211_wowlan_pattern_support pat = { | 951 | struct nl80211_wowlan_pattern_support pat = { |
925 | .max_patterns = dev->wiphy.wowlan.n_patterns, | 952 | .max_patterns = dev->wiphy.wowlan.n_patterns, |
@@ -2209,6 +2236,10 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
2209 | } | 2236 | } |
2210 | nla_nest_end(msg, sinfoattr); | 2237 | nla_nest_end(msg, sinfoattr); |
2211 | 2238 | ||
2239 | if (sinfo->assoc_req_ies) | ||
2240 | NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, | ||
2241 | sinfo->assoc_req_ies); | ||
2242 | |||
2212 | return genlmsg_end(msg, hdr); | 2243 | return genlmsg_end(msg, hdr); |
2213 | 2244 | ||
2214 | nla_put_failure: | 2245 | nla_put_failure: |
@@ -2236,6 +2267,7 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
2236 | } | 2267 | } |
2237 | 2268 | ||
2238 | while (1) { | 2269 | while (1) { |
2270 | memset(&sinfo, 0, sizeof(sinfo)); | ||
2239 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, | 2271 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, |
2240 | mac_addr, &sinfo); | 2272 | mac_addr, &sinfo); |
2241 | if (err == -ENOENT) | 2273 | if (err == -ENOENT) |
@@ -3297,7 +3329,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3297 | struct nlattr *attr; | 3329 | struct nlattr *attr; |
3298 | struct wiphy *wiphy; | 3330 | struct wiphy *wiphy; |
3299 | int err, tmp, n_ssids = 0, n_channels, i; | 3331 | int err, tmp, n_ssids = 0, n_channels, i; |
3300 | enum ieee80211_band band; | ||
3301 | size_t ie_len; | 3332 | size_t ie_len; |
3302 | 3333 | ||
3303 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3334 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
@@ -3317,6 +3348,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3317 | if (!n_channels) | 3348 | if (!n_channels) |
3318 | return -EINVAL; | 3349 | return -EINVAL; |
3319 | } else { | 3350 | } else { |
3351 | enum ieee80211_band band; | ||
3320 | n_channels = 0; | 3352 | n_channels = 0; |
3321 | 3353 | ||
3322 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 3354 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) |
@@ -3377,6 +3409,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3377 | i++; | 3409 | i++; |
3378 | } | 3410 | } |
3379 | } else { | 3411 | } else { |
3412 | enum ieee80211_band band; | ||
3413 | |||
3380 | /* all channels */ | 3414 | /* all channels */ |
3381 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 3415 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
3382 | int j; | 3416 | int j; |
@@ -3423,6 +3457,30 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3423 | request->ie_len); | 3457 | request->ie_len); |
3424 | } | 3458 | } |
3425 | 3459 | ||
3460 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
3461 | if (wiphy->bands[i]) | ||
3462 | request->rates[i] = | ||
3463 | (1 << wiphy->bands[i]->n_bitrates) - 1; | ||
3464 | |||
3465 | if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) { | ||
3466 | nla_for_each_nested(attr, | ||
3467 | info->attrs[NL80211_ATTR_SCAN_SUPP_RATES], | ||
3468 | tmp) { | ||
3469 | enum ieee80211_band band = nla_type(attr); | ||
3470 | |||
3471 | if (band < 0 || band >= IEEE80211_NUM_BANDS) { | ||
3472 | err = -EINVAL; | ||
3473 | goto out_free; | ||
3474 | } | ||
3475 | err = ieee80211_get_ratemask(wiphy->bands[band], | ||
3476 | nla_data(attr), | ||
3477 | nla_len(attr), | ||
3478 | &request->rates[band]); | ||
3479 | if (err) | ||
3480 | goto out_free; | ||
3481 | } | ||
3482 | } | ||
3483 | |||
3426 | request->dev = dev; | 3484 | request->dev = dev; |
3427 | request->wiphy = &rdev->wiphy; | 3485 | request->wiphy = &rdev->wiphy; |
3428 | 3486 | ||
@@ -3488,7 +3546,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
3488 | tmp) | 3546 | tmp) |
3489 | n_ssids++; | 3547 | n_ssids++; |
3490 | 3548 | ||
3491 | if (n_ssids > wiphy->max_scan_ssids) | 3549 | if (n_ssids > wiphy->max_sched_scan_ssids) |
3492 | return -EINVAL; | 3550 | return -EINVAL; |
3493 | 3551 | ||
3494 | if (info->attrs[NL80211_ATTR_IE]) | 3552 | if (info->attrs[NL80211_ATTR_IE]) |
@@ -3496,7 +3554,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
3496 | else | 3554 | else |
3497 | ie_len = 0; | 3555 | ie_len = 0; |
3498 | 3556 | ||
3499 | if (ie_len > wiphy->max_scan_ie_len) | 3557 | if (ie_len > wiphy->max_sched_scan_ie_len) |
3500 | return -EINVAL; | 3558 | return -EINVAL; |
3501 | 3559 | ||
3502 | mutex_lock(&rdev->sched_scan_mtx); | 3560 | mutex_lock(&rdev->sched_scan_mtx); |
@@ -3632,7 +3690,8 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, | |||
3632 | return err; | 3690 | return err; |
3633 | } | 3691 | } |
3634 | 3692 | ||
3635 | static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 3693 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, |
3694 | u32 seq, int flags, | ||
3636 | struct cfg80211_registered_device *rdev, | 3695 | struct cfg80211_registered_device *rdev, |
3637 | struct wireless_dev *wdev, | 3696 | struct wireless_dev *wdev, |
3638 | struct cfg80211_internal_bss *intbss) | 3697 | struct cfg80211_internal_bss *intbss) |
@@ -3644,11 +3703,13 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
3644 | 3703 | ||
3645 | ASSERT_WDEV_LOCK(wdev); | 3704 | ASSERT_WDEV_LOCK(wdev); |
3646 | 3705 | ||
3647 | hdr = nl80211hdr_put(msg, pid, seq, flags, | 3706 | hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).pid, seq, flags, |
3648 | NL80211_CMD_NEW_SCAN_RESULTS); | 3707 | NL80211_CMD_NEW_SCAN_RESULTS); |
3649 | if (!hdr) | 3708 | if (!hdr) |
3650 | return -1; | 3709 | return -1; |
3651 | 3710 | ||
3711 | genl_dump_check_consistent(cb, hdr, &nl80211_fam); | ||
3712 | |||
3652 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); | 3713 | NLA_PUT_U32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation); |
3653 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); | 3714 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex); |
3654 | 3715 | ||
@@ -3737,11 +3798,12 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3737 | spin_lock_bh(&rdev->bss_lock); | 3798 | spin_lock_bh(&rdev->bss_lock); |
3738 | cfg80211_bss_expire(rdev); | 3799 | cfg80211_bss_expire(rdev); |
3739 | 3800 | ||
3801 | cb->seq = rdev->bss_generation; | ||
3802 | |||
3740 | list_for_each_entry(scan, &rdev->bss_list, list) { | 3803 | list_for_each_entry(scan, &rdev->bss_list, list) { |
3741 | if (++idx <= start) | 3804 | if (++idx <= start) |
3742 | continue; | 3805 | continue; |
3743 | if (nl80211_send_bss(skb, | 3806 | if (nl80211_send_bss(skb, cb, |
3744 | NETLINK_CB(cb->skb).pid, | ||
3745 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3807 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
3746 | rdev, wdev, scan) < 0) { | 3808 | rdev, wdev, scan) < 0) { |
3747 | idx--; | 3809 | idx--; |
@@ -3765,10 +3827,6 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | |||
3765 | void *hdr; | 3827 | void *hdr; |
3766 | struct nlattr *infoattr; | 3828 | struct nlattr *infoattr; |
3767 | 3829 | ||
3768 | /* Survey without a channel doesn't make sense */ | ||
3769 | if (!survey->channel) | ||
3770 | return -EINVAL; | ||
3771 | |||
3772 | hdr = nl80211hdr_put(msg, pid, seq, flags, | 3830 | hdr = nl80211hdr_put(msg, pid, seq, flags, |
3773 | NL80211_CMD_NEW_SURVEY_RESULTS); | 3831 | NL80211_CMD_NEW_SURVEY_RESULTS); |
3774 | if (!hdr) | 3832 | if (!hdr) |
@@ -3831,6 +3889,8 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3831 | } | 3889 | } |
3832 | 3890 | ||
3833 | while (1) { | 3891 | while (1) { |
3892 | struct ieee80211_channel *chan; | ||
3893 | |||
3834 | res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, | 3894 | res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, |
3835 | &survey); | 3895 | &survey); |
3836 | if (res == -ENOENT) | 3896 | if (res == -ENOENT) |
@@ -3838,6 +3898,19 @@ static int nl80211_dump_survey(struct sk_buff *skb, | |||
3838 | if (res) | 3898 | if (res) |
3839 | goto out_err; | 3899 | goto out_err; |
3840 | 3900 | ||
3901 | /* Survey without a channel doesn't make sense */ | ||
3902 | if (!survey.channel) { | ||
3903 | res = -EINVAL; | ||
3904 | goto out; | ||
3905 | } | ||
3906 | |||
3907 | chan = ieee80211_get_channel(&dev->wiphy, | ||
3908 | survey.channel->center_freq); | ||
3909 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { | ||
3910 | survey_idx++; | ||
3911 | continue; | ||
3912 | } | ||
3913 | |||
3841 | if (nl80211_send_survey(skb, | 3914 | if (nl80211_send_survey(skb, |
3842 | NETLINK_CB(cb->skb).pid, | 3915 | NETLINK_CB(cb->skb).pid, |
3843 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 3916 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
@@ -4044,9 +4117,12 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, | |||
4044 | if (len % sizeof(u32)) | 4117 | if (len % sizeof(u32)) |
4045 | return -EINVAL; | 4118 | return -EINVAL; |
4046 | 4119 | ||
4120 | if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES) | ||
4121 | return -EINVAL; | ||
4122 | |||
4047 | memcpy(settings->akm_suites, data, len); | 4123 | memcpy(settings->akm_suites, data, len); |
4048 | 4124 | ||
4049 | for (i = 0; i < settings->n_ciphers_pairwise; i++) | 4125 | for (i = 0; i < settings->n_akm_suites; i++) |
4050 | if (!nl80211_valid_akm_suite(settings->akm_suites[i])) | 4126 | if (!nl80211_valid_akm_suite(settings->akm_suites[i])) |
4051 | return -EINVAL; | 4127 | return -EINVAL; |
4052 | } | 4128 | } |
@@ -4294,25 +4370,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4294 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 4370 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
4295 | struct ieee80211_supported_band *sband = | 4371 | struct ieee80211_supported_band *sband = |
4296 | wiphy->bands[ibss.channel->band]; | 4372 | wiphy->bands[ibss.channel->band]; |
4297 | int i, j; | 4373 | int err; |
4298 | |||
4299 | if (n_rates == 0) | ||
4300 | return -EINVAL; | ||
4301 | 4374 | ||
4302 | for (i = 0; i < n_rates; i++) { | 4375 | err = ieee80211_get_ratemask(sband, rates, n_rates, |
4303 | int rate = (rates[i] & 0x7f) * 5; | 4376 | &ibss.basic_rates); |
4304 | bool found = false; | 4377 | if (err) |
4305 | 4378 | return err; | |
4306 | for (j = 0; j < sband->n_bitrates; j++) { | ||
4307 | if (sband->bitrates[j].bitrate == rate) { | ||
4308 | found = true; | ||
4309 | ibss.basic_rates |= BIT(j); | ||
4310 | break; | ||
4311 | } | ||
4312 | } | ||
4313 | if (!found) | ||
4314 | return -EINVAL; | ||
4315 | } | ||
4316 | } | 4379 | } |
4317 | 4380 | ||
4318 | if (info->attrs[NL80211_ATTR_MCAST_RATE] && | 4381 | if (info->attrs[NL80211_ATTR_MCAST_RATE] && |
@@ -4372,6 +4435,93 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info) | |||
4372 | return err; | 4435 | return err; |
4373 | } | 4436 | } |
4374 | 4437 | ||
4438 | static int nl80211_testmode_dump(struct sk_buff *skb, | ||
4439 | struct netlink_callback *cb) | ||
4440 | { | ||
4441 | struct cfg80211_registered_device *dev; | ||
4442 | int err; | ||
4443 | long phy_idx; | ||
4444 | void *data = NULL; | ||
4445 | int data_len = 0; | ||
4446 | |||
4447 | if (cb->args[0]) { | ||
4448 | /* | ||
4449 | * 0 is a valid index, but not valid for args[0], | ||
4450 | * so we need to offset by 1. | ||
4451 | */ | ||
4452 | phy_idx = cb->args[0] - 1; | ||
4453 | } else { | ||
4454 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
4455 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | ||
4456 | nl80211_policy); | ||
4457 | if (err) | ||
4458 | return err; | ||
4459 | if (!nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) | ||
4460 | return -EINVAL; | ||
4461 | phy_idx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]); | ||
4462 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) | ||
4463 | cb->args[1] = | ||
4464 | (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; | ||
4465 | } | ||
4466 | |||
4467 | if (cb->args[1]) { | ||
4468 | data = nla_data((void *)cb->args[1]); | ||
4469 | data_len = nla_len((void *)cb->args[1]); | ||
4470 | } | ||
4471 | |||
4472 | mutex_lock(&cfg80211_mutex); | ||
4473 | dev = cfg80211_rdev_by_wiphy_idx(phy_idx); | ||
4474 | if (!dev) { | ||
4475 | mutex_unlock(&cfg80211_mutex); | ||
4476 | return -ENOENT; | ||
4477 | } | ||
4478 | cfg80211_lock_rdev(dev); | ||
4479 | mutex_unlock(&cfg80211_mutex); | ||
4480 | |||
4481 | if (!dev->ops->testmode_dump) { | ||
4482 | err = -EOPNOTSUPP; | ||
4483 | goto out_err; | ||
4484 | } | ||
4485 | |||
4486 | while (1) { | ||
4487 | void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).pid, | ||
4488 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
4489 | NL80211_CMD_TESTMODE); | ||
4490 | struct nlattr *tmdata; | ||
4491 | |||
4492 | if (nla_put_u32(skb, NL80211_ATTR_WIPHY, dev->wiphy_idx) < 0) { | ||
4493 | genlmsg_cancel(skb, hdr); | ||
4494 | break; | ||
4495 | } | ||
4496 | |||
4497 | tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA); | ||
4498 | if (!tmdata) { | ||
4499 | genlmsg_cancel(skb, hdr); | ||
4500 | break; | ||
4501 | } | ||
4502 | err = dev->ops->testmode_dump(&dev->wiphy, skb, cb, | ||
4503 | data, data_len); | ||
4504 | nla_nest_end(skb, tmdata); | ||
4505 | |||
4506 | if (err == -ENOBUFS || err == -ENOENT) { | ||
4507 | genlmsg_cancel(skb, hdr); | ||
4508 | break; | ||
4509 | } else if (err) { | ||
4510 | genlmsg_cancel(skb, hdr); | ||
4511 | goto out_err; | ||
4512 | } | ||
4513 | |||
4514 | genlmsg_end(skb, hdr); | ||
4515 | } | ||
4516 | |||
4517 | err = skb->len; | ||
4518 | /* see above */ | ||
4519 | cb->args[0] = phy_idx + 1; | ||
4520 | out_err: | ||
4521 | cfg80211_unlock_rdev(dev); | ||
4522 | return err; | ||
4523 | } | ||
4524 | |||
4375 | static struct sk_buff * | 4525 | static struct sk_buff * |
4376 | __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, | 4526 | __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev, |
4377 | int approxlen, u32 pid, u32 seq, gfp_t gfp) | 4527 | int approxlen, u32 pid, u32 seq, gfp_t gfp) |
@@ -5161,6 +5311,14 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
5161 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | 5311 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); |
5162 | if (rdev->wowlan->magic_pkt) | 5312 | if (rdev->wowlan->magic_pkt) |
5163 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | 5313 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); |
5314 | if (rdev->wowlan->gtk_rekey_failure) | ||
5315 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); | ||
5316 | if (rdev->wowlan->eap_identity_req) | ||
5317 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); | ||
5318 | if (rdev->wowlan->four_way_handshake) | ||
5319 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); | ||
5320 | if (rdev->wowlan->rfkill_release) | ||
5321 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); | ||
5164 | if (rdev->wowlan->n_patterns) { | 5322 | if (rdev->wowlan->n_patterns) { |
5165 | struct nlattr *nl_pats, *nl_pat; | 5323 | struct nlattr *nl_pats, *nl_pat; |
5166 | int i, pat_len; | 5324 | int i, pat_len; |
@@ -5237,6 +5395,33 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
5237 | new_triggers.magic_pkt = true; | 5395 | new_triggers.magic_pkt = true; |
5238 | } | 5396 | } |
5239 | 5397 | ||
5398 | if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) | ||
5399 | return -EINVAL; | ||
5400 | |||
5401 | if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) { | ||
5402 | if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE)) | ||
5403 | return -EINVAL; | ||
5404 | new_triggers.gtk_rekey_failure = true; | ||
5405 | } | ||
5406 | |||
5407 | if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) { | ||
5408 | if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ)) | ||
5409 | return -EINVAL; | ||
5410 | new_triggers.eap_identity_req = true; | ||
5411 | } | ||
5412 | |||
5413 | if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) { | ||
5414 | if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE)) | ||
5415 | return -EINVAL; | ||
5416 | new_triggers.four_way_handshake = true; | ||
5417 | } | ||
5418 | |||
5419 | if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) { | ||
5420 | if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE)) | ||
5421 | return -EINVAL; | ||
5422 | new_triggers.rfkill_release = true; | ||
5423 | } | ||
5424 | |||
5240 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { | 5425 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { |
5241 | struct nlattr *pat; | 5426 | struct nlattr *pat; |
5242 | int n_patterns = 0; | 5427 | int n_patterns = 0; |
@@ -5318,6 +5503,57 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
5318 | return err; | 5503 | return err; |
5319 | } | 5504 | } |
5320 | 5505 | ||
5506 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | ||
5507 | { | ||
5508 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5509 | struct net_device *dev = info->user_ptr[1]; | ||
5510 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
5511 | struct nlattr *tb[NUM_NL80211_REKEY_DATA]; | ||
5512 | struct cfg80211_gtk_rekey_data rekey_data; | ||
5513 | int err; | ||
5514 | |||
5515 | if (!info->attrs[NL80211_ATTR_REKEY_DATA]) | ||
5516 | return -EINVAL; | ||
5517 | |||
5518 | err = nla_parse(tb, MAX_NL80211_REKEY_DATA, | ||
5519 | nla_data(info->attrs[NL80211_ATTR_REKEY_DATA]), | ||
5520 | nla_len(info->attrs[NL80211_ATTR_REKEY_DATA]), | ||
5521 | nl80211_rekey_policy); | ||
5522 | if (err) | ||
5523 | return err; | ||
5524 | |||
5525 | if (nla_len(tb[NL80211_REKEY_DATA_REPLAY_CTR]) != NL80211_REPLAY_CTR_LEN) | ||
5526 | return -ERANGE; | ||
5527 | if (nla_len(tb[NL80211_REKEY_DATA_KEK]) != NL80211_KEK_LEN) | ||
5528 | return -ERANGE; | ||
5529 | if (nla_len(tb[NL80211_REKEY_DATA_KCK]) != NL80211_KCK_LEN) | ||
5530 | return -ERANGE; | ||
5531 | |||
5532 | memcpy(rekey_data.kek, nla_data(tb[NL80211_REKEY_DATA_KEK]), | ||
5533 | NL80211_KEK_LEN); | ||
5534 | memcpy(rekey_data.kck, nla_data(tb[NL80211_REKEY_DATA_KCK]), | ||
5535 | NL80211_KCK_LEN); | ||
5536 | memcpy(rekey_data.replay_ctr, | ||
5537 | nla_data(tb[NL80211_REKEY_DATA_REPLAY_CTR]), | ||
5538 | NL80211_REPLAY_CTR_LEN); | ||
5539 | |||
5540 | wdev_lock(wdev); | ||
5541 | if (!wdev->current_bss) { | ||
5542 | err = -ENOTCONN; | ||
5543 | goto out; | ||
5544 | } | ||
5545 | |||
5546 | if (!rdev->ops->set_rekey_data) { | ||
5547 | err = -EOPNOTSUPP; | ||
5548 | goto out; | ||
5549 | } | ||
5550 | |||
5551 | err = rdev->ops->set_rekey_data(&rdev->wiphy, dev, &rekey_data); | ||
5552 | out: | ||
5553 | wdev_unlock(wdev); | ||
5554 | return err; | ||
5555 | } | ||
5556 | |||
5321 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 5557 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
5322 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 5558 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
5323 | #define NL80211_FLAG_NEED_RTNL 0x04 | 5559 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -5669,6 +5905,7 @@ static struct genl_ops nl80211_ops[] = { | |||
5669 | { | 5905 | { |
5670 | .cmd = NL80211_CMD_TESTMODE, | 5906 | .cmd = NL80211_CMD_TESTMODE, |
5671 | .doit = nl80211_testmode_do, | 5907 | .doit = nl80211_testmode_do, |
5908 | .dumpit = nl80211_testmode_dump, | ||
5672 | .policy = nl80211_policy, | 5909 | .policy = nl80211_policy, |
5673 | .flags = GENL_ADMIN_PERM, | 5910 | .flags = GENL_ADMIN_PERM, |
5674 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 5911 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
@@ -5848,6 +6085,14 @@ static struct genl_ops nl80211_ops[] = { | |||
5848 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 6085 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
5849 | NL80211_FLAG_NEED_RTNL, | 6086 | NL80211_FLAG_NEED_RTNL, |
5850 | }, | 6087 | }, |
6088 | { | ||
6089 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, | ||
6090 | .doit = nl80211_set_rekey_data, | ||
6091 | .policy = nl80211_policy, | ||
6092 | .flags = GENL_ADMIN_PERM, | ||
6093 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
6094 | NL80211_FLAG_NEED_RTNL, | ||
6095 | }, | ||
5851 | }; | 6096 | }; |
5852 | 6097 | ||
5853 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 6098 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -6792,6 +7037,51 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
6792 | nlmsg_free(msg); | 7037 | nlmsg_free(msg); |
6793 | } | 7038 | } |
6794 | 7039 | ||
7040 | void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | ||
7041 | struct net_device *netdev, const u8 *bssid, | ||
7042 | const u8 *replay_ctr, gfp_t gfp) | ||
7043 | { | ||
7044 | struct sk_buff *msg; | ||
7045 | struct nlattr *rekey_attr; | ||
7046 | void *hdr; | ||
7047 | |||
7048 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
7049 | if (!msg) | ||
7050 | return; | ||
7051 | |||
7052 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_SET_REKEY_OFFLOAD); | ||
7053 | if (!hdr) { | ||
7054 | nlmsg_free(msg); | ||
7055 | return; | ||
7056 | } | ||
7057 | |||
7058 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
7059 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
7060 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | ||
7061 | |||
7062 | rekey_attr = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA); | ||
7063 | if (!rekey_attr) | ||
7064 | goto nla_put_failure; | ||
7065 | |||
7066 | NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, | ||
7067 | NL80211_REPLAY_CTR_LEN, replay_ctr); | ||
7068 | |||
7069 | nla_nest_end(msg, rekey_attr); | ||
7070 | |||
7071 | if (genlmsg_end(msg, hdr) < 0) { | ||
7072 | nlmsg_free(msg); | ||
7073 | return; | ||
7074 | } | ||
7075 | |||
7076 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
7077 | nl80211_mlme_mcgrp.id, gfp); | ||
7078 | return; | ||
7079 | |||
7080 | nla_put_failure: | ||
7081 | genlmsg_cancel(msg, hdr); | ||
7082 | nlmsg_free(msg); | ||
7083 | } | ||
7084 | |||
6795 | void | 7085 | void |
6796 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 7086 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
6797 | struct net_device *netdev, const u8 *peer, | 7087 | struct net_device *netdev, const u8 *peer, |