diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 794 |
1 files changed, 742 insertions, 52 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4ebce4284e9d..ec83f413a7ed 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -124,6 +124,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
124 | [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 }, | 124 | [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 }, |
125 | 125 | ||
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 | 128 | ||
128 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, | 129 | [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, |
129 | .len = NL80211_HT_CAPABILITY_LEN }, | 130 | .len = NL80211_HT_CAPABILITY_LEN }, |
@@ -172,6 +173,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
172 | [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, | 173 | [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 }, |
173 | [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, | 174 | [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG }, |
174 | [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, | 175 | [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED }, |
176 | [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED }, | ||
177 | [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 }, | ||
178 | [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 }, | ||
175 | }; | 179 | }; |
176 | 180 | ||
177 | /* policy for the key attributes */ | 181 | /* policy for the key attributes */ |
@@ -193,6 +197,15 @@ nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = { | |||
193 | [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, | 197 | [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG }, |
194 | }; | 198 | }; |
195 | 199 | ||
200 | /* policy for WoWLAN attributes */ | ||
201 | static const struct nla_policy | ||
202 | nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = { | ||
203 | [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG }, | ||
204 | [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG }, | ||
205 | [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG }, | ||
206 | [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED }, | ||
207 | }; | ||
208 | |||
196 | /* ifidx get helper */ | 209 | /* ifidx get helper */ |
197 | static int nl80211_get_ifidx(struct netlink_callback *cb) | 210 | static int nl80211_get_ifidx(struct netlink_callback *cb) |
198 | { | 211 | { |
@@ -533,6 +546,7 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
533 | case NL80211_IFTYPE_AP: | 546 | case NL80211_IFTYPE_AP: |
534 | case NL80211_IFTYPE_AP_VLAN: | 547 | case NL80211_IFTYPE_AP_VLAN: |
535 | case NL80211_IFTYPE_P2P_GO: | 548 | case NL80211_IFTYPE_P2P_GO: |
549 | case NL80211_IFTYPE_MESH_POINT: | ||
536 | break; | 550 | break; |
537 | case NL80211_IFTYPE_ADHOC: | 551 | case NL80211_IFTYPE_ADHOC: |
538 | if (!wdev->current_bss) | 552 | if (!wdev->current_bss) |
@@ -550,6 +564,88 @@ static int nl80211_key_allowed(struct wireless_dev *wdev) | |||
550 | return 0; | 564 | return 0; |
551 | } | 565 | } |
552 | 566 | ||
567 | static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes) | ||
568 | { | ||
569 | struct nlattr *nl_modes = nla_nest_start(msg, attr); | ||
570 | int i; | ||
571 | |||
572 | if (!nl_modes) | ||
573 | goto nla_put_failure; | ||
574 | |||
575 | i = 0; | ||
576 | while (ifmodes) { | ||
577 | if (ifmodes & 1) | ||
578 | NLA_PUT_FLAG(msg, i); | ||
579 | ifmodes >>= 1; | ||
580 | i++; | ||
581 | } | ||
582 | |||
583 | nla_nest_end(msg, nl_modes); | ||
584 | return 0; | ||
585 | |||
586 | nla_put_failure: | ||
587 | return -ENOBUFS; | ||
588 | } | ||
589 | |||
590 | static int nl80211_put_iface_combinations(struct wiphy *wiphy, | ||
591 | struct sk_buff *msg) | ||
592 | { | ||
593 | struct nlattr *nl_combis; | ||
594 | int i, j; | ||
595 | |||
596 | nl_combis = nla_nest_start(msg, | ||
597 | NL80211_ATTR_INTERFACE_COMBINATIONS); | ||
598 | if (!nl_combis) | ||
599 | goto nla_put_failure; | ||
600 | |||
601 | for (i = 0; i < wiphy->n_iface_combinations; i++) { | ||
602 | const struct ieee80211_iface_combination *c; | ||
603 | struct nlattr *nl_combi, *nl_limits; | ||
604 | |||
605 | c = &wiphy->iface_combinations[i]; | ||
606 | |||
607 | nl_combi = nla_nest_start(msg, i + 1); | ||
608 | if (!nl_combi) | ||
609 | goto nla_put_failure; | ||
610 | |||
611 | nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS); | ||
612 | if (!nl_limits) | ||
613 | goto nla_put_failure; | ||
614 | |||
615 | for (j = 0; j < c->n_limits; j++) { | ||
616 | struct nlattr *nl_limit; | ||
617 | |||
618 | nl_limit = nla_nest_start(msg, j + 1); | ||
619 | if (!nl_limit) | ||
620 | goto nla_put_failure; | ||
621 | NLA_PUT_U32(msg, NL80211_IFACE_LIMIT_MAX, | ||
622 | c->limits[j].max); | ||
623 | if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES, | ||
624 | c->limits[j].types)) | ||
625 | goto nla_put_failure; | ||
626 | nla_nest_end(msg, nl_limit); | ||
627 | } | ||
628 | |||
629 | nla_nest_end(msg, nl_limits); | ||
630 | |||
631 | if (c->beacon_int_infra_match) | ||
632 | NLA_PUT_FLAG(msg, | ||
633 | NL80211_IFACE_COMB_STA_AP_BI_MATCH); | ||
634 | NLA_PUT_U32(msg, NL80211_IFACE_COMB_NUM_CHANNELS, | ||
635 | c->num_different_channels); | ||
636 | NLA_PUT_U32(msg, NL80211_IFACE_COMB_MAXNUM, | ||
637 | c->max_interfaces); | ||
638 | |||
639 | nla_nest_end(msg, nl_combi); | ||
640 | } | ||
641 | |||
642 | nla_nest_end(msg, nl_combis); | ||
643 | |||
644 | return 0; | ||
645 | nla_put_failure: | ||
646 | return -ENOBUFS; | ||
647 | } | ||
648 | |||
553 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 649 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
554 | struct cfg80211_registered_device *dev) | 650 | struct cfg80211_registered_device *dev) |
555 | { | 651 | { |
@@ -557,13 +653,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
557 | struct nlattr *nl_bands, *nl_band; | 653 | struct nlattr *nl_bands, *nl_band; |
558 | struct nlattr *nl_freqs, *nl_freq; | 654 | struct nlattr *nl_freqs, *nl_freq; |
559 | struct nlattr *nl_rates, *nl_rate; | 655 | struct nlattr *nl_rates, *nl_rate; |
560 | struct nlattr *nl_modes; | ||
561 | struct nlattr *nl_cmds; | 656 | struct nlattr *nl_cmds; |
562 | enum ieee80211_band band; | 657 | enum ieee80211_band band; |
563 | struct ieee80211_channel *chan; | 658 | struct ieee80211_channel *chan; |
564 | struct ieee80211_rate *rate; | 659 | struct ieee80211_rate *rate; |
565 | int i; | 660 | int i; |
566 | u16 ifmodes = dev->wiphy.interface_modes; | ||
567 | const struct ieee80211_txrx_stypes *mgmt_stypes = | 661 | const struct ieee80211_txrx_stypes *mgmt_stypes = |
568 | dev->wiphy.mgmt_stypes; | 662 | dev->wiphy.mgmt_stypes; |
569 | 663 | ||
@@ -594,6 +688,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
594 | 688 | ||
595 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) | 689 | if (dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) |
596 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); | 690 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_IBSS_RSN); |
691 | if (dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) | ||
692 | NLA_PUT_FLAG(msg, NL80211_ATTR_SUPPORT_MESH_AUTH); | ||
597 | 693 | ||
598 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | 694 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, |
599 | sizeof(u32) * dev->wiphy.n_cipher_suites, | 695 | sizeof(u32) * dev->wiphy.n_cipher_suites, |
@@ -621,20 +717,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
621 | } | 717 | } |
622 | } | 718 | } |
623 | 719 | ||
624 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 720 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, |
625 | if (!nl_modes) | 721 | dev->wiphy.interface_modes)) |
626 | goto nla_put_failure; | 722 | goto nla_put_failure; |
627 | 723 | ||
628 | i = 0; | ||
629 | while (ifmodes) { | ||
630 | if (ifmodes & 1) | ||
631 | NLA_PUT_FLAG(msg, i); | ||
632 | ifmodes >>= 1; | ||
633 | i++; | ||
634 | } | ||
635 | |||
636 | nla_nest_end(msg, nl_modes); | ||
637 | |||
638 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); | 724 | nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); |
639 | if (!nl_bands) | 725 | if (!nl_bands) |
640 | goto nla_put_failure; | 726 | goto nla_put_failure; |
@@ -746,6 +832,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
746 | } | 832 | } |
747 | CMD(set_channel, SET_CHANNEL); | 833 | CMD(set_channel, SET_CHANNEL); |
748 | CMD(set_wds_peer, SET_WDS_PEER); | 834 | CMD(set_wds_peer, SET_WDS_PEER); |
835 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) | ||
836 | CMD(sched_scan_start, START_SCHED_SCAN); | ||
749 | 837 | ||
750 | #undef CMD | 838 | #undef CMD |
751 | 839 | ||
@@ -818,6 +906,42 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
818 | nla_nest_end(msg, nl_ifs); | 906 | nla_nest_end(msg, nl_ifs); |
819 | } | 907 | } |
820 | 908 | ||
909 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | ||
910 | struct nlattr *nl_wowlan; | ||
911 | |||
912 | nl_wowlan = nla_nest_start(msg, | ||
913 | NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED); | ||
914 | if (!nl_wowlan) | ||
915 | goto nla_put_failure; | ||
916 | |||
917 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) | ||
918 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); | ||
919 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) | ||
920 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | ||
921 | if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) | ||
922 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | ||
923 | if (dev->wiphy.wowlan.n_patterns) { | ||
924 | struct nl80211_wowlan_pattern_support pat = { | ||
925 | .max_patterns = dev->wiphy.wowlan.n_patterns, | ||
926 | .min_pattern_len = | ||
927 | dev->wiphy.wowlan.pattern_min_len, | ||
928 | .max_pattern_len = | ||
929 | dev->wiphy.wowlan.pattern_max_len, | ||
930 | }; | ||
931 | NLA_PUT(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, | ||
932 | sizeof(pat), &pat); | ||
933 | } | ||
934 | |||
935 | nla_nest_end(msg, nl_wowlan); | ||
936 | } | ||
937 | |||
938 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | ||
939 | dev->wiphy.software_iftypes)) | ||
940 | goto nla_put_failure; | ||
941 | |||
942 | if (nl80211_put_iface_combinations(&dev->wiphy, msg)) | ||
943 | goto nla_put_failure; | ||
944 | |||
821 | return genlmsg_end(msg, hdr); | 945 | return genlmsg_end(msg, hdr); |
822 | 946 | ||
823 | nla_put_failure: | 947 | nla_put_failure: |
@@ -1679,14 +1803,6 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1679 | if (err) | 1803 | if (err) |
1680 | goto out; | 1804 | goto out; |
1681 | 1805 | ||
1682 | if (!(rdev->wiphy.flags & | ||
1683 | WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS)) { | ||
1684 | if (!key.def_uni || !key.def_multi) { | ||
1685 | err = -EOPNOTSUPP; | ||
1686 | goto out; | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, | 1806 | err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx, |
1691 | key.def_uni, key.def_multi); | 1807 | key.def_uni, key.def_multi); |
1692 | 1808 | ||
@@ -1837,8 +1953,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1837 | struct beacon_parameters *info); | 1953 | struct beacon_parameters *info); |
1838 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 1954 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1839 | struct net_device *dev = info->user_ptr[1]; | 1955 | struct net_device *dev = info->user_ptr[1]; |
1956 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1840 | struct beacon_parameters params; | 1957 | struct beacon_parameters params; |
1841 | int haveinfo = 0; | 1958 | int haveinfo = 0, err; |
1842 | 1959 | ||
1843 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) | 1960 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) |
1844 | return -EINVAL; | 1961 | return -EINVAL; |
@@ -1847,6 +1964,8 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1847 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 1964 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1848 | return -EOPNOTSUPP; | 1965 | return -EOPNOTSUPP; |
1849 | 1966 | ||
1967 | memset(¶ms, 0, sizeof(params)); | ||
1968 | |||
1850 | switch (info->genlhdr->cmd) { | 1969 | switch (info->genlhdr->cmd) { |
1851 | case NL80211_CMD_NEW_BEACON: | 1970 | case NL80211_CMD_NEW_BEACON: |
1852 | /* these are required for NEW_BEACON */ | 1971 | /* these are required for NEW_BEACON */ |
@@ -1855,6 +1974,15 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1855 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) | 1974 | !info->attrs[NL80211_ATTR_BEACON_HEAD]) |
1856 | return -EINVAL; | 1975 | return -EINVAL; |
1857 | 1976 | ||
1977 | params.interval = | ||
1978 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | ||
1979 | params.dtim_period = | ||
1980 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); | ||
1981 | |||
1982 | err = cfg80211_validate_beacon_int(rdev, params.interval); | ||
1983 | if (err) | ||
1984 | return err; | ||
1985 | |||
1858 | call = rdev->ops->add_beacon; | 1986 | call = rdev->ops->add_beacon; |
1859 | break; | 1987 | break; |
1860 | case NL80211_CMD_SET_BEACON: | 1988 | case NL80211_CMD_SET_BEACON: |
@@ -1868,20 +1996,6 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1868 | if (!call) | 1996 | if (!call) |
1869 | return -EOPNOTSUPP; | 1997 | return -EOPNOTSUPP; |
1870 | 1998 | ||
1871 | memset(¶ms, 0, sizeof(params)); | ||
1872 | |||
1873 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | ||
1874 | params.interval = | ||
1875 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | ||
1876 | haveinfo = 1; | ||
1877 | } | ||
1878 | |||
1879 | if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) { | ||
1880 | params.dtim_period = | ||
1881 | nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]); | ||
1882 | haveinfo = 1; | ||
1883 | } | ||
1884 | |||
1885 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { | 1999 | if (info->attrs[NL80211_ATTR_BEACON_HEAD]) { |
1886 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); | 2000 | params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]); |
1887 | params.head_len = | 2001 | params.head_len = |
@@ -1899,13 +2013,18 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1899 | if (!haveinfo) | 2013 | if (!haveinfo) |
1900 | return -EINVAL; | 2014 | return -EINVAL; |
1901 | 2015 | ||
1902 | return call(&rdev->wiphy, dev, ¶ms); | 2016 | err = call(&rdev->wiphy, dev, ¶ms); |
2017 | if (!err && params.interval) | ||
2018 | wdev->beacon_interval = params.interval; | ||
2019 | return err; | ||
1903 | } | 2020 | } |
1904 | 2021 | ||
1905 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | 2022 | static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) |
1906 | { | 2023 | { |
1907 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2024 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1908 | struct net_device *dev = info->user_ptr[1]; | 2025 | struct net_device *dev = info->user_ptr[1]; |
2026 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2027 | int err; | ||
1909 | 2028 | ||
1910 | if (!rdev->ops->del_beacon) | 2029 | if (!rdev->ops->del_beacon) |
1911 | return -EOPNOTSUPP; | 2030 | return -EOPNOTSUPP; |
@@ -1914,7 +2033,10 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1914 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 2033 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
1915 | return -EOPNOTSUPP; | 2034 | return -EOPNOTSUPP; |
1916 | 2035 | ||
1917 | return rdev->ops->del_beacon(&rdev->wiphy, dev); | 2036 | err = rdev->ops->del_beacon(&rdev->wiphy, dev); |
2037 | if (!err) | ||
2038 | wdev->beacon_interval = 0; | ||
2039 | return err; | ||
1918 | } | 2040 | } |
1919 | 2041 | ||
1920 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 2042 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -1922,6 +2044,7 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | |||
1922 | [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, | 2044 | [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, |
1923 | [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, | 2045 | [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, |
1924 | [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, | 2046 | [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, |
2047 | [NL80211_STA_FLAG_AUTHENTICATED] = { .type = NLA_FLAG }, | ||
1925 | }; | 2048 | }; |
1926 | 2049 | ||
1927 | static int parse_station_flags(struct genl_info *info, | 2050 | static int parse_station_flags(struct genl_info *info, |
@@ -2002,7 +2125,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
2002 | const u8 *mac_addr, struct station_info *sinfo) | 2125 | const u8 *mac_addr, struct station_info *sinfo) |
2003 | { | 2126 | { |
2004 | void *hdr; | 2127 | void *hdr; |
2005 | struct nlattr *sinfoattr; | 2128 | struct nlattr *sinfoattr, *bss_param; |
2006 | 2129 | ||
2007 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | 2130 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); |
2008 | if (!hdr) | 2131 | if (!hdr) |
@@ -2016,6 +2139,9 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
2016 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); | 2139 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
2017 | if (!sinfoattr) | 2140 | if (!sinfoattr) |
2018 | goto nla_put_failure; | 2141 | goto nla_put_failure; |
2142 | if (sinfo->filled & STATION_INFO_CONNECTED_TIME) | ||
2143 | NLA_PUT_U32(msg, NL80211_STA_INFO_CONNECTED_TIME, | ||
2144 | sinfo->connected_time); | ||
2019 | if (sinfo->filled & STATION_INFO_INACTIVE_TIME) | 2145 | if (sinfo->filled & STATION_INFO_INACTIVE_TIME) |
2020 | NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, | 2146 | NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, |
2021 | sinfo->inactive_time); | 2147 | sinfo->inactive_time); |
@@ -2062,6 +2188,25 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
2062 | if (sinfo->filled & STATION_INFO_TX_FAILED) | 2188 | if (sinfo->filled & STATION_INFO_TX_FAILED) |
2063 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, | 2189 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, |
2064 | sinfo->tx_failed); | 2190 | sinfo->tx_failed); |
2191 | if (sinfo->filled & STATION_INFO_BSS_PARAM) { | ||
2192 | bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); | ||
2193 | if (!bss_param) | ||
2194 | goto nla_put_failure; | ||
2195 | |||
2196 | if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_CTS_PROT) | ||
2197 | NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_CTS_PROT); | ||
2198 | if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_PREAMBLE) | ||
2199 | NLA_PUT_FLAG(msg, NL80211_STA_BSS_PARAM_SHORT_PREAMBLE); | ||
2200 | if (sinfo->bss_param.flags & BSS_PARAM_FLAGS_SHORT_SLOT_TIME) | ||
2201 | NLA_PUT_FLAG(msg, | ||
2202 | NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME); | ||
2203 | NLA_PUT_U8(msg, NL80211_STA_BSS_PARAM_DTIM_PERIOD, | ||
2204 | sinfo->bss_param.dtim_period); | ||
2205 | NLA_PUT_U16(msg, NL80211_STA_BSS_PARAM_BEACON_INTERVAL, | ||
2206 | sinfo->bss_param.beacon_interval); | ||
2207 | |||
2208 | nla_nest_end(msg, bss_param); | ||
2209 | } | ||
2065 | nla_nest_end(msg, sinfoattr); | 2210 | nla_nest_end(msg, sinfoattr); |
2066 | 2211 | ||
2067 | return genlmsg_end(msg, hdr); | 2212 | return genlmsg_end(msg, hdr); |
@@ -2190,6 +2335,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2190 | memset(¶ms, 0, sizeof(params)); | 2335 | memset(¶ms, 0, sizeof(params)); |
2191 | 2336 | ||
2192 | params.listen_interval = -1; | 2337 | params.listen_interval = -1; |
2338 | params.plink_state = -1; | ||
2193 | 2339 | ||
2194 | if (info->attrs[NL80211_ATTR_STA_AID]) | 2340 | if (info->attrs[NL80211_ATTR_STA_AID]) |
2195 | return -EINVAL; | 2341 | return -EINVAL; |
@@ -2221,6 +2367,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2221 | params.plink_action = | 2367 | params.plink_action = |
2222 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 2368 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
2223 | 2369 | ||
2370 | if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) | ||
2371 | params.plink_state = | ||
2372 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]); | ||
2373 | |||
2224 | err = get_vlan(info, rdev, ¶ms.vlan); | 2374 | err = get_vlan(info, rdev, ¶ms.vlan); |
2225 | if (err) | 2375 | if (err) |
2226 | goto out; | 2376 | goto out; |
@@ -2260,9 +2410,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
2260 | err = -EINVAL; | 2410 | err = -EINVAL; |
2261 | if (params.listen_interval >= 0) | 2411 | if (params.listen_interval >= 0) |
2262 | err = -EINVAL; | 2412 | err = -EINVAL; |
2263 | if (params.supported_rates) | 2413 | if (params.sta_flags_mask & |
2264 | err = -EINVAL; | 2414 | ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) | |
2265 | if (params.sta_flags_mask) | 2415 | BIT(NL80211_STA_FLAG_MFP) | |
2416 | BIT(NL80211_STA_FLAG_AUTHORIZED))) | ||
2266 | err = -EINVAL; | 2417 | err = -EINVAL; |
2267 | break; | 2418 | break; |
2268 | default: | 2419 | default: |
@@ -2324,11 +2475,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
2324 | params.ht_capa = | 2475 | params.ht_capa = |
2325 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 2476 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
2326 | 2477 | ||
2478 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | ||
2479 | params.plink_action = | ||
2480 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | ||
2481 | |||
2327 | if (parse_station_flags(info, ¶ms)) | 2482 | if (parse_station_flags(info, ¶ms)) |
2328 | return -EINVAL; | 2483 | return -EINVAL; |
2329 | 2484 | ||
2330 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 2485 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && |
2331 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 2486 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && |
2487 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | ||
2332 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 2488 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) |
2333 | return -EINVAL; | 2489 | return -EINVAL; |
2334 | 2490 | ||
@@ -2804,8 +2960,10 @@ static const struct nla_policy | |||
2804 | nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = { | 2960 | nl80211_mesh_setup_params_policy[NL80211_MESH_SETUP_ATTR_MAX+1] = { |
2805 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, | 2961 | [NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 }, |
2806 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | 2962 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, |
2807 | [NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE] = { .type = NLA_BINARY, | 2963 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, |
2964 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, | ||
2808 | .len = IEEE80211_MAX_DATA_LEN }, | 2965 | .len = IEEE80211_MAX_DATA_LEN }, |
2966 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, | ||
2809 | }; | 2967 | }; |
2810 | 2968 | ||
2811 | static int nl80211_parse_mesh_config(struct genl_info *info, | 2969 | static int nl80211_parse_mesh_config(struct genl_info *info, |
@@ -2906,14 +3064,17 @@ static int nl80211_parse_mesh_setup(struct genl_info *info, | |||
2906 | IEEE80211_PATH_METRIC_VENDOR : | 3064 | IEEE80211_PATH_METRIC_VENDOR : |
2907 | IEEE80211_PATH_METRIC_AIRTIME; | 3065 | IEEE80211_PATH_METRIC_AIRTIME; |
2908 | 3066 | ||
2909 | if (tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]) { | 3067 | |
3068 | if (tb[NL80211_MESH_SETUP_IE]) { | ||
2910 | struct nlattr *ieattr = | 3069 | struct nlattr *ieattr = |
2911 | tb[NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE]; | 3070 | tb[NL80211_MESH_SETUP_IE]; |
2912 | if (!is_valid_ie_attr(ieattr)) | 3071 | if (!is_valid_ie_attr(ieattr)) |
2913 | return -EINVAL; | 3072 | return -EINVAL; |
2914 | setup->vendor_ie = nla_data(ieattr); | 3073 | setup->ie = nla_data(ieattr); |
2915 | setup->vendor_ie_len = nla_len(ieattr); | 3074 | setup->ie_len = nla_len(ieattr); |
2916 | } | 3075 | } |
3076 | setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]); | ||
3077 | setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]); | ||
2917 | 3078 | ||
2918 | return 0; | 3079 | return 0; |
2919 | } | 3080 | } |
@@ -3133,8 +3294,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3133 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 3294 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3134 | struct net_device *dev = info->user_ptr[1]; | 3295 | struct net_device *dev = info->user_ptr[1]; |
3135 | struct cfg80211_scan_request *request; | 3296 | struct cfg80211_scan_request *request; |
3136 | struct cfg80211_ssid *ssid; | ||
3137 | struct ieee80211_channel *channel; | ||
3138 | struct nlattr *attr; | 3297 | struct nlattr *attr; |
3139 | struct wiphy *wiphy; | 3298 | struct wiphy *wiphy; |
3140 | int err, tmp, n_ssids = 0, n_channels, i; | 3299 | int err, tmp, n_ssids = 0, n_channels, i; |
@@ -3181,8 +3340,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3181 | return -EINVAL; | 3340 | return -EINVAL; |
3182 | 3341 | ||
3183 | request = kzalloc(sizeof(*request) | 3342 | request = kzalloc(sizeof(*request) |
3184 | + sizeof(*ssid) * n_ssids | 3343 | + sizeof(*request->ssids) * n_ssids |
3185 | + sizeof(channel) * n_channels | 3344 | + sizeof(*request->channels) * n_channels |
3186 | + ie_len, GFP_KERNEL); | 3345 | + ie_len, GFP_KERNEL); |
3187 | if (!request) | 3346 | if (!request) |
3188 | return -ENOMEM; | 3347 | return -ENOMEM; |
@@ -3282,6 +3441,186 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3282 | return err; | 3441 | return err; |
3283 | } | 3442 | } |
3284 | 3443 | ||
3444 | static int nl80211_start_sched_scan(struct sk_buff *skb, | ||
3445 | struct genl_info *info) | ||
3446 | { | ||
3447 | struct cfg80211_sched_scan_request *request; | ||
3448 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
3449 | struct net_device *dev = info->user_ptr[1]; | ||
3450 | struct nlattr *attr; | ||
3451 | struct wiphy *wiphy; | ||
3452 | int err, tmp, n_ssids = 0, n_channels, i; | ||
3453 | u32 interval; | ||
3454 | enum ieee80211_band band; | ||
3455 | size_t ie_len; | ||
3456 | |||
3457 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | ||
3458 | !rdev->ops->sched_scan_start) | ||
3459 | return -EOPNOTSUPP; | ||
3460 | |||
3461 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3462 | return -EINVAL; | ||
3463 | |||
3464 | if (rdev->sched_scan_req) | ||
3465 | return -EINPROGRESS; | ||
3466 | |||
3467 | if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]) | ||
3468 | return -EINVAL; | ||
3469 | |||
3470 | interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]); | ||
3471 | if (interval == 0) | ||
3472 | return -EINVAL; | ||
3473 | |||
3474 | wiphy = &rdev->wiphy; | ||
3475 | |||
3476 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | ||
3477 | n_channels = validate_scan_freqs( | ||
3478 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]); | ||
3479 | if (!n_channels) | ||
3480 | return -EINVAL; | ||
3481 | } else { | ||
3482 | n_channels = 0; | ||
3483 | |||
3484 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | ||
3485 | if (wiphy->bands[band]) | ||
3486 | n_channels += wiphy->bands[band]->n_channels; | ||
3487 | } | ||
3488 | |||
3489 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) | ||
3490 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], | ||
3491 | tmp) | ||
3492 | n_ssids++; | ||
3493 | |||
3494 | if (n_ssids > wiphy->max_scan_ssids) | ||
3495 | return -EINVAL; | ||
3496 | |||
3497 | if (info->attrs[NL80211_ATTR_IE]) | ||
3498 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
3499 | else | ||
3500 | ie_len = 0; | ||
3501 | |||
3502 | if (ie_len > wiphy->max_scan_ie_len) | ||
3503 | return -EINVAL; | ||
3504 | |||
3505 | request = kzalloc(sizeof(*request) | ||
3506 | + sizeof(*request->ssids) * n_ssids | ||
3507 | + sizeof(*request->channels) * n_channels | ||
3508 | + ie_len, GFP_KERNEL); | ||
3509 | if (!request) | ||
3510 | return -ENOMEM; | ||
3511 | |||
3512 | if (n_ssids) | ||
3513 | request->ssids = (void *)&request->channels[n_channels]; | ||
3514 | request->n_ssids = n_ssids; | ||
3515 | if (ie_len) { | ||
3516 | if (request->ssids) | ||
3517 | request->ie = (void *)(request->ssids + n_ssids); | ||
3518 | else | ||
3519 | request->ie = (void *)(request->channels + n_channels); | ||
3520 | } | ||
3521 | |||
3522 | i = 0; | ||
3523 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | ||
3524 | /* user specified, bail out if channel not found */ | ||
3525 | nla_for_each_nested(attr, | ||
3526 | info->attrs[NL80211_ATTR_SCAN_FREQUENCIES], | ||
3527 | tmp) { | ||
3528 | struct ieee80211_channel *chan; | ||
3529 | |||
3530 | chan = ieee80211_get_channel(wiphy, nla_get_u32(attr)); | ||
3531 | |||
3532 | if (!chan) { | ||
3533 | err = -EINVAL; | ||
3534 | goto out_free; | ||
3535 | } | ||
3536 | |||
3537 | /* ignore disabled channels */ | ||
3538 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
3539 | continue; | ||
3540 | |||
3541 | request->channels[i] = chan; | ||
3542 | i++; | ||
3543 | } | ||
3544 | } else { | ||
3545 | /* all channels */ | ||
3546 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||
3547 | int j; | ||
3548 | if (!wiphy->bands[band]) | ||
3549 | continue; | ||
3550 | for (j = 0; j < wiphy->bands[band]->n_channels; j++) { | ||
3551 | struct ieee80211_channel *chan; | ||
3552 | |||
3553 | chan = &wiphy->bands[band]->channels[j]; | ||
3554 | |||
3555 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
3556 | continue; | ||
3557 | |||
3558 | request->channels[i] = chan; | ||
3559 | i++; | ||
3560 | } | ||
3561 | } | ||
3562 | } | ||
3563 | |||
3564 | if (!i) { | ||
3565 | err = -EINVAL; | ||
3566 | goto out_free; | ||
3567 | } | ||
3568 | |||
3569 | request->n_channels = i; | ||
3570 | |||
3571 | i = 0; | ||
3572 | if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) { | ||
3573 | nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], | ||
3574 | tmp) { | ||
3575 | if (request->ssids[i].ssid_len > | ||
3576 | IEEE80211_MAX_SSID_LEN) { | ||
3577 | err = -EINVAL; | ||
3578 | goto out_free; | ||
3579 | } | ||
3580 | memcpy(request->ssids[i].ssid, nla_data(attr), | ||
3581 | nla_len(attr)); | ||
3582 | request->ssids[i].ssid_len = nla_len(attr); | ||
3583 | i++; | ||
3584 | } | ||
3585 | } | ||
3586 | |||
3587 | if (info->attrs[NL80211_ATTR_IE]) { | ||
3588 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
3589 | memcpy((void *)request->ie, | ||
3590 | nla_data(info->attrs[NL80211_ATTR_IE]), | ||
3591 | request->ie_len); | ||
3592 | } | ||
3593 | |||
3594 | request->dev = dev; | ||
3595 | request->wiphy = &rdev->wiphy; | ||
3596 | request->interval = interval; | ||
3597 | |||
3598 | err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request); | ||
3599 | if (!err) { | ||
3600 | rdev->sched_scan_req = request; | ||
3601 | nl80211_send_sched_scan(rdev, dev, | ||
3602 | NL80211_CMD_START_SCHED_SCAN); | ||
3603 | goto out; | ||
3604 | } | ||
3605 | |||
3606 | out_free: | ||
3607 | kfree(request); | ||
3608 | out: | ||
3609 | return err; | ||
3610 | } | ||
3611 | |||
3612 | static int nl80211_stop_sched_scan(struct sk_buff *skb, | ||
3613 | struct genl_info *info) | ||
3614 | { | ||
3615 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
3616 | |||
3617 | if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) || | ||
3618 | !rdev->ops->sched_scan_stop) | ||
3619 | return -EOPNOTSUPP; | ||
3620 | |||
3621 | return __cfg80211_stop_sched_scan(rdev, false); | ||
3622 | } | ||
3623 | |||
3285 | static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 3624 | static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
3286 | struct cfg80211_registered_device *rdev, | 3625 | struct cfg80211_registered_device *rdev, |
3287 | struct wireless_dev *wdev, | 3626 | struct wireless_dev *wdev, |
@@ -4780,6 +5119,194 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
4780 | return cfg80211_leave_mesh(rdev, dev); | 5119 | return cfg80211_leave_mesh(rdev, dev); |
4781 | } | 5120 | } |
4782 | 5121 | ||
5122 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | ||
5123 | { | ||
5124 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5125 | struct sk_buff *msg; | ||
5126 | void *hdr; | ||
5127 | |||
5128 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | ||
5129 | return -EOPNOTSUPP; | ||
5130 | |||
5131 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
5132 | if (!msg) | ||
5133 | return -ENOMEM; | ||
5134 | |||
5135 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | ||
5136 | NL80211_CMD_GET_WOWLAN); | ||
5137 | if (!hdr) | ||
5138 | goto nla_put_failure; | ||
5139 | |||
5140 | if (rdev->wowlan) { | ||
5141 | struct nlattr *nl_wowlan; | ||
5142 | |||
5143 | nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); | ||
5144 | if (!nl_wowlan) | ||
5145 | goto nla_put_failure; | ||
5146 | |||
5147 | if (rdev->wowlan->any) | ||
5148 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); | ||
5149 | if (rdev->wowlan->disconnect) | ||
5150 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); | ||
5151 | if (rdev->wowlan->magic_pkt) | ||
5152 | NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); | ||
5153 | if (rdev->wowlan->n_patterns) { | ||
5154 | struct nlattr *nl_pats, *nl_pat; | ||
5155 | int i, pat_len; | ||
5156 | |||
5157 | nl_pats = nla_nest_start(msg, | ||
5158 | NL80211_WOWLAN_TRIG_PKT_PATTERN); | ||
5159 | if (!nl_pats) | ||
5160 | goto nla_put_failure; | ||
5161 | |||
5162 | for (i = 0; i < rdev->wowlan->n_patterns; i++) { | ||
5163 | nl_pat = nla_nest_start(msg, i + 1); | ||
5164 | if (!nl_pat) | ||
5165 | goto nla_put_failure; | ||
5166 | pat_len = rdev->wowlan->patterns[i].pattern_len; | ||
5167 | NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_MASK, | ||
5168 | DIV_ROUND_UP(pat_len, 8), | ||
5169 | rdev->wowlan->patterns[i].mask); | ||
5170 | NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_PATTERN, | ||
5171 | pat_len, | ||
5172 | rdev->wowlan->patterns[i].pattern); | ||
5173 | nla_nest_end(msg, nl_pat); | ||
5174 | } | ||
5175 | nla_nest_end(msg, nl_pats); | ||
5176 | } | ||
5177 | |||
5178 | nla_nest_end(msg, nl_wowlan); | ||
5179 | } | ||
5180 | |||
5181 | genlmsg_end(msg, hdr); | ||
5182 | return genlmsg_reply(msg, info); | ||
5183 | |||
5184 | nla_put_failure: | ||
5185 | nlmsg_free(msg); | ||
5186 | return -ENOBUFS; | ||
5187 | } | ||
5188 | |||
5189 | static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | ||
5190 | { | ||
5191 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
5192 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; | ||
5193 | struct cfg80211_wowlan no_triggers = {}; | ||
5194 | struct cfg80211_wowlan new_triggers = {}; | ||
5195 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; | ||
5196 | int err, i; | ||
5197 | |||
5198 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | ||
5199 | return -EOPNOTSUPP; | ||
5200 | |||
5201 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) | ||
5202 | goto no_triggers; | ||
5203 | |||
5204 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, | ||
5205 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), | ||
5206 | nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), | ||
5207 | nl80211_wowlan_policy); | ||
5208 | if (err) | ||
5209 | return err; | ||
5210 | |||
5211 | if (tb[NL80211_WOWLAN_TRIG_ANY]) { | ||
5212 | if (!(wowlan->flags & WIPHY_WOWLAN_ANY)) | ||
5213 | return -EINVAL; | ||
5214 | new_triggers.any = true; | ||
5215 | } | ||
5216 | |||
5217 | if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) { | ||
5218 | if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT)) | ||
5219 | return -EINVAL; | ||
5220 | new_triggers.disconnect = true; | ||
5221 | } | ||
5222 | |||
5223 | if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) { | ||
5224 | if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT)) | ||
5225 | return -EINVAL; | ||
5226 | new_triggers.magic_pkt = true; | ||
5227 | } | ||
5228 | |||
5229 | if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { | ||
5230 | struct nlattr *pat; | ||
5231 | int n_patterns = 0; | ||
5232 | int rem, pat_len, mask_len; | ||
5233 | struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT]; | ||
5234 | |||
5235 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | ||
5236 | rem) | ||
5237 | n_patterns++; | ||
5238 | if (n_patterns > wowlan->n_patterns) | ||
5239 | return -EINVAL; | ||
5240 | |||
5241 | new_triggers.patterns = kcalloc(n_patterns, | ||
5242 | sizeof(new_triggers.patterns[0]), | ||
5243 | GFP_KERNEL); | ||
5244 | if (!new_triggers.patterns) | ||
5245 | return -ENOMEM; | ||
5246 | |||
5247 | new_triggers.n_patterns = n_patterns; | ||
5248 | i = 0; | ||
5249 | |||
5250 | nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], | ||
5251 | rem) { | ||
5252 | nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT, | ||
5253 | nla_data(pat), nla_len(pat), NULL); | ||
5254 | err = -EINVAL; | ||
5255 | if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] || | ||
5256 | !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]) | ||
5257 | goto error; | ||
5258 | pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]); | ||
5259 | mask_len = DIV_ROUND_UP(pat_len, 8); | ||
5260 | if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) != | ||
5261 | mask_len) | ||
5262 | goto error; | ||
5263 | if (pat_len > wowlan->pattern_max_len || | ||
5264 | pat_len < wowlan->pattern_min_len) | ||
5265 | goto error; | ||
5266 | |||
5267 | new_triggers.patterns[i].mask = | ||
5268 | kmalloc(mask_len + pat_len, GFP_KERNEL); | ||
5269 | if (!new_triggers.patterns[i].mask) { | ||
5270 | err = -ENOMEM; | ||
5271 | goto error; | ||
5272 | } | ||
5273 | new_triggers.patterns[i].pattern = | ||
5274 | new_triggers.patterns[i].mask + mask_len; | ||
5275 | memcpy(new_triggers.patterns[i].mask, | ||
5276 | nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]), | ||
5277 | mask_len); | ||
5278 | new_triggers.patterns[i].pattern_len = pat_len; | ||
5279 | memcpy(new_triggers.patterns[i].pattern, | ||
5280 | nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]), | ||
5281 | pat_len); | ||
5282 | i++; | ||
5283 | } | ||
5284 | } | ||
5285 | |||
5286 | if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) { | ||
5287 | struct cfg80211_wowlan *ntrig; | ||
5288 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), | ||
5289 | GFP_KERNEL); | ||
5290 | if (!ntrig) { | ||
5291 | err = -ENOMEM; | ||
5292 | goto error; | ||
5293 | } | ||
5294 | cfg80211_rdev_free_wowlan(rdev); | ||
5295 | rdev->wowlan = ntrig; | ||
5296 | } else { | ||
5297 | no_triggers: | ||
5298 | cfg80211_rdev_free_wowlan(rdev); | ||
5299 | rdev->wowlan = NULL; | ||
5300 | } | ||
5301 | |||
5302 | return 0; | ||
5303 | error: | ||
5304 | for (i = 0; i < new_triggers.n_patterns; i++) | ||
5305 | kfree(new_triggers.patterns[i].mask); | ||
5306 | kfree(new_triggers.patterns); | ||
5307 | return err; | ||
5308 | } | ||
5309 | |||
4783 | #define NL80211_FLAG_NEED_WIPHY 0x01 | 5310 | #define NL80211_FLAG_NEED_WIPHY 0x01 |
4784 | #define NL80211_FLAG_NEED_NETDEV 0x02 | 5311 | #define NL80211_FLAG_NEED_NETDEV 0x02 |
4785 | #define NL80211_FLAG_NEED_RTNL 0x04 | 5312 | #define NL80211_FLAG_NEED_RTNL 0x04 |
@@ -5064,6 +5591,22 @@ static struct genl_ops nl80211_ops[] = { | |||
5064 | .dumpit = nl80211_dump_scan, | 5591 | .dumpit = nl80211_dump_scan, |
5065 | }, | 5592 | }, |
5066 | { | 5593 | { |
5594 | .cmd = NL80211_CMD_START_SCHED_SCAN, | ||
5595 | .doit = nl80211_start_sched_scan, | ||
5596 | .policy = nl80211_policy, | ||
5597 | .flags = GENL_ADMIN_PERM, | ||
5598 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5599 | NL80211_FLAG_NEED_RTNL, | ||
5600 | }, | ||
5601 | { | ||
5602 | .cmd = NL80211_CMD_STOP_SCHED_SCAN, | ||
5603 | .doit = nl80211_stop_sched_scan, | ||
5604 | .policy = nl80211_policy, | ||
5605 | .flags = GENL_ADMIN_PERM, | ||
5606 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | ||
5607 | NL80211_FLAG_NEED_RTNL, | ||
5608 | }, | ||
5609 | { | ||
5067 | .cmd = NL80211_CMD_AUTHENTICATE, | 5610 | .cmd = NL80211_CMD_AUTHENTICATE, |
5068 | .doit = nl80211_authenticate, | 5611 | .doit = nl80211_authenticate, |
5069 | .policy = nl80211_policy, | 5612 | .policy = nl80211_policy, |
@@ -5278,6 +5821,22 @@ static struct genl_ops nl80211_ops[] = { | |||
5278 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 5821 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
5279 | NL80211_FLAG_NEED_RTNL, | 5822 | NL80211_FLAG_NEED_RTNL, |
5280 | }, | 5823 | }, |
5824 | { | ||
5825 | .cmd = NL80211_CMD_GET_WOWLAN, | ||
5826 | .doit = nl80211_get_wowlan, | ||
5827 | .policy = nl80211_policy, | ||
5828 | /* can be retrieved by unprivileged users */ | ||
5829 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
5830 | NL80211_FLAG_NEED_RTNL, | ||
5831 | }, | ||
5832 | { | ||
5833 | .cmd = NL80211_CMD_SET_WOWLAN, | ||
5834 | .doit = nl80211_set_wowlan, | ||
5835 | .policy = nl80211_policy, | ||
5836 | .flags = GENL_ADMIN_PERM, | ||
5837 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | ||
5838 | NL80211_FLAG_NEED_RTNL, | ||
5839 | }, | ||
5281 | }; | 5840 | }; |
5282 | 5841 | ||
5283 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 5842 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
@@ -5373,6 +5932,28 @@ static int nl80211_send_scan_msg(struct sk_buff *msg, | |||
5373 | return -EMSGSIZE; | 5932 | return -EMSGSIZE; |
5374 | } | 5933 | } |
5375 | 5934 | ||
5935 | static int | ||
5936 | nl80211_send_sched_scan_msg(struct sk_buff *msg, | ||
5937 | struct cfg80211_registered_device *rdev, | ||
5938 | struct net_device *netdev, | ||
5939 | u32 pid, u32 seq, int flags, u32 cmd) | ||
5940 | { | ||
5941 | void *hdr; | ||
5942 | |||
5943 | hdr = nl80211hdr_put(msg, pid, seq, flags, cmd); | ||
5944 | if (!hdr) | ||
5945 | return -1; | ||
5946 | |||
5947 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
5948 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
5949 | |||
5950 | return genlmsg_end(msg, hdr); | ||
5951 | |||
5952 | nla_put_failure: | ||
5953 | genlmsg_cancel(msg, hdr); | ||
5954 | return -EMSGSIZE; | ||
5955 | } | ||
5956 | |||
5376 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | 5957 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, |
5377 | struct net_device *netdev) | 5958 | struct net_device *netdev) |
5378 | { | 5959 | { |
@@ -5430,6 +6011,43 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
5430 | nl80211_scan_mcgrp.id, GFP_KERNEL); | 6011 | nl80211_scan_mcgrp.id, GFP_KERNEL); |
5431 | } | 6012 | } |
5432 | 6013 | ||
6014 | void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, | ||
6015 | struct net_device *netdev) | ||
6016 | { | ||
6017 | struct sk_buff *msg; | ||
6018 | |||
6019 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
6020 | if (!msg) | ||
6021 | return; | ||
6022 | |||
6023 | if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, | ||
6024 | NL80211_CMD_SCHED_SCAN_RESULTS) < 0) { | ||
6025 | nlmsg_free(msg); | ||
6026 | return; | ||
6027 | } | ||
6028 | |||
6029 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
6030 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
6031 | } | ||
6032 | |||
6033 | void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | ||
6034 | struct net_device *netdev, u32 cmd) | ||
6035 | { | ||
6036 | struct sk_buff *msg; | ||
6037 | |||
6038 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
6039 | if (!msg) | ||
6040 | return; | ||
6041 | |||
6042 | if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) { | ||
6043 | nlmsg_free(msg); | ||
6044 | return; | ||
6045 | } | ||
6046 | |||
6047 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
6048 | nl80211_scan_mcgrp.id, GFP_KERNEL); | ||
6049 | } | ||
6050 | |||
5433 | /* | 6051 | /* |
5434 | * This can happen on global regulatory changes or device specific settings | 6052 | * This can happen on global regulatory changes or device specific settings |
5435 | * based on custom world regulatory domains. | 6053 | * based on custom world regulatory domains. |
@@ -5785,6 +6403,44 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | |||
5785 | nlmsg_free(msg); | 6403 | nlmsg_free(msg); |
5786 | } | 6404 | } |
5787 | 6405 | ||
6406 | void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev, | ||
6407 | struct net_device *netdev, | ||
6408 | const u8 *macaddr, const u8* ie, u8 ie_len, | ||
6409 | gfp_t gfp) | ||
6410 | { | ||
6411 | struct sk_buff *msg; | ||
6412 | void *hdr; | ||
6413 | |||
6414 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
6415 | if (!msg) | ||
6416 | return; | ||
6417 | |||
6418 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NEW_PEER_CANDIDATE); | ||
6419 | if (!hdr) { | ||
6420 | nlmsg_free(msg); | ||
6421 | return; | ||
6422 | } | ||
6423 | |||
6424 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
6425 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
6426 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr); | ||
6427 | if (ie_len && ie) | ||
6428 | NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie); | ||
6429 | |||
6430 | if (genlmsg_end(msg, hdr) < 0) { | ||
6431 | nlmsg_free(msg); | ||
6432 | return; | ||
6433 | } | ||
6434 | |||
6435 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
6436 | nl80211_mlme_mcgrp.id, gfp); | ||
6437 | return; | ||
6438 | |||
6439 | nla_put_failure: | ||
6440 | genlmsg_cancel(msg, hdr); | ||
6441 | nlmsg_free(msg); | ||
6442 | } | ||
6443 | |||
5788 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 6444 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, |
5789 | struct net_device *netdev, const u8 *addr, | 6445 | struct net_device *netdev, const u8 *addr, |
5790 | enum nl80211_key_type key_type, int key_id, | 6446 | enum nl80211_key_type key_type, int key_id, |
@@ -5966,6 +6622,40 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
5966 | nl80211_mlme_mcgrp.id, gfp); | 6622 | nl80211_mlme_mcgrp.id, gfp); |
5967 | } | 6623 | } |
5968 | 6624 | ||
6625 | void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | ||
6626 | struct net_device *dev, const u8 *mac_addr, | ||
6627 | gfp_t gfp) | ||
6628 | { | ||
6629 | struct sk_buff *msg; | ||
6630 | void *hdr; | ||
6631 | |||
6632 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
6633 | if (!msg) | ||
6634 | return; | ||
6635 | |||
6636 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION); | ||
6637 | if (!hdr) { | ||
6638 | nlmsg_free(msg); | ||
6639 | return; | ||
6640 | } | ||
6641 | |||
6642 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
6643 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | ||
6644 | |||
6645 | if (genlmsg_end(msg, hdr) < 0) { | ||
6646 | nlmsg_free(msg); | ||
6647 | return; | ||
6648 | } | ||
6649 | |||
6650 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
6651 | nl80211_mlme_mcgrp.id, gfp); | ||
6652 | return; | ||
6653 | |||
6654 | nla_put_failure: | ||
6655 | genlmsg_cancel(msg, hdr); | ||
6656 | nlmsg_free(msg); | ||
6657 | } | ||
6658 | |||
5969 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 6659 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
5970 | struct net_device *netdev, u32 nlpid, | 6660 | struct net_device *netdev, u32 nlpid, |
5971 | int freq, const u8 *buf, size_t len, gfp_t gfp) | 6661 | int freq, const u8 *buf, size_t len, gfp_t gfp) |