diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-07-20 12:30:48 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-07-20 12:30:48 -0400 |
commit | 90b90f60c4f8e3a8525dfeb4aec46a9c7a29c857 (patch) | |
tree | 9b1d8ca6084012a02b302520bc26e5be65ba7b2a /net/wireless/nl80211.c | |
parent | 769162e38b91e1d300752e666260fa6c7b203fbc (diff) | |
parent | 36eb22e97a2b621fb707eead58ef915ab0f46e9e (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 537 |
1 files changed, 398 insertions, 139 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0249cea5385..97026f3b215 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -46,28 +46,60 @@ static struct genl_family nl80211_fam = { | |||
46 | .post_doit = nl80211_post_doit, | 46 | .post_doit = nl80211_post_doit, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | /* internal helper: get rdev and dev */ | 49 | /* returns ERR_PTR values */ |
50 | static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs, | 50 | static struct wireless_dev * |
51 | struct cfg80211_registered_device **rdev, | 51 | __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) |
52 | struct net_device **dev) | ||
53 | { | 52 | { |
54 | int ifindex; | 53 | struct cfg80211_registered_device *rdev; |
54 | struct wireless_dev *result = NULL; | ||
55 | bool have_ifidx = attrs[NL80211_ATTR_IFINDEX]; | ||
56 | bool have_wdev_id = attrs[NL80211_ATTR_WDEV]; | ||
57 | u64 wdev_id; | ||
58 | int wiphy_idx = -1; | ||
59 | int ifidx = -1; | ||
55 | 60 | ||
56 | if (!attrs[NL80211_ATTR_IFINDEX]) | 61 | assert_cfg80211_lock(); |
57 | return -EINVAL; | ||
58 | 62 | ||
59 | ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 63 | if (!have_ifidx && !have_wdev_id) |
60 | *dev = dev_get_by_index(netns, ifindex); | 64 | return ERR_PTR(-EINVAL); |
61 | if (!*dev) | ||
62 | return -ENODEV; | ||
63 | 65 | ||
64 | *rdev = cfg80211_get_dev_from_ifindex(netns, ifindex); | 66 | if (have_ifidx) |
65 | if (IS_ERR(*rdev)) { | 67 | ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
66 | dev_put(*dev); | 68 | if (have_wdev_id) { |
67 | return PTR_ERR(*rdev); | 69 | wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); |
70 | wiphy_idx = wdev_id >> 32; | ||
68 | } | 71 | } |
69 | 72 | ||
70 | return 0; | 73 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { |
74 | struct wireless_dev *wdev; | ||
75 | |||
76 | if (wiphy_net(&rdev->wiphy) != netns) | ||
77 | continue; | ||
78 | |||
79 | if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) | ||
80 | continue; | ||
81 | |||
82 | mutex_lock(&rdev->devlist_mtx); | ||
83 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
84 | if (have_ifidx && wdev->netdev && | ||
85 | wdev->netdev->ifindex == ifidx) { | ||
86 | result = wdev; | ||
87 | break; | ||
88 | } | ||
89 | if (have_wdev_id && wdev->identifier == (u32)wdev_id) { | ||
90 | result = wdev; | ||
91 | break; | ||
92 | } | ||
93 | } | ||
94 | mutex_unlock(&rdev->devlist_mtx); | ||
95 | |||
96 | if (result) | ||
97 | break; | ||
98 | } | ||
99 | |||
100 | if (result) | ||
101 | return result; | ||
102 | return ERR_PTR(-ENODEV); | ||
71 | } | 103 | } |
72 | 104 | ||
73 | static struct cfg80211_registered_device * | 105 | static struct cfg80211_registered_device * |
@@ -79,13 +111,40 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | |||
79 | assert_cfg80211_lock(); | 111 | assert_cfg80211_lock(); |
80 | 112 | ||
81 | if (!attrs[NL80211_ATTR_WIPHY] && | 113 | if (!attrs[NL80211_ATTR_WIPHY] && |
82 | !attrs[NL80211_ATTR_IFINDEX]) | 114 | !attrs[NL80211_ATTR_IFINDEX] && |
115 | !attrs[NL80211_ATTR_WDEV]) | ||
83 | return ERR_PTR(-EINVAL); | 116 | return ERR_PTR(-EINVAL); |
84 | 117 | ||
85 | if (attrs[NL80211_ATTR_WIPHY]) | 118 | if (attrs[NL80211_ATTR_WIPHY]) |
86 | rdev = cfg80211_rdev_by_wiphy_idx( | 119 | rdev = cfg80211_rdev_by_wiphy_idx( |
87 | nla_get_u32(attrs[NL80211_ATTR_WIPHY])); | 120 | nla_get_u32(attrs[NL80211_ATTR_WIPHY])); |
88 | 121 | ||
122 | if (attrs[NL80211_ATTR_WDEV]) { | ||
123 | u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); | ||
124 | struct wireless_dev *wdev; | ||
125 | bool found = false; | ||
126 | |||
127 | tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); | ||
128 | if (tmp) { | ||
129 | /* make sure wdev exists */ | ||
130 | mutex_lock(&tmp->devlist_mtx); | ||
131 | list_for_each_entry(wdev, &tmp->wdev_list, list) { | ||
132 | if (wdev->identifier != (u32)wdev_id) | ||
133 | continue; | ||
134 | found = true; | ||
135 | break; | ||
136 | } | ||
137 | mutex_unlock(&tmp->devlist_mtx); | ||
138 | |||
139 | if (!found) | ||
140 | tmp = NULL; | ||
141 | |||
142 | if (rdev && tmp != rdev) | ||
143 | return ERR_PTR(-EINVAL); | ||
144 | rdev = tmp; | ||
145 | } | ||
146 | } | ||
147 | |||
89 | if (attrs[NL80211_ATTR_IFINDEX]) { | 148 | if (attrs[NL80211_ATTR_IFINDEX]) { |
90 | int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | 149 | int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); |
91 | netdev = dev_get_by_index(netns, ifindex); | 150 | netdev = dev_get_by_index(netns, ifindex); |
@@ -294,6 +353,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
294 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, | 353 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, |
295 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, | 354 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, |
296 | [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, | 355 | [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, |
356 | [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, | ||
357 | [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 }, | ||
297 | }; | 358 | }; |
298 | 359 | ||
299 | /* policy for the key attributes */ | 360 | /* policy for the key attributes */ |
@@ -1668,32 +1729,48 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1668 | return result; | 1729 | return result; |
1669 | } | 1730 | } |
1670 | 1731 | ||
1732 | static inline u64 wdev_id(struct wireless_dev *wdev) | ||
1733 | { | ||
1734 | return (u64)wdev->identifier | | ||
1735 | ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); | ||
1736 | } | ||
1671 | 1737 | ||
1672 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 1738 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
1673 | struct cfg80211_registered_device *rdev, | 1739 | struct cfg80211_registered_device *rdev, |
1674 | struct net_device *dev) | 1740 | struct wireless_dev *wdev) |
1675 | { | 1741 | { |
1742 | struct net_device *dev = wdev->netdev; | ||
1676 | void *hdr; | 1743 | void *hdr; |
1677 | 1744 | ||
1678 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); | 1745 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); |
1679 | if (!hdr) | 1746 | if (!hdr) |
1680 | return -1; | 1747 | return -1; |
1681 | 1748 | ||
1682 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | 1749 | if (dev && |
1683 | nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 1750 | (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
1684 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || | 1751 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || |
1685 | nla_put_u32(msg, NL80211_ATTR_IFTYPE, | 1752 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr))) |
1686 | dev->ieee80211_ptr->iftype) || | 1753 | goto nla_put_failure; |
1754 | |||
1755 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
1756 | nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) || | ||
1757 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || | ||
1687 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | 1758 | nla_put_u32(msg, NL80211_ATTR_GENERATION, |
1688 | rdev->devlist_generation ^ | 1759 | rdev->devlist_generation ^ |
1689 | (cfg80211_rdev_list_generation << 2))) | 1760 | (cfg80211_rdev_list_generation << 2))) |
1690 | goto nla_put_failure; | 1761 | goto nla_put_failure; |
1691 | 1762 | ||
1692 | if (rdev->monitor_channel) { | 1763 | if (rdev->ops->get_channel) { |
1693 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | 1764 | struct ieee80211_channel *chan; |
1694 | rdev->monitor_channel->center_freq) || | 1765 | enum nl80211_channel_type channel_type; |
1695 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | 1766 | |
1696 | rdev->monitor_channel_type)) | 1767 | chan = rdev->ops->get_channel(&rdev->wiphy, wdev, |
1768 | &channel_type); | ||
1769 | if (chan && | ||
1770 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | ||
1771 | chan->center_freq) || | ||
1772 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | ||
1773 | channel_type))) | ||
1697 | goto nla_put_failure; | 1774 | goto nla_put_failure; |
1698 | } | 1775 | } |
1699 | 1776 | ||
@@ -1724,14 +1801,14 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
1724 | if_idx = 0; | 1801 | if_idx = 0; |
1725 | 1802 | ||
1726 | mutex_lock(&rdev->devlist_mtx); | 1803 | mutex_lock(&rdev->devlist_mtx); |
1727 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 1804 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
1728 | if (if_idx < if_start) { | 1805 | if (if_idx < if_start) { |
1729 | if_idx++; | 1806 | if_idx++; |
1730 | continue; | 1807 | continue; |
1731 | } | 1808 | } |
1732 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 1809 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
1733 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1810 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
1734 | rdev, wdev->netdev) < 0) { | 1811 | rdev, wdev) < 0) { |
1735 | mutex_unlock(&rdev->devlist_mtx); | 1812 | mutex_unlock(&rdev->devlist_mtx); |
1736 | goto out; | 1813 | goto out; |
1737 | } | 1814 | } |
@@ -1754,14 +1831,14 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
1754 | { | 1831 | { |
1755 | struct sk_buff *msg; | 1832 | struct sk_buff *msg; |
1756 | struct cfg80211_registered_device *dev = info->user_ptr[0]; | 1833 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1757 | struct net_device *netdev = info->user_ptr[1]; | 1834 | struct wireless_dev *wdev = info->user_ptr[1]; |
1758 | 1835 | ||
1759 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1836 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1760 | if (!msg) | 1837 | if (!msg) |
1761 | return -ENOMEM; | 1838 | return -ENOMEM; |
1762 | 1839 | ||
1763 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, | 1840 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
1764 | dev, netdev) < 0) { | 1841 | dev, wdev) < 0) { |
1765 | nlmsg_free(msg); | 1842 | nlmsg_free(msg); |
1766 | return -ENOBUFS; | 1843 | return -ENOBUFS; |
1767 | } | 1844 | } |
@@ -1901,7 +1978,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1901 | { | 1978 | { |
1902 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 1979 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1903 | struct vif_params params; | 1980 | struct vif_params params; |
1904 | struct net_device *dev; | 1981 | struct wireless_dev *wdev; |
1982 | struct sk_buff *msg; | ||
1905 | int err; | 1983 | int err; |
1906 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1984 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
1907 | u32 flags; | 1985 | u32 flags; |
@@ -1928,19 +2006,23 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1928 | return err; | 2006 | return err; |
1929 | } | 2007 | } |
1930 | 2008 | ||
2009 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2010 | if (!msg) | ||
2011 | return -ENOMEM; | ||
2012 | |||
1931 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 2013 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
1932 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 2014 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
1933 | &flags); | 2015 | &flags); |
1934 | dev = rdev->ops->add_virtual_intf(&rdev->wiphy, | 2016 | wdev = rdev->ops->add_virtual_intf(&rdev->wiphy, |
1935 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 2017 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1936 | type, err ? NULL : &flags, ¶ms); | 2018 | type, err ? NULL : &flags, ¶ms); |
1937 | if (IS_ERR(dev)) | 2019 | if (IS_ERR(wdev)) { |
1938 | return PTR_ERR(dev); | 2020 | nlmsg_free(msg); |
2021 | return PTR_ERR(wdev); | ||
2022 | } | ||
1939 | 2023 | ||
1940 | if (type == NL80211_IFTYPE_MESH_POINT && | 2024 | if (type == NL80211_IFTYPE_MESH_POINT && |
1941 | info->attrs[NL80211_ATTR_MESH_ID]) { | 2025 | info->attrs[NL80211_ATTR_MESH_ID]) { |
1942 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1943 | |||
1944 | wdev_lock(wdev); | 2026 | wdev_lock(wdev); |
1945 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | 2027 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != |
1946 | IEEE80211_MAX_MESH_ID_LEN); | 2028 | IEEE80211_MAX_MESH_ID_LEN); |
@@ -1951,18 +2033,34 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1951 | wdev_unlock(wdev); | 2033 | wdev_unlock(wdev); |
1952 | } | 2034 | } |
1953 | 2035 | ||
1954 | return 0; | 2036 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
2037 | rdev, wdev) < 0) { | ||
2038 | nlmsg_free(msg); | ||
2039 | return -ENOBUFS; | ||
2040 | } | ||
2041 | |||
2042 | return genlmsg_reply(msg, info); | ||
1955 | } | 2043 | } |
1956 | 2044 | ||
1957 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | 2045 | static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) |
1958 | { | 2046 | { |
1959 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2047 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1960 | struct net_device *dev = info->user_ptr[1]; | 2048 | struct wireless_dev *wdev = info->user_ptr[1]; |
1961 | 2049 | ||
1962 | if (!rdev->ops->del_virtual_intf) | 2050 | if (!rdev->ops->del_virtual_intf) |
1963 | return -EOPNOTSUPP; | 2051 | return -EOPNOTSUPP; |
1964 | 2052 | ||
1965 | return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); | 2053 | /* |
2054 | * If we remove a wireless device without a netdev then clear | ||
2055 | * user_ptr[1] so that nl80211_post_doit won't dereference it | ||
2056 | * to check if it needs to do dev_put(). Otherwise it crashes | ||
2057 | * since the wdev has been freed, unlike with a netdev where | ||
2058 | * we need the dev_put() for the netdev to really be freed. | ||
2059 | */ | ||
2060 | if (!wdev->netdev) | ||
2061 | info->user_ptr[1] = NULL; | ||
2062 | |||
2063 | return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev); | ||
1966 | } | 2064 | } |
1967 | 2065 | ||
1968 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) | 2066 | static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) |
@@ -2350,7 +2448,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | |||
2350 | 2448 | ||
2351 | mutex_lock(&rdev->devlist_mtx); | 2449 | mutex_lock(&rdev->devlist_mtx); |
2352 | 2450 | ||
2353 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 2451 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
2354 | if (wdev->iftype != NL80211_IFTYPE_AP && | 2452 | if (wdev->iftype != NL80211_IFTYPE_AP && |
2355 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | 2453 | wdev->iftype != NL80211_IFTYPE_P2P_GO) |
2356 | continue; | 2454 | continue; |
@@ -3485,6 +3583,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3485 | { | 3583 | { |
3486 | int r; | 3584 | int r; |
3487 | char *data = NULL; | 3585 | char *data = NULL; |
3586 | enum nl80211_user_reg_hint_type user_reg_hint_type; | ||
3488 | 3587 | ||
3489 | /* | 3588 | /* |
3490 | * You should only get this when cfg80211 hasn't yet initialized | 3589 | * You should only get this when cfg80211 hasn't yet initialized |
@@ -3504,7 +3603,21 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3504 | 3603 | ||
3505 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 3604 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
3506 | 3605 | ||
3507 | r = regulatory_hint_user(data); | 3606 | if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]) |
3607 | user_reg_hint_type = | ||
3608 | nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]); | ||
3609 | else | ||
3610 | user_reg_hint_type = NL80211_USER_REG_HINT_USER; | ||
3611 | |||
3612 | switch (user_reg_hint_type) { | ||
3613 | case NL80211_USER_REG_HINT_USER: | ||
3614 | case NL80211_USER_REG_HINT_CELL_BASE: | ||
3615 | break; | ||
3616 | default: | ||
3617 | return -EINVAL; | ||
3618 | } | ||
3619 | |||
3620 | r = regulatory_hint_user(data, user_reg_hint_type); | ||
3508 | 3621 | ||
3509 | return r; | 3622 | return r; |
3510 | } | 3623 | } |
@@ -3874,6 +3987,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
3874 | cfg80211_regdomain->dfs_region))) | 3987 | cfg80211_regdomain->dfs_region))) |
3875 | goto nla_put_failure; | 3988 | goto nla_put_failure; |
3876 | 3989 | ||
3990 | if (reg_last_request_cell_base() && | ||
3991 | nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, | ||
3992 | NL80211_USER_REG_HINT_CELL_BASE)) | ||
3993 | goto nla_put_failure; | ||
3994 | |||
3877 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 3995 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
3878 | if (!nl_reg_rules) | 3996 | if (!nl_reg_rules) |
3879 | goto nla_put_failure; | 3997 | goto nla_put_failure; |
@@ -4039,7 +4157,7 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
4039 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 4157 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
4040 | { | 4158 | { |
4041 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4159 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
4042 | struct net_device *dev = info->user_ptr[1]; | 4160 | struct wireless_dev *wdev = info->user_ptr[1]; |
4043 | struct cfg80211_scan_request *request; | 4161 | struct cfg80211_scan_request *request; |
4044 | struct nlattr *attr; | 4162 | struct nlattr *attr; |
4045 | struct wiphy *wiphy; | 4163 | struct wiphy *wiphy; |
@@ -4199,15 +4317,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
4199 | request->no_cck = | 4317 | request->no_cck = |
4200 | nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 4318 | nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
4201 | 4319 | ||
4202 | request->dev = dev; | 4320 | request->wdev = wdev; |
4203 | request->wiphy = &rdev->wiphy; | 4321 | request->wiphy = &rdev->wiphy; |
4204 | 4322 | ||
4205 | rdev->scan_req = request; | 4323 | rdev->scan_req = request; |
4206 | err = rdev->ops->scan(&rdev->wiphy, dev, request); | 4324 | err = rdev->ops->scan(&rdev->wiphy, request); |
4207 | 4325 | ||
4208 | if (!err) { | 4326 | if (!err) { |
4209 | nl80211_send_scan_start(rdev, dev); | 4327 | nl80211_send_scan_start(rdev, wdev); |
4210 | dev_hold(dev); | 4328 | if (wdev->netdev) |
4329 | dev_hold(wdev->netdev); | ||
4211 | } else { | 4330 | } else { |
4212 | out_free: | 4331 | out_free: |
4213 | rdev->scan_req = NULL; | 4332 | rdev->scan_req = NULL; |
@@ -5685,7 +5804,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5685 | struct genl_info *info) | 5804 | struct genl_info *info) |
5686 | { | 5805 | { |
5687 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5806 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5688 | struct net_device *dev = info->user_ptr[1]; | 5807 | struct wireless_dev *wdev = info->user_ptr[1]; |
5689 | struct ieee80211_channel *chan; | 5808 | struct ieee80211_channel *chan; |
5690 | struct sk_buff *msg; | 5809 | struct sk_buff *msg; |
5691 | void *hdr; | 5810 | void *hdr; |
@@ -5733,7 +5852,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5733 | goto free_msg; | 5852 | goto free_msg; |
5734 | } | 5853 | } |
5735 | 5854 | ||
5736 | err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, | 5855 | err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, |
5737 | channel_type, duration, &cookie); | 5856 | channel_type, duration, &cookie); |
5738 | 5857 | ||
5739 | if (err) | 5858 | if (err) |
@@ -5757,7 +5876,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
5757 | struct genl_info *info) | 5876 | struct genl_info *info) |
5758 | { | 5877 | { |
5759 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5878 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5760 | struct net_device *dev = info->user_ptr[1]; | 5879 | struct wireless_dev *wdev = info->user_ptr[1]; |
5761 | u64 cookie; | 5880 | u64 cookie; |
5762 | 5881 | ||
5763 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 5882 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
@@ -5768,7 +5887,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
5768 | 5887 | ||
5769 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 5888 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
5770 | 5889 | ||
5771 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | 5890 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); |
5772 | } | 5891 | } |
5773 | 5892 | ||
5774 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | 5893 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, |
@@ -5917,7 +6036,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
5917 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | 6036 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) |
5918 | { | 6037 | { |
5919 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6038 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5920 | struct net_device *dev = info->user_ptr[1]; | 6039 | struct wireless_dev *wdev = info->user_ptr[1]; |
5921 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; | 6040 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; |
5922 | 6041 | ||
5923 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 6042 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
@@ -5926,21 +6045,24 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5926 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) | 6045 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
5927 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); | 6046 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
5928 | 6047 | ||
5929 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6048 | switch (wdev->iftype) { |
5930 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6049 | case NL80211_IFTYPE_STATION: |
5931 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6050 | case NL80211_IFTYPE_ADHOC: |
5932 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6051 | case NL80211_IFTYPE_P2P_CLIENT: |
5933 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6052 | case NL80211_IFTYPE_AP: |
5934 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 6053 | case NL80211_IFTYPE_AP_VLAN: |
5935 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6054 | case NL80211_IFTYPE_MESH_POINT: |
6055 | case NL80211_IFTYPE_P2P_GO: | ||
6056 | break; | ||
6057 | default: | ||
5936 | return -EOPNOTSUPP; | 6058 | return -EOPNOTSUPP; |
6059 | } | ||
5937 | 6060 | ||
5938 | /* not much point in registering if we can't reply */ | 6061 | /* not much point in registering if we can't reply */ |
5939 | if (!rdev->ops->mgmt_tx) | 6062 | if (!rdev->ops->mgmt_tx) |
5940 | return -EOPNOTSUPP; | 6063 | return -EOPNOTSUPP; |
5941 | 6064 | ||
5942 | return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, | 6065 | return cfg80211_mlme_register_mgmt(wdev, info->snd_pid, frame_type, |
5943 | frame_type, | ||
5944 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 6066 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
5945 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 6067 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
5946 | } | 6068 | } |
@@ -5948,7 +6070,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5948 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | 6070 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) |
5949 | { | 6071 | { |
5950 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6072 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5951 | struct net_device *dev = info->user_ptr[1]; | 6073 | struct wireless_dev *wdev = info->user_ptr[1]; |
5952 | struct ieee80211_channel *chan; | 6074 | struct ieee80211_channel *chan; |
5953 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 6075 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
5954 | bool channel_type_valid = false; | 6076 | bool channel_type_valid = false; |
@@ -5969,14 +6091,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5969 | if (!rdev->ops->mgmt_tx) | 6091 | if (!rdev->ops->mgmt_tx) |
5970 | return -EOPNOTSUPP; | 6092 | return -EOPNOTSUPP; |
5971 | 6093 | ||
5972 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6094 | switch (wdev->iftype) { |
5973 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6095 | case NL80211_IFTYPE_STATION: |
5974 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6096 | case NL80211_IFTYPE_ADHOC: |
5975 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6097 | case NL80211_IFTYPE_P2P_CLIENT: |
5976 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6098 | case NL80211_IFTYPE_AP: |
5977 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 6099 | case NL80211_IFTYPE_AP_VLAN: |
5978 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6100 | case NL80211_IFTYPE_MESH_POINT: |
6101 | case NL80211_IFTYPE_P2P_GO: | ||
6102 | break; | ||
6103 | default: | ||
5979 | return -EOPNOTSUPP; | 6104 | return -EOPNOTSUPP; |
6105 | } | ||
5980 | 6106 | ||
5981 | if (info->attrs[NL80211_ATTR_DURATION]) { | 6107 | if (info->attrs[NL80211_ATTR_DURATION]) { |
5982 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | 6108 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
@@ -6025,7 +6151,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
6025 | } | 6151 | } |
6026 | } | 6152 | } |
6027 | 6153 | ||
6028 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, | 6154 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type, |
6029 | channel_type_valid, wait, | 6155 | channel_type_valid, wait, |
6030 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 6156 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
6031 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 6157 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
@@ -6053,7 +6179,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
6053 | static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) | 6179 | static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) |
6054 | { | 6180 | { |
6055 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6181 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6056 | struct net_device *dev = info->user_ptr[1]; | 6182 | struct wireless_dev *wdev = info->user_ptr[1]; |
6057 | u64 cookie; | 6183 | u64 cookie; |
6058 | 6184 | ||
6059 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 6185 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
@@ -6062,17 +6188,21 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in | |||
6062 | if (!rdev->ops->mgmt_tx_cancel_wait) | 6188 | if (!rdev->ops->mgmt_tx_cancel_wait) |
6063 | return -EOPNOTSUPP; | 6189 | return -EOPNOTSUPP; |
6064 | 6190 | ||
6065 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6191 | switch (wdev->iftype) { |
6066 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6192 | case NL80211_IFTYPE_STATION: |
6067 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6193 | case NL80211_IFTYPE_ADHOC: |
6068 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6194 | case NL80211_IFTYPE_P2P_CLIENT: |
6069 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6195 | case NL80211_IFTYPE_AP: |
6070 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6196 | case NL80211_IFTYPE_AP_VLAN: |
6197 | case NL80211_IFTYPE_P2P_GO: | ||
6198 | break; | ||
6199 | default: | ||
6071 | return -EOPNOTSUPP; | 6200 | return -EOPNOTSUPP; |
6201 | } | ||
6072 | 6202 | ||
6073 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 6203 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
6074 | 6204 | ||
6075 | return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie); | 6205 | return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); |
6076 | } | 6206 | } |
6077 | 6207 | ||
6078 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) | 6208 | static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) |
@@ -6158,8 +6288,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
6158 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | 6288 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, |
6159 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, | 6289 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, |
6160 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, | 6290 | [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, |
6291 | [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 }, | ||
6292 | [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 }, | ||
6293 | [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 }, | ||
6161 | }; | 6294 | }; |
6162 | 6295 | ||
6296 | static int nl80211_set_cqm_txe(struct genl_info *info, | ||
6297 | u32 rate, u32 pkts, u32 intvl) | ||
6298 | { | ||
6299 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | ||
6300 | struct wireless_dev *wdev; | ||
6301 | struct net_device *dev = info->user_ptr[1]; | ||
6302 | |||
6303 | if ((rate < 0 || rate > 100) || | ||
6304 | (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL)) | ||
6305 | return -EINVAL; | ||
6306 | |||
6307 | wdev = dev->ieee80211_ptr; | ||
6308 | |||
6309 | if (!rdev->ops->set_cqm_txe_config) | ||
6310 | return -EOPNOTSUPP; | ||
6311 | |||
6312 | if (wdev->iftype != NL80211_IFTYPE_STATION && | ||
6313 | wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) | ||
6314 | return -EOPNOTSUPP; | ||
6315 | |||
6316 | return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev, | ||
6317 | rate, pkts, intvl); | ||
6318 | } | ||
6319 | |||
6163 | static int nl80211_set_cqm_rssi(struct genl_info *info, | 6320 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
6164 | s32 threshold, u32 hysteresis) | 6321 | s32 threshold, u32 hysteresis) |
6165 | { | 6322 | { |
@@ -6207,6 +6364,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | |||
6207 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | 6364 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); |
6208 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); | 6365 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); |
6209 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); | 6366 | err = nl80211_set_cqm_rssi(info, threshold, hysteresis); |
6367 | } else if (attrs[NL80211_ATTR_CQM_TXE_RATE] && | ||
6368 | attrs[NL80211_ATTR_CQM_TXE_PKTS] && | ||
6369 | attrs[NL80211_ATTR_CQM_TXE_INTVL]) { | ||
6370 | u32 rate, pkts, intvl; | ||
6371 | rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]); | ||
6372 | pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]); | ||
6373 | intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]); | ||
6374 | err = nl80211_set_cqm_txe(info, rate, pkts, intvl); | ||
6210 | } else | 6375 | } else |
6211 | err = -EINVAL; | 6376 | err = -EINVAL; |
6212 | 6377 | ||
@@ -6363,8 +6528,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6363 | { | 6528 | { |
6364 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6529 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6365 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; | 6530 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; |
6366 | struct cfg80211_wowlan no_triggers = {}; | ||
6367 | struct cfg80211_wowlan new_triggers = {}; | 6531 | struct cfg80211_wowlan new_triggers = {}; |
6532 | struct cfg80211_wowlan *ntrig; | ||
6368 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; | 6533 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; |
6369 | int err, i; | 6534 | int err, i; |
6370 | bool prev_enabled = rdev->wowlan; | 6535 | bool prev_enabled = rdev->wowlan; |
@@ -6372,8 +6537,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6372 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 6537 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) |
6373 | return -EOPNOTSUPP; | 6538 | return -EOPNOTSUPP; |
6374 | 6539 | ||
6375 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) | 6540 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
6376 | goto no_triggers; | 6541 | cfg80211_rdev_free_wowlan(rdev); |
6542 | rdev->wowlan = NULL; | ||
6543 | goto set_wakeup; | ||
6544 | } | ||
6377 | 6545 | ||
6378 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, | 6546 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, |
6379 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), | 6547 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), |
@@ -6484,22 +6652,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6484 | } | 6652 | } |
6485 | } | 6653 | } |
6486 | 6654 | ||
6487 | if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) { | 6655 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
6488 | struct cfg80211_wowlan *ntrig; | 6656 | if (!ntrig) { |
6489 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), | 6657 | err = -ENOMEM; |
6490 | GFP_KERNEL); | 6658 | goto error; |
6491 | if (!ntrig) { | ||
6492 | err = -ENOMEM; | ||
6493 | goto error; | ||
6494 | } | ||
6495 | cfg80211_rdev_free_wowlan(rdev); | ||
6496 | rdev->wowlan = ntrig; | ||
6497 | } else { | ||
6498 | no_triggers: | ||
6499 | cfg80211_rdev_free_wowlan(rdev); | ||
6500 | rdev->wowlan = NULL; | ||
6501 | } | 6659 | } |
6660 | cfg80211_rdev_free_wowlan(rdev); | ||
6661 | rdev->wowlan = ntrig; | ||
6502 | 6662 | ||
6663 | set_wakeup: | ||
6503 | if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) | 6664 | if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) |
6504 | rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); | 6665 | rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); |
6505 | 6666 | ||
@@ -6655,13 +6816,17 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) | |||
6655 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 | 6816 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 |
6656 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ | 6817 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ |
6657 | NL80211_FLAG_CHECK_NETDEV_UP) | 6818 | NL80211_FLAG_CHECK_NETDEV_UP) |
6819 | #define NL80211_FLAG_NEED_WDEV 0x10 | ||
6820 | /* If a netdev is associated, it must be UP */ | ||
6821 | #define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ | ||
6822 | NL80211_FLAG_CHECK_NETDEV_UP) | ||
6658 | 6823 | ||
6659 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | 6824 | static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, |
6660 | struct genl_info *info) | 6825 | struct genl_info *info) |
6661 | { | 6826 | { |
6662 | struct cfg80211_registered_device *rdev; | 6827 | struct cfg80211_registered_device *rdev; |
6828 | struct wireless_dev *wdev; | ||
6663 | struct net_device *dev; | 6829 | struct net_device *dev; |
6664 | int err; | ||
6665 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; | 6830 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; |
6666 | 6831 | ||
6667 | if (rtnl) | 6832 | if (rtnl) |
@@ -6675,24 +6840,51 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
6675 | return PTR_ERR(rdev); | 6840 | return PTR_ERR(rdev); |
6676 | } | 6841 | } |
6677 | info->user_ptr[0] = rdev; | 6842 | info->user_ptr[0] = rdev; |
6678 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | 6843 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || |
6679 | err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs, | 6844 | ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
6680 | &rdev, &dev); | 6845 | mutex_lock(&cfg80211_mutex); |
6681 | if (err) { | 6846 | wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), |
6847 | info->attrs); | ||
6848 | if (IS_ERR(wdev)) { | ||
6849 | mutex_unlock(&cfg80211_mutex); | ||
6682 | if (rtnl) | 6850 | if (rtnl) |
6683 | rtnl_unlock(); | 6851 | rtnl_unlock(); |
6684 | return err; | 6852 | return PTR_ERR(wdev); |
6685 | } | 6853 | } |
6686 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | 6854 | |
6687 | !netif_running(dev)) { | 6855 | dev = wdev->netdev; |
6688 | cfg80211_unlock_rdev(rdev); | 6856 | rdev = wiphy_to_dev(wdev->wiphy); |
6689 | dev_put(dev); | 6857 | |
6690 | if (rtnl) | 6858 | if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { |
6691 | rtnl_unlock(); | 6859 | if (!dev) { |
6692 | return -ENETDOWN; | 6860 | mutex_unlock(&cfg80211_mutex); |
6861 | if (rtnl) | ||
6862 | rtnl_unlock(); | ||
6863 | return -EINVAL; | ||
6864 | } | ||
6865 | |||
6866 | info->user_ptr[1] = dev; | ||
6867 | } else { | ||
6868 | info->user_ptr[1] = wdev; | ||
6693 | } | 6869 | } |
6870 | |||
6871 | if (dev) { | ||
6872 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | ||
6873 | !netif_running(dev)) { | ||
6874 | mutex_unlock(&cfg80211_mutex); | ||
6875 | if (rtnl) | ||
6876 | rtnl_unlock(); | ||
6877 | return -ENETDOWN; | ||
6878 | } | ||
6879 | |||
6880 | dev_hold(dev); | ||
6881 | } | ||
6882 | |||
6883 | cfg80211_lock_rdev(rdev); | ||
6884 | |||
6885 | mutex_unlock(&cfg80211_mutex); | ||
6886 | |||
6694 | info->user_ptr[0] = rdev; | 6887 | info->user_ptr[0] = rdev; |
6695 | info->user_ptr[1] = dev; | ||
6696 | } | 6888 | } |
6697 | 6889 | ||
6698 | return 0; | 6890 | return 0; |
@@ -6703,8 +6895,16 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
6703 | { | 6895 | { |
6704 | if (info->user_ptr[0]) | 6896 | if (info->user_ptr[0]) |
6705 | cfg80211_unlock_rdev(info->user_ptr[0]); | 6897 | cfg80211_unlock_rdev(info->user_ptr[0]); |
6706 | if (info->user_ptr[1]) | 6898 | if (info->user_ptr[1]) { |
6707 | dev_put(info->user_ptr[1]); | 6899 | if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
6900 | struct wireless_dev *wdev = info->user_ptr[1]; | ||
6901 | |||
6902 | if (wdev->netdev) | ||
6903 | dev_put(wdev->netdev); | ||
6904 | } else { | ||
6905 | dev_put(info->user_ptr[1]); | ||
6906 | } | ||
6907 | } | ||
6708 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) | 6908 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) |
6709 | rtnl_unlock(); | 6909 | rtnl_unlock(); |
6710 | } | 6910 | } |
@@ -6731,7 +6931,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6731 | .dumpit = nl80211_dump_interface, | 6931 | .dumpit = nl80211_dump_interface, |
6732 | .policy = nl80211_policy, | 6932 | .policy = nl80211_policy, |
6733 | /* can be retrieved by unprivileged users */ | 6933 | /* can be retrieved by unprivileged users */ |
6734 | .internal_flags = NL80211_FLAG_NEED_NETDEV, | 6934 | .internal_flags = NL80211_FLAG_NEED_WDEV, |
6735 | }, | 6935 | }, |
6736 | { | 6936 | { |
6737 | .cmd = NL80211_CMD_SET_INTERFACE, | 6937 | .cmd = NL80211_CMD_SET_INTERFACE, |
@@ -6754,7 +6954,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6754 | .doit = nl80211_del_interface, | 6954 | .doit = nl80211_del_interface, |
6755 | .policy = nl80211_policy, | 6955 | .policy = nl80211_policy, |
6756 | .flags = GENL_ADMIN_PERM, | 6956 | .flags = GENL_ADMIN_PERM, |
6757 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 6957 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
6758 | NL80211_FLAG_NEED_RTNL, | 6958 | NL80211_FLAG_NEED_RTNL, |
6759 | }, | 6959 | }, |
6760 | { | 6960 | { |
@@ -6925,7 +7125,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6925 | .doit = nl80211_trigger_scan, | 7125 | .doit = nl80211_trigger_scan, |
6926 | .policy = nl80211_policy, | 7126 | .policy = nl80211_policy, |
6927 | .flags = GENL_ADMIN_PERM, | 7127 | .flags = GENL_ADMIN_PERM, |
6928 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7128 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6929 | NL80211_FLAG_NEED_RTNL, | 7129 | NL80211_FLAG_NEED_RTNL, |
6930 | }, | 7130 | }, |
6931 | { | 7131 | { |
@@ -7066,7 +7266,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7066 | .doit = nl80211_remain_on_channel, | 7266 | .doit = nl80211_remain_on_channel, |
7067 | .policy = nl80211_policy, | 7267 | .policy = nl80211_policy, |
7068 | .flags = GENL_ADMIN_PERM, | 7268 | .flags = GENL_ADMIN_PERM, |
7069 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7269 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
7070 | NL80211_FLAG_NEED_RTNL, | 7270 | NL80211_FLAG_NEED_RTNL, |
7071 | }, | 7271 | }, |
7072 | { | 7272 | { |
@@ -7074,7 +7274,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7074 | .doit = nl80211_cancel_remain_on_channel, | 7274 | .doit = nl80211_cancel_remain_on_channel, |
7075 | .policy = nl80211_policy, | 7275 | .policy = nl80211_policy, |
7076 | .flags = GENL_ADMIN_PERM, | 7276 | .flags = GENL_ADMIN_PERM, |
7077 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7277 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
7078 | NL80211_FLAG_NEED_RTNL, | 7278 | NL80211_FLAG_NEED_RTNL, |
7079 | }, | 7279 | }, |
7080 | { | 7280 | { |
@@ -7090,7 +7290,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7090 | .doit = nl80211_register_mgmt, | 7290 | .doit = nl80211_register_mgmt, |
7091 | .policy = nl80211_policy, | 7291 | .policy = nl80211_policy, |
7092 | .flags = GENL_ADMIN_PERM, | 7292 | .flags = GENL_ADMIN_PERM, |
7093 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 7293 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
7094 | NL80211_FLAG_NEED_RTNL, | 7294 | NL80211_FLAG_NEED_RTNL, |
7095 | }, | 7295 | }, |
7096 | { | 7296 | { |
@@ -7098,7 +7298,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7098 | .doit = nl80211_tx_mgmt, | 7298 | .doit = nl80211_tx_mgmt, |
7099 | .policy = nl80211_policy, | 7299 | .policy = nl80211_policy, |
7100 | .flags = GENL_ADMIN_PERM, | 7300 | .flags = GENL_ADMIN_PERM, |
7101 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7301 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
7102 | NL80211_FLAG_NEED_RTNL, | 7302 | NL80211_FLAG_NEED_RTNL, |
7103 | }, | 7303 | }, |
7104 | { | 7304 | { |
@@ -7106,7 +7306,7 @@ static struct genl_ops nl80211_ops[] = { | |||
7106 | .doit = nl80211_tx_mgmt_cancel_wait, | 7306 | .doit = nl80211_tx_mgmt_cancel_wait, |
7107 | .policy = nl80211_policy, | 7307 | .policy = nl80211_policy, |
7108 | .flags = GENL_ADMIN_PERM, | 7308 | .flags = GENL_ADMIN_PERM, |
7109 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7309 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
7110 | NL80211_FLAG_NEED_RTNL, | 7310 | NL80211_FLAG_NEED_RTNL, |
7111 | }, | 7311 | }, |
7112 | { | 7312 | { |
@@ -7317,7 +7517,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg, | |||
7317 | 7517 | ||
7318 | static int nl80211_send_scan_msg(struct sk_buff *msg, | 7518 | static int nl80211_send_scan_msg(struct sk_buff *msg, |
7319 | struct cfg80211_registered_device *rdev, | 7519 | struct cfg80211_registered_device *rdev, |
7320 | struct net_device *netdev, | 7520 | struct wireless_dev *wdev, |
7321 | u32 pid, u32 seq, int flags, | 7521 | u32 pid, u32 seq, int flags, |
7322 | u32 cmd) | 7522 | u32 cmd) |
7323 | { | 7523 | { |
@@ -7328,7 +7528,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg, | |||
7328 | return -1; | 7528 | return -1; |
7329 | 7529 | ||
7330 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 7530 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7331 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) | 7531 | (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
7532 | wdev->netdev->ifindex)) || | ||
7533 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) | ||
7332 | goto nla_put_failure; | 7534 | goto nla_put_failure; |
7333 | 7535 | ||
7334 | /* ignore errors and send incomplete event anyway */ | 7536 | /* ignore errors and send incomplete event anyway */ |
@@ -7365,7 +7567,7 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg, | |||
7365 | } | 7567 | } |
7366 | 7568 | ||
7367 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | 7569 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, |
7368 | struct net_device *netdev) | 7570 | struct wireless_dev *wdev) |
7369 | { | 7571 | { |
7370 | struct sk_buff *msg; | 7572 | struct sk_buff *msg; |
7371 | 7573 | ||
@@ -7373,7 +7575,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | |||
7373 | if (!msg) | 7575 | if (!msg) |
7374 | return; | 7576 | return; |
7375 | 7577 | ||
7376 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7578 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7377 | NL80211_CMD_TRIGGER_SCAN) < 0) { | 7579 | NL80211_CMD_TRIGGER_SCAN) < 0) { |
7378 | nlmsg_free(msg); | 7580 | nlmsg_free(msg); |
7379 | return; | 7581 | return; |
@@ -7384,7 +7586,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | |||
7384 | } | 7586 | } |
7385 | 7587 | ||
7386 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 7588 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
7387 | struct net_device *netdev) | 7589 | struct wireless_dev *wdev) |
7388 | { | 7590 | { |
7389 | struct sk_buff *msg; | 7591 | struct sk_buff *msg; |
7390 | 7592 | ||
@@ -7392,7 +7594,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
7392 | if (!msg) | 7594 | if (!msg) |
7393 | return; | 7595 | return; |
7394 | 7596 | ||
7395 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7597 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7396 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { | 7598 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { |
7397 | nlmsg_free(msg); | 7599 | nlmsg_free(msg); |
7398 | return; | 7600 | return; |
@@ -7403,7 +7605,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
7403 | } | 7605 | } |
7404 | 7606 | ||
7405 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 7607 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
7406 | struct net_device *netdev) | 7608 | struct wireless_dev *wdev) |
7407 | { | 7609 | { |
7408 | struct sk_buff *msg; | 7610 | struct sk_buff *msg; |
7409 | 7611 | ||
@@ -7411,7 +7613,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
7411 | if (!msg) | 7613 | if (!msg) |
7412 | return; | 7614 | return; |
7413 | 7615 | ||
7414 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7616 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7415 | NL80211_CMD_SCAN_ABORTED) < 0) { | 7617 | NL80211_CMD_SCAN_ABORTED) < 0) { |
7416 | nlmsg_free(msg); | 7618 | nlmsg_free(msg); |
7417 | return; | 7619 | return; |
@@ -7934,7 +8136,7 @@ nla_put_failure: | |||
7934 | 8136 | ||
7935 | static void nl80211_send_remain_on_chan_event( | 8137 | static void nl80211_send_remain_on_chan_event( |
7936 | int cmd, struct cfg80211_registered_device *rdev, | 8138 | int cmd, struct cfg80211_registered_device *rdev, |
7937 | struct net_device *netdev, u64 cookie, | 8139 | struct wireless_dev *wdev, u64 cookie, |
7938 | struct ieee80211_channel *chan, | 8140 | struct ieee80211_channel *chan, |
7939 | enum nl80211_channel_type channel_type, | 8141 | enum nl80211_channel_type channel_type, |
7940 | unsigned int duration, gfp_t gfp) | 8142 | unsigned int duration, gfp_t gfp) |
@@ -7953,7 +8155,9 @@ static void nl80211_send_remain_on_chan_event( | |||
7953 | } | 8155 | } |
7954 | 8156 | ||
7955 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8157 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7956 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8158 | (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8159 | wdev->netdev->ifindex)) || | ||
8160 | nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || | ||
7957 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || | 8161 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || |
7958 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || | 8162 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || |
7959 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) | 8163 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) |
@@ -7975,23 +8179,24 @@ static void nl80211_send_remain_on_chan_event( | |||
7975 | } | 8179 | } |
7976 | 8180 | ||
7977 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 8181 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, |
7978 | struct net_device *netdev, u64 cookie, | 8182 | struct wireless_dev *wdev, u64 cookie, |
7979 | struct ieee80211_channel *chan, | 8183 | struct ieee80211_channel *chan, |
7980 | enum nl80211_channel_type channel_type, | 8184 | enum nl80211_channel_type channel_type, |
7981 | unsigned int duration, gfp_t gfp) | 8185 | unsigned int duration, gfp_t gfp) |
7982 | { | 8186 | { |
7983 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | 8187 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, |
7984 | rdev, netdev, cookie, chan, | 8188 | rdev, wdev, cookie, chan, |
7985 | channel_type, duration, gfp); | 8189 | channel_type, duration, gfp); |
7986 | } | 8190 | } |
7987 | 8191 | ||
7988 | void nl80211_send_remain_on_channel_cancel( | 8192 | void nl80211_send_remain_on_channel_cancel( |
7989 | struct cfg80211_registered_device *rdev, struct net_device *netdev, | 8193 | struct cfg80211_registered_device *rdev, |
8194 | struct wireless_dev *wdev, | ||
7990 | u64 cookie, struct ieee80211_channel *chan, | 8195 | u64 cookie, struct ieee80211_channel *chan, |
7991 | enum nl80211_channel_type channel_type, gfp_t gfp) | 8196 | enum nl80211_channel_type channel_type, gfp_t gfp) |
7992 | { | 8197 | { |
7993 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | 8198 | nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, |
7994 | rdev, netdev, cookie, chan, | 8199 | rdev, wdev, cookie, chan, |
7995 | channel_type, 0, gfp); | 8200 | channel_type, 0, gfp); |
7996 | } | 8201 | } |
7997 | 8202 | ||
@@ -8105,10 +8310,11 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev, | |||
8105 | } | 8310 | } |
8106 | 8311 | ||
8107 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 8312 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
8108 | struct net_device *netdev, u32 nlpid, | 8313 | struct wireless_dev *wdev, u32 nlpid, |
8109 | int freq, int sig_dbm, | 8314 | int freq, int sig_dbm, |
8110 | const u8 *buf, size_t len, gfp_t gfp) | 8315 | const u8 *buf, size_t len, gfp_t gfp) |
8111 | { | 8316 | { |
8317 | struct net_device *netdev = wdev->netdev; | ||
8112 | struct sk_buff *msg; | 8318 | struct sk_buff *msg; |
8113 | void *hdr; | 8319 | void *hdr; |
8114 | 8320 | ||
@@ -8123,7 +8329,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
8123 | } | 8329 | } |
8124 | 8330 | ||
8125 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8331 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
8126 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8332 | (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8333 | netdev->ifindex)) || | ||
8127 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || | 8334 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || |
8128 | (sig_dbm && | 8335 | (sig_dbm && |
8129 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || | 8336 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || |
@@ -8141,10 +8348,11 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
8141 | } | 8348 | } |
8142 | 8349 | ||
8143 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | 8350 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
8144 | struct net_device *netdev, u64 cookie, | 8351 | struct wireless_dev *wdev, u64 cookie, |
8145 | const u8 *buf, size_t len, bool ack, | 8352 | const u8 *buf, size_t len, bool ack, |
8146 | gfp_t gfp) | 8353 | gfp_t gfp) |
8147 | { | 8354 | { |
8355 | struct net_device *netdev = wdev->netdev; | ||
8148 | struct sk_buff *msg; | 8356 | struct sk_buff *msg; |
8149 | void *hdr; | 8357 | void *hdr; |
8150 | 8358 | ||
@@ -8159,7 +8367,8 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | |||
8159 | } | 8367 | } |
8160 | 8368 | ||
8161 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8369 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
8162 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8370 | (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8371 | netdev->ifindex)) || | ||
8163 | nla_put(msg, NL80211_ATTR_FRAME, len, buf) || | 8372 | nla_put(msg, NL80211_ATTR_FRAME, len, buf) || |
8164 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || | 8373 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || |
8165 | (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) | 8374 | (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) |
@@ -8343,6 +8552,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
8343 | } | 8552 | } |
8344 | 8553 | ||
8345 | void | 8554 | void |
8555 | nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, | ||
8556 | struct net_device *netdev, const u8 *peer, | ||
8557 | u32 num_packets, u32 rate, u32 intvl, gfp_t gfp) | ||
8558 | { | ||
8559 | struct sk_buff *msg; | ||
8560 | struct nlattr *pinfoattr; | ||
8561 | void *hdr; | ||
8562 | |||
8563 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
8564 | if (!msg) | ||
8565 | return; | ||
8566 | |||
8567 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); | ||
8568 | if (!hdr) { | ||
8569 | nlmsg_free(msg); | ||
8570 | return; | ||
8571 | } | ||
8572 | |||
8573 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | ||
8574 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | ||
8575 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) | ||
8576 | goto nla_put_failure; | ||
8577 | |||
8578 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); | ||
8579 | if (!pinfoattr) | ||
8580 | goto nla_put_failure; | ||
8581 | |||
8582 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets)) | ||
8583 | goto nla_put_failure; | ||
8584 | |||
8585 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate)) | ||
8586 | goto nla_put_failure; | ||
8587 | |||
8588 | if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl)) | ||
8589 | goto nla_put_failure; | ||
8590 | |||
8591 | nla_nest_end(msg, pinfoattr); | ||
8592 | |||
8593 | genlmsg_end(msg, hdr); | ||
8594 | |||
8595 | genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||
8596 | nl80211_mlme_mcgrp.id, gfp); | ||
8597 | return; | ||
8598 | |||
8599 | nla_put_failure: | ||
8600 | genlmsg_cancel(msg, hdr); | ||
8601 | nlmsg_free(msg); | ||
8602 | } | ||
8603 | |||
8604 | void | ||
8346 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 8605 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
8347 | struct net_device *netdev, const u8 *peer, | 8606 | struct net_device *netdev, const u8 *peer, |
8348 | u32 num_packets, gfp_t gfp) | 8607 | u32 num_packets, gfp_t gfp) |
@@ -8483,7 +8742,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
8483 | rcu_read_lock(); | 8742 | rcu_read_lock(); |
8484 | 8743 | ||
8485 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 8744 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
8486 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 8745 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) |
8487 | cfg80211_mlme_unregister_socket(wdev, notify->pid); | 8746 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
8488 | if (rdev->ap_beacons_nlpid == notify->pid) | 8747 | if (rdev->ap_beacons_nlpid == notify->pid) |
8489 | rdev->ap_beacons_nlpid = 0; | 8748 | rdev->ap_beacons_nlpid = 0; |