diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 734 |
1 files changed, 415 insertions, 319 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 7d5108a867ad..d41974aacf51 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -20,31 +20,31 @@ | |||
20 | #include "rate.h" | 20 | #include "rate.h" |
21 | #include "mesh.h" | 21 | #include "mesh.h" |
22 | 22 | ||
23 | static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, | 23 | static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name, |
24 | enum nl80211_iftype type, | 24 | enum nl80211_iftype type, |
25 | u32 *flags, | 25 | u32 *flags, |
26 | struct vif_params *params) | 26 | struct vif_params *params) |
27 | { | 27 | { |
28 | struct ieee80211_local *local = wiphy_priv(wiphy); | 28 | struct ieee80211_local *local = wiphy_priv(wiphy); |
29 | struct net_device *dev; | 29 | struct wireless_dev *wdev; |
30 | struct ieee80211_sub_if_data *sdata; | 30 | struct ieee80211_sub_if_data *sdata; |
31 | int err; | 31 | int err; |
32 | 32 | ||
33 | err = ieee80211_if_add(local, name, &dev, type, params); | 33 | err = ieee80211_if_add(local, name, &wdev, type, params); |
34 | if (err) | 34 | if (err) |
35 | return ERR_PTR(err); | 35 | return ERR_PTR(err); |
36 | 36 | ||
37 | if (type == NL80211_IFTYPE_MONITOR && flags) { | 37 | if (type == NL80211_IFTYPE_MONITOR && flags) { |
38 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 38 | sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
39 | sdata->u.mntr_flags = *flags; | 39 | sdata->u.mntr_flags = *flags; |
40 | } | 40 | } |
41 | 41 | ||
42 | return dev; | 42 | return wdev; |
43 | } | 43 | } |
44 | 44 | ||
45 | static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) | 45 | static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) |
46 | { | 46 | { |
47 | ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); | 47 | ieee80211_if_remove(IEEE80211_WDEV_TO_SUB_IF(wdev)); |
48 | 48 | ||
49 | return 0; | 49 | return 0; |
50 | } | 50 | } |
@@ -353,6 +353,7 @@ void sta_set_rate_info_tx(struct sta_info *sta, | |||
353 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 353 | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
354 | { | 354 | { |
355 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 355 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
356 | struct ieee80211_local *local = sdata->local; | ||
356 | struct timespec uptime; | 357 | struct timespec uptime; |
357 | 358 | ||
358 | sinfo->generation = sdata->local->sta_generation; | 359 | sinfo->generation = sdata->local->sta_generation; |
@@ -388,7 +389,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
388 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | 389 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || |
389 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | 390 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { |
390 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; | 391 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; |
391 | sinfo->signal = (s8)sta->last_signal; | 392 | if (!local->ops->get_rssi || |
393 | drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) | ||
394 | sinfo->signal = (s8)sta->last_signal; | ||
392 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | 395 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); |
393 | } | 396 | } |
394 | 397 | ||
@@ -517,7 +520,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, | |||
517 | * network device. | 520 | * network device. |
518 | */ | 521 | */ |
519 | 522 | ||
520 | rcu_read_lock(); | 523 | mutex_lock(&local->sta_mtx); |
521 | 524 | ||
522 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 525 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
523 | sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); | 526 | sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); |
@@ -546,7 +549,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, | |||
546 | data[i] = (u8)sinfo.signal_avg; | 549 | data[i] = (u8)sinfo.signal_avg; |
547 | i++; | 550 | i++; |
548 | } else { | 551 | } else { |
549 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | 552 | list_for_each_entry(sta, &local->sta_list, list) { |
550 | /* Make sure this station belongs to the proper dev */ | 553 | /* Make sure this station belongs to the proper dev */ |
551 | if (sta->sdata->dev != dev) | 554 | if (sta->sdata->dev != dev) |
552 | continue; | 555 | continue; |
@@ -603,7 +606,7 @@ do_survey: | |||
603 | else | 606 | else |
604 | data[i++] = -1LL; | 607 | data[i++] = -1LL; |
605 | 608 | ||
606 | rcu_read_unlock(); | 609 | mutex_unlock(&local->sta_mtx); |
607 | 610 | ||
608 | if (WARN_ON(i != STA_STATS_LEN)) | 611 | if (WARN_ON(i != STA_STATS_LEN)) |
609 | return; | 612 | return; |
@@ -629,10 +632,11 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | |||
629 | int idx, u8 *mac, struct station_info *sinfo) | 632 | int idx, u8 *mac, struct station_info *sinfo) |
630 | { | 633 | { |
631 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 634 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
635 | struct ieee80211_local *local = sdata->local; | ||
632 | struct sta_info *sta; | 636 | struct sta_info *sta; |
633 | int ret = -ENOENT; | 637 | int ret = -ENOENT; |
634 | 638 | ||
635 | rcu_read_lock(); | 639 | mutex_lock(&local->sta_mtx); |
636 | 640 | ||
637 | sta = sta_info_get_by_idx(sdata, idx); | 641 | sta = sta_info_get_by_idx(sdata, idx); |
638 | if (sta) { | 642 | if (sta) { |
@@ -641,7 +645,7 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | |||
641 | sta_set_sinfo(sta, sinfo); | 645 | sta_set_sinfo(sta, sinfo); |
642 | } | 646 | } |
643 | 647 | ||
644 | rcu_read_unlock(); | 648 | mutex_unlock(&local->sta_mtx); |
645 | 649 | ||
646 | return ret; | 650 | return ret; |
647 | } | 651 | } |
@@ -658,10 +662,11 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
658 | u8 *mac, struct station_info *sinfo) | 662 | u8 *mac, struct station_info *sinfo) |
659 | { | 663 | { |
660 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 664 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
665 | struct ieee80211_local *local = sdata->local; | ||
661 | struct sta_info *sta; | 666 | struct sta_info *sta; |
662 | int ret = -ENOENT; | 667 | int ret = -ENOENT; |
663 | 668 | ||
664 | rcu_read_lock(); | 669 | mutex_lock(&local->sta_mtx); |
665 | 670 | ||
666 | sta = sta_info_get_bss(sdata, mac); | 671 | sta = sta_info_get_bss(sdata, mac); |
667 | if (sta) { | 672 | if (sta) { |
@@ -669,11 +674,54 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
669 | sta_set_sinfo(sta, sinfo); | 674 | sta_set_sinfo(sta, sinfo); |
670 | } | 675 | } |
671 | 676 | ||
672 | rcu_read_unlock(); | 677 | mutex_unlock(&local->sta_mtx); |
673 | 678 | ||
674 | return ret; | 679 | return ret; |
675 | } | 680 | } |
676 | 681 | ||
682 | static int ieee80211_set_channel(struct wiphy *wiphy, | ||
683 | struct net_device *netdev, | ||
684 | struct ieee80211_channel *chan, | ||
685 | enum nl80211_channel_type channel_type) | ||
686 | { | ||
687 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
688 | struct ieee80211_sub_if_data *sdata = NULL; | ||
689 | |||
690 | if (netdev) | ||
691 | sdata = IEEE80211_DEV_TO_SUB_IF(netdev); | ||
692 | |||
693 | switch (ieee80211_get_channel_mode(local, NULL)) { | ||
694 | case CHAN_MODE_HOPPING: | ||
695 | return -EBUSY; | ||
696 | case CHAN_MODE_FIXED: | ||
697 | if (local->oper_channel != chan || | ||
698 | (!sdata && local->_oper_channel_type != channel_type)) | ||
699 | return -EBUSY; | ||
700 | if (!sdata && local->_oper_channel_type == channel_type) | ||
701 | return 0; | ||
702 | break; | ||
703 | case CHAN_MODE_UNDEFINED: | ||
704 | break; | ||
705 | } | ||
706 | |||
707 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) | ||
708 | return -EBUSY; | ||
709 | |||
710 | local->oper_channel = chan; | ||
711 | |||
712 | /* auto-detects changes */ | ||
713 | ieee80211_hw_config(local, 0); | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | static int ieee80211_set_monitor_channel(struct wiphy *wiphy, | ||
719 | struct ieee80211_channel *chan, | ||
720 | enum nl80211_channel_type channel_type) | ||
721 | { | ||
722 | return ieee80211_set_channel(wiphy, NULL, chan, channel_type); | ||
723 | } | ||
724 | |||
677 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | 725 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, |
678 | const u8 *resp, size_t resp_len) | 726 | const u8 *resp, size_t resp_len) |
679 | { | 727 | { |
@@ -788,6 +836,11 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, | |||
788 | if (old) | 836 | if (old) |
789 | return -EALREADY; | 837 | return -EALREADY; |
790 | 838 | ||
839 | err = ieee80211_set_channel(wiphy, dev, params->channel, | ||
840 | params->channel_type); | ||
841 | if (err) | ||
842 | return err; | ||
843 | |||
791 | /* | 844 | /* |
792 | * Apply control port protocol, this allows us to | 845 | * Apply control port protocol, this allows us to |
793 | * not encrypt dynamic WEP control frames. | 846 | * not encrypt dynamic WEP control frames. |
@@ -864,6 +917,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
864 | 917 | ||
865 | kfree_rcu(old, rcu_head); | 918 | kfree_rcu(old, rcu_head); |
866 | 919 | ||
920 | sta_info_flush(sdata->local, sdata); | ||
867 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); | 921 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); |
868 | 922 | ||
869 | return 0; | 923 | return 0; |
@@ -1482,7 +1536,7 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
1482 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) | 1536 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) |
1483 | conf->dot11MeshTTL = nconf->dot11MeshTTL; | 1537 | conf->dot11MeshTTL = nconf->dot11MeshTTL; |
1484 | if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) | 1538 | if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) |
1485 | conf->dot11MeshTTL = nconf->element_ttl; | 1539 | conf->element_ttl = nconf->element_ttl; |
1486 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) | 1540 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) |
1487 | conf->auto_open_plinks = nconf->auto_open_plinks; | 1541 | conf->auto_open_plinks = nconf->auto_open_plinks; |
1488 | if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) | 1542 | if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) |
@@ -1517,17 +1571,16 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
1517 | * announcements, so require this ifmsh to also be a root node | 1571 | * announcements, so require this ifmsh to also be a root node |
1518 | * */ | 1572 | * */ |
1519 | if (nconf->dot11MeshGateAnnouncementProtocol && | 1573 | if (nconf->dot11MeshGateAnnouncementProtocol && |
1520 | !conf->dot11MeshHWMPRootMode) { | 1574 | !(conf->dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)) { |
1521 | conf->dot11MeshHWMPRootMode = 1; | 1575 | conf->dot11MeshHWMPRootMode = IEEE80211_PROACTIVE_RANN; |
1522 | ieee80211_mesh_root_setup(ifmsh); | 1576 | ieee80211_mesh_root_setup(ifmsh); |
1523 | } | 1577 | } |
1524 | conf->dot11MeshGateAnnouncementProtocol = | 1578 | conf->dot11MeshGateAnnouncementProtocol = |
1525 | nconf->dot11MeshGateAnnouncementProtocol; | 1579 | nconf->dot11MeshGateAnnouncementProtocol; |
1526 | } | 1580 | } |
1527 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) { | 1581 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) |
1528 | conf->dot11MeshHWMPRannInterval = | 1582 | conf->dot11MeshHWMPRannInterval = |
1529 | nconf->dot11MeshHWMPRannInterval; | 1583 | nconf->dot11MeshHWMPRannInterval; |
1530 | } | ||
1531 | if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask)) | 1584 | if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask)) |
1532 | conf->dot11MeshForwarding = nconf->dot11MeshForwarding; | 1585 | conf->dot11MeshForwarding = nconf->dot11MeshForwarding; |
1533 | if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) { | 1586 | if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) { |
@@ -1543,6 +1596,15 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, | |||
1543 | sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode; | 1596 | sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode; |
1544 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); | 1597 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); |
1545 | } | 1598 | } |
1599 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask)) | ||
1600 | conf->dot11MeshHWMPactivePathToRootTimeout = | ||
1601 | nconf->dot11MeshHWMPactivePathToRootTimeout; | ||
1602 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOT_INTERVAL, mask)) | ||
1603 | conf->dot11MeshHWMProotInterval = | ||
1604 | nconf->dot11MeshHWMProotInterval; | ||
1605 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask)) | ||
1606 | conf->dot11MeshHWMPconfirmationInterval = | ||
1607 | nconf->dot11MeshHWMPconfirmationInterval; | ||
1546 | return 0; | 1608 | return 0; |
1547 | } | 1609 | } |
1548 | 1610 | ||
@@ -1558,6 +1620,12 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | |||
1558 | err = copy_mesh_setup(ifmsh, setup); | 1620 | err = copy_mesh_setup(ifmsh, setup); |
1559 | if (err) | 1621 | if (err) |
1560 | return err; | 1622 | return err; |
1623 | |||
1624 | err = ieee80211_set_channel(wiphy, dev, setup->channel, | ||
1625 | setup->channel_type); | ||
1626 | if (err) | ||
1627 | return err; | ||
1628 | |||
1561 | ieee80211_start_mesh(sdata); | 1629 | ieee80211_start_mesh(sdata); |
1562 | 1630 | ||
1563 | return 0; | 1631 | return 0; |
@@ -1674,54 +1742,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, | |||
1674 | return -EINVAL; | 1742 | return -EINVAL; |
1675 | } | 1743 | } |
1676 | 1744 | ||
1677 | return 0; | 1745 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); |
1678 | } | ||
1679 | |||
1680 | static int ieee80211_set_channel(struct wiphy *wiphy, | ||
1681 | struct net_device *netdev, | ||
1682 | struct ieee80211_channel *chan, | ||
1683 | enum nl80211_channel_type channel_type) | ||
1684 | { | ||
1685 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1686 | struct ieee80211_sub_if_data *sdata = NULL; | ||
1687 | struct ieee80211_channel *old_oper; | ||
1688 | enum nl80211_channel_type old_oper_type; | ||
1689 | enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT; | ||
1690 | |||
1691 | if (netdev) | ||
1692 | sdata = IEEE80211_DEV_TO_SUB_IF(netdev); | ||
1693 | |||
1694 | switch (ieee80211_get_channel_mode(local, NULL)) { | ||
1695 | case CHAN_MODE_HOPPING: | ||
1696 | return -EBUSY; | ||
1697 | case CHAN_MODE_FIXED: | ||
1698 | if (local->oper_channel != chan) | ||
1699 | return -EBUSY; | ||
1700 | if (!sdata && local->_oper_channel_type == channel_type) | ||
1701 | return 0; | ||
1702 | break; | ||
1703 | case CHAN_MODE_UNDEFINED: | ||
1704 | break; | ||
1705 | } | ||
1706 | |||
1707 | if (sdata) | ||
1708 | old_vif_oper_type = sdata->vif.bss_conf.channel_type; | ||
1709 | old_oper_type = local->_oper_channel_type; | ||
1710 | |||
1711 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) | ||
1712 | return -EBUSY; | ||
1713 | |||
1714 | old_oper = local->oper_channel; | ||
1715 | local->oper_channel = chan; | ||
1716 | |||
1717 | /* Update driver if changes were actually made. */ | ||
1718 | if ((old_oper != local->oper_channel) || | ||
1719 | (old_oper_type != local->_oper_channel_type)) | ||
1720 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
1721 | |||
1722 | if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||
1723 | old_vif_oper_type != sdata->vif.bss_conf.channel_type) | ||
1724 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); | ||
1725 | 1746 | ||
1726 | return 0; | 1747 | return 0; |
1727 | } | 1748 | } |
@@ -1743,10 +1764,11 @@ static int ieee80211_resume(struct wiphy *wiphy) | |||
1743 | #endif | 1764 | #endif |
1744 | 1765 | ||
1745 | static int ieee80211_scan(struct wiphy *wiphy, | 1766 | static int ieee80211_scan(struct wiphy *wiphy, |
1746 | struct net_device *dev, | ||
1747 | struct cfg80211_scan_request *req) | 1767 | struct cfg80211_scan_request *req) |
1748 | { | 1768 | { |
1749 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1769 | struct ieee80211_sub_if_data *sdata; |
1770 | |||
1771 | sdata = IEEE80211_WDEV_TO_SUB_IF(req->wdev); | ||
1750 | 1772 | ||
1751 | switch (ieee80211_vif_type_p2p(&sdata->vif)) { | 1773 | switch (ieee80211_vif_type_p2p(&sdata->vif)) { |
1752 | case NL80211_IFTYPE_STATION: | 1774 | case NL80211_IFTYPE_STATION: |
@@ -2111,143 +2133,291 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
2111 | return 0; | 2133 | return 0; |
2112 | } | 2134 | } |
2113 | 2135 | ||
2114 | static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local, | 2136 | static int ieee80211_start_roc_work(struct ieee80211_local *local, |
2115 | struct net_device *dev, | 2137 | struct ieee80211_sub_if_data *sdata, |
2116 | struct ieee80211_channel *chan, | 2138 | struct ieee80211_channel *channel, |
2117 | enum nl80211_channel_type chantype, | 2139 | enum nl80211_channel_type channel_type, |
2118 | unsigned int duration, u64 *cookie) | 2140 | unsigned int duration, u64 *cookie, |
2141 | struct sk_buff *txskb) | ||
2119 | { | 2142 | { |
2143 | struct ieee80211_roc_work *roc, *tmp; | ||
2144 | bool queued = false; | ||
2120 | int ret; | 2145 | int ret; |
2121 | u32 random_cookie; | ||
2122 | 2146 | ||
2123 | lockdep_assert_held(&local->mtx); | 2147 | lockdep_assert_held(&local->mtx); |
2124 | 2148 | ||
2125 | if (local->hw_roc_cookie) | 2149 | roc = kzalloc(sizeof(*roc), GFP_KERNEL); |
2126 | return -EBUSY; | 2150 | if (!roc) |
2127 | /* must be nonzero */ | 2151 | return -ENOMEM; |
2128 | random_cookie = random32() | 1; | 2152 | |
2129 | 2153 | roc->chan = channel; | |
2130 | *cookie = random_cookie; | 2154 | roc->chan_type = channel_type; |
2131 | local->hw_roc_dev = dev; | 2155 | roc->duration = duration; |
2132 | local->hw_roc_cookie = random_cookie; | 2156 | roc->req_duration = duration; |
2133 | local->hw_roc_channel = chan; | 2157 | roc->frame = txskb; |
2134 | local->hw_roc_channel_type = chantype; | 2158 | roc->mgmt_tx_cookie = (unsigned long)txskb; |
2135 | local->hw_roc_duration = duration; | 2159 | roc->sdata = sdata; |
2136 | ret = drv_remain_on_channel(local, chan, chantype, duration); | 2160 | INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work); |
2161 | INIT_LIST_HEAD(&roc->dependents); | ||
2162 | |||
2163 | /* if there's one pending or we're scanning, queue this one */ | ||
2164 | if (!list_empty(&local->roc_list) || local->scanning) | ||
2165 | goto out_check_combine; | ||
2166 | |||
2167 | /* if not HW assist, just queue & schedule work */ | ||
2168 | if (!local->ops->remain_on_channel) { | ||
2169 | ieee80211_queue_delayed_work(&local->hw, &roc->work, 0); | ||
2170 | goto out_queue; | ||
2171 | } | ||
2172 | |||
2173 | /* otherwise actually kick it off here (for error handling) */ | ||
2174 | |||
2175 | /* | ||
2176 | * If the duration is zero, then the driver | ||
2177 | * wouldn't actually do anything. Set it to | ||
2178 | * 10 for now. | ||
2179 | * | ||
2180 | * TODO: cancel the off-channel operation | ||
2181 | * when we get the SKB's TX status and | ||
2182 | * the wait time was zero before. | ||
2183 | */ | ||
2184 | if (!duration) | ||
2185 | duration = 10; | ||
2186 | |||
2187 | ret = drv_remain_on_channel(local, channel, channel_type, duration); | ||
2137 | if (ret) { | 2188 | if (ret) { |
2138 | local->hw_roc_channel = NULL; | 2189 | kfree(roc); |
2139 | local->hw_roc_cookie = 0; | 2190 | return ret; |
2140 | } | 2191 | } |
2141 | 2192 | ||
2142 | return ret; | 2193 | roc->started = true; |
2194 | goto out_queue; | ||
2195 | |||
2196 | out_check_combine: | ||
2197 | list_for_each_entry(tmp, &local->roc_list, list) { | ||
2198 | if (tmp->chan != channel || tmp->chan_type != channel_type) | ||
2199 | continue; | ||
2200 | |||
2201 | /* | ||
2202 | * Extend this ROC if possible: | ||
2203 | * | ||
2204 | * If it hasn't started yet, just increase the duration | ||
2205 | * and add the new one to the list of dependents. | ||
2206 | */ | ||
2207 | if (!tmp->started) { | ||
2208 | list_add_tail(&roc->list, &tmp->dependents); | ||
2209 | tmp->duration = max(tmp->duration, roc->duration); | ||
2210 | queued = true; | ||
2211 | break; | ||
2212 | } | ||
2213 | |||
2214 | /* If it has already started, it's more difficult ... */ | ||
2215 | if (local->ops->remain_on_channel) { | ||
2216 | unsigned long j = jiffies; | ||
2217 | |||
2218 | /* | ||
2219 | * In the offloaded ROC case, if it hasn't begun, add | ||
2220 | * this new one to the dependent list to be handled | ||
2221 | * when the the master one begins. If it has begun, | ||
2222 | * check that there's still a minimum time left and | ||
2223 | * if so, start this one, transmitting the frame, but | ||
2224 | * add it to the list directly after this one with a | ||
2225 | * a reduced time so we'll ask the driver to execute | ||
2226 | * it right after finishing the previous one, in the | ||
2227 | * hope that it'll also be executed right afterwards, | ||
2228 | * effectively extending the old one. | ||
2229 | * If there's no minimum time left, just add it to the | ||
2230 | * normal list. | ||
2231 | */ | ||
2232 | if (!tmp->hw_begun) { | ||
2233 | list_add_tail(&roc->list, &tmp->dependents); | ||
2234 | queued = true; | ||
2235 | break; | ||
2236 | } | ||
2237 | |||
2238 | if (time_before(j + IEEE80211_ROC_MIN_LEFT, | ||
2239 | tmp->hw_start_time + | ||
2240 | msecs_to_jiffies(tmp->duration))) { | ||
2241 | int new_dur; | ||
2242 | |||
2243 | ieee80211_handle_roc_started(roc); | ||
2244 | |||
2245 | new_dur = roc->duration - | ||
2246 | jiffies_to_msecs(tmp->hw_start_time + | ||
2247 | msecs_to_jiffies( | ||
2248 | tmp->duration) - | ||
2249 | j); | ||
2250 | |||
2251 | if (new_dur > 0) { | ||
2252 | /* add right after tmp */ | ||
2253 | list_add(&roc->list, &tmp->list); | ||
2254 | } else { | ||
2255 | list_add_tail(&roc->list, | ||
2256 | &tmp->dependents); | ||
2257 | } | ||
2258 | queued = true; | ||
2259 | } | ||
2260 | } else if (del_timer_sync(&tmp->work.timer)) { | ||
2261 | unsigned long new_end; | ||
2262 | |||
2263 | /* | ||
2264 | * In the software ROC case, cancel the timer, if | ||
2265 | * that fails then the finish work is already | ||
2266 | * queued/pending and thus we queue the new ROC | ||
2267 | * normally, if that succeeds then we can extend | ||
2268 | * the timer duration and TX the frame (if any.) | ||
2269 | */ | ||
2270 | |||
2271 | list_add_tail(&roc->list, &tmp->dependents); | ||
2272 | queued = true; | ||
2273 | |||
2274 | new_end = jiffies + msecs_to_jiffies(roc->duration); | ||
2275 | |||
2276 | /* ok, it was started & we canceled timer */ | ||
2277 | if (time_after(new_end, tmp->work.timer.expires)) | ||
2278 | mod_timer(&tmp->work.timer, new_end); | ||
2279 | else | ||
2280 | add_timer(&tmp->work.timer); | ||
2281 | |||
2282 | ieee80211_handle_roc_started(roc); | ||
2283 | } | ||
2284 | break; | ||
2285 | } | ||
2286 | |||
2287 | out_queue: | ||
2288 | if (!queued) | ||
2289 | list_add_tail(&roc->list, &local->roc_list); | ||
2290 | |||
2291 | /* | ||
2292 | * cookie is either the roc (for normal roc) | ||
2293 | * or the SKB (for mgmt TX) | ||
2294 | */ | ||
2295 | if (txskb) | ||
2296 | *cookie = (unsigned long)txskb; | ||
2297 | else | ||
2298 | *cookie = (unsigned long)roc; | ||
2299 | |||
2300 | return 0; | ||
2143 | } | 2301 | } |
2144 | 2302 | ||
2145 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, | 2303 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
2146 | struct net_device *dev, | 2304 | struct wireless_dev *wdev, |
2147 | struct ieee80211_channel *chan, | 2305 | struct ieee80211_channel *chan, |
2148 | enum nl80211_channel_type channel_type, | 2306 | enum nl80211_channel_type channel_type, |
2149 | unsigned int duration, | 2307 | unsigned int duration, |
2150 | u64 *cookie) | 2308 | u64 *cookie) |
2151 | { | 2309 | { |
2152 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2310 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
2153 | struct ieee80211_local *local = sdata->local; | 2311 | struct ieee80211_local *local = sdata->local; |
2312 | int ret; | ||
2154 | 2313 | ||
2155 | if (local->ops->remain_on_channel) { | 2314 | mutex_lock(&local->mtx); |
2156 | int ret; | 2315 | ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, |
2157 | 2316 | duration, cookie, NULL); | |
2158 | mutex_lock(&local->mtx); | 2317 | mutex_unlock(&local->mtx); |
2159 | ret = ieee80211_remain_on_channel_hw(local, dev, | ||
2160 | chan, channel_type, | ||
2161 | duration, cookie); | ||
2162 | local->hw_roc_for_tx = false; | ||
2163 | mutex_unlock(&local->mtx); | ||
2164 | |||
2165 | return ret; | ||
2166 | } | ||
2167 | 2318 | ||
2168 | return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, | 2319 | return ret; |
2169 | duration, cookie); | ||
2170 | } | 2320 | } |
2171 | 2321 | ||
2172 | static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local, | 2322 | static int ieee80211_cancel_roc(struct ieee80211_local *local, |
2173 | u64 cookie) | 2323 | u64 cookie, bool mgmt_tx) |
2174 | { | 2324 | { |
2325 | struct ieee80211_roc_work *roc, *tmp, *found = NULL; | ||
2175 | int ret; | 2326 | int ret; |
2176 | 2327 | ||
2177 | lockdep_assert_held(&local->mtx); | 2328 | mutex_lock(&local->mtx); |
2329 | list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { | ||
2330 | struct ieee80211_roc_work *dep, *tmp2; | ||
2178 | 2331 | ||
2179 | if (local->hw_roc_cookie != cookie) | 2332 | list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { |
2180 | return -ENOENT; | 2333 | if (!mgmt_tx && (unsigned long)dep != cookie) |
2334 | continue; | ||
2335 | else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) | ||
2336 | continue; | ||
2337 | /* found dependent item -- just remove it */ | ||
2338 | list_del(&dep->list); | ||
2339 | mutex_unlock(&local->mtx); | ||
2181 | 2340 | ||
2182 | ret = drv_cancel_remain_on_channel(local); | 2341 | ieee80211_roc_notify_destroy(dep); |
2183 | if (ret) | 2342 | return 0; |
2184 | return ret; | 2343 | } |
2185 | 2344 | ||
2186 | local->hw_roc_cookie = 0; | 2345 | if (!mgmt_tx && (unsigned long)roc != cookie) |
2187 | local->hw_roc_channel = NULL; | 2346 | continue; |
2347 | else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) | ||
2348 | continue; | ||
2349 | |||
2350 | found = roc; | ||
2351 | break; | ||
2352 | } | ||
2188 | 2353 | ||
2189 | ieee80211_recalc_idle(local); | 2354 | if (!found) { |
2355 | mutex_unlock(&local->mtx); | ||
2356 | return -ENOENT; | ||
2357 | } | ||
2190 | 2358 | ||
2191 | return 0; | 2359 | /* |
2192 | } | 2360 | * We found the item to cancel, so do that. Note that it |
2361 | * may have dependents, which we also cancel (and send | ||
2362 | * the expired signal for.) Not doing so would be quite | ||
2363 | * tricky here, but we may need to fix it later. | ||
2364 | */ | ||
2193 | 2365 | ||
2194 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | 2366 | if (local->ops->remain_on_channel) { |
2195 | struct net_device *dev, | 2367 | if (found->started) { |
2196 | u64 cookie) | 2368 | ret = drv_cancel_remain_on_channel(local); |
2197 | { | 2369 | if (WARN_ON_ONCE(ret)) { |
2198 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2370 | mutex_unlock(&local->mtx); |
2199 | struct ieee80211_local *local = sdata->local; | 2371 | return ret; |
2372 | } | ||
2373 | } | ||
2200 | 2374 | ||
2201 | if (local->ops->cancel_remain_on_channel) { | 2375 | list_del(&found->list); |
2202 | int ret; | ||
2203 | 2376 | ||
2204 | mutex_lock(&local->mtx); | 2377 | if (found->started) |
2205 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); | 2378 | ieee80211_start_next_roc(local); |
2206 | mutex_unlock(&local->mtx); | 2379 | mutex_unlock(&local->mtx); |
2207 | 2380 | ||
2208 | return ret; | 2381 | ieee80211_roc_notify_destroy(found); |
2382 | } else { | ||
2383 | /* work may be pending so use it all the time */ | ||
2384 | found->abort = true; | ||
2385 | ieee80211_queue_delayed_work(&local->hw, &found->work, 0); | ||
2386 | |||
2387 | mutex_unlock(&local->mtx); | ||
2388 | |||
2389 | /* work will clean up etc */ | ||
2390 | flush_delayed_work(&found->work); | ||
2209 | } | 2391 | } |
2210 | 2392 | ||
2211 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | 2393 | return 0; |
2212 | } | 2394 | } |
2213 | 2395 | ||
2214 | static enum work_done_result | 2396 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, |
2215 | ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb) | 2397 | struct wireless_dev *wdev, |
2398 | u64 cookie) | ||
2216 | { | 2399 | { |
2217 | /* | 2400 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
2218 | * Use the data embedded in the work struct for reporting | 2401 | struct ieee80211_local *local = sdata->local; |
2219 | * here so if the driver mangled the SKB before dropping | ||
2220 | * it (which is the only way we really should get here) | ||
2221 | * then we don't report mangled data. | ||
2222 | * | ||
2223 | * If there was no wait time, then by the time we get here | ||
2224 | * the driver will likely not have reported the status yet, | ||
2225 | * so in that case userspace will have to deal with it. | ||
2226 | */ | ||
2227 | |||
2228 | if (wk->offchan_tx.wait && !wk->offchan_tx.status) | ||
2229 | cfg80211_mgmt_tx_status(wk->sdata->dev, | ||
2230 | (unsigned long) wk->offchan_tx.frame, | ||
2231 | wk->data, wk->data_len, false, GFP_KERNEL); | ||
2232 | 2402 | ||
2233 | return WORK_DONE_DESTROY; | 2403 | return ieee80211_cancel_roc(local, cookie, false); |
2234 | } | 2404 | } |
2235 | 2405 | ||
2236 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | 2406 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, |
2237 | struct ieee80211_channel *chan, bool offchan, | 2407 | struct ieee80211_channel *chan, bool offchan, |
2238 | enum nl80211_channel_type channel_type, | 2408 | enum nl80211_channel_type channel_type, |
2239 | bool channel_type_valid, unsigned int wait, | 2409 | bool channel_type_valid, unsigned int wait, |
2240 | const u8 *buf, size_t len, bool no_cck, | 2410 | const u8 *buf, size_t len, bool no_cck, |
2241 | bool dont_wait_for_ack, u64 *cookie) | 2411 | bool dont_wait_for_ack, u64 *cookie) |
2242 | { | 2412 | { |
2243 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2413 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); |
2244 | struct ieee80211_local *local = sdata->local; | 2414 | struct ieee80211_local *local = sdata->local; |
2245 | struct sk_buff *skb; | 2415 | struct sk_buff *skb; |
2246 | struct sta_info *sta; | 2416 | struct sta_info *sta; |
2247 | struct ieee80211_work *wk; | ||
2248 | const struct ieee80211_mgmt *mgmt = (void *)buf; | 2417 | const struct ieee80211_mgmt *mgmt = (void *)buf; |
2418 | bool need_offchan = false; | ||
2249 | u32 flags; | 2419 | u32 flags; |
2250 | bool is_offchan = false; | 2420 | int ret; |
2251 | 2421 | ||
2252 | if (dont_wait_for_ack) | 2422 | if (dont_wait_for_ack) |
2253 | flags = IEEE80211_TX_CTL_NO_ACK; | 2423 | flags = IEEE80211_TX_CTL_NO_ACK; |
@@ -2255,33 +2425,28 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2255 | flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | | 2425 | flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | |
2256 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 2426 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
2257 | 2427 | ||
2258 | /* Check that we are on the requested channel for transmission */ | ||
2259 | if (chan != local->tmp_channel && | ||
2260 | chan != local->oper_channel) | ||
2261 | is_offchan = true; | ||
2262 | if (channel_type_valid && | ||
2263 | (channel_type != local->tmp_channel_type && | ||
2264 | channel_type != local->_oper_channel_type)) | ||
2265 | is_offchan = true; | ||
2266 | |||
2267 | if (chan == local->hw_roc_channel) { | ||
2268 | /* TODO: check channel type? */ | ||
2269 | is_offchan = false; | ||
2270 | flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | ||
2271 | } | ||
2272 | |||
2273 | if (no_cck) | 2428 | if (no_cck) |
2274 | flags |= IEEE80211_TX_CTL_NO_CCK_RATE; | 2429 | flags |= IEEE80211_TX_CTL_NO_CCK_RATE; |
2275 | 2430 | ||
2276 | if (is_offchan && !offchan) | ||
2277 | return -EBUSY; | ||
2278 | |||
2279 | switch (sdata->vif.type) { | 2431 | switch (sdata->vif.type) { |
2280 | case NL80211_IFTYPE_ADHOC: | 2432 | case NL80211_IFTYPE_ADHOC: |
2433 | if (!sdata->vif.bss_conf.ibss_joined) | ||
2434 | need_offchan = true; | ||
2435 | /* fall through */ | ||
2436 | #ifdef CONFIG_MAC80211_MESH | ||
2437 | case NL80211_IFTYPE_MESH_POINT: | ||
2438 | if (ieee80211_vif_is_mesh(&sdata->vif) && | ||
2439 | !sdata->u.mesh.mesh_id_len) | ||
2440 | need_offchan = true; | ||
2441 | /* fall through */ | ||
2442 | #endif | ||
2281 | case NL80211_IFTYPE_AP: | 2443 | case NL80211_IFTYPE_AP: |
2282 | case NL80211_IFTYPE_AP_VLAN: | 2444 | case NL80211_IFTYPE_AP_VLAN: |
2283 | case NL80211_IFTYPE_P2P_GO: | 2445 | case NL80211_IFTYPE_P2P_GO: |
2284 | case NL80211_IFTYPE_MESH_POINT: | 2446 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC && |
2447 | !ieee80211_vif_is_mesh(&sdata->vif) && | ||
2448 | !rcu_access_pointer(sdata->bss->beacon)) | ||
2449 | need_offchan = true; | ||
2285 | if (!ieee80211_is_action(mgmt->frame_control) || | 2450 | if (!ieee80211_is_action(mgmt->frame_control) || |
2286 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) | 2451 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) |
2287 | break; | 2452 | break; |
@@ -2293,167 +2458,101 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
2293 | break; | 2458 | break; |
2294 | case NL80211_IFTYPE_STATION: | 2459 | case NL80211_IFTYPE_STATION: |
2295 | case NL80211_IFTYPE_P2P_CLIENT: | 2460 | case NL80211_IFTYPE_P2P_CLIENT: |
2461 | if (!sdata->u.mgd.associated) | ||
2462 | need_offchan = true; | ||
2296 | break; | 2463 | break; |
2297 | default: | 2464 | default: |
2298 | return -EOPNOTSUPP; | 2465 | return -EOPNOTSUPP; |
2299 | } | 2466 | } |
2300 | 2467 | ||
2468 | mutex_lock(&local->mtx); | ||
2469 | |||
2470 | /* Check if the operating channel is the requested channel */ | ||
2471 | if (!need_offchan) { | ||
2472 | need_offchan = chan != local->oper_channel; | ||
2473 | if (channel_type_valid && | ||
2474 | channel_type != local->_oper_channel_type) | ||
2475 | need_offchan = true; | ||
2476 | } | ||
2477 | |||
2478 | if (need_offchan && !offchan) { | ||
2479 | ret = -EBUSY; | ||
2480 | goto out_unlock; | ||
2481 | } | ||
2482 | |||
2301 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); | 2483 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); |
2302 | if (!skb) | 2484 | if (!skb) { |
2303 | return -ENOMEM; | 2485 | ret = -ENOMEM; |
2486 | goto out_unlock; | ||
2487 | } | ||
2304 | skb_reserve(skb, local->hw.extra_tx_headroom); | 2488 | skb_reserve(skb, local->hw.extra_tx_headroom); |
2305 | 2489 | ||
2306 | memcpy(skb_put(skb, len), buf, len); | 2490 | memcpy(skb_put(skb, len), buf, len); |
2307 | 2491 | ||
2308 | IEEE80211_SKB_CB(skb)->flags = flags; | 2492 | IEEE80211_SKB_CB(skb)->flags = flags; |
2309 | 2493 | ||
2310 | if (flags & IEEE80211_TX_CTL_TX_OFFCHAN) | ||
2311 | IEEE80211_SKB_CB(skb)->hw_queue = | ||
2312 | local->hw.offchannel_tx_hw_queue; | ||
2313 | |||
2314 | skb->dev = sdata->dev; | 2494 | skb->dev = sdata->dev; |
2315 | 2495 | ||
2316 | *cookie = (unsigned long) skb; | 2496 | if (!need_offchan) { |
2317 | 2497 | *cookie = (unsigned long) skb; | |
2318 | if (is_offchan && local->ops->remain_on_channel) { | 2498 | ieee80211_tx_skb(sdata, skb); |
2319 | unsigned int duration; | 2499 | ret = 0; |
2320 | int ret; | 2500 | goto out_unlock; |
2321 | 2501 | } | |
2322 | mutex_lock(&local->mtx); | ||
2323 | /* | ||
2324 | * If the duration is zero, then the driver | ||
2325 | * wouldn't actually do anything. Set it to | ||
2326 | * 100 for now. | ||
2327 | * | ||
2328 | * TODO: cancel the off-channel operation | ||
2329 | * when we get the SKB's TX status and | ||
2330 | * the wait time was zero before. | ||
2331 | */ | ||
2332 | duration = 100; | ||
2333 | if (wait) | ||
2334 | duration = wait; | ||
2335 | ret = ieee80211_remain_on_channel_hw(local, dev, chan, | ||
2336 | channel_type, | ||
2337 | duration, cookie); | ||
2338 | if (ret) { | ||
2339 | kfree_skb(skb); | ||
2340 | mutex_unlock(&local->mtx); | ||
2341 | return ret; | ||
2342 | } | ||
2343 | |||
2344 | local->hw_roc_for_tx = true; | ||
2345 | local->hw_roc_duration = wait; | ||
2346 | |||
2347 | /* | ||
2348 | * queue up frame for transmission after | ||
2349 | * ieee80211_ready_on_channel call | ||
2350 | */ | ||
2351 | 2502 | ||
2352 | /* modify cookie to prevent API mismatches */ | 2503 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; |
2353 | *cookie ^= 2; | 2504 | if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) |
2354 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | ||
2355 | IEEE80211_SKB_CB(skb)->hw_queue = | 2505 | IEEE80211_SKB_CB(skb)->hw_queue = |
2356 | local->hw.offchannel_tx_hw_queue; | 2506 | local->hw.offchannel_tx_hw_queue; |
2357 | local->hw_roc_skb = skb; | ||
2358 | local->hw_roc_skb_for_status = skb; | ||
2359 | mutex_unlock(&local->mtx); | ||
2360 | |||
2361 | return 0; | ||
2362 | } | ||
2363 | |||
2364 | /* | ||
2365 | * Can transmit right away if the channel was the | ||
2366 | * right one and there's no wait involved... If a | ||
2367 | * wait is involved, we might otherwise not be on | ||
2368 | * the right channel for long enough! | ||
2369 | */ | ||
2370 | if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) { | ||
2371 | ieee80211_tx_skb(sdata, skb); | ||
2372 | return 0; | ||
2373 | } | ||
2374 | 2507 | ||
2375 | wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL); | 2508 | /* This will handle all kinds of coalescing and immediate TX */ |
2376 | if (!wk) { | 2509 | ret = ieee80211_start_roc_work(local, sdata, chan, channel_type, |
2510 | wait, cookie, skb); | ||
2511 | if (ret) | ||
2377 | kfree_skb(skb); | 2512 | kfree_skb(skb); |
2378 | return -ENOMEM; | 2513 | out_unlock: |
2379 | } | 2514 | mutex_unlock(&local->mtx); |
2380 | 2515 | return ret; | |
2381 | wk->type = IEEE80211_WORK_OFFCHANNEL_TX; | ||
2382 | wk->chan = chan; | ||
2383 | wk->chan_type = channel_type; | ||
2384 | wk->sdata = sdata; | ||
2385 | wk->done = ieee80211_offchan_tx_done; | ||
2386 | wk->offchan_tx.frame = skb; | ||
2387 | wk->offchan_tx.wait = wait; | ||
2388 | wk->data_len = len; | ||
2389 | memcpy(wk->data, buf, len); | ||
2390 | |||
2391 | ieee80211_add_work(wk); | ||
2392 | return 0; | ||
2393 | } | 2516 | } |
2394 | 2517 | ||
2395 | static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, | 2518 | static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, |
2396 | struct net_device *dev, | 2519 | struct wireless_dev *wdev, |
2397 | u64 cookie) | 2520 | u64 cookie) |
2398 | { | 2521 | { |
2399 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 2522 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2400 | struct ieee80211_local *local = sdata->local; | ||
2401 | struct ieee80211_work *wk; | ||
2402 | int ret = -ENOENT; | ||
2403 | |||
2404 | mutex_lock(&local->mtx); | ||
2405 | |||
2406 | if (local->ops->cancel_remain_on_channel) { | ||
2407 | cookie ^= 2; | ||
2408 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); | ||
2409 | |||
2410 | if (ret == 0) { | ||
2411 | kfree_skb(local->hw_roc_skb); | ||
2412 | local->hw_roc_skb = NULL; | ||
2413 | local->hw_roc_skb_for_status = NULL; | ||
2414 | } | ||
2415 | |||
2416 | mutex_unlock(&local->mtx); | ||
2417 | |||
2418 | return ret; | ||
2419 | } | ||
2420 | |||
2421 | list_for_each_entry(wk, &local->work_list, list) { | ||
2422 | if (wk->sdata != sdata) | ||
2423 | continue; | ||
2424 | |||
2425 | if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) | ||
2426 | continue; | ||
2427 | |||
2428 | if (cookie != (unsigned long) wk->offchan_tx.frame) | ||
2429 | continue; | ||
2430 | |||
2431 | wk->timeout = jiffies; | ||
2432 | |||
2433 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
2434 | ret = 0; | ||
2435 | break; | ||
2436 | } | ||
2437 | mutex_unlock(&local->mtx); | ||
2438 | 2523 | ||
2439 | return ret; | 2524 | return ieee80211_cancel_roc(local, cookie, true); |
2440 | } | 2525 | } |
2441 | 2526 | ||
2442 | static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, | 2527 | static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, |
2443 | struct net_device *dev, | 2528 | struct wireless_dev *wdev, |
2444 | u16 frame_type, bool reg) | 2529 | u16 frame_type, bool reg) |
2445 | { | 2530 | { |
2446 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2531 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2532 | struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); | ||
2447 | 2533 | ||
2448 | if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) | 2534 | switch (frame_type) { |
2449 | return; | 2535 | case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH: |
2536 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
2537 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
2450 | 2538 | ||
2451 | if (reg) | 2539 | if (reg) |
2452 | local->probe_req_reg++; | 2540 | ifibss->auth_frame_registrations++; |
2453 | else | 2541 | else |
2454 | local->probe_req_reg--; | 2542 | ifibss->auth_frame_registrations--; |
2543 | } | ||
2544 | break; | ||
2545 | case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ: | ||
2546 | if (reg) | ||
2547 | local->probe_req_reg++; | ||
2548 | else | ||
2549 | local->probe_req_reg--; | ||
2455 | 2550 | ||
2456 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); | 2551 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); |
2552 | break; | ||
2553 | default: | ||
2554 | break; | ||
2555 | } | ||
2457 | } | 2556 | } |
2458 | 2557 | ||
2459 | static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) | 2558 | static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) |
@@ -2573,8 +2672,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2573 | tf->u.setup_req.capability = | 2672 | tf->u.setup_req.capability = |
2574 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2673 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2575 | 2674 | ||
2576 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2675 | ieee80211_add_srates_ie(sdata, skb, false); |
2577 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2676 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2578 | ieee80211_tdls_add_ext_capab(skb); | 2677 | ieee80211_tdls_add_ext_capab(skb); |
2579 | break; | 2678 | break; |
2580 | case WLAN_TDLS_SETUP_RESPONSE: | 2679 | case WLAN_TDLS_SETUP_RESPONSE: |
@@ -2587,8 +2686,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, | |||
2587 | tf->u.setup_resp.capability = | 2686 | tf->u.setup_resp.capability = |
2588 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2687 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2589 | 2688 | ||
2590 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2689 | ieee80211_add_srates_ie(sdata, skb, false); |
2591 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2690 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2592 | ieee80211_tdls_add_ext_capab(skb); | 2691 | ieee80211_tdls_add_ext_capab(skb); |
2593 | break; | 2692 | break; |
2594 | case WLAN_TDLS_SETUP_CONFIRM: | 2693 | case WLAN_TDLS_SETUP_CONFIRM: |
@@ -2648,8 +2747,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, | |||
2648 | mgmt->u.action.u.tdls_discover_resp.capability = | 2747 | mgmt->u.action.u.tdls_discover_resp.capability = |
2649 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); | 2748 | cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); |
2650 | 2749 | ||
2651 | ieee80211_add_srates_ie(&sdata->vif, skb, false); | 2750 | ieee80211_add_srates_ie(sdata, skb, false); |
2652 | ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); | 2751 | ieee80211_add_ext_srates_ie(sdata, skb, false); |
2653 | ieee80211_tdls_add_ext_capab(skb); | 2752 | ieee80211_tdls_add_ext_capab(skb); |
2654 | break; | 2753 | break; |
2655 | default: | 2754 | default: |
@@ -2679,9 +2778,8 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, | |||
2679 | !sdata->u.mgd.associated) | 2778 | !sdata->u.mgd.associated) |
2680 | return -EINVAL; | 2779 | return -EINVAL; |
2681 | 2780 | ||
2682 | #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG | 2781 | tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n", |
2683 | printk(KERN_DEBUG "TDLS mgmt action %d peer %pM\n", action_code, peer); | 2782 | action_code, peer); |
2684 | #endif | ||
2685 | 2783 | ||
2686 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 2784 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
2687 | max(sizeof(struct ieee80211_mgmt), | 2785 | max(sizeof(struct ieee80211_mgmt), |
@@ -2790,9 +2888,7 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
2790 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 2888 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
2791 | return -EINVAL; | 2889 | return -EINVAL; |
2792 | 2890 | ||
2793 | #ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG | 2891 | tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); |
2794 | printk(KERN_DEBUG "TDLS oper %d peer %pM\n", oper, peer); | ||
2795 | #endif | ||
2796 | 2892 | ||
2797 | switch (oper) { | 2893 | switch (oper) { |
2798 | case NL80211_TDLS_ENABLE_LINK: | 2894 | case NL80211_TDLS_ENABLE_LINK: |
@@ -2889,8 +2985,8 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | |||
2889 | } | 2985 | } |
2890 | 2986 | ||
2891 | static struct ieee80211_channel * | 2987 | static struct ieee80211_channel * |
2892 | ieee80211_wiphy_get_channel(struct wiphy *wiphy, | 2988 | ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, |
2893 | enum nl80211_channel_type *type) | 2989 | enum nl80211_channel_type *type) |
2894 | { | 2990 | { |
2895 | struct ieee80211_local *local = wiphy_priv(wiphy); | 2991 | struct ieee80211_local *local = wiphy_priv(wiphy); |
2896 | 2992 | ||
@@ -2936,7 +3032,7 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2936 | #endif | 3032 | #endif |
2937 | .change_bss = ieee80211_change_bss, | 3033 | .change_bss = ieee80211_change_bss, |
2938 | .set_txq_params = ieee80211_set_txq_params, | 3034 | .set_txq_params = ieee80211_set_txq_params, |
2939 | .set_channel = ieee80211_set_channel, | 3035 | .set_monitor_channel = ieee80211_set_monitor_channel, |
2940 | .suspend = ieee80211_suspend, | 3036 | .suspend = ieee80211_suspend, |
2941 | .resume = ieee80211_resume, | 3037 | .resume = ieee80211_resume, |
2942 | .scan = ieee80211_scan, | 3038 | .scan = ieee80211_scan, |
@@ -2971,7 +3067,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2971 | .tdls_oper = ieee80211_tdls_oper, | 3067 | .tdls_oper = ieee80211_tdls_oper, |
2972 | .tdls_mgmt = ieee80211_tdls_mgmt, | 3068 | .tdls_mgmt = ieee80211_tdls_mgmt, |
2973 | .probe_client = ieee80211_probe_client, | 3069 | .probe_client = ieee80211_probe_client, |
2974 | .get_channel = ieee80211_wiphy_get_channel, | ||
2975 | .set_noack_map = ieee80211_set_noack_map, | 3070 | .set_noack_map = ieee80211_set_noack_map, |
2976 | #ifdef CONFIG_PM | 3071 | #ifdef CONFIG_PM |
2977 | .set_wakeup = ieee80211_set_wakeup, | 3072 | .set_wakeup = ieee80211_set_wakeup, |
@@ -2979,4 +3074,5 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2979 | .get_et_sset_count = ieee80211_get_et_sset_count, | 3074 | .get_et_sset_count = ieee80211_get_et_sset_count, |
2980 | .get_et_stats = ieee80211_get_et_stats, | 3075 | .get_et_stats = ieee80211_get_et_stats, |
2981 | .get_et_strings = ieee80211_get_et_strings, | 3076 | .get_et_strings = ieee80211_get_et_strings, |
3077 | .get_channel = ieee80211_cfg_get_channel, | ||
2982 | }; | 3078 | }; |