aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h25
-rw-r--r--include/net/cfg80211.h57
-rw-r--r--net/wireless/core.c12
-rw-r--r--net/wireless/core.h7
-rw-r--r--net/wireless/nl80211.c250
-rw-r--r--net/wireless/nl80211.h4
-rw-r--r--net/wireless/scan.c70
7 files changed, 424 insertions, 1 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index de96783954a..f8b5595ba4a 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -203,6 +203,26 @@
203 * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons, 203 * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
204 * partial scan results may be available 204 * partial scan results may be available
205 * 205 *
206 * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan. Like with normal
207 * scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS) are passed, they are used
208 * in the probe requests. For broadcast, a broadcast SSID must be
209 * passed (ie. an empty string). If no SSID is passed, no probe
210 * requests are sent and a passive scan is performed.
211 * %NL80211_ATTR_SCAN_FREQUENCIES, if passed, define which channels
212 * should be scanned; if not passed, all channels allowed for the
213 * current regulatory domain are used. Extra IEs can also be passed
214 * from the userspace by using the %NL80211_ATTR_IE attribute.
215 * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan
216 * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
217 * results available.
218 * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
219 * stopped. The driver may issue this event at any time during a
220 * scheduled scan. One reason for stopping the scan is if the hardware
221 * does not support starting an association or a normal scan while running
222 * a scheduled scan. This event is also sent when the
223 * %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface
224 * is brought down while a scheduled scan was running.
225 *
206 * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation 226 * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
207 * or noise level 227 * or noise level
208 * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to 228 * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
@@ -545,6 +565,11 @@ enum nl80211_commands {
545 NL80211_CMD_GET_WOWLAN, 565 NL80211_CMD_GET_WOWLAN,
546 NL80211_CMD_SET_WOWLAN, 566 NL80211_CMD_SET_WOWLAN,
547 567
568 NL80211_CMD_START_SCHED_SCAN,
569 NL80211_CMD_STOP_SCHED_SCAN,
570 NL80211_CMD_SCHED_SCAN_RESULTS,
571 NL80211_CMD_SCHED_SCAN_STOPPED,
572
548 /* add new commands above here */ 573 /* add new commands above here */
549 574
550 /* used to define NL80211_CMD_MAX below */ 575 /* used to define NL80211_CMD_MAX below */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4b0d035be64..e214c85b74d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -824,6 +824,33 @@ struct cfg80211_scan_request {
824}; 824};
825 825
826/** 826/**
827 * struct cfg80211_sched_scan_request - scheduled scan request description
828 *
829 * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans)
830 * @n_ssids: number of SSIDs
831 * @n_channels: total number of channels to scan
832 * @ie: optional information element(s) to add into Probe Request or %NULL
833 * @ie_len: length of ie in octets
834 * @wiphy: the wiphy this was for
835 * @dev: the interface
836 * @channels: channels to scan
837 */
838struct cfg80211_sched_scan_request {
839 struct cfg80211_ssid *ssids;
840 int n_ssids;
841 u32 n_channels;
842 const u8 *ie;
843 size_t ie_len;
844
845 /* internal */
846 struct wiphy *wiphy;
847 struct net_device *dev;
848
849 /* keep last */
850 struct ieee80211_channel *channels[0];
851};
852
853/**
827 * enum cfg80211_signal_type - signal type 854 * enum cfg80211_signal_type - signal type
828 * 855 *
829 * @CFG80211_SIGNAL_TYPE_NONE: no signal strength information available 856 * @CFG80211_SIGNAL_TYPE_NONE: no signal strength information available
@@ -1292,6 +1319,10 @@ struct cfg80211_wowlan {
1292 * @set_power_mgmt: Configure WLAN power management. A timeout value of -1 1319 * @set_power_mgmt: Configure WLAN power management. A timeout value of -1
1293 * allows the driver to adjust the dynamic ps timeout value. 1320 * allows the driver to adjust the dynamic ps timeout value.
1294 * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold. 1321 * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold.
1322 * @sched_scan_start: Tell the driver to start a scheduled scan.
1323 * @sched_scan_stop: Tell the driver to stop an ongoing scheduled
1324 * scan. The driver_initiated flag specifies whether the driver
1325 * itself has informed that the scan has stopped.
1295 * 1326 *
1296 * @mgmt_frame_register: Notify driver that a management frame type was 1327 * @mgmt_frame_register: Notify driver that a management frame type was
1297 * registered. Note that this callback may not sleep, and cannot run 1328 * registered. Note that this callback may not sleep, and cannot run
@@ -1478,6 +1509,12 @@ struct cfg80211_ops {
1478 int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx); 1509 int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx);
1479 void (*get_ringparam)(struct wiphy *wiphy, 1510 void (*get_ringparam)(struct wiphy *wiphy,
1480 u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); 1511 u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
1512
1513 int (*sched_scan_start)(struct wiphy *wiphy,
1514 struct net_device *dev,
1515 struct cfg80211_sched_scan_request *request);
1516 int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev,
1517 bool driver_initiated);
1481}; 1518};
1482 1519
1483/* 1520/*
@@ -1522,6 +1559,7 @@ struct cfg80211_ops {
1522 * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN. 1559 * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
1523 * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing 1560 * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing
1524 * auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH. 1561 * auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH.
1562 * @WIPHY_FLAG_SCHED_SCAN: The device supports scheduled scans.
1525 */ 1563 */
1526enum wiphy_flags { 1564enum wiphy_flags {
1527 WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0), 1565 WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -1534,6 +1572,7 @@ enum wiphy_flags {
1534 WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7), 1572 WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7),
1535 WIPHY_FLAG_IBSS_RSN = BIT(8), 1573 WIPHY_FLAG_IBSS_RSN = BIT(8),
1536 WIPHY_FLAG_MESH_AUTH = BIT(10), 1574 WIPHY_FLAG_MESH_AUTH = BIT(10),
1575 WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11),
1537}; 1576};
1538 1577
1539struct mac_address { 1578struct mac_address {
@@ -2355,6 +2394,24 @@ int cfg80211_wext_siwpmksa(struct net_device *dev,
2355void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted); 2394void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
2356 2395
2357/** 2396/**
2397 * cfg80211_sched_scan_results - notify that new scan results are available
2398 *
2399 * @wiphy: the wiphy which got scheduled scan results
2400 */
2401void cfg80211_sched_scan_results(struct wiphy *wiphy);
2402
2403/**
2404 * cfg80211_sched_scan_stopped - notify that the scheduled scan has stopped
2405 *
2406 * @wiphy: the wiphy on which the scheduled scan stopped
2407 *
2408 * The driver can call this function to inform cfg80211 that the
2409 * scheduled scan had to be stopped, for whatever reason. The driver
2410 * is then called back via the sched_scan_stop operation when done.
2411 */
2412void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
2413
2414/**
2358 * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame 2415 * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame
2359 * 2416 *
2360 * @wiphy: the wiphy reporting the BSS 2417 * @wiphy: the wiphy reporting the BSS
diff --git a/net/wireless/core.c b/net/wireless/core.c
index bea0d80710c..f924a49b242 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -370,7 +370,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
370 spin_lock_init(&rdev->bss_lock); 370 spin_lock_init(&rdev->bss_lock);
371 INIT_LIST_HEAD(&rdev->bss_list); 371 INIT_LIST_HEAD(&rdev->bss_list);
372 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); 372 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
373 373 INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);
374 INIT_WORK(&rdev->sched_scan_stopped_wk, __cfg80211_sched_scan_stopped);
374#ifdef CONFIG_CFG80211_WEXT 375#ifdef CONFIG_CFG80211_WEXT
375 rdev->wiphy.wext = &cfg80211_wext_handler; 376 rdev->wiphy.wext = &cfg80211_wext_handler;
376#endif 377#endif
@@ -672,6 +673,11 @@ static void wdev_cleanup_work(struct work_struct *work)
672 ___cfg80211_scan_done(rdev, true); 673 ___cfg80211_scan_done(rdev, true);
673 } 674 }
674 675
676 if (WARN_ON(rdev->sched_scan_req &&
677 rdev->sched_scan_req->dev == wdev->netdev)) {
678 __cfg80211_stop_sched_scan(rdev, false);
679 }
680
675 cfg80211_unlock_rdev(rdev); 681 cfg80211_unlock_rdev(rdev);
676 682
677 mutex_lock(&rdev->devlist_mtx); 683 mutex_lock(&rdev->devlist_mtx);
@@ -759,6 +765,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
759 break; 765 break;
760 case NL80211_IFTYPE_P2P_CLIENT: 766 case NL80211_IFTYPE_P2P_CLIENT:
761 case NL80211_IFTYPE_STATION: 767 case NL80211_IFTYPE_STATION:
768 cfg80211_lock_rdev(rdev);
769 __cfg80211_stop_sched_scan(rdev, false);
770 cfg80211_unlock_rdev(rdev);
771
762 wdev_lock(wdev); 772 wdev_lock(wdev);
763#ifdef CONFIG_CFG80211_WEXT 773#ifdef CONFIG_CFG80211_WEXT
764 kfree(wdev->wext.ie); 774 kfree(wdev->wext.ie);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 7a18c10a7fb..e3f7b1d995c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -60,8 +60,11 @@ struct cfg80211_registered_device {
60 struct rb_root bss_tree; 60 struct rb_root bss_tree;
61 u32 bss_generation; 61 u32 bss_generation;
62 struct cfg80211_scan_request *scan_req; /* protected by RTNL */ 62 struct cfg80211_scan_request *scan_req; /* protected by RTNL */
63 struct cfg80211_sched_scan_request *sched_scan_req;
63 unsigned long suspend_at; 64 unsigned long suspend_at;
64 struct work_struct scan_done_wk; 65 struct work_struct scan_done_wk;
66 struct work_struct sched_scan_results_wk;
67 struct work_struct sched_scan_stopped_wk;
65 68
66#ifdef CONFIG_NL80211_TESTMODE 69#ifdef CONFIG_NL80211_TESTMODE
67 struct genl_info *testmode_info; 70 struct genl_info *testmode_info;
@@ -411,6 +414,10 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
411void cfg80211_sme_disassoc(struct net_device *dev, int idx); 414void cfg80211_sme_disassoc(struct net_device *dev, int idx);
412void __cfg80211_scan_done(struct work_struct *wk); 415void __cfg80211_scan_done(struct work_struct *wk);
413void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak); 416void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
417void __cfg80211_sched_scan_results(struct work_struct *wk);
418int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
419 bool driver_initiated);
420void __cfg80211_sched_scan_stopped(struct work_struct *wk);
414void cfg80211_upload_connect_keys(struct wireless_dev *wdev); 421void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
415int cfg80211_change_iface(struct cfg80211_registered_device *rdev, 422int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
416 struct net_device *dev, enum nl80211_iftype ntype, 423 struct net_device *dev, enum nl80211_iftype ntype,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 95dd5832e71..4fac370284c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -761,6 +761,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
761 } 761 }
762 CMD(set_channel, SET_CHANNEL); 762 CMD(set_channel, SET_CHANNEL);
763 CMD(set_wds_peer, SET_WDS_PEER); 763 CMD(set_wds_peer, SET_WDS_PEER);
764 if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
765 CMD(sched_scan_start, START_SCHED_SCAN);
764 766
765#undef CMD 767#undef CMD
766 768
@@ -3357,6 +3359,179 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
3357 return err; 3359 return err;
3358} 3360}
3359 3361
3362static int nl80211_start_sched_scan(struct sk_buff *skb,
3363 struct genl_info *info)
3364{
3365 struct cfg80211_sched_scan_request *request;
3366 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3367 struct net_device *dev = info->user_ptr[1];
3368 struct cfg80211_ssid *ssid;
3369 struct ieee80211_channel *channel;
3370 struct nlattr *attr;
3371 struct wiphy *wiphy;
3372 int err, tmp, n_ssids = 0, n_channels, i;
3373 enum ieee80211_band band;
3374 size_t ie_len;
3375
3376 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
3377 !rdev->ops->sched_scan_start)
3378 return -EOPNOTSUPP;
3379
3380 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3381 return -EINVAL;
3382
3383 if (rdev->sched_scan_req)
3384 return -EINPROGRESS;
3385
3386 wiphy = &rdev->wiphy;
3387
3388 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
3389 n_channels = validate_scan_freqs(
3390 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
3391 if (!n_channels)
3392 return -EINVAL;
3393 } else {
3394 n_channels = 0;
3395
3396 for (band = 0; band < IEEE80211_NUM_BANDS; band++)
3397 if (wiphy->bands[band])
3398 n_channels += wiphy->bands[band]->n_channels;
3399 }
3400
3401 if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
3402 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
3403 tmp)
3404 n_ssids++;
3405
3406 if (n_ssids > wiphy->max_scan_ssids)
3407 return -EINVAL;
3408
3409 if (info->attrs[NL80211_ATTR_IE])
3410 ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3411 else
3412 ie_len = 0;
3413
3414 if (ie_len > wiphy->max_scan_ie_len)
3415 return -EINVAL;
3416
3417 request = kzalloc(sizeof(*request)
3418 + sizeof(*ssid) * n_ssids
3419 + sizeof(channel) * n_channels
3420 + ie_len, GFP_KERNEL);
3421 if (!request)
3422 return -ENOMEM;
3423
3424 if (n_ssids)
3425 request->ssids = (void *)&request->channels[n_channels];
3426 request->n_ssids = n_ssids;
3427 if (ie_len) {
3428 if (request->ssids)
3429 request->ie = (void *)(request->ssids + n_ssids);
3430 else
3431 request->ie = (void *)(request->channels + n_channels);
3432 }
3433
3434 i = 0;
3435 if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
3436 /* user specified, bail out if channel not found */
3437 nla_for_each_nested(attr,
3438 info->attrs[NL80211_ATTR_SCAN_FREQUENCIES],
3439 tmp) {
3440 struct ieee80211_channel *chan;
3441
3442 chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
3443
3444 if (!chan) {
3445 err = -EINVAL;
3446 goto out_free;
3447 }
3448
3449 /* ignore disabled channels */
3450 if (chan->flags & IEEE80211_CHAN_DISABLED)
3451 continue;
3452
3453 request->channels[i] = chan;
3454 i++;
3455 }
3456 } else {
3457 /* all channels */
3458 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
3459 int j;
3460 if (!wiphy->bands[band])
3461 continue;
3462 for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
3463 struct ieee80211_channel *chan;
3464
3465 chan = &wiphy->bands[band]->channels[j];
3466
3467 if (chan->flags & IEEE80211_CHAN_DISABLED)
3468 continue;
3469
3470 request->channels[i] = chan;
3471 i++;
3472 }
3473 }
3474 }
3475
3476 if (!i) {
3477 err = -EINVAL;
3478 goto out_free;
3479 }
3480
3481 request->n_channels = i;
3482
3483 i = 0;
3484 if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
3485 nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
3486 tmp) {
3487 if (request->ssids[i].ssid_len >
3488 IEEE80211_MAX_SSID_LEN) {
3489 err = -EINVAL;
3490 goto out_free;
3491 }
3492 memcpy(request->ssids[i].ssid, nla_data(attr),
3493 nla_len(attr));
3494 request->ssids[i].ssid_len = nla_len(attr);
3495 i++;
3496 }
3497 }
3498
3499 if (info->attrs[NL80211_ATTR_IE]) {
3500 request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
3501 memcpy((void *)request->ie,
3502 nla_data(info->attrs[NL80211_ATTR_IE]),
3503 request->ie_len);
3504 }
3505
3506 request->dev = dev;
3507 request->wiphy = &rdev->wiphy;
3508
3509 err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request);
3510 if (!err) {
3511 rdev->sched_scan_req = request;
3512 nl80211_send_sched_scan(rdev, dev,
3513 NL80211_CMD_START_SCHED_SCAN);
3514 goto out;
3515 }
3516
3517out_free:
3518 kfree(request);
3519out:
3520 return err;
3521}
3522
3523static int nl80211_stop_sched_scan(struct sk_buff *skb,
3524 struct genl_info *info)
3525{
3526 struct cfg80211_registered_device *rdev = info->user_ptr[0];
3527
3528 if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
3529 !rdev->ops->sched_scan_stop)
3530 return -EOPNOTSUPP;
3531
3532 return __cfg80211_stop_sched_scan(rdev, false);
3533}
3534
3360static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, 3535static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
3361 struct cfg80211_registered_device *rdev, 3536 struct cfg80211_registered_device *rdev,
3362 struct wireless_dev *wdev, 3537 struct wireless_dev *wdev,
@@ -5327,6 +5502,22 @@ static struct genl_ops nl80211_ops[] = {
5327 .dumpit = nl80211_dump_scan, 5502 .dumpit = nl80211_dump_scan,
5328 }, 5503 },
5329 { 5504 {
5505 .cmd = NL80211_CMD_START_SCHED_SCAN,
5506 .doit = nl80211_start_sched_scan,
5507 .policy = nl80211_policy,
5508 .flags = GENL_ADMIN_PERM,
5509 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
5510 NL80211_FLAG_NEED_RTNL,
5511 },
5512 {
5513 .cmd = NL80211_CMD_STOP_SCHED_SCAN,
5514 .doit = nl80211_stop_sched_scan,
5515 .policy = nl80211_policy,
5516 .flags = GENL_ADMIN_PERM,
5517 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
5518 NL80211_FLAG_NEED_RTNL,
5519 },
5520 {
5330 .cmd = NL80211_CMD_AUTHENTICATE, 5521 .cmd = NL80211_CMD_AUTHENTICATE,
5331 .doit = nl80211_authenticate, 5522 .doit = nl80211_authenticate,
5332 .policy = nl80211_policy, 5523 .policy = nl80211_policy,
@@ -5652,6 +5843,28 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
5652 return -EMSGSIZE; 5843 return -EMSGSIZE;
5653} 5844}
5654 5845
5846static int
5847nl80211_send_sched_scan_msg(struct sk_buff *msg,
5848 struct cfg80211_registered_device *rdev,
5849 struct net_device *netdev,
5850 u32 pid, u32 seq, int flags, u32 cmd)
5851{
5852 void *hdr;
5853
5854 hdr = nl80211hdr_put(msg, pid, seq, flags, cmd);
5855 if (!hdr)
5856 return -1;
5857
5858 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5859 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5860
5861 return genlmsg_end(msg, hdr);
5862
5863 nla_put_failure:
5864 genlmsg_cancel(msg, hdr);
5865 return -EMSGSIZE;
5866}
5867
5655void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, 5868void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
5656 struct net_device *netdev) 5869 struct net_device *netdev)
5657{ 5870{
@@ -5709,6 +5922,43 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
5709 nl80211_scan_mcgrp.id, GFP_KERNEL); 5922 nl80211_scan_mcgrp.id, GFP_KERNEL);
5710} 5923}
5711 5924
5925void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
5926 struct net_device *netdev)
5927{
5928 struct sk_buff *msg;
5929
5930 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
5931 if (!msg)
5932 return;
5933
5934 if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0,
5935 NL80211_CMD_SCHED_SCAN_RESULTS) < 0) {
5936 nlmsg_free(msg);
5937 return;
5938 }
5939
5940 genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
5941 nl80211_scan_mcgrp.id, GFP_KERNEL);
5942}
5943
5944void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
5945 struct net_device *netdev, u32 cmd)
5946{
5947 struct sk_buff *msg;
5948
5949 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
5950 if (!msg)
5951 return;
5952
5953 if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
5954 nlmsg_free(msg);
5955 return;
5956 }
5957
5958 genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
5959 nl80211_scan_mcgrp.id, GFP_KERNEL);
5960}
5961
5712/* 5962/*
5713 * This can happen on global regulatory changes or device specific settings 5963 * This can happen on global regulatory changes or device specific settings
5714 * based on custom world regulatory domains. 5964 * based on custom world regulatory domains.
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index f2af6955a66..2f1bfb87a65 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -12,6 +12,10 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
12 struct net_device *netdev); 12 struct net_device *netdev);
13void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, 13void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
14 struct net_device *netdev); 14 struct net_device *netdev);
15void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
16 struct net_device *netdev, u32 cmd);
17void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
18 struct net_device *netdev);
15void nl80211_send_reg_change_event(struct regulatory_request *request); 19void nl80211_send_reg_change_event(struct regulatory_request *request);
16void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, 20void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
17 struct net_device *netdev, 21 struct net_device *netdev,
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 62e542a2b19..65dfae3b9d4 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -93,6 +93,76 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
93} 93}
94EXPORT_SYMBOL(cfg80211_scan_done); 94EXPORT_SYMBOL(cfg80211_scan_done);
95 95
96void __cfg80211_sched_scan_results(struct work_struct *wk)
97{
98 struct cfg80211_registered_device *rdev;
99
100 rdev = container_of(wk, struct cfg80211_registered_device,
101 sched_scan_results_wk);
102
103 cfg80211_lock_rdev(rdev);
104
105 /* we don't have sched_scan_req anymore if the scan is stopping */
106 if (rdev->sched_scan_req)
107 nl80211_send_sched_scan_results(rdev,
108 rdev->sched_scan_req->dev);
109
110 cfg80211_unlock_rdev(rdev);
111}
112
113void cfg80211_sched_scan_results(struct wiphy *wiphy)
114{
115 /* ignore if we're not scanning */
116 if (wiphy_to_dev(wiphy)->sched_scan_req)
117 queue_work(cfg80211_wq,
118 &wiphy_to_dev(wiphy)->sched_scan_results_wk);
119}
120EXPORT_SYMBOL(cfg80211_sched_scan_results);
121
122void __cfg80211_sched_scan_stopped(struct work_struct *wk)
123{
124 struct cfg80211_registered_device *rdev;
125
126 rdev = container_of(wk, struct cfg80211_registered_device,
127 sched_scan_stopped_wk);
128
129 cfg80211_lock_rdev(rdev);
130 __cfg80211_stop_sched_scan(rdev, true);
131 cfg80211_unlock_rdev(rdev);
132}
133
134void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
135{
136 queue_work(cfg80211_wq, &wiphy_to_dev(wiphy)->sched_scan_stopped_wk);
137}
138EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
139
140int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
141 bool driver_initiated)
142{
143 int err;
144 struct net_device *dev;
145
146 ASSERT_RDEV_LOCK(rdev);
147
148 if (!rdev->sched_scan_req)
149 return 0;
150
151 dev = rdev->sched_scan_req->dev;
152
153 err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev,
154 driver_initiated);
155 if (err)
156 return err;
157
158 nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
159
160 kfree(rdev->sched_scan_req);
161 rdev->sched_scan_req = NULL;
162
163 return err;
164}
165
96static void bss_release(struct kref *ref) 166static void bss_release(struct kref *ref)
97{ 167{
98 struct cfg80211_internal_bss *bss; 168 struct cfg80211_internal_bss *bss;