diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 140 |
1 files changed, 104 insertions, 36 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0f1b18f209d6..62bdb1adaa4d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -371,8 +371,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
371 | [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 }, | 371 | [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 }, |
372 | [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG }, | 372 | [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG }, |
373 | [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED }, | 373 | [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED }, |
374 | [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 }, | 374 | [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_BINARY }, |
375 | [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 }, | 375 | [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_BINARY }, |
376 | [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, | 376 | [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, |
377 | [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, | 377 | [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, |
378 | [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG }, | 378 | [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG }, |
@@ -386,6 +386,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
386 | [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, | 386 | [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, |
387 | [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, | 387 | [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, |
388 | [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG }, | 388 | [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG }, |
389 | [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY }, | ||
389 | }; | 390 | }; |
390 | 391 | ||
391 | /* policy for the key attributes */ | 392 | /* policy for the key attributes */ |
@@ -970,8 +971,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy, | |||
970 | c->max_interfaces)) | 971 | c->max_interfaces)) |
971 | goto nla_put_failure; | 972 | goto nla_put_failure; |
972 | if (large && | 973 | if (large && |
973 | nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, | 974 | (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, |
974 | c->radar_detect_widths)) | 975 | c->radar_detect_widths) || |
976 | nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS, | ||
977 | c->radar_detect_regions))) | ||
975 | goto nla_put_failure; | 978 | goto nla_put_failure; |
976 | 979 | ||
977 | nla_nest_end(msg, nl_combi); | 980 | nla_nest_end(msg, nl_combi); |
@@ -1667,6 +1670,13 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, | |||
1667 | } | 1670 | } |
1668 | nla_nest_end(msg, nested); | 1671 | nla_nest_end(msg, nested); |
1669 | } | 1672 | } |
1673 | state->split_start++; | ||
1674 | break; | ||
1675 | case 12: | ||
1676 | if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH && | ||
1677 | nla_put_u8(msg, NL80211_ATTR_MAX_CSA_COUNTERS, | ||
1678 | rdev->wiphy.max_num_csa_counters)) | ||
1679 | goto nla_put_failure; | ||
1670 | 1680 | ||
1671 | /* done */ | 1681 | /* done */ |
1672 | state->split_start = 0; | 1682 | state->split_start = 0; |
@@ -3640,6 +3650,10 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq, | |||
3640 | nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED, | 3650 | nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED, |
3641 | sinfo->tx_failed)) | 3651 | sinfo->tx_failed)) |
3642 | goto nla_put_failure; | 3652 | goto nla_put_failure; |
3653 | if ((sinfo->filled & STATION_INFO_EXPECTED_THROUGHPUT) && | ||
3654 | nla_put_u32(msg, NL80211_STA_INFO_EXPECTED_THROUGHPUT, | ||
3655 | sinfo->expected_throughput)) | ||
3656 | goto nla_put_failure; | ||
3643 | if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) && | 3657 | if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) && |
3644 | nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS, | 3658 | nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS, |
3645 | sinfo->beacon_loss_count)) | 3659 | sinfo->beacon_loss_count)) |
@@ -5820,7 +5834,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5820 | return -EBUSY; | 5834 | return -EBUSY; |
5821 | 5835 | ||
5822 | err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, | 5836 | err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef, |
5823 | NL80211_IFTYPE_UNSPECIFIED); | 5837 | wdev->iftype); |
5824 | if (err < 0) | 5838 | if (err < 0) |
5825 | return err; | 5839 | return err; |
5826 | 5840 | ||
@@ -5861,6 +5875,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5861 | u8 radar_detect_width = 0; | 5875 | u8 radar_detect_width = 0; |
5862 | int err; | 5876 | int err; |
5863 | bool need_new_beacon = false; | 5877 | bool need_new_beacon = false; |
5878 | int len, i; | ||
5864 | 5879 | ||
5865 | if (!rdev->ops->channel_switch || | 5880 | if (!rdev->ops->channel_switch || |
5866 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) | 5881 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) |
@@ -5919,26 +5934,55 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) | |||
5919 | if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]) | 5934 | if (!csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]) |
5920 | return -EINVAL; | 5935 | return -EINVAL; |
5921 | 5936 | ||
5922 | params.counter_offset_beacon = | 5937 | len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]); |
5923 | nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]); | 5938 | if (!len || (len % sizeof(u16))) |
5924 | if (params.counter_offset_beacon >= params.beacon_csa.tail_len) | ||
5925 | return -EINVAL; | 5939 | return -EINVAL; |
5926 | 5940 | ||
5927 | /* sanity check - counters should be the same */ | 5941 | params.n_counter_offsets_beacon = len / sizeof(u16); |
5928 | if (params.beacon_csa.tail[params.counter_offset_beacon] != | 5942 | if (rdev->wiphy.max_num_csa_counters && |
5929 | params.count) | 5943 | (params.n_counter_offsets_beacon > |
5944 | rdev->wiphy.max_num_csa_counters)) | ||
5930 | return -EINVAL; | 5945 | return -EINVAL; |
5931 | 5946 | ||
5947 | params.counter_offsets_beacon = | ||
5948 | nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_BEACON]); | ||
5949 | |||
5950 | /* sanity checks - counters should fit and be the same */ | ||
5951 | for (i = 0; i < params.n_counter_offsets_beacon; i++) { | ||
5952 | u16 offset = params.counter_offsets_beacon[i]; | ||
5953 | |||
5954 | if (offset >= params.beacon_csa.tail_len) | ||
5955 | return -EINVAL; | ||
5956 | |||
5957 | if (params.beacon_csa.tail[offset] != params.count) | ||
5958 | return -EINVAL; | ||
5959 | } | ||
5960 | |||
5932 | if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) { | 5961 | if (csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]) { |
5933 | params.counter_offset_presp = | 5962 | len = nla_len(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]); |
5934 | nla_get_u16(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]); | 5963 | if (!len || (len % sizeof(u16))) |
5935 | if (params.counter_offset_presp >= | ||
5936 | params.beacon_csa.probe_resp_len) | ||
5937 | return -EINVAL; | 5964 | return -EINVAL; |
5938 | 5965 | ||
5939 | if (params.beacon_csa.probe_resp[params.counter_offset_presp] != | 5966 | params.n_counter_offsets_presp = len / sizeof(u16); |
5940 | params.count) | 5967 | if (rdev->wiphy.max_num_csa_counters && |
5968 | (params.n_counter_offsets_beacon > | ||
5969 | rdev->wiphy.max_num_csa_counters)) | ||
5941 | return -EINVAL; | 5970 | return -EINVAL; |
5971 | |||
5972 | params.counter_offsets_presp = | ||
5973 | nla_data(csa_attrs[NL80211_ATTR_CSA_C_OFF_PRESP]); | ||
5974 | |||
5975 | /* sanity checks - counters should fit and be the same */ | ||
5976 | for (i = 0; i < params.n_counter_offsets_presp; i++) { | ||
5977 | u16 offset = params.counter_offsets_presp[i]; | ||
5978 | |||
5979 | if (offset >= params.beacon_csa.probe_resp_len) | ||
5980 | return -EINVAL; | ||
5981 | |||
5982 | if (params.beacon_csa.probe_resp[offset] != | ||
5983 | params.count) | ||
5984 | return -EINVAL; | ||
5985 | } | ||
5942 | } | 5986 | } |
5943 | 5987 | ||
5944 | skip_beacons: | 5988 | skip_beacons: |
@@ -7784,6 +7828,27 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7784 | if (!chandef.chan && params.offchan) | 7828 | if (!chandef.chan && params.offchan) |
7785 | return -EINVAL; | 7829 | return -EINVAL; |
7786 | 7830 | ||
7831 | params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); | ||
7832 | params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]); | ||
7833 | |||
7834 | if (info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]) { | ||
7835 | int len = nla_len(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]); | ||
7836 | int i; | ||
7837 | |||
7838 | if (len % sizeof(u16)) | ||
7839 | return -EINVAL; | ||
7840 | |||
7841 | params.n_csa_offsets = len / sizeof(u16); | ||
7842 | params.csa_offsets = | ||
7843 | nla_data(info->attrs[NL80211_ATTR_CSA_C_OFFSETS_TX]); | ||
7844 | |||
7845 | /* check that all the offsets fit the frame */ | ||
7846 | for (i = 0; i < params.n_csa_offsets; i++) { | ||
7847 | if (params.csa_offsets[i] >= params.len) | ||
7848 | return -EINVAL; | ||
7849 | } | ||
7850 | } | ||
7851 | |||
7787 | if (!params.dont_wait_for_ack) { | 7852 | if (!params.dont_wait_for_ack) { |
7788 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 7853 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7789 | if (!msg) | 7854 | if (!msg) |
@@ -7797,8 +7862,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
7797 | } | 7862 | } |
7798 | } | 7863 | } |
7799 | 7864 | ||
7800 | params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]); | ||
7801 | params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]); | ||
7802 | params.chan = chandef.chan; | 7865 | params.chan = chandef.chan; |
7803 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, ¶ms, &cookie); | 7866 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, ¶ms, &cookie); |
7804 | if (err) | 7867 | if (err) |
@@ -8495,6 +8558,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
8495 | 8558 | ||
8496 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | 8559 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], |
8497 | rem) { | 8560 | rem) { |
8561 | u8 *mask_pat; | ||
8562 | |||
8498 | nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), | 8563 | nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), |
8499 | nla_len(pat), NULL); | 8564 | nla_len(pat), NULL); |
8500 | err = -EINVAL; | 8565 | err = -EINVAL; |
@@ -8518,19 +8583,18 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
8518 | goto error; | 8583 | goto error; |
8519 | new_triggers.patterns[i].pkt_offset = pkt_offset; | 8584 | new_triggers.patterns[i].pkt_offset = pkt_offset; |
8520 | 8585 | ||
8521 | new_triggers.patterns[i].mask = | 8586 | mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL); |
8522 | kmalloc(mask_len + pat_len, GFP_KERNEL); | 8587 | if (!mask_pat) { |
8523 | if (!new_triggers.patterns[i].mask) { | ||
8524 | err = -ENOMEM; | 8588 | err = -ENOMEM; |
8525 | goto error; | 8589 | goto error; |
8526 | } | 8590 | } |
8527 | new_triggers.patterns[i].pattern = | 8591 | new_triggers.patterns[i].mask = mask_pat; |
8528 | new_triggers.patterns[i].mask + mask_len; | 8592 | memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]), |
8529 | memcpy(new_triggers.patterns[i].mask, | ||
8530 | nla_data(pat_tb[NL80211_PKTPAT_MASK]), | ||
8531 | mask_len); | 8593 | mask_len); |
8594 | mask_pat += mask_len; | ||
8595 | new_triggers.patterns[i].pattern = mask_pat; | ||
8532 | new_triggers.patterns[i].pattern_len = pat_len; | 8596 | new_triggers.patterns[i].pattern_len = pat_len; |
8533 | memcpy(new_triggers.patterns[i].pattern, | 8597 | memcpy(mask_pat, |
8534 | nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), | 8598 | nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), |
8535 | pat_len); | 8599 | pat_len); |
8536 | i++; | 8600 | i++; |
@@ -8722,6 +8786,8 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev, | |||
8722 | 8786 | ||
8723 | nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN], | 8787 | nla_for_each_nested(pat, tb[NL80211_ATTR_COALESCE_RULE_PKT_PATTERN], |
8724 | rem) { | 8788 | rem) { |
8789 | u8 *mask_pat; | ||
8790 | |||
8725 | nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), | 8791 | nla_parse(pat_tb, MAX_NL80211_PKTPAT, nla_data(pat), |
8726 | nla_len(pat), NULL); | 8792 | nla_len(pat), NULL); |
8727 | if (!pat_tb[NL80211_PKTPAT_MASK] || | 8793 | if (!pat_tb[NL80211_PKTPAT_MASK] || |
@@ -8743,17 +8809,19 @@ static int nl80211_parse_coalesce_rule(struct cfg80211_registered_device *rdev, | |||
8743 | return -EINVAL; | 8809 | return -EINVAL; |
8744 | new_rule->patterns[i].pkt_offset = pkt_offset; | 8810 | new_rule->patterns[i].pkt_offset = pkt_offset; |
8745 | 8811 | ||
8746 | new_rule->patterns[i].mask = | 8812 | mask_pat = kmalloc(mask_len + pat_len, GFP_KERNEL); |
8747 | kmalloc(mask_len + pat_len, GFP_KERNEL); | 8813 | if (!mask_pat) |
8748 | if (!new_rule->patterns[i].mask) | ||
8749 | return -ENOMEM; | 8814 | return -ENOMEM; |
8750 | new_rule->patterns[i].pattern = | 8815 | |
8751 | new_rule->patterns[i].mask + mask_len; | 8816 | new_rule->patterns[i].mask = mask_pat; |
8752 | memcpy(new_rule->patterns[i].mask, | 8817 | memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_MASK]), |
8753 | nla_data(pat_tb[NL80211_PKTPAT_MASK]), mask_len); | 8818 | mask_len); |
8819 | |||
8820 | mask_pat += mask_len; | ||
8821 | new_rule->patterns[i].pattern = mask_pat; | ||
8754 | new_rule->patterns[i].pattern_len = pat_len; | 8822 | new_rule->patterns[i].pattern_len = pat_len; |
8755 | memcpy(new_rule->patterns[i].pattern, | 8823 | memcpy(mask_pat, nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), |
8756 | nla_data(pat_tb[NL80211_PKTPAT_PATTERN]), pat_len); | 8824 | pat_len); |
8757 | i++; | 8825 | i++; |
8758 | } | 8826 | } |
8759 | 8827 | ||