diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 643 |
1 files changed, 603 insertions, 40 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 93bc63eae076..580ffeaef3d5 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <net/genetlink.h> | 19 | #include <net/genetlink.h> |
20 | #include <net/cfg80211.h> | 20 | #include <net/cfg80211.h> |
21 | #include <net/sock.h> | 21 | #include <net/sock.h> |
22 | #include <net/inet_connection_sock.h> | ||
22 | #include "core.h" | 23 | #include "core.h" |
23 | #include "nl80211.h" | 24 | #include "nl80211.h" |
24 | #include "reg.h" | 25 | #include "reg.h" |
@@ -367,6 +368,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
367 | [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, | 368 | [NL80211_ATTR_P2P_OPPPS] = { .type = NLA_U8 }, |
368 | [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, | 369 | [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 }, |
369 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, | 370 | [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED }, |
371 | [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 }, | ||
372 | [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, }, | ||
370 | }; | 373 | }; |
371 | 374 | ||
372 | /* policy for the key attributes */ | 375 | /* policy for the key attributes */ |
@@ -399,6 +402,26 @@ nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | |||
399 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, | 402 | [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG }, |
400 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, | 403 | [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG }, |
401 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, | 404 | [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG }, |
405 | [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED }, | ||
406 | }; | ||
407 | |||
408 | static const struct nla_policy | ||
409 | nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = { | ||
410 | [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 }, | ||
411 | [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 }, | ||
412 | [NL80211_WOWLAN_TCP_DST_MAC] = { .len = ETH_ALEN }, | ||
413 | [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 }, | ||
414 | [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 }, | ||
415 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .len = 1 }, | ||
416 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = { | ||
417 | .len = sizeof(struct nl80211_wowlan_tcp_data_seq) | ||
418 | }, | ||
419 | [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = { | ||
420 | .len = sizeof(struct nl80211_wowlan_tcp_data_token) | ||
421 | }, | ||
422 | [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 }, | ||
423 | [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = { .len = 1 }, | ||
424 | [NL80211_WOWLAN_TCP_WAKE_MASK] = { .len = 1 }, | ||
402 | }; | 425 | }; |
403 | 426 | ||
404 | /* policy for GTK rekey offload attributes */ | 427 | /* policy for GTK rekey offload attributes */ |
@@ -531,8 +554,27 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
531 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && | 554 | if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && |
532 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) | 555 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) |
533 | goto nla_put_failure; | 556 | goto nla_put_failure; |
534 | if ((chan->flags & IEEE80211_CHAN_RADAR) && | 557 | if (chan->flags & IEEE80211_CHAN_RADAR) { |
535 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | 558 | u32 time = elapsed_jiffies_msecs(chan->dfs_state_entered); |
559 | if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) | ||
560 | goto nla_put_failure; | ||
561 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE, | ||
562 | chan->dfs_state)) | ||
563 | goto nla_put_failure; | ||
564 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, time)) | ||
565 | goto nla_put_failure; | ||
566 | } | ||
567 | if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) && | ||
568 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS)) | ||
569 | goto nla_put_failure; | ||
570 | if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) && | ||
571 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS)) | ||
572 | goto nla_put_failure; | ||
573 | if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) && | ||
574 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ)) | ||
575 | goto nla_put_failure; | ||
576 | if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) && | ||
577 | nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ)) | ||
536 | goto nla_put_failure; | 578 | goto nla_put_failure; |
537 | 579 | ||
538 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 580 | if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, |
@@ -872,6 +914,48 @@ nla_put_failure: | |||
872 | return -ENOBUFS; | 914 | return -ENOBUFS; |
873 | } | 915 | } |
874 | 916 | ||
917 | #ifdef CONFIG_PM | ||
918 | static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev, | ||
919 | struct sk_buff *msg) | ||
920 | { | ||
921 | const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp; | ||
922 | struct nlattr *nl_tcp; | ||
923 | |||
924 | if (!tcp) | ||
925 | return 0; | ||
926 | |||
927 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); | ||
928 | if (!nl_tcp) | ||
929 | return -ENOBUFS; | ||
930 | |||
931 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
932 | tcp->data_payload_max)) | ||
933 | return -ENOBUFS; | ||
934 | |||
935 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
936 | tcp->data_payload_max)) | ||
937 | return -ENOBUFS; | ||
938 | |||
939 | if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ)) | ||
940 | return -ENOBUFS; | ||
941 | |||
942 | if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
943 | sizeof(*tcp->tok), tcp->tok)) | ||
944 | return -ENOBUFS; | ||
945 | |||
946 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
947 | tcp->data_interval_max)) | ||
948 | return -ENOBUFS; | ||
949 | |||
950 | if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
951 | tcp->wake_payload_max)) | ||
952 | return -ENOBUFS; | ||
953 | |||
954 | nla_nest_end(msg, nl_tcp); | ||
955 | return 0; | ||
956 | } | ||
957 | #endif | ||
958 | |||
875 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, | 959 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags, |
876 | struct cfg80211_registered_device *dev) | 960 | struct cfg80211_registered_device *dev) |
877 | { | 961 | { |
@@ -1238,12 +1322,17 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
1238 | dev->wiphy.wowlan.pattern_min_len, | 1322 | dev->wiphy.wowlan.pattern_min_len, |
1239 | .max_pattern_len = | 1323 | .max_pattern_len = |
1240 | dev->wiphy.wowlan.pattern_max_len, | 1324 | dev->wiphy.wowlan.pattern_max_len, |
1325 | .max_pkt_offset = | ||
1326 | dev->wiphy.wowlan.max_pkt_offset, | ||
1241 | }; | 1327 | }; |
1242 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | 1328 | if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, |
1243 | sizeof(pat), &pat)) | 1329 | sizeof(pat), &pat)) |
1244 | goto nla_put_failure; | 1330 | goto nla_put_failure; |
1245 | } | 1331 | } |
1246 | 1332 | ||
1333 | if (nl80211_send_wowlan_tcp_caps(dev, msg)) | ||
1334 | goto nla_put_failure; | ||
1335 | |||
1247 | nla_nest_end(msg, nl_wowlan); | 1336 | nla_nest_end(msg, nl_wowlan); |
1248 | } | 1337 | } |
1249 | #endif | 1338 | #endif |
@@ -1276,6 +1365,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag | |||
1276 | dev->wiphy.max_acl_mac_addrs)) | 1365 | dev->wiphy.max_acl_mac_addrs)) |
1277 | goto nla_put_failure; | 1366 | goto nla_put_failure; |
1278 | 1367 | ||
1368 | if (dev->wiphy.extended_capabilities && | ||
1369 | (nla_put(msg, NL80211_ATTR_EXT_CAPA, | ||
1370 | dev->wiphy.extended_capabilities_len, | ||
1371 | dev->wiphy.extended_capabilities) || | ||
1372 | nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK, | ||
1373 | dev->wiphy.extended_capabilities_len, | ||
1374 | dev->wiphy.extended_capabilities_mask))) | ||
1375 | goto nla_put_failure; | ||
1376 | |||
1279 | return genlmsg_end(msg, hdr); | 1377 | return genlmsg_end(msg, hdr); |
1280 | 1378 | ||
1281 | nla_put_failure: | 1379 | nla_put_failure: |
@@ -2707,6 +2805,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2707 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 2805 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
2708 | struct cfg80211_ap_settings params; | 2806 | struct cfg80211_ap_settings params; |
2709 | int err; | 2807 | int err; |
2808 | u8 radar_detect_width = 0; | ||
2710 | 2809 | ||
2711 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2810 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2712 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 2811 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
@@ -2825,9 +2924,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2825 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) | 2924 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) |
2826 | return -EINVAL; | 2925 | return -EINVAL; |
2827 | 2926 | ||
2927 | err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); | ||
2928 | if (err < 0) | ||
2929 | return err; | ||
2930 | if (err) { | ||
2931 | radar_detect_width = BIT(params.chandef.width); | ||
2932 | params.radar_required = true; | ||
2933 | } | ||
2934 | |||
2828 | mutex_lock(&rdev->devlist_mtx); | 2935 | mutex_lock(&rdev->devlist_mtx); |
2829 | err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan, | 2936 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, |
2830 | CHAN_MODE_SHARED); | 2937 | params.chandef.chan, |
2938 | CHAN_MODE_SHARED, | ||
2939 | radar_detect_width); | ||
2831 | mutex_unlock(&rdev->devlist_mtx); | 2940 | mutex_unlock(&rdev->devlist_mtx); |
2832 | 2941 | ||
2833 | if (err) | 2942 | if (err) |
@@ -3300,6 +3409,63 @@ static struct net_device *get_vlan(struct genl_info *info, | |||
3300 | return ERR_PTR(ret); | 3409 | return ERR_PTR(ret); |
3301 | } | 3410 | } |
3302 | 3411 | ||
3412 | static struct nla_policy | ||
3413 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | ||
3414 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | ||
3415 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | ||
3416 | }; | ||
3417 | |||
3418 | static int nl80211_set_station_tdls(struct genl_info *info, | ||
3419 | struct station_parameters *params) | ||
3420 | { | ||
3421 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
3422 | struct nlattr *tb[NL80211_STA_WME_MAX + 1]; | ||
3423 | struct nlattr *nla; | ||
3424 | int err; | ||
3425 | |||
3426 | /* Can only set if TDLS ... */ | ||
3427 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS)) | ||
3428 | return -EOPNOTSUPP; | ||
3429 | |||
3430 | /* ... with external setup is supported */ | ||
3431 | if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) | ||
3432 | return -EOPNOTSUPP; | ||
3433 | |||
3434 | /* Dummy STA entry gets updated once the peer capabilities are known */ | ||
3435 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | ||
3436 | params->ht_capa = | ||
3437 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | ||
3438 | if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3439 | params->vht_capa = | ||
3440 | nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); | ||
3441 | |||
3442 | /* parse WME attributes if present */ | ||
3443 | if (!info->attrs[NL80211_ATTR_STA_WME]) | ||
3444 | return 0; | ||
3445 | |||
3446 | nla = info->attrs[NL80211_ATTR_STA_WME]; | ||
3447 | err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla, | ||
3448 | nl80211_sta_wme_policy); | ||
3449 | if (err) | ||
3450 | return err; | ||
3451 | |||
3452 | if (tb[NL80211_STA_WME_UAPSD_QUEUES]) | ||
3453 | params->uapsd_queues = nla_get_u8( | ||
3454 | tb[NL80211_STA_WME_UAPSD_QUEUES]); | ||
3455 | if (params->uapsd_queues & ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) | ||
3456 | return -EINVAL; | ||
3457 | |||
3458 | if (tb[NL80211_STA_WME_MAX_SP]) | ||
3459 | params->max_sp = nla_get_u8(tb[NL80211_STA_WME_MAX_SP]); | ||
3460 | |||
3461 | if (params->max_sp & ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK) | ||
3462 | return -EINVAL; | ||
3463 | |||
3464 | params->sta_modify_mask |= STATION_PARAM_APPLY_UAPSD; | ||
3465 | |||
3466 | return 0; | ||
3467 | } | ||
3468 | |||
3303 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | 3469 | static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) |
3304 | { | 3470 | { |
3305 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3471 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -3328,8 +3494,20 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3328 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 3494 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
3329 | } | 3495 | } |
3330 | 3496 | ||
3331 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL] || | 3497 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { |
3332 | info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 3498 | params.capability = |
3499 | nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]); | ||
3500 | params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY; | ||
3501 | } | ||
3502 | |||
3503 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) { | ||
3504 | params.ext_capab = | ||
3505 | nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
3506 | params.ext_capab_len = | ||
3507 | nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
3508 | } | ||
3509 | |||
3510 | if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | ||
3333 | return -EINVAL; | 3511 | return -EINVAL; |
3334 | 3512 | ||
3335 | if (!rdev->ops->change_station) | 3513 | if (!rdev->ops->change_station) |
@@ -3398,6 +3576,13 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3398 | /* reject other things that can't change */ | 3576 | /* reject other things that can't change */ |
3399 | if (params.supported_rates) | 3577 | if (params.supported_rates) |
3400 | return -EINVAL; | 3578 | return -EINVAL; |
3579 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
3580 | return -EINVAL; | ||
3581 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
3582 | return -EINVAL; | ||
3583 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3584 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3585 | return -EINVAL; | ||
3401 | 3586 | ||
3402 | /* must be last in here for error handling */ | 3587 | /* must be last in here for error handling */ |
3403 | params.vlan = get_vlan(info, rdev); | 3588 | params.vlan = get_vlan(info, rdev); |
@@ -3413,13 +3598,29 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3413 | * to change the flag. | 3598 | * to change the flag. |
3414 | */ | 3599 | */ |
3415 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); | 3600 | params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER); |
3416 | /* fall through */ | 3601 | /* Include parameters for TDLS peer (driver will check) */ |
3602 | err = nl80211_set_station_tdls(info, ¶ms); | ||
3603 | if (err) | ||
3604 | return err; | ||
3605 | /* disallow things sta doesn't support */ | ||
3606 | if (params.plink_action) | ||
3607 | return -EINVAL; | ||
3608 | if (params.local_pm) | ||
3609 | return -EINVAL; | ||
3610 | /* reject any changes other than AUTHORIZED or WME (for TDLS) */ | ||
3611 | if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) | | ||
3612 | BIT(NL80211_STA_FLAG_WME))) | ||
3613 | return -EINVAL; | ||
3614 | break; | ||
3417 | case NL80211_IFTYPE_ADHOC: | 3615 | case NL80211_IFTYPE_ADHOC: |
3418 | /* disallow things sta doesn't support */ | 3616 | /* disallow things sta doesn't support */ |
3419 | if (params.plink_action) | 3617 | if (params.plink_action) |
3420 | return -EINVAL; | 3618 | return -EINVAL; |
3421 | if (params.local_pm) | 3619 | if (params.local_pm) |
3422 | return -EINVAL; | 3620 | return -EINVAL; |
3621 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3622 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3623 | return -EINVAL; | ||
3423 | /* reject any changes other than AUTHORIZED */ | 3624 | /* reject any changes other than AUTHORIZED */ |
3424 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | 3625 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) |
3425 | return -EINVAL; | 3626 | return -EINVAL; |
@@ -3430,6 +3631,13 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3430 | return -EINVAL; | 3631 | return -EINVAL; |
3431 | if (params.supported_rates) | 3632 | if (params.supported_rates) |
3432 | return -EINVAL; | 3633 | return -EINVAL; |
3634 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) | ||
3635 | return -EINVAL; | ||
3636 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) | ||
3637 | return -EINVAL; | ||
3638 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY] || | ||
3639 | info->attrs[NL80211_ATTR_VHT_CAPABILITY]) | ||
3640 | return -EINVAL; | ||
3433 | /* | 3641 | /* |
3434 | * No special handling for TDLS here -- the userspace | 3642 | * No special handling for TDLS here -- the userspace |
3435 | * mesh code doesn't have this bug. | 3643 | * mesh code doesn't have this bug. |
@@ -3454,12 +3662,6 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
3454 | return err; | 3662 | return err; |
3455 | } | 3663 | } |
3456 | 3664 | ||
3457 | static struct nla_policy | ||
3458 | nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = { | ||
3459 | [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 }, | ||
3460 | [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 }, | ||
3461 | }; | ||
3462 | |||
3463 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | 3665 | static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) |
3464 | { | 3666 | { |
3465 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3667 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -3494,6 +3696,19 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
3494 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | 3696 | if (!params.aid || params.aid > IEEE80211_MAX_AID) |
3495 | return -EINVAL; | 3697 | return -EINVAL; |
3496 | 3698 | ||
3699 | if (info->attrs[NL80211_ATTR_STA_CAPABILITY]) { | ||
3700 | params.capability = | ||
3701 | nla_get_u16(info->attrs[NL80211_ATTR_STA_CAPABILITY]); | ||
3702 | params.sta_modify_mask |= STATION_PARAM_APPLY_CAPABILITY; | ||
3703 | } | ||
3704 | |||
3705 | if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]) { | ||
3706 | params.ext_capab = | ||
3707 | nla_data(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
3708 | params.ext_capab_len = | ||
3709 | nla_len(info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY]); | ||
3710 | } | ||
3711 | |||
3497 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 3712 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
3498 | params.ht_capa = | 3713 | params.ht_capa = |
3499 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 3714 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
@@ -4987,6 +5202,54 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb, | |||
4987 | return err; | 5202 | return err; |
4988 | } | 5203 | } |
4989 | 5204 | ||
5205 | static int nl80211_start_radar_detection(struct sk_buff *skb, | ||
5206 | struct genl_info *info) | ||
5207 | { | ||
5208 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5209 | struct net_device *dev = info->user_ptr[1]; | ||
5210 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
5211 | struct cfg80211_chan_def chandef; | ||
5212 | int err; | ||
5213 | |||
5214 | err = nl80211_parse_chandef(rdev, info, &chandef); | ||
5215 | if (err) | ||
5216 | return err; | ||
5217 | |||
5218 | if (wdev->cac_started) | ||
5219 | return -EBUSY; | ||
5220 | |||
5221 | err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef); | ||
5222 | if (err < 0) | ||
5223 | return err; | ||
5224 | |||
5225 | if (err == 0) | ||
5226 | return -EINVAL; | ||
5227 | |||
5228 | if (chandef.chan->dfs_state != NL80211_DFS_USABLE) | ||
5229 | return -EINVAL; | ||
5230 | |||
5231 | if (!rdev->ops->start_radar_detection) | ||
5232 | return -EOPNOTSUPP; | ||
5233 | |||
5234 | mutex_lock(&rdev->devlist_mtx); | ||
5235 | err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, | ||
5236 | chandef.chan, CHAN_MODE_SHARED, | ||
5237 | BIT(chandef.width)); | ||
5238 | if (err) | ||
5239 | goto err_locked; | ||
5240 | |||
5241 | err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef); | ||
5242 | if (!err) { | ||
5243 | wdev->channel = chandef.chan; | ||
5244 | wdev->cac_started = true; | ||
5245 | wdev->cac_start_time = jiffies; | ||
5246 | } | ||
5247 | err_locked: | ||
5248 | mutex_unlock(&rdev->devlist_mtx); | ||
5249 | |||
5250 | return err; | ||
5251 | } | ||
5252 | |||
4990 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, | 5253 | static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, |
4991 | u32 seq, int flags, | 5254 | u32 seq, int flags, |
4992 | struct cfg80211_registered_device *rdev, | 5255 | struct cfg80211_registered_device *rdev, |
@@ -6895,16 +7158,100 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6895 | } | 7158 | } |
6896 | 7159 | ||
6897 | #ifdef CONFIG_PM | 7160 | #ifdef CONFIG_PM |
7161 | static int nl80211_send_wowlan_patterns(struct sk_buff *msg, | ||
7162 | struct cfg80211_registered_device *rdev) | ||
7163 | { | ||
7164 | struct nlattr *nl_pats, *nl_pat; | ||
7165 | int i, pat_len; | ||
7166 | |||
7167 | if (!rdev->wowlan->n_patterns) | ||
7168 | return 0; | ||
7169 | |||
7170 | nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN); | ||
7171 | if (!nl_pats) | ||
7172 | return -ENOBUFS; | ||
7173 | |||
7174 | for (i = 0; i < rdev->wowlan->n_patterns; i++) { | ||
7175 | nl_pat = nla_nest_start(msg, i + 1); | ||
7176 | if (!nl_pat) | ||
7177 | return -ENOBUFS; | ||
7178 | pat_len = rdev->wowlan->patterns[i].pattern_len; | ||
7179 | if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, | ||
7180 | DIV_ROUND_UP(pat_len, 8), | ||
7181 | rdev->wowlan->patterns[i].mask) || | ||
7182 | nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | ||
7183 | pat_len, rdev->wowlan->patterns[i].pattern) || | ||
7184 | nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET, | ||
7185 | rdev->wowlan->patterns[i].pkt_offset)) | ||
7186 | return -ENOBUFS; | ||
7187 | nla_nest_end(msg, nl_pat); | ||
7188 | } | ||
7189 | nla_nest_end(msg, nl_pats); | ||
7190 | |||
7191 | return 0; | ||
7192 | } | ||
7193 | |||
7194 | static int nl80211_send_wowlan_tcp(struct sk_buff *msg, | ||
7195 | struct cfg80211_wowlan_tcp *tcp) | ||
7196 | { | ||
7197 | struct nlattr *nl_tcp; | ||
7198 | |||
7199 | if (!tcp) | ||
7200 | return 0; | ||
7201 | |||
7202 | nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION); | ||
7203 | if (!nl_tcp) | ||
7204 | return -ENOBUFS; | ||
7205 | |||
7206 | if (nla_put_be32(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) || | ||
7207 | nla_put_be32(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) || | ||
7208 | nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) || | ||
7209 | nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) || | ||
7210 | nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) || | ||
7211 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD, | ||
7212 | tcp->payload_len, tcp->payload) || | ||
7213 | nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL, | ||
7214 | tcp->data_interval) || | ||
7215 | nla_put(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD, | ||
7216 | tcp->wake_len, tcp->wake_data) || | ||
7217 | nla_put(msg, NL80211_WOWLAN_TCP_WAKE_MASK, | ||
7218 | DIV_ROUND_UP(tcp->wake_len, 8), tcp->wake_mask)) | ||
7219 | return -ENOBUFS; | ||
7220 | |||
7221 | if (tcp->payload_seq.len && | ||
7222 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ, | ||
7223 | sizeof(tcp->payload_seq), &tcp->payload_seq)) | ||
7224 | return -ENOBUFS; | ||
7225 | |||
7226 | if (tcp->payload_tok.len && | ||
7227 | nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN, | ||
7228 | sizeof(tcp->payload_tok) + tcp->tokens_size, | ||
7229 | &tcp->payload_tok)) | ||
7230 | return -ENOBUFS; | ||
7231 | |||
7232 | return 0; | ||
7233 | } | ||
7234 | |||
6898 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 7235 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6899 | { | 7236 | { |
6900 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 7237 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6901 | struct sk_buff *msg; | 7238 | struct sk_buff *msg; |
6902 | void *hdr; | 7239 | void *hdr; |
7240 | u32 size = NLMSG_DEFAULT_SIZE; | ||
6903 | 7241 | ||
6904 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 7242 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && |
7243 | !rdev->wiphy.wowlan.tcp) | ||
6905 | return -EOPNOTSUPP; | 7244 | return -EOPNOTSUPP; |
6906 | 7245 | ||
6907 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 7246 | if (rdev->wowlan && rdev->wowlan->tcp) { |
7247 | /* adjust size to have room for all the data */ | ||
7248 | size += rdev->wowlan->tcp->tokens_size + | ||
7249 | rdev->wowlan->tcp->payload_len + | ||
7250 | rdev->wowlan->tcp->wake_len + | ||
7251 | rdev->wowlan->tcp->wake_len / 8; | ||
7252 | } | ||
7253 | |||
7254 | msg = nlmsg_new(size, GFP_KERNEL); | ||
6908 | if (!msg) | 7255 | if (!msg) |
6909 | return -ENOMEM; | 7256 | return -ENOMEM; |
6910 | 7257 | ||
@@ -6935,31 +7282,12 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6935 | (rdev->wowlan->rfkill_release && | 7282 | (rdev->wowlan->rfkill_release && |
6936 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) | 7283 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) |
6937 | goto nla_put_failure; | 7284 | goto nla_put_failure; |
6938 | if (rdev->wowlan->n_patterns) { | ||
6939 | struct nlattr *nl_pats, *nl_pat; | ||
6940 | int i, pat_len; | ||
6941 | 7285 | ||
6942 | nl_pats = nla_nest_start(msg, | 7286 | if (nl80211_send_wowlan_patterns(msg, rdev)) |
6943 | NL80211_WOWLAN_TRIG_PKT_PATTERN); | 7287 | goto nla_put_failure; |
6944 | if (!nl_pats) | ||
6945 | goto nla_put_failure; | ||
6946 | 7288 | ||
6947 | for (i = 0; i < rdev->wowlan->n_patterns; i++) { | 7289 | if (nl80211_send_wowlan_tcp(msg, rdev->wowlan->tcp)) |
6948 | nl_pat = nla_nest_start(msg, i + 1); | 7290 | goto nla_put_failure; |
6949 | if (!nl_pat) | ||
6950 | goto nla_put_failure; | ||
6951 | pat_len = rdev->wowlan->patterns[i].pattern_len; | ||
6952 | if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK, | ||
6953 | DIV_ROUND_UP(pat_len, 8), | ||
6954 | rdev->wowlan->patterns[i].mask) || | ||
6955 | nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | ||
6956 | pat_len, | ||
6957 | rdev->wowlan->patterns[i].pattern)) | ||
6958 | goto nla_put_failure; | ||
6959 | nla_nest_end(msg, nl_pat); | ||
6960 | } | ||
6961 | nla_nest_end(msg, nl_pats); | ||
6962 | } | ||
6963 | 7291 | ||
6964 | nla_nest_end(msg, nl_wowlan); | 7292 | nla_nest_end(msg, nl_wowlan); |
6965 | } | 7293 | } |
@@ -6972,6 +7300,150 @@ nla_put_failure: | |||
6972 | return -ENOBUFS; | 7300 | return -ENOBUFS; |
6973 | } | 7301 | } |
6974 | 7302 | ||
7303 | static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev, | ||
7304 | struct nlattr *attr, | ||
7305 | struct cfg80211_wowlan *trig) | ||
7306 | { | ||
7307 | struct nlattr *tb[NUM_NL80211_WOWLAN_TCP]; | ||
7308 | struct cfg80211_wowlan_tcp *cfg; | ||
7309 | struct nl80211_wowlan_tcp_data_token *tok = NULL; | ||
7310 | struct nl80211_wowlan_tcp_data_seq *seq = NULL; | ||
7311 | u32 size; | ||
7312 | u32 data_size, wake_size, tokens_size = 0, wake_mask_size; | ||
7313 | int err, port; | ||
7314 | |||
7315 | if (!rdev->wiphy.wowlan.tcp) | ||
7316 | return -EINVAL; | ||
7317 | |||
7318 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TCP, | ||
7319 | nla_data(attr), nla_len(attr), | ||
7320 | nl80211_wowlan_tcp_policy); | ||
7321 | if (err) | ||
7322 | return err; | ||
7323 | |||
7324 | if (!tb[NL80211_WOWLAN_TCP_SRC_IPV4] || | ||
7325 | !tb[NL80211_WOWLAN_TCP_DST_IPV4] || | ||
7326 | !tb[NL80211_WOWLAN_TCP_DST_MAC] || | ||
7327 | !tb[NL80211_WOWLAN_TCP_DST_PORT] || | ||
7328 | !tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD] || | ||
7329 | !tb[NL80211_WOWLAN_TCP_DATA_INTERVAL] || | ||
7330 | !tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD] || | ||
7331 | !tb[NL80211_WOWLAN_TCP_WAKE_MASK]) | ||
7332 | return -EINVAL; | ||
7333 | |||
7334 | data_size = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]); | ||
7335 | if (data_size > rdev->wiphy.wowlan.tcp->data_payload_max) | ||
7336 | return -EINVAL; | ||
7337 | |||
7338 | if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) > | ||
7339 | rdev->wiphy.wowlan.tcp->data_interval_max) | ||
7340 | return -EINVAL; | ||
7341 | |||
7342 | wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]); | ||
7343 | if (wake_size > rdev->wiphy.wowlan.tcp->wake_payload_max) | ||
7344 | return -EINVAL; | ||
7345 | |||
7346 | wake_mask_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_MASK]); | ||
7347 | if (wake_mask_size != DIV_ROUND_UP(wake_size, 8)) | ||
7348 | return -EINVAL; | ||
7349 | |||
7350 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]) { | ||
7351 | u32 tokln = nla_len(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]); | ||
7352 | |||
7353 | tok = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN]); | ||
7354 | tokens_size = tokln - sizeof(*tok); | ||
7355 | |||
7356 | if (!tok->len || tokens_size % tok->len) | ||
7357 | return -EINVAL; | ||
7358 | if (!rdev->wiphy.wowlan.tcp->tok) | ||
7359 | return -EINVAL; | ||
7360 | if (tok->len > rdev->wiphy.wowlan.tcp->tok->max_len) | ||
7361 | return -EINVAL; | ||
7362 | if (tok->len < rdev->wiphy.wowlan.tcp->tok->min_len) | ||
7363 | return -EINVAL; | ||
7364 | if (tokens_size > rdev->wiphy.wowlan.tcp->tok->bufsize) | ||
7365 | return -EINVAL; | ||
7366 | if (tok->offset + tok->len > data_size) | ||
7367 | return -EINVAL; | ||
7368 | } | ||
7369 | |||
7370 | if (tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]) { | ||
7371 | seq = nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ]); | ||
7372 | if (!rdev->wiphy.wowlan.tcp->seq) | ||
7373 | return -EINVAL; | ||
7374 | if (seq->len == 0 || seq->len > 4) | ||
7375 | return -EINVAL; | ||
7376 | if (seq->len + seq->offset > data_size) | ||
7377 | return -EINVAL; | ||
7378 | } | ||
7379 | |||
7380 | size = sizeof(*cfg); | ||
7381 | size += data_size; | ||
7382 | size += wake_size + wake_mask_size; | ||
7383 | size += tokens_size; | ||
7384 | |||
7385 | cfg = kzalloc(size, GFP_KERNEL); | ||
7386 | if (!cfg) | ||
7387 | return -ENOMEM; | ||
7388 | cfg->src = nla_get_be32(tb[NL80211_WOWLAN_TCP_SRC_IPV4]); | ||
7389 | cfg->dst = nla_get_be32(tb[NL80211_WOWLAN_TCP_DST_IPV4]); | ||
7390 | memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]), | ||
7391 | ETH_ALEN); | ||
7392 | if (tb[NL80211_WOWLAN_TCP_SRC_PORT]) | ||
7393 | port = nla_get_u16(tb[NL80211_WOWLAN_TCP_SRC_PORT]); | ||
7394 | else | ||
7395 | port = 0; | ||
7396 | #ifdef CONFIG_INET | ||
7397 | /* allocate a socket and port for it and use it */ | ||
7398 | err = __sock_create(wiphy_net(&rdev->wiphy), PF_INET, SOCK_STREAM, | ||
7399 | IPPROTO_TCP, &cfg->sock, 1); | ||
7400 | if (err) { | ||
7401 | kfree(cfg); | ||
7402 | return err; | ||
7403 | } | ||
7404 | if (inet_csk_get_port(cfg->sock->sk, port)) { | ||
7405 | sock_release(cfg->sock); | ||
7406 | kfree(cfg); | ||
7407 | return -EADDRINUSE; | ||
7408 | } | ||
7409 | cfg->src_port = inet_sk(cfg->sock->sk)->inet_num; | ||
7410 | #else | ||
7411 | if (!port) { | ||
7412 | kfree(cfg); | ||
7413 | return -EINVAL; | ||
7414 | } | ||
7415 | cfg->src_port = port; | ||
7416 | #endif | ||
7417 | |||
7418 | cfg->dst_port = nla_get_u16(tb[NL80211_WOWLAN_TCP_DST_PORT]); | ||
7419 | cfg->payload_len = data_size; | ||
7420 | cfg->payload = (u8 *)cfg + sizeof(*cfg) + tokens_size; | ||
7421 | memcpy((void *)cfg->payload, | ||
7422 | nla_data(tb[NL80211_WOWLAN_TCP_DATA_PAYLOAD]), | ||
7423 | data_size); | ||
7424 | if (seq) | ||
7425 | cfg->payload_seq = *seq; | ||
7426 | cfg->data_interval = nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]); | ||
7427 | cfg->wake_len = wake_size; | ||
7428 | cfg->wake_data = (u8 *)cfg + sizeof(*cfg) + tokens_size + data_size; | ||
7429 | memcpy((void *)cfg->wake_data, | ||
7430 | nla_data(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]), | ||
7431 | wake_size); | ||
7432 | cfg->wake_mask = (u8 *)cfg + sizeof(*cfg) + tokens_size + | ||
7433 | data_size + wake_size; | ||
7434 | memcpy((void *)cfg->wake_mask, | ||
7435 | nla_data(tb[NL80211_WOWLAN_TCP_WAKE_MASK]), | ||
7436 | wake_mask_size); | ||
7437 | if (tok) { | ||
7438 | cfg->tokens_size = tokens_size; | ||
7439 | memcpy(&cfg->payload_tok, tok, sizeof(*tok) + tokens_size); | ||
7440 | } | ||
7441 | |||
7442 | trig->tcp = cfg; | ||
7443 | |||
7444 | return 0; | ||
7445 | } | ||
7446 | |||
6975 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | 7447 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) |
6976 | { | 7448 | { |
6977 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 7449 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6982,7 +7454,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6982 | int err, i; | 7454 | int err, i; |
6983 | bool prev_enabled = rdev->wowlan; | 7455 | bool prev_enabled = rdev->wowlan; |
6984 | 7456 | ||
6985 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 7457 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns && |
7458 | !rdev->wiphy.wowlan.tcp) | ||
6986 | return -EOPNOTSUPP; | 7459 | return -EOPNOTSUPP; |
6987 | 7460 | ||
6988 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { | 7461 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
@@ -7046,7 +7519,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7046 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { | 7519 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { |
7047 | struct nlattr *pat; | 7520 | struct nlattr *pat; |
7048 | int n_patterns = 0; | 7521 | int n_patterns = 0; |
7049 | int rem, pat_len, mask_len; | 7522 | int rem, pat_len, mask_len, pkt_offset; |
7050 | struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; | 7523 | struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; |
7051 | 7524 | ||
7052 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | 7525 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], |
@@ -7081,6 +7554,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7081 | pat_len < wowlan->pattern_min_len) | 7554 | pat_len < wowlan->pattern_min_len) |
7082 | goto error; | 7555 | goto error; |
7083 | 7556 | ||
7557 | if (!pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]) | ||
7558 | pkt_offset = 0; | ||
7559 | else | ||
7560 | pkt_offset = nla_get_u32( | ||
7561 | pat_tb[NL80211_WOWLAN_PKTPAT_OFFSET]); | ||
7562 | if (pkt_offset > wowlan->max_pkt_offset) | ||
7563 | goto error; | ||
7564 | new_triggers.patterns[i].pkt_offset = pkt_offset; | ||
7565 | |||
7084 | new_triggers.patterns[i].mask = | 7566 | new_triggers.patterns[i].mask = |
7085 | kmalloc(mask_len + pat_len, GFP_KERNEL); | 7567 | kmalloc(mask_len + pat_len, GFP_KERNEL); |
7086 | if (!new_triggers.patterns[i].mask) { | 7568 | if (!new_triggers.patterns[i].mask) { |
@@ -7100,6 +7582,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7100 | } | 7582 | } |
7101 | } | 7583 | } |
7102 | 7584 | ||
7585 | if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) { | ||
7586 | err = nl80211_parse_wowlan_tcp( | ||
7587 | rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION], | ||
7588 | &new_triggers); | ||
7589 | if (err) | ||
7590 | goto error; | ||
7591 | } | ||
7592 | |||
7103 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); | 7593 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
7104 | if (!ntrig) { | 7594 | if (!ntrig) { |
7105 | err = -ENOMEM; | 7595 | err = -ENOMEM; |
@@ -7117,6 +7607,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
7117 | for (i = 0; i < new_triggers.n_patterns; i++) | 7607 | for (i = 0; i < new_triggers.n_patterns; i++) |
7118 | kfree(new_triggers.patterns[i].mask); | 7608 | kfree(new_triggers.patterns[i].mask); |
7119 | kfree(new_triggers.patterns); | 7609 | kfree(new_triggers.patterns); |
7610 | if (new_triggers.tcp && new_triggers.tcp->sock) | ||
7611 | sock_release(new_triggers.tcp->sock); | ||
7612 | kfree(new_triggers.tcp); | ||
7120 | return err; | 7613 | return err; |
7121 | } | 7614 | } |
7122 | #endif | 7615 | #endif |
@@ -8007,6 +8500,14 @@ static struct genl_ops nl80211_ops[] = { | |||
8007 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 8500 | .internal_flags = NL80211_FLAG_NEED_NETDEV | |
8008 | NL80211_FLAG_NEED_RTNL, | 8501 | NL80211_FLAG_NEED_RTNL, |
8009 | }, | 8502 | }, |
8503 | { | ||
8504 | .cmd = NL80211_CMD_RADAR_DETECT, | ||
8505 | .doit = nl80211_start_radar_detection, | ||
8506 | .policy = nl80211_policy, | ||
8507 | .flags = GENL_ADMIN_PERM, | ||
8508 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
8509 | NL80211_FLAG_NEED_RTNL, | ||
8510 | }, | ||
8010 | }; | 8511 | }; |
8011 | 8512 | ||
8012 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 8513 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -9204,6 +9705,57 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | |||
9204 | } | 9705 | } |
9205 | 9706 | ||
9206 | void | 9707 | void |
9708 | nl80211_radar_notify(struct cfg80211_registered_device *rdev, | ||
9709 | struct cfg80211_chan_def *chandef, | ||
9710 | enum nl80211_radar_event event, | ||
9711 | struct net_device *netdev, gfp_t gfp) | ||
9712 | { | ||
9713 | struct sk_buff *msg; | ||
9714 | void *hdr; | ||
9715 | |||
9716 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
9717 | if (!msg) | ||
9718 | return; | ||
9719 | |||
9720 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT); | ||
9721 | if (!hdr) { | ||
9722 | nlmsg_free(msg); | ||
9723 | return; | ||
9724 | } | ||
9725 | |||
9726 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) | ||
9727 | goto nla_put_failure; | ||
9728 | |||
9729 | /* NOP and radar events don't need a netdev parameter */ | ||
9730 | if (netdev) { | ||
9731 | struct wireless_dev *wdev = netdev->ieee80211_ptr; | ||
9732 | |||
9733 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | ||
9734 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
9735 | goto nla_put_failure; | ||
9736 | } | ||
9737 | |||
9738 | if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event)) | ||
9739 | goto nla_put_failure; | ||
9740 | |||
9741 | if (nl80211_send_chandef(msg, chandef)) | ||
9742 | goto nla_put_failure; | ||
9743 | |||
9744 | if (genlmsg_end(msg, hdr) < 0) { | ||
9745 | nlmsg_free(msg); | ||
9746 | return; | ||
9747 | } | ||
9748 | |||
9749 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
9750 | nl80211_mlme_mcgrp.id, gfp); | ||
9751 | return; | ||
9752 | |||
9753 | nla_put_failure: | ||
9754 | genlmsg_cancel(msg, hdr); | ||
9755 | nlmsg_free(msg); | ||
9756 | } | ||
9757 | |||
9758 | void | ||
9207 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 9759 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
9208 | struct net_device *netdev, const u8 *peer, | 9760 | struct net_device *netdev, const u8 *peer, |
9209 | u32 num_packets, gfp_t gfp) | 9761 | u32 num_packets, gfp_t gfp) |
@@ -9398,6 +9950,17 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev, | |||
9398 | wakeup->pattern_idx)) | 9950 | wakeup->pattern_idx)) |
9399 | goto free_msg; | 9951 | goto free_msg; |
9400 | 9952 | ||
9953 | if (wakeup->tcp_match) | ||
9954 | nla_put_flag(msg, NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH); | ||
9955 | |||
9956 | if (wakeup->tcp_connlost) | ||
9957 | nla_put_flag(msg, | ||
9958 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST); | ||
9959 | |||
9960 | if (wakeup->tcp_nomoretokens) | ||
9961 | nla_put_flag(msg, | ||
9962 | NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS); | ||
9963 | |||
9401 | if (wakeup->packet) { | 9964 | if (wakeup->packet) { |
9402 | u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211; | 9965 | u32 pkt_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211; |
9403 | u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN; | 9966 | u32 len_attr = NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211_LEN; |