diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 7 | ||||
-rw-r--r-- | net/wireless/core.h | 4 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 109 | ||||
-rw-r--r-- | net/wireless/scan.c | 4 | ||||
-rw-r--r-- | net/wireless/util.c | 38 |
5 files changed, 140 insertions, 22 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index 880dbe2e6f94..645437cfc464 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -488,6 +488,10 @@ int wiphy_register(struct wiphy *wiphy) | |||
488 | int i; | 488 | int i; |
489 | u16 ifmodes = wiphy->interface_modes; | 489 | u16 ifmodes = wiphy->interface_modes; |
490 | 490 | ||
491 | if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && | ||
492 | !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) | ||
493 | return -EINVAL; | ||
494 | |||
491 | if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) | 495 | if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) |
492 | return -EINVAL; | 496 | return -EINVAL; |
493 | 497 | ||
@@ -918,7 +922,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
918 | * Configure power management to the driver here so that its | 922 | * Configure power management to the driver here so that its |
919 | * correctly set also after interface type changes etc. | 923 | * correctly set also after interface type changes etc. |
920 | */ | 924 | */ |
921 | if (wdev->iftype == NL80211_IFTYPE_STATION && | 925 | if ((wdev->iftype == NL80211_IFTYPE_STATION || |
926 | wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) && | ||
922 | rdev->ops->set_power_mgmt) | 927 | rdev->ops->set_power_mgmt) |
923 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, | 928 | if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, |
924 | wdev->ps, | 929 | wdev->ps, |
diff --git a/net/wireless/core.h b/net/wireless/core.h index a570ff9214ec..8672e028022f 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -447,6 +447,10 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, | |||
447 | 447 | ||
448 | u16 cfg80211_calculate_bitrate(struct rate_info *rate); | 448 | u16 cfg80211_calculate_bitrate(struct rate_info *rate); |
449 | 449 | ||
450 | int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | ||
451 | const u8 *rates, unsigned int n_rates, | ||
452 | u32 *mask); | ||
453 | |||
450 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 454 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
451 | u32 beacon_int); | 455 | u32 beacon_int); |
452 | 456 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 6a82c898f831..28d2aa109bee 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -177,6 +177,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
177 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, | 177 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, |
178 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, | 178 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, |
179 | [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, | 179 | [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED }, |
180 | [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED }, | ||
180 | }; | 181 | }; |
181 | 182 | ||
182 | /* policy for the key attributes */ | 183 | /* policy for the key attributes */ |
@@ -205,6 +206,10 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
205 | [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, | 206 | [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, |
206 | [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, | 207 | [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, |
207 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, | 208 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, |
209 | [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG }, | ||
210 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, | ||
211 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, | ||
212 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, | ||
208 | }; | 213 | }; |
209 | 214 | ||
210 | /* policy for GTK rekey offload attributes */ | 215 | /* policy for GTK rekey offload attributes */ |
@@ -692,8 +697,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
692 | dev->wiphy.coverage_class); | 697 | dev->wiphy.coverage_class); |
693 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 698 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
694 | dev->wiphy.max_scan_ssids); | 699 | dev->wiphy.max_scan_ssids); |
700 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, | ||
701 | dev->wiphy.max_sched_scan_ssids); | ||
695 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | 702 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, |
696 | dev->wiphy.max_scan_ie_len); | 703 | dev->wiphy.max_scan_ie_len); |
704 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, | ||
705 | dev->wiphy.max_sched_scan_ie_len); | ||
697 | 706 | ||
698 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) | 707 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) |
699 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); | 708 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); |
@@ -929,6 +938,16 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
929 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | 938 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); |
930 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) | 939 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) |
931 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | 940 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); |
941 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) | ||
942 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED); | ||
943 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) | ||
944 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); | ||
945 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) | ||
946 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); | ||
947 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) | ||
948 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); | ||
949 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) | ||
950 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); | ||
932 | if (dev->wiphy.wowlan.n_patterns) { | 951 | if (dev->wiphy.wowlan.n_patterns) { |
933 | struct nl80211_wowlan_pattern_support pat = { | 952 | struct nl80211_wowlan_pattern_support pat = { |
934 | .max_patterns = dev->wiphy.wowlan.n_patterns, | 953 | .max_patterns = dev->wiphy.wowlan.n_patterns, |
@@ -3306,7 +3325,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3306 | struct nlattr *attr; | 3325 | struct nlattr *attr; |
3307 | struct wiphy *wiphy; | 3326 | struct wiphy *wiphy; |
3308 | int err, tmp, n_ssids = 0, n_channels, i; | 3327 | int err, tmp, n_ssids = 0, n_channels, i; |
3309 | enum ieee80211_band band; | ||
3310 | size_t ie_len; | 3328 | size_t ie_len; |
3311 | 3329 | ||
3312 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | 3330 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) |
@@ -3326,6 +3344,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3326 | if (!n_channels) | 3344 | if (!n_channels) |
3327 | return -EINVAL; | 3345 | return -EINVAL; |
3328 | } else { | 3346 | } else { |
3347 | enum ieee80211_band band; | ||
3329 | n_channels = 0; | 3348 | n_channels = 0; |
3330 | 3349 | ||
3331 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 3350 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) |
@@ -3386,6 +3405,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3386 | i++; | 3405 | i++; |
3387 | } | 3406 | } |
3388 | } else { | 3407 | } else { |
3408 | enum ieee80211_band band; | ||
3409 | |||
3389 | /* all channels */ | 3410 | /* all channels */ |
3390 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 3411 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
3391 | int j; | 3412 | int j; |
@@ -3432,6 +3453,30 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3432 | request->ie_len); | 3453 | request->ie_len); |
3433 | } | 3454 | } |
3434 | 3455 | ||
3456 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
3457 | if (wiphy->bands[i]) | ||
3458 | request->rates[i] = | ||
3459 | (1 << wiphy->bands[i]->n_bitrates) - 1; | ||
3460 | |||
3461 | if (info->attrs[NL80211_ATTR_SCAN_SUPP_RATES]) { | ||
3462 | nla_for_each_nested(attr, | ||
3463 | info->attrs[NL80211_ATTR_SCAN_SUPP_RATES], | ||
3464 | tmp) { | ||
3465 | enum ieee80211_band band = nla_type(attr); | ||
3466 | |||
3467 | if (band < 0 || band > IEEE80211_NUM_BANDS) { | ||
3468 | err = -EINVAL; | ||
3469 | goto out_free; | ||
3470 | } | ||
3471 | err = ieee80211_get_ratemask(wiphy->bands[band], | ||
3472 | nla_data(attr), | ||
3473 | nla_len(attr), | ||
3474 | &request->rates[band]); | ||
3475 | if (err) | ||
3476 | goto out_free; | ||
3477 | } | ||
3478 | } | ||
3479 | |||
3435 | request->dev = dev; | 3480 | request->dev = dev; |
3436 | request->wiphy = &rdev->wiphy; | 3481 | request->wiphy = &rdev->wiphy; |
3437 | 3482 | ||
@@ -3497,7 +3542,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
3497 | tmp) | 3542 | tmp) |
3498 | n_ssids++; | 3543 | n_ssids++; |
3499 | 3544 | ||
3500 | if (n_ssids > wiphy->max_scan_ssids) | 3545 | if (n_ssids > wiphy->max_sched_scan_ssids) |
3501 | return -EINVAL; | 3546 | return -EINVAL; |
3502 | 3547 | ||
3503 | if (info->attrs[NL80211_ATTR_IE]) | 3548 | if (info->attrs[NL80211_ATTR_IE]) |
@@ -3505,7 +3550,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
3505 | else | 3550 | else |
3506 | ie_len = 0; | 3551 | ie_len = 0; |
3507 | 3552 | ||
3508 | if (ie_len > wiphy->max_scan_ie_len) | 3553 | if (ie_len > wiphy->max_sched_scan_ie_len) |
3509 | return -EINVAL; | 3554 | return -EINVAL; |
3510 | 3555 | ||
3511 | mutex_lock(&rdev->sched_scan_mtx); | 3556 | mutex_lock(&rdev->sched_scan_mtx); |
@@ -4318,25 +4363,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | |||
4318 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 4363 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
4319 | struct ieee80211_supported_band *sband = | 4364 | struct ieee80211_supported_band *sband = |
4320 | wiphy->bands[ibss.channel->band]; | 4365 | wiphy->bands[ibss.channel->band]; |
4321 | int i, j; | 4366 | int err; |
4322 | 4367 | ||
4323 | if (n_rates == 0) | 4368 | err = ieee80211_get_ratemask(sband, rates, n_rates, |
4324 | return -EINVAL; | 4369 | &ibss.basic_rates); |
4325 | 4370 | if (err) | |
4326 | for (i = 0; i < n_rates; i++) { | 4371 | return err; |
4327 | int rate = (rates[i] & 0x7f) * 5; | ||
4328 | bool found = false; | ||
4329 | |||
4330 | for (j = 0; j < sband->n_bitrates; j++) { | ||
4331 | if (sband->bitrates[j].bitrate == rate) { | ||
4332 | found = true; | ||
4333 | ibss.basic_rates |= BIT(j); | ||
4334 | break; | ||
4335 | } | ||
4336 | } | ||
4337 | if (!found) | ||
4338 | return -EINVAL; | ||
4339 | } | ||
4340 | } | 4372 | } |
4341 | 4373 | ||
4342 | if (info->attrs[NL80211_ATTR_MCAST_RATE] && | 4374 | if (info->attrs[NL80211_ATTR_MCAST_RATE] && |
@@ -5272,6 +5304,14 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
5272 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | 5304 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); |
5273 | if (rdev->wowlan->magic_pkt) | 5305 | if (rdev->wowlan->magic_pkt) |
5274 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | 5306 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); |
5307 | if (rdev->wowlan->gtk_rekey_failure) | ||
5308 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); | ||
5309 | if (rdev->wowlan->eap_identity_req) | ||
5310 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); | ||
5311 | if (rdev->wowlan->four_way_handshake) | ||
5312 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); | ||
5313 | if (rdev->wowlan->rfkill_release) | ||
5314 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); | ||
5275 | if (rdev->wowlan->n_patterns) { | 5315 | if (rdev->wowlan->n_patterns) { |
5276 | struct nlattr *nl_pats, *nl_pat; | 5316 | struct nlattr *nl_pats, *nl_pat; |
5277 | int i, pat_len; | 5317 | int i, pat_len; |
@@ -5348,6 +5388,33 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
5348 | new_triggers.magic_pkt = true; | 5388 | new_triggers.magic_pkt = true; |
5349 | } | 5389 | } |
5350 | 5390 | ||
5391 | if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) | ||
5392 | return -EINVAL; | ||
5393 | |||
5394 | if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) { | ||
5395 | if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE)) | ||
5396 | return -EINVAL; | ||
5397 | new_triggers.gtk_rekey_failure = true; | ||
5398 | } | ||
5399 | |||
5400 | if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) { | ||
5401 | if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ)) | ||
5402 | return -EINVAL; | ||
5403 | new_triggers.eap_identity_req = true; | ||
5404 | } | ||
5405 | |||
5406 | if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) { | ||
5407 | if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE)) | ||
5408 | return -EINVAL; | ||
5409 | new_triggers.four_way_handshake = true; | ||
5410 | } | ||
5411 | |||
5412 | if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) { | ||
5413 | if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE)) | ||
5414 | return -EINVAL; | ||
5415 | new_triggers.rfkill_release = true; | ||
5416 | } | ||
5417 | |||
5351 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { | 5418 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { |
5352 | struct nlattr *pat; | 5419 | struct nlattr *pat; |
5353 | int n_patterns = 0; | 5420 | int n_patterns = 0; |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 1c4672e35144..2936cb809152 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -862,6 +862,10 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
862 | creq->n_ssids = 0; | 862 | creq->n_ssids = 0; |
863 | } | 863 | } |
864 | 864 | ||
865 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) | ||
866 | if (wiphy->bands[i]) | ||
867 | creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; | ||
868 | |||
865 | rdev->scan_req = creq; | 869 | rdev->scan_req = creq; |
866 | err = rdev->ops->scan(wiphy, dev, creq); | 870 | err = rdev->ops->scan(wiphy, dev, creq); |
867 | if (err) { | 871 | if (err) { |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 4d7b83fbc32f..be75a3a0424e 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -1006,3 +1006,41 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
1006 | 1006 | ||
1007 | return -EBUSY; | 1007 | return -EBUSY; |
1008 | } | 1008 | } |
1009 | |||
1010 | int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | ||
1011 | const u8 *rates, unsigned int n_rates, | ||
1012 | u32 *mask) | ||
1013 | { | ||
1014 | int i, j; | ||
1015 | |||
1016 | if (!sband) | ||
1017 | return -EINVAL; | ||
1018 | |||
1019 | if (n_rates == 0 || n_rates > NL80211_MAX_SUPP_RATES) | ||
1020 | return -EINVAL; | ||
1021 | |||
1022 | *mask = 0; | ||
1023 | |||
1024 | for (i = 0; i < n_rates; i++) { | ||
1025 | int rate = (rates[i] & 0x7f) * 5; | ||
1026 | bool found = false; | ||
1027 | |||
1028 | for (j = 0; j < sband->n_bitrates; j++) { | ||
1029 | if (sband->bitrates[j].bitrate == rate) { | ||
1030 | found = true; | ||
1031 | *mask |= BIT(j); | ||
1032 | break; | ||
1033 | } | ||
1034 | } | ||
1035 | if (!found) | ||
1036 | return -EINVAL; | ||
1037 | } | ||
1038 | |||
1039 | /* | ||
1040 | * mask must have at least one bit set here since we | ||
1041 | * didn't accept a 0-length rates array nor allowed | ||
1042 | * entries in the array that didn't exist | ||
1043 | */ | ||
1044 | |||
1045 | return 0; | ||
1046 | } | ||