diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 1009 |
1 files changed, 755 insertions, 254 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 206465dc0cab..97026f3b215a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -46,28 +46,175 @@ 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); | ||
103 | } | ||
104 | |||
105 | static struct cfg80211_registered_device * | ||
106 | __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) | ||
107 | { | ||
108 | struct cfg80211_registered_device *rdev = NULL, *tmp; | ||
109 | struct net_device *netdev; | ||
110 | |||
111 | assert_cfg80211_lock(); | ||
112 | |||
113 | if (!attrs[NL80211_ATTR_WIPHY] && | ||
114 | !attrs[NL80211_ATTR_IFINDEX] && | ||
115 | !attrs[NL80211_ATTR_WDEV]) | ||
116 | return ERR_PTR(-EINVAL); | ||
117 | |||
118 | if (attrs[NL80211_ATTR_WIPHY]) | ||
119 | rdev = cfg80211_rdev_by_wiphy_idx( | ||
120 | nla_get_u32(attrs[NL80211_ATTR_WIPHY])); | ||
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 | |||
148 | if (attrs[NL80211_ATTR_IFINDEX]) { | ||
149 | int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); | ||
150 | netdev = dev_get_by_index(netns, ifindex); | ||
151 | if (netdev) { | ||
152 | if (netdev->ieee80211_ptr) | ||
153 | tmp = wiphy_to_dev( | ||
154 | netdev->ieee80211_ptr->wiphy); | ||
155 | else | ||
156 | tmp = NULL; | ||
157 | |||
158 | dev_put(netdev); | ||
159 | |||
160 | /* not wireless device -- return error */ | ||
161 | if (!tmp) | ||
162 | return ERR_PTR(-EINVAL); | ||
163 | |||
164 | /* mismatch -- return error */ | ||
165 | if (rdev && tmp != rdev) | ||
166 | return ERR_PTR(-EINVAL); | ||
167 | |||
168 | rdev = tmp; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | if (!rdev) | ||
173 | return ERR_PTR(-ENODEV); | ||
174 | |||
175 | if (netns != wiphy_net(&rdev->wiphy)) | ||
176 | return ERR_PTR(-ENODEV); | ||
177 | |||
178 | return rdev; | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * This function returns a pointer to the driver | ||
183 | * that the genl_info item that is passed refers to. | ||
184 | * If successful, it returns non-NULL and also locks | ||
185 | * the driver's mutex! | ||
186 | * | ||
187 | * This means that you need to call cfg80211_unlock_rdev() | ||
188 | * before being allowed to acquire &cfg80211_mutex! | ||
189 | * | ||
190 | * This is necessary because we need to lock the global | ||
191 | * mutex to get an item off the list safely, and then | ||
192 | * we lock the rdev mutex so it doesn't go away under us. | ||
193 | * | ||
194 | * We don't want to keep cfg80211_mutex locked | ||
195 | * for all the time in order to allow requests on | ||
196 | * other interfaces to go through at the same time. | ||
197 | * | ||
198 | * The result of this can be a PTR_ERR and hence must | ||
199 | * be checked with IS_ERR() for errors. | ||
200 | */ | ||
201 | static struct cfg80211_registered_device * | ||
202 | cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) | ||
203 | { | ||
204 | struct cfg80211_registered_device *rdev; | ||
205 | |||
206 | mutex_lock(&cfg80211_mutex); | ||
207 | rdev = __cfg80211_rdev_from_attrs(netns, info->attrs); | ||
208 | |||
209 | /* if it is not an error we grab the lock on | ||
210 | * it to assure it won't be going away while | ||
211 | * we operate on it */ | ||
212 | if (!IS_ERR(rdev)) | ||
213 | mutex_lock(&rdev->mtx); | ||
214 | |||
215 | mutex_unlock(&cfg80211_mutex); | ||
216 | |||
217 | return rdev; | ||
71 | } | 218 | } |
72 | 219 | ||
73 | /* policy for the attributes */ | 220 | /* policy for the attributes */ |
@@ -115,7 +262,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
115 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | 262 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, |
116 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, | 263 | [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, |
117 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, | 264 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, |
118 | .len = IEEE80211_MAX_MESH_ID_LEN }, | 265 | .len = IEEE80211_MAX_MESH_ID_LEN }, |
119 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, | 266 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, |
120 | 267 | ||
121 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, | 268 | [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, |
@@ -206,6 +353,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
206 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, | 353 | [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, |
207 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, | 354 | [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, |
208 | [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 }, | ||
209 | }; | 358 | }; |
210 | 359 | ||
211 | /* policy for the key attributes */ | 360 | /* policy for the key attributes */ |
@@ -250,8 +399,9 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { | |||
250 | 399 | ||
251 | static const struct nla_policy | 400 | static const struct nla_policy |
252 | nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { | 401 | nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { |
253 | [NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY, | 402 | [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY, |
254 | .len = IEEE80211_MAX_SSID_LEN }, | 403 | .len = IEEE80211_MAX_SSID_LEN }, |
404 | [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, | ||
255 | }; | 405 | }; |
256 | 406 | ||
257 | /* ifidx get helper */ | 407 | /* ifidx get helper */ |
@@ -832,6 +982,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
832 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) | 982 | dev->wiphy.bands[band]->ht_cap.ampdu_density))) |
833 | goto nla_put_failure; | 983 | goto nla_put_failure; |
834 | 984 | ||
985 | /* add VHT info */ | ||
986 | if (dev->wiphy.bands[band]->vht_cap.vht_supported && | ||
987 | (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, | ||
988 | sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), | ||
989 | &dev->wiphy.bands[band]->vht_cap.vht_mcs) || | ||
990 | nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, | ||
991 | dev->wiphy.bands[band]->vht_cap.cap))) | ||
992 | goto nla_put_failure; | ||
993 | |||
835 | /* add frequencies */ | 994 | /* add frequencies */ |
836 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); | 995 | nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); |
837 | if (!nl_freqs) | 996 | if (!nl_freqs) |
@@ -921,7 +1080,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
921 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) | 1080 | if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS)) |
922 | goto nla_put_failure; | 1081 | goto nla_put_failure; |
923 | } | 1082 | } |
924 | CMD(set_channel, SET_CHANNEL); | 1083 | if (dev->ops->set_monitor_channel || dev->ops->start_ap || |
1084 | dev->ops->join_mesh) { | ||
1085 | i++; | ||
1086 | if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL)) | ||
1087 | goto nla_put_failure; | ||
1088 | } | ||
925 | CMD(set_wds_peer, SET_WDS_PEER); | 1089 | CMD(set_wds_peer, SET_WDS_PEER); |
926 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { | 1090 | if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) { |
927 | CMD(tdls_mgmt, TDLS_MGMT); | 1091 | CMD(tdls_mgmt, TDLS_MGMT); |
@@ -1018,6 +1182,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1018 | nla_nest_end(msg, nl_ifs); | 1182 | nla_nest_end(msg, nl_ifs); |
1019 | } | 1183 | } |
1020 | 1184 | ||
1185 | #ifdef CONFIG_PM | ||
1021 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { | 1186 | if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { |
1022 | struct nlattr *nl_wowlan; | 1187 | struct nlattr *nl_wowlan; |
1023 | 1188 | ||
@@ -1058,6 +1223,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1058 | 1223 | ||
1059 | nla_nest_end(msg, nl_wowlan); | 1224 | nla_nest_end(msg, nl_wowlan); |
1060 | } | 1225 | } |
1226 | #endif | ||
1061 | 1227 | ||
1062 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, | 1228 | if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, |
1063 | dev->wiphy.software_iftypes)) | 1229 | dev->wiphy.software_iftypes)) |
@@ -1162,18 +1328,22 @@ static int parse_txq_params(struct nlattr *tb[], | |||
1162 | static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) | 1328 | static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) |
1163 | { | 1329 | { |
1164 | /* | 1330 | /* |
1165 | * You can only set the channel explicitly for AP, mesh | 1331 | * You can only set the channel explicitly for WDS interfaces, |
1166 | * and WDS type interfaces; all others have their channel | 1332 | * all others have their channel managed via their respective |
1167 | * managed via their respective "establish a connection" | 1333 | * "establish a connection" command (connect, join, ...) |
1168 | * command (connect, join, ...) | 1334 | * |
1335 | * For AP/GO and mesh mode, the channel can be set with the | ||
1336 | * channel userspace API, but is only stored and passed to the | ||
1337 | * low-level driver when the AP starts or the mesh is joined. | ||
1338 | * This is for backward compatibility, userspace can also give | ||
1339 | * the channel in the start-ap or join-mesh commands instead. | ||
1169 | * | 1340 | * |
1170 | * Monitors are special as they are normally slaved to | 1341 | * Monitors are special as they are normally slaved to |
1171 | * whatever else is going on, so they behave as though | 1342 | * whatever else is going on, so they have their own special |
1172 | * you tried setting the wiphy channel itself. | 1343 | * operation to set the monitor channel if possible. |
1173 | */ | 1344 | */ |
1174 | return !wdev || | 1345 | return !wdev || |
1175 | wdev->iftype == NL80211_IFTYPE_AP || | 1346 | wdev->iftype == NL80211_IFTYPE_AP || |
1176 | wdev->iftype == NL80211_IFTYPE_WDS || | ||
1177 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || | 1347 | wdev->iftype == NL80211_IFTYPE_MESH_POINT || |
1178 | wdev->iftype == NL80211_IFTYPE_MONITOR || | 1348 | wdev->iftype == NL80211_IFTYPE_MONITOR || |
1179 | wdev->iftype == NL80211_IFTYPE_P2P_GO; | 1349 | wdev->iftype == NL80211_IFTYPE_P2P_GO; |
@@ -1204,9 +1374,14 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1204 | struct wireless_dev *wdev, | 1374 | struct wireless_dev *wdev, |
1205 | struct genl_info *info) | 1375 | struct genl_info *info) |
1206 | { | 1376 | { |
1377 | struct ieee80211_channel *channel; | ||
1207 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 1378 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
1208 | u32 freq; | 1379 | u32 freq; |
1209 | int result; | 1380 | int result; |
1381 | enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR; | ||
1382 | |||
1383 | if (wdev) | ||
1384 | iftype = wdev->iftype; | ||
1210 | 1385 | ||
1211 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) | 1386 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) |
1212 | return -EINVAL; | 1387 | return -EINVAL; |
@@ -1221,12 +1396,32 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, | |||
1221 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | 1396 | freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); |
1222 | 1397 | ||
1223 | mutex_lock(&rdev->devlist_mtx); | 1398 | mutex_lock(&rdev->devlist_mtx); |
1224 | if (wdev) { | 1399 | switch (iftype) { |
1225 | wdev_lock(wdev); | 1400 | case NL80211_IFTYPE_AP: |
1226 | result = cfg80211_set_freq(rdev, wdev, freq, channel_type); | 1401 | case NL80211_IFTYPE_P2P_GO: |
1227 | wdev_unlock(wdev); | 1402 | if (wdev->beacon_interval) { |
1228 | } else { | 1403 | result = -EBUSY; |
1229 | result = cfg80211_set_freq(rdev, NULL, freq, channel_type); | 1404 | break; |
1405 | } | ||
1406 | channel = rdev_freq_to_chan(rdev, freq, channel_type); | ||
1407 | if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, | ||
1408 | channel, | ||
1409 | channel_type)) { | ||
1410 | result = -EINVAL; | ||
1411 | break; | ||
1412 | } | ||
1413 | wdev->preset_chan = channel; | ||
1414 | wdev->preset_chantype = channel_type; | ||
1415 | result = 0; | ||
1416 | break; | ||
1417 | case NL80211_IFTYPE_MESH_POINT: | ||
1418 | result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type); | ||
1419 | break; | ||
1420 | case NL80211_IFTYPE_MONITOR: | ||
1421 | result = cfg80211_set_monitor_channel(rdev, freq, channel_type); | ||
1422 | break; | ||
1423 | default: | ||
1424 | result = -EINVAL; | ||
1230 | } | 1425 | } |
1231 | mutex_unlock(&rdev->devlist_mtx); | 1426 | mutex_unlock(&rdev->devlist_mtx); |
1232 | 1427 | ||
@@ -1300,7 +1495,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1300 | } | 1495 | } |
1301 | 1496 | ||
1302 | if (!netdev) { | 1497 | if (!netdev) { |
1303 | rdev = __cfg80211_rdev_from_info(info); | 1498 | rdev = __cfg80211_rdev_from_attrs(genl_info_net(info), |
1499 | info->attrs); | ||
1304 | if (IS_ERR(rdev)) { | 1500 | if (IS_ERR(rdev)) { |
1305 | mutex_unlock(&cfg80211_mutex); | 1501 | mutex_unlock(&cfg80211_mutex); |
1306 | return PTR_ERR(rdev); | 1502 | return PTR_ERR(rdev); |
@@ -1310,8 +1506,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1310 | result = 0; | 1506 | result = 0; |
1311 | 1507 | ||
1312 | mutex_lock(&rdev->mtx); | 1508 | mutex_lock(&rdev->mtx); |
1313 | } else if (netif_running(netdev) && | 1509 | } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) |
1314 | nl80211_can_set_dev_channel(netdev->ieee80211_ptr)) | ||
1315 | wdev = netdev->ieee80211_ptr; | 1510 | wdev = netdev->ieee80211_ptr; |
1316 | else | 1511 | else |
1317 | wdev = NULL; | 1512 | wdev = NULL; |
@@ -1534,22 +1729,32 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
1534 | return result; | 1729 | return result; |
1535 | } | 1730 | } |
1536 | 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 | } | ||
1537 | 1737 | ||
1538 | 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, |
1539 | struct cfg80211_registered_device *rdev, | 1739 | struct cfg80211_registered_device *rdev, |
1540 | struct net_device *dev) | 1740 | struct wireless_dev *wdev) |
1541 | { | 1741 | { |
1742 | struct net_device *dev = wdev->netdev; | ||
1542 | void *hdr; | 1743 | void *hdr; |
1543 | 1744 | ||
1544 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); | 1745 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); |
1545 | if (!hdr) | 1746 | if (!hdr) |
1546 | return -1; | 1747 | return -1; |
1547 | 1748 | ||
1548 | if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || | 1749 | if (dev && |
1549 | nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 1750 | (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || |
1550 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || | 1751 | nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || |
1551 | nla_put_u32(msg, NL80211_ATTR_IFTYPE, | 1752 | nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr))) |
1552 | 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)) || | ||
1553 | nla_put_u32(msg, NL80211_ATTR_GENERATION, | 1758 | nla_put_u32(msg, NL80211_ATTR_GENERATION, |
1554 | rdev->devlist_generation ^ | 1759 | rdev->devlist_generation ^ |
1555 | (cfg80211_rdev_list_generation << 2))) | 1760 | (cfg80211_rdev_list_generation << 2))) |
@@ -1559,12 +1764,13 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
1559 | struct ieee80211_channel *chan; | 1764 | struct ieee80211_channel *chan; |
1560 | enum nl80211_channel_type channel_type; | 1765 | enum nl80211_channel_type channel_type; |
1561 | 1766 | ||
1562 | chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type); | 1767 | chan = rdev->ops->get_channel(&rdev->wiphy, wdev, |
1768 | &channel_type); | ||
1563 | if (chan && | 1769 | if (chan && |
1564 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | 1770 | (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
1565 | chan->center_freq) || | 1771 | chan->center_freq) || |
1566 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, | 1772 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, |
1567 | channel_type))) | 1773 | channel_type))) |
1568 | goto nla_put_failure; | 1774 | goto nla_put_failure; |
1569 | } | 1775 | } |
1570 | 1776 | ||
@@ -1595,14 +1801,14 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
1595 | if_idx = 0; | 1801 | if_idx = 0; |
1596 | 1802 | ||
1597 | mutex_lock(&rdev->devlist_mtx); | 1803 | mutex_lock(&rdev->devlist_mtx); |
1598 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | 1804 | list_for_each_entry(wdev, &rdev->wdev_list, list) { |
1599 | if (if_idx < if_start) { | 1805 | if (if_idx < if_start) { |
1600 | if_idx++; | 1806 | if_idx++; |
1601 | continue; | 1807 | continue; |
1602 | } | 1808 | } |
1603 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 1809 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
1604 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1810 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
1605 | rdev, wdev->netdev) < 0) { | 1811 | rdev, wdev) < 0) { |
1606 | mutex_unlock(&rdev->devlist_mtx); | 1812 | mutex_unlock(&rdev->devlist_mtx); |
1607 | goto out; | 1813 | goto out; |
1608 | } | 1814 | } |
@@ -1625,14 +1831,14 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
1625 | { | 1831 | { |
1626 | struct sk_buff *msg; | 1832 | struct sk_buff *msg; |
1627 | struct cfg80211_registered_device *dev = info->user_ptr[0]; | 1833 | struct cfg80211_registered_device *dev = info->user_ptr[0]; |
1628 | struct net_device *netdev = info->user_ptr[1]; | 1834 | struct wireless_dev *wdev = info->user_ptr[1]; |
1629 | 1835 | ||
1630 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 1836 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1631 | if (!msg) | 1837 | if (!msg) |
1632 | return -ENOMEM; | 1838 | return -ENOMEM; |
1633 | 1839 | ||
1634 | 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, |
1635 | dev, netdev) < 0) { | 1841 | dev, wdev) < 0) { |
1636 | nlmsg_free(msg); | 1842 | nlmsg_free(msg); |
1637 | return -ENOBUFS; | 1843 | return -ENOBUFS; |
1638 | } | 1844 | } |
@@ -1772,7 +1978,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1772 | { | 1978 | { |
1773 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 1979 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1774 | struct vif_params params; | 1980 | struct vif_params params; |
1775 | struct net_device *dev; | 1981 | struct wireless_dev *wdev; |
1982 | struct sk_buff *msg; | ||
1776 | int err; | 1983 | int err; |
1777 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 1984 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
1778 | u32 flags; | 1985 | u32 flags; |
@@ -1799,19 +2006,23 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1799 | return err; | 2006 | return err; |
1800 | } | 2007 | } |
1801 | 2008 | ||
2009 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
2010 | if (!msg) | ||
2011 | return -ENOMEM; | ||
2012 | |||
1802 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 2013 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
1803 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 2014 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
1804 | &flags); | 2015 | &flags); |
1805 | dev = rdev->ops->add_virtual_intf(&rdev->wiphy, | 2016 | wdev = rdev->ops->add_virtual_intf(&rdev->wiphy, |
1806 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 2017 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
1807 | type, err ? NULL : &flags, ¶ms); | 2018 | type, err ? NULL : &flags, ¶ms); |
1808 | if (IS_ERR(dev)) | 2019 | if (IS_ERR(wdev)) { |
1809 | return PTR_ERR(dev); | 2020 | nlmsg_free(msg); |
2021 | return PTR_ERR(wdev); | ||
2022 | } | ||
1810 | 2023 | ||
1811 | if (type == NL80211_IFTYPE_MESH_POINT && | 2024 | if (type == NL80211_IFTYPE_MESH_POINT && |
1812 | info->attrs[NL80211_ATTR_MESH_ID]) { | 2025 | info->attrs[NL80211_ATTR_MESH_ID]) { |
1813 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
1814 | |||
1815 | wdev_lock(wdev); | 2026 | wdev_lock(wdev); |
1816 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != | 2027 | BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != |
1817 | IEEE80211_MAX_MESH_ID_LEN); | 2028 | IEEE80211_MAX_MESH_ID_LEN); |
@@ -1822,18 +2033,34 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1822 | wdev_unlock(wdev); | 2033 | wdev_unlock(wdev); |
1823 | } | 2034 | } |
1824 | 2035 | ||
1825 | 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); | ||
1826 | } | 2043 | } |
1827 | 2044 | ||
1828 | 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) |
1829 | { | 2046 | { |
1830 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2047 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
1831 | struct net_device *dev = info->user_ptr[1]; | 2048 | struct wireless_dev *wdev = info->user_ptr[1]; |
1832 | 2049 | ||
1833 | if (!rdev->ops->del_virtual_intf) | 2050 | if (!rdev->ops->del_virtual_intf) |
1834 | return -EOPNOTSUPP; | 2051 | return -EOPNOTSUPP; |
1835 | 2052 | ||
1836 | 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); | ||
1837 | } | 2064 | } |
1838 | 2065 | ||
1839 | 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) |
@@ -2213,6 +2440,33 @@ static int nl80211_parse_beacon(struct genl_info *info, | |||
2213 | return 0; | 2440 | return 0; |
2214 | } | 2441 | } |
2215 | 2442 | ||
2443 | static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, | ||
2444 | struct cfg80211_ap_settings *params) | ||
2445 | { | ||
2446 | struct wireless_dev *wdev; | ||
2447 | bool ret = false; | ||
2448 | |||
2449 | mutex_lock(&rdev->devlist_mtx); | ||
2450 | |||
2451 | list_for_each_entry(wdev, &rdev->wdev_list, list) { | ||
2452 | if (wdev->iftype != NL80211_IFTYPE_AP && | ||
2453 | wdev->iftype != NL80211_IFTYPE_P2P_GO) | ||
2454 | continue; | ||
2455 | |||
2456 | if (!wdev->preset_chan) | ||
2457 | continue; | ||
2458 | |||
2459 | params->channel = wdev->preset_chan; | ||
2460 | params->channel_type = wdev->preset_chantype; | ||
2461 | ret = true; | ||
2462 | break; | ||
2463 | } | ||
2464 | |||
2465 | mutex_unlock(&rdev->devlist_mtx); | ||
2466 | |||
2467 | return ret; | ||
2468 | } | ||
2469 | |||
2216 | static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | 2470 | static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) |
2217 | { | 2471 | { |
2218 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2472 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -2299,9 +2553,44 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) | |||
2299 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); | 2553 | info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]); |
2300 | } | 2554 | } |
2301 | 2555 | ||
2556 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2557 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
2558 | |||
2559 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | ||
2560 | !nl80211_valid_channel_type(info, &channel_type)) | ||
2561 | return -EINVAL; | ||
2562 | |||
2563 | params.channel = rdev_freq_to_chan(rdev, | ||
2564 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
2565 | channel_type); | ||
2566 | if (!params.channel) | ||
2567 | return -EINVAL; | ||
2568 | params.channel_type = channel_type; | ||
2569 | } else if (wdev->preset_chan) { | ||
2570 | params.channel = wdev->preset_chan; | ||
2571 | params.channel_type = wdev->preset_chantype; | ||
2572 | } else if (!nl80211_get_ap_channel(rdev, ¶ms)) | ||
2573 | return -EINVAL; | ||
2574 | |||
2575 | if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel, | ||
2576 | params.channel_type)) | ||
2577 | return -EINVAL; | ||
2578 | |||
2579 | mutex_lock(&rdev->devlist_mtx); | ||
2580 | err = cfg80211_can_use_chan(rdev, wdev, params.channel, | ||
2581 | CHAN_MODE_SHARED); | ||
2582 | mutex_unlock(&rdev->devlist_mtx); | ||
2583 | |||
2584 | if (err) | ||
2585 | return err; | ||
2586 | |||
2302 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); | 2587 | err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); |
2303 | if (!err) | 2588 | if (!err) { |
2589 | wdev->preset_chan = params.channel; | ||
2590 | wdev->preset_chantype = params.channel_type; | ||
2304 | wdev->beacon_interval = params.beacon_interval; | 2591 | wdev->beacon_interval = params.beacon_interval; |
2592 | wdev->channel = params.channel; | ||
2593 | } | ||
2305 | return err; | 2594 | return err; |
2306 | } | 2595 | } |
2307 | 2596 | ||
@@ -2334,23 +2623,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) | |||
2334 | { | 2623 | { |
2335 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 2624 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
2336 | struct net_device *dev = info->user_ptr[1]; | 2625 | struct net_device *dev = info->user_ptr[1]; |
2337 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
2338 | int err; | ||
2339 | 2626 | ||
2340 | if (!rdev->ops->stop_ap) | 2627 | return cfg80211_stop_ap(rdev, dev); |
2341 | return -EOPNOTSUPP; | ||
2342 | |||
2343 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
2344 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | ||
2345 | return -EOPNOTSUPP; | ||
2346 | |||
2347 | if (!wdev->beacon_interval) | ||
2348 | return -ENOENT; | ||
2349 | |||
2350 | err = rdev->ops->stop_ap(&rdev->wiphy, dev); | ||
2351 | if (!err) | ||
2352 | wdev->beacon_interval = 0; | ||
2353 | return err; | ||
2354 | } | 2628 | } |
2355 | 2629 | ||
2356 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | 2630 | static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { |
@@ -2442,7 +2716,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2442 | int attr) | 2716 | int attr) |
2443 | { | 2717 | { |
2444 | struct nlattr *rate; | 2718 | struct nlattr *rate; |
2445 | u16 bitrate; | 2719 | u32 bitrate; |
2720 | u16 bitrate_compat; | ||
2446 | 2721 | ||
2447 | rate = nla_nest_start(msg, attr); | 2722 | rate = nla_nest_start(msg, attr); |
2448 | if (!rate) | 2723 | if (!rate) |
@@ -2450,8 +2725,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, | |||
2450 | 2725 | ||
2451 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ | 2726 | /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ |
2452 | bitrate = cfg80211_calculate_bitrate(info); | 2727 | bitrate = cfg80211_calculate_bitrate(info); |
2728 | /* report 16-bit bitrate only if we can */ | ||
2729 | bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; | ||
2453 | if ((bitrate > 0 && | 2730 | if ((bitrate > 0 && |
2454 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) || | 2731 | nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || |
2732 | (bitrate_compat > 0 && | ||
2733 | nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || | ||
2455 | ((info->flags & RATE_INFO_FLAGS_MCS) && | 2734 | ((info->flags & RATE_INFO_FLAGS_MCS) && |
2456 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || | 2735 | nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || |
2457 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && | 2736 | ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && |
@@ -3304,6 +3583,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3304 | { | 3583 | { |
3305 | int r; | 3584 | int r; |
3306 | char *data = NULL; | 3585 | char *data = NULL; |
3586 | enum nl80211_user_reg_hint_type user_reg_hint_type; | ||
3307 | 3587 | ||
3308 | /* | 3588 | /* |
3309 | * You should only get this when cfg80211 hasn't yet initialized | 3589 | * You should only get this when cfg80211 hasn't yet initialized |
@@ -3323,7 +3603,21 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
3323 | 3603 | ||
3324 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | 3604 | data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); |
3325 | 3605 | ||
3326 | 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); | ||
3327 | 3621 | ||
3328 | return r; | 3622 | return r; |
3329 | } | 3623 | } |
@@ -3413,7 +3707,13 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, | |||
3413 | nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, | 3707 | nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, |
3414 | cur_params.rssi_threshold) || | 3708 | cur_params.rssi_threshold) || |
3415 | nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE, | 3709 | nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE, |
3416 | cur_params.ht_opmode)) | 3710 | cur_params.ht_opmode) || |
3711 | nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, | ||
3712 | cur_params.dot11MeshHWMPactivePathToRootTimeout) || | ||
3713 | nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, | ||
3714 | cur_params.dot11MeshHWMProotInterval) || | ||
3715 | nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, | ||
3716 | cur_params.dot11MeshHWMPconfirmationInterval)) | ||
3417 | goto nla_put_failure; | 3717 | goto nla_put_failure; |
3418 | nla_nest_end(msg, pinfoattr); | 3718 | nla_nest_end(msg, pinfoattr); |
3419 | genlmsg_end(msg, hdr); | 3719 | genlmsg_end(msg, hdr); |
@@ -3436,7 +3736,6 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
3436 | [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, | 3736 | [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, |
3437 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, | 3737 | [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, |
3438 | [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 }, | 3738 | [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 }, |
3439 | |||
3440 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, | 3739 | [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, |
3441 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, | 3740 | [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, |
3442 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, | 3741 | [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, |
@@ -3448,8 +3747,11 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A | |||
3448 | [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, | 3747 | [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, |
3449 | [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, | 3748 | [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, |
3450 | [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, | 3749 | [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, |
3451 | [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32}, | 3750 | [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 }, |
3452 | [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16}, | 3751 | [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 }, |
3752 | [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 }, | ||
3753 | [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 }, | ||
3754 | [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 }, | ||
3453 | }; | 3755 | }; |
3454 | 3756 | ||
3455 | static const struct nla_policy | 3757 | static const struct nla_policy |
@@ -3459,7 +3761,7 @@ static const struct nla_policy | |||
3459 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, | 3761 | [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, |
3460 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, | 3762 | [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, |
3461 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, | 3763 | [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, |
3462 | .len = IEEE80211_MAX_DATA_LEN }, | 3764 | .len = IEEE80211_MAX_DATA_LEN }, |
3463 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, | 3765 | [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, |
3464 | }; | 3766 | }; |
3465 | 3767 | ||
@@ -3492,63 +3794,82 @@ do {\ | |||
3492 | 3794 | ||
3493 | /* Fill in the params struct */ | 3795 | /* Fill in the params struct */ |
3494 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, | 3796 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, |
3495 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); | 3797 | mask, NL80211_MESHCONF_RETRY_TIMEOUT, |
3798 | nla_get_u16); | ||
3496 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, | 3799 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, |
3497 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); | 3800 | mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, |
3801 | nla_get_u16); | ||
3498 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, | 3802 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, |
3499 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); | 3803 | mask, NL80211_MESHCONF_HOLDING_TIMEOUT, |
3804 | nla_get_u16); | ||
3500 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, | 3805 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, |
3501 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); | 3806 | mask, NL80211_MESHCONF_MAX_PEER_LINKS, |
3807 | nla_get_u16); | ||
3502 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, | 3808 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, |
3503 | mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); | 3809 | mask, NL80211_MESHCONF_MAX_RETRIES, |
3810 | nla_get_u8); | ||
3504 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, | 3811 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, |
3505 | mask, NL80211_MESHCONF_TTL, nla_get_u8); | 3812 | mask, NL80211_MESHCONF_TTL, nla_get_u8); |
3506 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, | 3813 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, |
3507 | mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8); | 3814 | mask, NL80211_MESHCONF_ELEMENT_TTL, |
3815 | nla_get_u8); | ||
3508 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, | 3816 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, |
3509 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); | 3817 | mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, |
3510 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, | 3818 | nla_get_u8); |
3511 | mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, | 3819 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, mask, |
3512 | nla_get_u32); | 3820 | NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, |
3821 | nla_get_u32); | ||
3513 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, | 3822 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, |
3514 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, | 3823 | mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, |
3515 | nla_get_u8); | 3824 | nla_get_u8); |
3516 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, | 3825 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, |
3517 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); | 3826 | mask, NL80211_MESHCONF_PATH_REFRESH_TIME, |
3827 | nla_get_u32); | ||
3518 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, | 3828 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, |
3519 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, | 3829 | mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, |
3520 | nla_get_u16); | 3830 | nla_get_u16); |
3521 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, | 3831 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, mask, |
3522 | mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, | 3832 | NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, |
3523 | nla_get_u32); | 3833 | nla_get_u32); |
3524 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, | 3834 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, |
3525 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, | 3835 | mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, |
3526 | nla_get_u16); | 3836 | nla_get_u16); |
3527 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, | 3837 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, |
3528 | mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, | 3838 | mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, |
3529 | nla_get_u16); | 3839 | nla_get_u16); |
3530 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | 3840 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, |
3531 | dot11MeshHWMPnetDiameterTraversalTime, | 3841 | dot11MeshHWMPnetDiameterTraversalTime, mask, |
3532 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 3842 | NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
3533 | nla_get_u16); | 3843 | nla_get_u16); |
3844 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask, | ||
3845 | NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8); | ||
3846 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask, | ||
3847 | NL80211_MESHCONF_HWMP_RANN_INTERVAL, | ||
3848 | nla_get_u16); | ||
3534 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | 3849 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, |
3535 | dot11MeshHWMPRootMode, mask, | 3850 | dot11MeshGateAnnouncementProtocol, mask, |
3536 | NL80211_MESHCONF_HWMP_ROOTMODE, | 3851 | NL80211_MESHCONF_GATE_ANNOUNCEMENTS, |
3537 | nla_get_u8); | 3852 | nla_get_u8); |
3538 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
3539 | dot11MeshHWMPRannInterval, mask, | ||
3540 | NL80211_MESHCONF_HWMP_RANN_INTERVAL, | ||
3541 | nla_get_u16); | ||
3542 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
3543 | dot11MeshGateAnnouncementProtocol, mask, | ||
3544 | NL80211_MESHCONF_GATE_ANNOUNCEMENTS, | ||
3545 | nla_get_u8); | ||
3546 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, | 3853 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, |
3547 | mask, NL80211_MESHCONF_FORWARDING, nla_get_u8); | 3854 | mask, NL80211_MESHCONF_FORWARDING, |
3855 | nla_get_u8); | ||
3548 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, | 3856 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, |
3549 | mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32); | 3857 | mask, NL80211_MESHCONF_RSSI_THRESHOLD, |
3858 | nla_get_u32); | ||
3550 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, | 3859 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, |
3551 | mask, NL80211_MESHCONF_HT_OPMODE, nla_get_u16); | 3860 | mask, NL80211_MESHCONF_HT_OPMODE, |
3861 | nla_get_u16); | ||
3862 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout, | ||
3863 | mask, | ||
3864 | NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, | ||
3865 | nla_get_u32); | ||
3866 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, | ||
3867 | mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, | ||
3868 | nla_get_u16); | ||
3869 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
3870 | dot11MeshHWMPconfirmationInterval, mask, | ||
3871 | NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, | ||
3872 | nla_get_u16); | ||
3552 | if (mask_out) | 3873 | if (mask_out) |
3553 | *mask_out = mask; | 3874 | *mask_out = mask; |
3554 | 3875 | ||
@@ -3666,6 +3987,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
3666 | cfg80211_regdomain->dfs_region))) | 3987 | cfg80211_regdomain->dfs_region))) |
3667 | goto nla_put_failure; | 3988 | goto nla_put_failure; |
3668 | 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 | |||
3669 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); | 3995 | nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); |
3670 | if (!nl_reg_rules) | 3996 | if (!nl_reg_rules) |
3671 | goto nla_put_failure; | 3997 | goto nla_put_failure; |
@@ -3831,7 +4157,7 @@ static int validate_scan_freqs(struct nlattr *freqs) | |||
3831 | 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) |
3832 | { | 4158 | { |
3833 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 4159 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
3834 | struct net_device *dev = info->user_ptr[1]; | 4160 | struct wireless_dev *wdev = info->user_ptr[1]; |
3835 | struct cfg80211_scan_request *request; | 4161 | struct cfg80211_scan_request *request; |
3836 | struct nlattr *attr; | 4162 | struct nlattr *attr; |
3837 | struct wiphy *wiphy; | 4163 | struct wiphy *wiphy; |
@@ -3991,15 +4317,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
3991 | request->no_cck = | 4317 | request->no_cck = |
3992 | nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); | 4318 | nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); |
3993 | 4319 | ||
3994 | request->dev = dev; | 4320 | request->wdev = wdev; |
3995 | request->wiphy = &rdev->wiphy; | 4321 | request->wiphy = &rdev->wiphy; |
3996 | 4322 | ||
3997 | rdev->scan_req = request; | 4323 | rdev->scan_req = request; |
3998 | err = rdev->ops->scan(&rdev->wiphy, dev, request); | 4324 | err = rdev->ops->scan(&rdev->wiphy, request); |
3999 | 4325 | ||
4000 | if (!err) { | 4326 | if (!err) { |
4001 | nl80211_send_scan_start(rdev, dev); | 4327 | nl80211_send_scan_start(rdev, wdev); |
4002 | dev_hold(dev); | 4328 | if (wdev->netdev) |
4329 | dev_hold(wdev->netdev); | ||
4003 | } else { | 4330 | } else { |
4004 | out_free: | 4331 | out_free: |
4005 | rdev->scan_req = NULL; | 4332 | rdev->scan_req = NULL; |
@@ -4185,12 +4512,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
4185 | nla_for_each_nested(attr, | 4512 | nla_for_each_nested(attr, |
4186 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], | 4513 | info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], |
4187 | tmp) { | 4514 | tmp) { |
4188 | struct nlattr *ssid; | 4515 | struct nlattr *ssid, *rssi; |
4189 | 4516 | ||
4190 | nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, | 4517 | nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, |
4191 | nla_data(attr), nla_len(attr), | 4518 | nla_data(attr), nla_len(attr), |
4192 | nl80211_match_policy); | 4519 | nl80211_match_policy); |
4193 | ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID]; | 4520 | ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; |
4194 | if (ssid) { | 4521 | if (ssid) { |
4195 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { | 4522 | if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { |
4196 | err = -EINVAL; | 4523 | err = -EINVAL; |
@@ -4201,6 +4528,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, | |||
4201 | request->match_sets[i].ssid.ssid_len = | 4528 | request->match_sets[i].ssid.ssid_len = |
4202 | nla_len(ssid); | 4529 | nla_len(ssid); |
4203 | } | 4530 | } |
4531 | rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; | ||
4532 | if (rssi) | ||
4533 | request->rssi_thold = nla_get_u32(rssi); | ||
4534 | else | ||
4535 | request->rssi_thold = | ||
4536 | NL80211_SCAN_RSSI_THOLD_OFF; | ||
4204 | i++; | 4537 | i++; |
4205 | } | 4538 | } |
4206 | } | 4539 | } |
@@ -5058,21 +5391,18 @@ static int nl80211_testmode_dump(struct sk_buff *skb, | |||
5058 | nl80211_policy); | 5391 | nl80211_policy); |
5059 | if (err) | 5392 | if (err) |
5060 | return err; | 5393 | return err; |
5061 | if (nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) { | ||
5062 | phy_idx = nla_get_u32( | ||
5063 | nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]); | ||
5064 | } else { | ||
5065 | struct net_device *netdev; | ||
5066 | 5394 | ||
5067 | err = get_rdev_dev_by_ifindex(sock_net(skb->sk), | 5395 | mutex_lock(&cfg80211_mutex); |
5068 | nl80211_fam.attrbuf, | 5396 | rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), |
5069 | &rdev, &netdev); | 5397 | nl80211_fam.attrbuf); |
5070 | if (err) | 5398 | if (IS_ERR(rdev)) { |
5071 | return err; | 5399 | mutex_unlock(&cfg80211_mutex); |
5072 | dev_put(netdev); | 5400 | return PTR_ERR(rdev); |
5073 | phy_idx = rdev->wiphy_idx; | ||
5074 | cfg80211_unlock_rdev(rdev); | ||
5075 | } | 5401 | } |
5402 | phy_idx = rdev->wiphy_idx; | ||
5403 | rdev = NULL; | ||
5404 | mutex_unlock(&cfg80211_mutex); | ||
5405 | |||
5076 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) | 5406 | if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) |
5077 | cb->args[1] = | 5407 | cb->args[1] = |
5078 | (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; | 5408 | (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; |
@@ -5474,7 +5804,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5474 | struct genl_info *info) | 5804 | struct genl_info *info) |
5475 | { | 5805 | { |
5476 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5806 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5477 | struct net_device *dev = info->user_ptr[1]; | 5807 | struct wireless_dev *wdev = info->user_ptr[1]; |
5478 | struct ieee80211_channel *chan; | 5808 | struct ieee80211_channel *chan; |
5479 | struct sk_buff *msg; | 5809 | struct sk_buff *msg; |
5480 | void *hdr; | 5810 | void *hdr; |
@@ -5489,18 +5819,18 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5489 | 5819 | ||
5490 | duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 5820 | duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
5491 | 5821 | ||
5822 | if (!rdev->ops->remain_on_channel || | ||
5823 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) | ||
5824 | return -EOPNOTSUPP; | ||
5825 | |||
5492 | /* | 5826 | /* |
5493 | * We should be on that channel for at least one jiffie, | 5827 | * We should be on that channel for at least a minimum amount of |
5494 | * and more than 5 seconds seems excessive. | 5828 | * time (10ms) but no longer than the driver supports. |
5495 | */ | 5829 | */ |
5496 | if (!duration || !msecs_to_jiffies(duration) || | 5830 | if (duration < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || |
5497 | duration > rdev->wiphy.max_remain_on_channel_duration) | 5831 | duration > rdev->wiphy.max_remain_on_channel_duration) |
5498 | return -EINVAL; | 5832 | return -EINVAL; |
5499 | 5833 | ||
5500 | if (!rdev->ops->remain_on_channel || | ||
5501 | !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) | ||
5502 | return -EOPNOTSUPP; | ||
5503 | |||
5504 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | 5834 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && |
5505 | !nl80211_valid_channel_type(info, &channel_type)) | 5835 | !nl80211_valid_channel_type(info, &channel_type)) |
5506 | return -EINVAL; | 5836 | return -EINVAL; |
@@ -5522,7 +5852,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, | |||
5522 | goto free_msg; | 5852 | goto free_msg; |
5523 | } | 5853 | } |
5524 | 5854 | ||
5525 | err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, | 5855 | err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, |
5526 | channel_type, duration, &cookie); | 5856 | channel_type, duration, &cookie); |
5527 | 5857 | ||
5528 | if (err) | 5858 | if (err) |
@@ -5546,7 +5876,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
5546 | struct genl_info *info) | 5876 | struct genl_info *info) |
5547 | { | 5877 | { |
5548 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 5878 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5549 | struct net_device *dev = info->user_ptr[1]; | 5879 | struct wireless_dev *wdev = info->user_ptr[1]; |
5550 | u64 cookie; | 5880 | u64 cookie; |
5551 | 5881 | ||
5552 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 5882 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
@@ -5557,7 +5887,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | |||
5557 | 5887 | ||
5558 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 5888 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
5559 | 5889 | ||
5560 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | 5890 | return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); |
5561 | } | 5891 | } |
5562 | 5892 | ||
5563 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, | 5893 | static u32 rateset_to_mask(struct ieee80211_supported_band *sband, |
@@ -5706,7 +6036,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
5706 | 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) |
5707 | { | 6037 | { |
5708 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6038 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5709 | struct net_device *dev = info->user_ptr[1]; | 6039 | struct wireless_dev *wdev = info->user_ptr[1]; |
5710 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; | 6040 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; |
5711 | 6041 | ||
5712 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 6042 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
@@ -5715,21 +6045,24 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5715 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) | 6045 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
5716 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); | 6046 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
5717 | 6047 | ||
5718 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6048 | switch (wdev->iftype) { |
5719 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6049 | case NL80211_IFTYPE_STATION: |
5720 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6050 | case NL80211_IFTYPE_ADHOC: |
5721 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6051 | case NL80211_IFTYPE_P2P_CLIENT: |
5722 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6052 | case NL80211_IFTYPE_AP: |
5723 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 6053 | case NL80211_IFTYPE_AP_VLAN: |
5724 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6054 | case NL80211_IFTYPE_MESH_POINT: |
6055 | case NL80211_IFTYPE_P2P_GO: | ||
6056 | break; | ||
6057 | default: | ||
5725 | return -EOPNOTSUPP; | 6058 | return -EOPNOTSUPP; |
6059 | } | ||
5726 | 6060 | ||
5727 | /* not much point in registering if we can't reply */ | 6061 | /* not much point in registering if we can't reply */ |
5728 | if (!rdev->ops->mgmt_tx) | 6062 | if (!rdev->ops->mgmt_tx) |
5729 | return -EOPNOTSUPP; | 6063 | return -EOPNOTSUPP; |
5730 | 6064 | ||
5731 | return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, | 6065 | return cfg80211_mlme_register_mgmt(wdev, info->snd_pid, frame_type, |
5732 | frame_type, | ||
5733 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 6066 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
5734 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 6067 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
5735 | } | 6068 | } |
@@ -5737,7 +6070,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5737 | 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) |
5738 | { | 6071 | { |
5739 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6072 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5740 | struct net_device *dev = info->user_ptr[1]; | 6073 | struct wireless_dev *wdev = info->user_ptr[1]; |
5741 | struct ieee80211_channel *chan; | 6074 | struct ieee80211_channel *chan; |
5742 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 6075 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
5743 | bool channel_type_valid = false; | 6076 | bool channel_type_valid = false; |
@@ -5758,19 +6091,32 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5758 | if (!rdev->ops->mgmt_tx) | 6091 | if (!rdev->ops->mgmt_tx) |
5759 | return -EOPNOTSUPP; | 6092 | return -EOPNOTSUPP; |
5760 | 6093 | ||
5761 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6094 | switch (wdev->iftype) { |
5762 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6095 | case NL80211_IFTYPE_STATION: |
5763 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6096 | case NL80211_IFTYPE_ADHOC: |
5764 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6097 | case NL80211_IFTYPE_P2P_CLIENT: |
5765 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6098 | case NL80211_IFTYPE_AP: |
5766 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && | 6099 | case NL80211_IFTYPE_AP_VLAN: |
5767 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6100 | case NL80211_IFTYPE_MESH_POINT: |
6101 | case NL80211_IFTYPE_P2P_GO: | ||
6102 | break; | ||
6103 | default: | ||
5768 | return -EOPNOTSUPP; | 6104 | return -EOPNOTSUPP; |
6105 | } | ||
5769 | 6106 | ||
5770 | if (info->attrs[NL80211_ATTR_DURATION]) { | 6107 | if (info->attrs[NL80211_ATTR_DURATION]) { |
5771 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) | 6108 | if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) |
5772 | return -EINVAL; | 6109 | return -EINVAL; |
5773 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | 6110 | wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); |
6111 | |||
6112 | /* | ||
6113 | * We should wait on the channel for at least a minimum amount | ||
6114 | * of time (10ms) but no longer than the driver supports. | ||
6115 | */ | ||
6116 | if (wait < NL80211_MIN_REMAIN_ON_CHANNEL_TIME || | ||
6117 | wait > rdev->wiphy.max_remain_on_channel_duration) | ||
6118 | return -EINVAL; | ||
6119 | |||
5774 | } | 6120 | } |
5775 | 6121 | ||
5776 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | 6122 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
@@ -5805,7 +6151,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5805 | } | 6151 | } |
5806 | } | 6152 | } |
5807 | 6153 | ||
5808 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, | 6154 | err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type, |
5809 | channel_type_valid, wait, | 6155 | channel_type_valid, wait, |
5810 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 6156 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
5811 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 6157 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
@@ -5833,7 +6179,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) | |||
5833 | 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) |
5834 | { | 6180 | { |
5835 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6181 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
5836 | struct net_device *dev = info->user_ptr[1]; | 6182 | struct wireless_dev *wdev = info->user_ptr[1]; |
5837 | u64 cookie; | 6183 | u64 cookie; |
5838 | 6184 | ||
5839 | if (!info->attrs[NL80211_ATTR_COOKIE]) | 6185 | if (!info->attrs[NL80211_ATTR_COOKIE]) |
@@ -5842,17 +6188,21 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in | |||
5842 | if (!rdev->ops->mgmt_tx_cancel_wait) | 6188 | if (!rdev->ops->mgmt_tx_cancel_wait) |
5843 | return -EOPNOTSUPP; | 6189 | return -EOPNOTSUPP; |
5844 | 6190 | ||
5845 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && | 6191 | switch (wdev->iftype) { |
5846 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && | 6192 | case NL80211_IFTYPE_STATION: |
5847 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && | 6193 | case NL80211_IFTYPE_ADHOC: |
5848 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | 6194 | case NL80211_IFTYPE_P2P_CLIENT: |
5849 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | 6195 | case NL80211_IFTYPE_AP: |
5850 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) | 6196 | case NL80211_IFTYPE_AP_VLAN: |
6197 | case NL80211_IFTYPE_P2P_GO: | ||
6198 | break; | ||
6199 | default: | ||
5851 | return -EOPNOTSUPP; | 6200 | return -EOPNOTSUPP; |
6201 | } | ||
5852 | 6202 | ||
5853 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | 6203 | cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); |
5854 | 6204 | ||
5855 | return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie); | 6205 | return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); |
5856 | } | 6206 | } |
5857 | 6207 | ||
5858 | 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) |
@@ -5938,8 +6288,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { | |||
5938 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, | 6288 | [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, |
5939 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, | 6289 | [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, |
5940 | [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 }, | ||
5941 | }; | 6294 | }; |
5942 | 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 | |||
5943 | static int nl80211_set_cqm_rssi(struct genl_info *info, | 6320 | static int nl80211_set_cqm_rssi(struct genl_info *info, |
5944 | s32 threshold, u32 hysteresis) | 6321 | s32 threshold, u32 hysteresis) |
5945 | { | 6322 | { |
@@ -5987,6 +6364,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) | |||
5987 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); | 6364 | threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); |
5988 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); | 6365 | hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); |
5989 | 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); | ||
5990 | } else | 6375 | } else |
5991 | err = -EINVAL; | 6376 | err = -EINVAL; |
5992 | 6377 | ||
@@ -6032,6 +6417,24 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6032 | return err; | 6417 | return err; |
6033 | } | 6418 | } |
6034 | 6419 | ||
6420 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
6421 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||
6422 | |||
6423 | if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && | ||
6424 | !nl80211_valid_channel_type(info, &channel_type)) | ||
6425 | return -EINVAL; | ||
6426 | |||
6427 | setup.channel = rdev_freq_to_chan(rdev, | ||
6428 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]), | ||
6429 | channel_type); | ||
6430 | if (!setup.channel) | ||
6431 | return -EINVAL; | ||
6432 | setup.channel_type = channel_type; | ||
6433 | } else { | ||
6434 | /* cfg80211_join_mesh() will sort it out */ | ||
6435 | setup.channel = NULL; | ||
6436 | } | ||
6437 | |||
6035 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); | 6438 | return cfg80211_join_mesh(rdev, dev, &setup, &cfg); |
6036 | } | 6439 | } |
6037 | 6440 | ||
@@ -6043,6 +6446,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) | |||
6043 | return cfg80211_leave_mesh(rdev, dev); | 6446 | return cfg80211_leave_mesh(rdev, dev); |
6044 | } | 6447 | } |
6045 | 6448 | ||
6449 | #ifdef CONFIG_PM | ||
6046 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) | 6450 | static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) |
6047 | { | 6451 | { |
6048 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6452 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
@@ -6124,8 +6528,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6124 | { | 6528 | { |
6125 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; | 6529 | struct cfg80211_registered_device *rdev = info->user_ptr[0]; |
6126 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; | 6530 | struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; |
6127 | struct cfg80211_wowlan no_triggers = {}; | ||
6128 | struct cfg80211_wowlan new_triggers = {}; | 6531 | struct cfg80211_wowlan new_triggers = {}; |
6532 | struct cfg80211_wowlan *ntrig; | ||
6129 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; | 6533 | struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; |
6130 | int err, i; | 6534 | int err, i; |
6131 | bool prev_enabled = rdev->wowlan; | 6535 | bool prev_enabled = rdev->wowlan; |
@@ -6133,8 +6537,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6133 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) | 6537 | if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) |
6134 | return -EOPNOTSUPP; | 6538 | return -EOPNOTSUPP; |
6135 | 6539 | ||
6136 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) | 6540 | if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { |
6137 | goto no_triggers; | 6541 | cfg80211_rdev_free_wowlan(rdev); |
6542 | rdev->wowlan = NULL; | ||
6543 | goto set_wakeup; | ||
6544 | } | ||
6138 | 6545 | ||
6139 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, | 6546 | err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, |
6140 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), | 6547 | nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), |
@@ -6245,22 +6652,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6245 | } | 6652 | } |
6246 | } | 6653 | } |
6247 | 6654 | ||
6248 | if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) { | 6655 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); |
6249 | struct cfg80211_wowlan *ntrig; | 6656 | if (!ntrig) { |
6250 | ntrig = kmemdup(&new_triggers, sizeof(new_triggers), | 6657 | err = -ENOMEM; |
6251 | GFP_KERNEL); | 6658 | goto error; |
6252 | if (!ntrig) { | ||
6253 | err = -ENOMEM; | ||
6254 | goto error; | ||
6255 | } | ||
6256 | cfg80211_rdev_free_wowlan(rdev); | ||
6257 | rdev->wowlan = ntrig; | ||
6258 | } else { | ||
6259 | no_triggers: | ||
6260 | cfg80211_rdev_free_wowlan(rdev); | ||
6261 | rdev->wowlan = NULL; | ||
6262 | } | 6659 | } |
6660 | cfg80211_rdev_free_wowlan(rdev); | ||
6661 | rdev->wowlan = ntrig; | ||
6263 | 6662 | ||
6663 | set_wakeup: | ||
6264 | if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) | 6664 | if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) |
6265 | rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); | 6665 | rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); |
6266 | 6666 | ||
@@ -6271,6 +6671,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) | |||
6271 | kfree(new_triggers.patterns); | 6671 | kfree(new_triggers.patterns); |
6272 | return err; | 6672 | return err; |
6273 | } | 6673 | } |
6674 | #endif | ||
6274 | 6675 | ||
6275 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) | 6676 | static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) |
6276 | { | 6677 | { |
@@ -6415,44 +6816,75 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) | |||
6415 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 | 6816 | #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 |
6416 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ | 6817 | #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ |
6417 | 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) | ||
6418 | 6823 | ||
6419 | 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, |
6420 | struct genl_info *info) | 6825 | struct genl_info *info) |
6421 | { | 6826 | { |
6422 | struct cfg80211_registered_device *rdev; | 6827 | struct cfg80211_registered_device *rdev; |
6828 | struct wireless_dev *wdev; | ||
6423 | struct net_device *dev; | 6829 | struct net_device *dev; |
6424 | int err; | ||
6425 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; | 6830 | bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; |
6426 | 6831 | ||
6427 | if (rtnl) | 6832 | if (rtnl) |
6428 | rtnl_lock(); | 6833 | rtnl_lock(); |
6429 | 6834 | ||
6430 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { | 6835 | if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { |
6431 | rdev = cfg80211_get_dev_from_info(info); | 6836 | rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); |
6432 | if (IS_ERR(rdev)) { | 6837 | if (IS_ERR(rdev)) { |
6433 | if (rtnl) | 6838 | if (rtnl) |
6434 | rtnl_unlock(); | 6839 | rtnl_unlock(); |
6435 | return PTR_ERR(rdev); | 6840 | return PTR_ERR(rdev); |
6436 | } | 6841 | } |
6437 | info->user_ptr[0] = rdev; | 6842 | info->user_ptr[0] = rdev; |
6438 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { | 6843 | } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || |
6439 | err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs, | 6844 | ops->internal_flags & NL80211_FLAG_NEED_WDEV) { |
6440 | &rdev, &dev); | 6845 | mutex_lock(&cfg80211_mutex); |
6441 | 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); | ||
6442 | if (rtnl) | 6850 | if (rtnl) |
6443 | rtnl_unlock(); | 6851 | rtnl_unlock(); |
6444 | return err; | 6852 | return PTR_ERR(wdev); |
6445 | } | 6853 | } |
6446 | if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && | 6854 | |
6447 | !netif_running(dev)) { | 6855 | dev = wdev->netdev; |
6448 | cfg80211_unlock_rdev(rdev); | 6856 | rdev = wiphy_to_dev(wdev->wiphy); |
6449 | dev_put(dev); | 6857 | |
6450 | if (rtnl) | 6858 | if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { |
6451 | rtnl_unlock(); | 6859 | if (!dev) { |
6452 | 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; | ||
6453 | } | 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 | |||
6454 | info->user_ptr[0] = rdev; | 6887 | info->user_ptr[0] = rdev; |
6455 | info->user_ptr[1] = dev; | ||
6456 | } | 6888 | } |
6457 | 6889 | ||
6458 | return 0; | 6890 | return 0; |
@@ -6463,8 +6895,16 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, | |||
6463 | { | 6895 | { |
6464 | if (info->user_ptr[0]) | 6896 | if (info->user_ptr[0]) |
6465 | cfg80211_unlock_rdev(info->user_ptr[0]); | 6897 | cfg80211_unlock_rdev(info->user_ptr[0]); |
6466 | if (info->user_ptr[1]) | 6898 | if (info->user_ptr[1]) { |
6467 | 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 | } | ||
6468 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) | 6908 | if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) |
6469 | rtnl_unlock(); | 6909 | rtnl_unlock(); |
6470 | } | 6910 | } |
@@ -6491,7 +6931,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6491 | .dumpit = nl80211_dump_interface, | 6931 | .dumpit = nl80211_dump_interface, |
6492 | .policy = nl80211_policy, | 6932 | .policy = nl80211_policy, |
6493 | /* can be retrieved by unprivileged users */ | 6933 | /* can be retrieved by unprivileged users */ |
6494 | .internal_flags = NL80211_FLAG_NEED_NETDEV, | 6934 | .internal_flags = NL80211_FLAG_NEED_WDEV, |
6495 | }, | 6935 | }, |
6496 | { | 6936 | { |
6497 | .cmd = NL80211_CMD_SET_INTERFACE, | 6937 | .cmd = NL80211_CMD_SET_INTERFACE, |
@@ -6514,7 +6954,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6514 | .doit = nl80211_del_interface, | 6954 | .doit = nl80211_del_interface, |
6515 | .policy = nl80211_policy, | 6955 | .policy = nl80211_policy, |
6516 | .flags = GENL_ADMIN_PERM, | 6956 | .flags = GENL_ADMIN_PERM, |
6517 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 6957 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
6518 | NL80211_FLAG_NEED_RTNL, | 6958 | NL80211_FLAG_NEED_RTNL, |
6519 | }, | 6959 | }, |
6520 | { | 6960 | { |
@@ -6685,7 +7125,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6685 | .doit = nl80211_trigger_scan, | 7125 | .doit = nl80211_trigger_scan, |
6686 | .policy = nl80211_policy, | 7126 | .policy = nl80211_policy, |
6687 | .flags = GENL_ADMIN_PERM, | 7127 | .flags = GENL_ADMIN_PERM, |
6688 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7128 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6689 | NL80211_FLAG_NEED_RTNL, | 7129 | NL80211_FLAG_NEED_RTNL, |
6690 | }, | 7130 | }, |
6691 | { | 7131 | { |
@@ -6826,7 +7266,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6826 | .doit = nl80211_remain_on_channel, | 7266 | .doit = nl80211_remain_on_channel, |
6827 | .policy = nl80211_policy, | 7267 | .policy = nl80211_policy, |
6828 | .flags = GENL_ADMIN_PERM, | 7268 | .flags = GENL_ADMIN_PERM, |
6829 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7269 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6830 | NL80211_FLAG_NEED_RTNL, | 7270 | NL80211_FLAG_NEED_RTNL, |
6831 | }, | 7271 | }, |
6832 | { | 7272 | { |
@@ -6834,7 +7274,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6834 | .doit = nl80211_cancel_remain_on_channel, | 7274 | .doit = nl80211_cancel_remain_on_channel, |
6835 | .policy = nl80211_policy, | 7275 | .policy = nl80211_policy, |
6836 | .flags = GENL_ADMIN_PERM, | 7276 | .flags = GENL_ADMIN_PERM, |
6837 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7277 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6838 | NL80211_FLAG_NEED_RTNL, | 7278 | NL80211_FLAG_NEED_RTNL, |
6839 | }, | 7279 | }, |
6840 | { | 7280 | { |
@@ -6850,7 +7290,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6850 | .doit = nl80211_register_mgmt, | 7290 | .doit = nl80211_register_mgmt, |
6851 | .policy = nl80211_policy, | 7291 | .policy = nl80211_policy, |
6852 | .flags = GENL_ADMIN_PERM, | 7292 | .flags = GENL_ADMIN_PERM, |
6853 | .internal_flags = NL80211_FLAG_NEED_NETDEV | | 7293 | .internal_flags = NL80211_FLAG_NEED_WDEV | |
6854 | NL80211_FLAG_NEED_RTNL, | 7294 | NL80211_FLAG_NEED_RTNL, |
6855 | }, | 7295 | }, |
6856 | { | 7296 | { |
@@ -6858,7 +7298,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6858 | .doit = nl80211_tx_mgmt, | 7298 | .doit = nl80211_tx_mgmt, |
6859 | .policy = nl80211_policy, | 7299 | .policy = nl80211_policy, |
6860 | .flags = GENL_ADMIN_PERM, | 7300 | .flags = GENL_ADMIN_PERM, |
6861 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7301 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6862 | NL80211_FLAG_NEED_RTNL, | 7302 | NL80211_FLAG_NEED_RTNL, |
6863 | }, | 7303 | }, |
6864 | { | 7304 | { |
@@ -6866,7 +7306,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6866 | .doit = nl80211_tx_mgmt_cancel_wait, | 7306 | .doit = nl80211_tx_mgmt_cancel_wait, |
6867 | .policy = nl80211_policy, | 7307 | .policy = nl80211_policy, |
6868 | .flags = GENL_ADMIN_PERM, | 7308 | .flags = GENL_ADMIN_PERM, |
6869 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7309 | .internal_flags = NL80211_FLAG_NEED_WDEV_UP | |
6870 | NL80211_FLAG_NEED_RTNL, | 7310 | NL80211_FLAG_NEED_RTNL, |
6871 | }, | 7311 | }, |
6872 | { | 7312 | { |
@@ -6925,6 +7365,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6925 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | | 7365 | .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | |
6926 | NL80211_FLAG_NEED_RTNL, | 7366 | NL80211_FLAG_NEED_RTNL, |
6927 | }, | 7367 | }, |
7368 | #ifdef CONFIG_PM | ||
6928 | { | 7369 | { |
6929 | .cmd = NL80211_CMD_GET_WOWLAN, | 7370 | .cmd = NL80211_CMD_GET_WOWLAN, |
6930 | .doit = nl80211_get_wowlan, | 7371 | .doit = nl80211_get_wowlan, |
@@ -6941,6 +7382,7 @@ static struct genl_ops nl80211_ops[] = { | |||
6941 | .internal_flags = NL80211_FLAG_NEED_WIPHY | | 7382 | .internal_flags = NL80211_FLAG_NEED_WIPHY | |
6942 | NL80211_FLAG_NEED_RTNL, | 7383 | NL80211_FLAG_NEED_RTNL, |
6943 | }, | 7384 | }, |
7385 | #endif | ||
6944 | { | 7386 | { |
6945 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, | 7387 | .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, |
6946 | .doit = nl80211_set_rekey_data, | 7388 | .doit = nl80211_set_rekey_data, |
@@ -7075,7 +7517,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg, | |||
7075 | 7517 | ||
7076 | static int nl80211_send_scan_msg(struct sk_buff *msg, | 7518 | static int nl80211_send_scan_msg(struct sk_buff *msg, |
7077 | struct cfg80211_registered_device *rdev, | 7519 | struct cfg80211_registered_device *rdev, |
7078 | struct net_device *netdev, | 7520 | struct wireless_dev *wdev, |
7079 | u32 pid, u32 seq, int flags, | 7521 | u32 pid, u32 seq, int flags, |
7080 | u32 cmd) | 7522 | u32 cmd) |
7081 | { | 7523 | { |
@@ -7086,7 +7528,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg, | |||
7086 | return -1; | 7528 | return -1; |
7087 | 7529 | ||
7088 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 7530 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7089 | 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))) | ||
7090 | goto nla_put_failure; | 7534 | goto nla_put_failure; |
7091 | 7535 | ||
7092 | /* ignore errors and send incomplete event anyway */ | 7536 | /* ignore errors and send incomplete event anyway */ |
@@ -7123,15 +7567,15 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg, | |||
7123 | } | 7567 | } |
7124 | 7568 | ||
7125 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | 7569 | void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, |
7126 | struct net_device *netdev) | 7570 | struct wireless_dev *wdev) |
7127 | { | 7571 | { |
7128 | struct sk_buff *msg; | 7572 | struct sk_buff *msg; |
7129 | 7573 | ||
7130 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 7574 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7131 | if (!msg) | 7575 | if (!msg) |
7132 | return; | 7576 | return; |
7133 | 7577 | ||
7134 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7578 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7135 | NL80211_CMD_TRIGGER_SCAN) < 0) { | 7579 | NL80211_CMD_TRIGGER_SCAN) < 0) { |
7136 | nlmsg_free(msg); | 7580 | nlmsg_free(msg); |
7137 | return; | 7581 | return; |
@@ -7142,7 +7586,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, | |||
7142 | } | 7586 | } |
7143 | 7587 | ||
7144 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 7588 | void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
7145 | struct net_device *netdev) | 7589 | struct wireless_dev *wdev) |
7146 | { | 7590 | { |
7147 | struct sk_buff *msg; | 7591 | struct sk_buff *msg; |
7148 | 7592 | ||
@@ -7150,7 +7594,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
7150 | if (!msg) | 7594 | if (!msg) |
7151 | return; | 7595 | return; |
7152 | 7596 | ||
7153 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7597 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7154 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { | 7598 | NL80211_CMD_NEW_SCAN_RESULTS) < 0) { |
7155 | nlmsg_free(msg); | 7599 | nlmsg_free(msg); |
7156 | return; | 7600 | return; |
@@ -7161,7 +7605,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
7161 | } | 7605 | } |
7162 | 7606 | ||
7163 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 7607 | void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
7164 | struct net_device *netdev) | 7608 | struct wireless_dev *wdev) |
7165 | { | 7609 | { |
7166 | struct sk_buff *msg; | 7610 | struct sk_buff *msg; |
7167 | 7611 | ||
@@ -7169,7 +7613,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
7169 | if (!msg) | 7613 | if (!msg) |
7170 | return; | 7614 | return; |
7171 | 7615 | ||
7172 | if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, | 7616 | if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, |
7173 | NL80211_CMD_SCAN_ABORTED) < 0) { | 7617 | NL80211_CMD_SCAN_ABORTED) < 0) { |
7174 | nlmsg_free(msg); | 7618 | nlmsg_free(msg); |
7175 | return; | 7619 | return; |
@@ -7203,7 +7647,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, | |||
7203 | { | 7647 | { |
7204 | struct sk_buff *msg; | 7648 | struct sk_buff *msg; |
7205 | 7649 | ||
7206 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 7650 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7207 | if (!msg) | 7651 | if (!msg) |
7208 | return; | 7652 | return; |
7209 | 7653 | ||
@@ -7419,7 +7863,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, | |||
7419 | struct sk_buff *msg; | 7863 | struct sk_buff *msg; |
7420 | void *hdr; | 7864 | void *hdr; |
7421 | 7865 | ||
7422 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 7866 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7423 | if (!msg) | 7867 | if (!msg) |
7424 | return; | 7868 | return; |
7425 | 7869 | ||
@@ -7459,7 +7903,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | |||
7459 | struct sk_buff *msg; | 7903 | struct sk_buff *msg; |
7460 | void *hdr; | 7904 | void *hdr; |
7461 | 7905 | ||
7462 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 7906 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7463 | if (!msg) | 7907 | if (!msg) |
7464 | return; | 7908 | return; |
7465 | 7909 | ||
@@ -7497,7 +7941,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | |||
7497 | struct sk_buff *msg; | 7941 | struct sk_buff *msg; |
7498 | void *hdr; | 7942 | void *hdr; |
7499 | 7943 | ||
7500 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 7944 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
7501 | if (!msg) | 7945 | if (!msg) |
7502 | return; | 7946 | return; |
7503 | 7947 | ||
@@ -7692,7 +8136,7 @@ nla_put_failure: | |||
7692 | 8136 | ||
7693 | static void nl80211_send_remain_on_chan_event( | 8137 | static void nl80211_send_remain_on_chan_event( |
7694 | int cmd, struct cfg80211_registered_device *rdev, | 8138 | int cmd, struct cfg80211_registered_device *rdev, |
7695 | struct net_device *netdev, u64 cookie, | 8139 | struct wireless_dev *wdev, u64 cookie, |
7696 | struct ieee80211_channel *chan, | 8140 | struct ieee80211_channel *chan, |
7697 | enum nl80211_channel_type channel_type, | 8141 | enum nl80211_channel_type channel_type, |
7698 | unsigned int duration, gfp_t gfp) | 8142 | unsigned int duration, gfp_t gfp) |
@@ -7711,7 +8155,9 @@ static void nl80211_send_remain_on_chan_event( | |||
7711 | } | 8155 | } |
7712 | 8156 | ||
7713 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8157 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7714 | 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)) || | ||
7715 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || | 8161 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || |
7716 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || | 8162 | nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || |
7717 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) | 8163 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) |
@@ -7733,23 +8179,24 @@ static void nl80211_send_remain_on_chan_event( | |||
7733 | } | 8179 | } |
7734 | 8180 | ||
7735 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | 8181 | void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, |
7736 | struct net_device *netdev, u64 cookie, | 8182 | struct wireless_dev *wdev, u64 cookie, |
7737 | struct ieee80211_channel *chan, | 8183 | struct ieee80211_channel *chan, |
7738 | enum nl80211_channel_type channel_type, | 8184 | enum nl80211_channel_type channel_type, |
7739 | unsigned int duration, gfp_t gfp) | 8185 | unsigned int duration, gfp_t gfp) |
7740 | { | 8186 | { |
7741 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | 8187 | nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, |
7742 | rdev, netdev, cookie, chan, | 8188 | rdev, wdev, cookie, chan, |
7743 | channel_type, duration, gfp); | 8189 | channel_type, duration, gfp); |
7744 | } | 8190 | } |
7745 | 8191 | ||
7746 | void nl80211_send_remain_on_channel_cancel( | 8192 | void nl80211_send_remain_on_channel_cancel( |
7747 | struct cfg80211_registered_device *rdev, struct net_device *netdev, | 8193 | struct cfg80211_registered_device *rdev, |
8194 | struct wireless_dev *wdev, | ||
7748 | u64 cookie, struct ieee80211_channel *chan, | 8195 | u64 cookie, struct ieee80211_channel *chan, |
7749 | enum nl80211_channel_type channel_type, gfp_t gfp) | 8196 | enum nl80211_channel_type channel_type, gfp_t gfp) |
7750 | { | 8197 | { |
7751 | 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, |
7752 | rdev, netdev, cookie, chan, | 8199 | rdev, wdev, cookie, chan, |
7753 | channel_type, 0, gfp); | 8200 | channel_type, 0, gfp); |
7754 | } | 8201 | } |
7755 | 8202 | ||
@@ -7759,7 +8206,7 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
7759 | { | 8206 | { |
7760 | struct sk_buff *msg; | 8207 | struct sk_buff *msg; |
7761 | 8208 | ||
7762 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8209 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7763 | if (!msg) | 8210 | if (!msg) |
7764 | return; | 8211 | return; |
7765 | 8212 | ||
@@ -7780,7 +8227,7 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, | |||
7780 | struct sk_buff *msg; | 8227 | struct sk_buff *msg; |
7781 | void *hdr; | 8228 | void *hdr; |
7782 | 8229 | ||
7783 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8230 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7784 | if (!msg) | 8231 | if (!msg) |
7785 | return; | 8232 | return; |
7786 | 8233 | ||
@@ -7863,10 +8310,11 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev, | |||
7863 | } | 8310 | } |
7864 | 8311 | ||
7865 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | 8312 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
7866 | struct net_device *netdev, u32 nlpid, | 8313 | struct wireless_dev *wdev, u32 nlpid, |
7867 | int freq, int sig_dbm, | 8314 | int freq, int sig_dbm, |
7868 | const u8 *buf, size_t len, gfp_t gfp) | 8315 | const u8 *buf, size_t len, gfp_t gfp) |
7869 | { | 8316 | { |
8317 | struct net_device *netdev = wdev->netdev; | ||
7870 | struct sk_buff *msg; | 8318 | struct sk_buff *msg; |
7871 | void *hdr; | 8319 | void *hdr; |
7872 | 8320 | ||
@@ -7881,7 +8329,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
7881 | } | 8329 | } |
7882 | 8330 | ||
7883 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8331 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7884 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8332 | (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8333 | netdev->ifindex)) || | ||
7885 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || | 8334 | nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || |
7886 | (sig_dbm && | 8335 | (sig_dbm && |
7887 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || | 8336 | nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || |
@@ -7899,10 +8348,11 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, | |||
7899 | } | 8348 | } |
7900 | 8349 | ||
7901 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | 8350 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
7902 | struct net_device *netdev, u64 cookie, | 8351 | struct wireless_dev *wdev, u64 cookie, |
7903 | const u8 *buf, size_t len, bool ack, | 8352 | const u8 *buf, size_t len, bool ack, |
7904 | gfp_t gfp) | 8353 | gfp_t gfp) |
7905 | { | 8354 | { |
8355 | struct net_device *netdev = wdev->netdev; | ||
7906 | struct sk_buff *msg; | 8356 | struct sk_buff *msg; |
7907 | void *hdr; | 8357 | void *hdr; |
7908 | 8358 | ||
@@ -7917,7 +8367,8 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, | |||
7917 | } | 8367 | } |
7918 | 8368 | ||
7919 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || | 8369 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || |
7920 | nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || | 8370 | (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, |
8371 | netdev->ifindex)) || | ||
7921 | nla_put(msg, NL80211_ATTR_FRAME, len, buf) || | 8372 | nla_put(msg, NL80211_ATTR_FRAME, len, buf) || |
7922 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || | 8373 | nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || |
7923 | (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) | 8374 | (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) |
@@ -7943,7 +8394,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | |||
7943 | struct nlattr *pinfoattr; | 8394 | struct nlattr *pinfoattr; |
7944 | void *hdr; | 8395 | void *hdr; |
7945 | 8396 | ||
7946 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8397 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7947 | if (!msg) | 8398 | if (!msg) |
7948 | return; | 8399 | return; |
7949 | 8400 | ||
@@ -7986,7 +8437,7 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, | |||
7986 | struct nlattr *rekey_attr; | 8437 | struct nlattr *rekey_attr; |
7987 | void *hdr; | 8438 | void *hdr; |
7988 | 8439 | ||
7989 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8440 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
7990 | if (!msg) | 8441 | if (!msg) |
7991 | return; | 8442 | return; |
7992 | 8443 | ||
@@ -8030,7 +8481,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev, | |||
8030 | struct nlattr *attr; | 8481 | struct nlattr *attr; |
8031 | void *hdr; | 8482 | void *hdr; |
8032 | 8483 | ||
8033 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8484 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8034 | if (!msg) | 8485 | if (!msg) |
8035 | return; | 8486 | return; |
8036 | 8487 | ||
@@ -8074,7 +8525,7 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
8074 | struct sk_buff *msg; | 8525 | struct sk_buff *msg; |
8075 | void *hdr; | 8526 | void *hdr; |
8076 | 8527 | ||
8077 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8528 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8078 | if (!msg) | 8529 | if (!msg) |
8079 | return; | 8530 | return; |
8080 | 8531 | ||
@@ -8101,6 +8552,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, | |||
8101 | } | 8552 | } |
8102 | 8553 | ||
8103 | 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 | ||
8104 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | 8605 | nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, |
8105 | struct net_device *netdev, const u8 *peer, | 8606 | struct net_device *netdev, const u8 *peer, |
8106 | u32 num_packets, gfp_t gfp) | 8607 | u32 num_packets, gfp_t gfp) |
@@ -8109,7 +8610,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, | |||
8109 | struct nlattr *pinfoattr; | 8610 | struct nlattr *pinfoattr; |
8110 | void *hdr; | 8611 | void *hdr; |
8111 | 8612 | ||
8112 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8613 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8113 | if (!msg) | 8614 | if (!msg) |
8114 | return; | 8615 | return; |
8115 | 8616 | ||
@@ -8153,7 +8654,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr, | |||
8153 | void *hdr; | 8654 | void *hdr; |
8154 | int err; | 8655 | int err; |
8155 | 8656 | ||
8156 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | 8657 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); |
8157 | if (!msg) | 8658 | if (!msg) |
8158 | return; | 8659 | return; |
8159 | 8660 | ||
@@ -8241,7 +8742,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
8241 | rcu_read_lock(); | 8742 | rcu_read_lock(); |
8242 | 8743 | ||
8243 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { | 8744 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { |
8244 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 8745 | list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) |
8245 | cfg80211_mlme_unregister_socket(wdev, notify->pid); | 8746 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
8246 | if (rdev->ap_beacons_nlpid == notify->pid) | 8747 | if (rdev->ap_beacons_nlpid == notify->pid) |
8247 | rdev->ap_beacons_nlpid = 0; | 8748 | rdev->ap_beacons_nlpid = 0; |