diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 373 |
1 files changed, 347 insertions, 26 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 18bd0e550600..4bc8a9250cfd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -19,9 +19,10 @@ | |||
19 | #include "rate.h" | 19 | #include "rate.h" |
20 | #include "mesh.h" | 20 | #include "mesh.h" |
21 | 21 | ||
22 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 22 | static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, |
23 | enum nl80211_iftype type, u32 *flags, | 23 | enum nl80211_iftype type, |
24 | struct vif_params *params) | 24 | u32 *flags, |
25 | struct vif_params *params) | ||
25 | { | 26 | { |
26 | struct ieee80211_local *local = wiphy_priv(wiphy); | 27 | struct ieee80211_local *local = wiphy_priv(wiphy); |
27 | struct net_device *dev; | 28 | struct net_device *dev; |
@@ -29,12 +30,15 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
29 | int err; | 30 | int err; |
30 | 31 | ||
31 | err = ieee80211_if_add(local, name, &dev, type, params); | 32 | err = ieee80211_if_add(local, name, &dev, type, params); |
32 | if (err || type != NL80211_IFTYPE_MONITOR || !flags) | 33 | if (err) |
33 | return err; | 34 | return ERR_PTR(err); |
34 | 35 | ||
35 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 36 | if (type == NL80211_IFTYPE_MONITOR && flags) { |
36 | sdata->u.mntr_flags = *flags; | 37 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
37 | return 0; | 38 | sdata->u.mntr_flags = *flags; |
39 | } | ||
40 | |||
41 | return dev; | ||
38 | } | 42 | } |
39 | 43 | ||
40 | static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) | 44 | static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) |
@@ -56,11 +60,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
56 | if (ret) | 60 | if (ret) |
57 | return ret; | 61 | return ret; |
58 | 62 | ||
59 | if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) | ||
60 | ieee80211_sdata_set_mesh_id(sdata, | ||
61 | params->mesh_id_len, | ||
62 | params->mesh_id); | ||
63 | |||
64 | if (type == NL80211_IFTYPE_AP_VLAN && | 63 | if (type == NL80211_IFTYPE_AP_VLAN && |
65 | params && params->use_4addr == 0) | 64 | params && params->use_4addr == 0) |
66 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | 65 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); |
@@ -296,11 +295,12 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
296 | 295 | ||
297 | static int ieee80211_config_default_key(struct wiphy *wiphy, | 296 | static int ieee80211_config_default_key(struct wiphy *wiphy, |
298 | struct net_device *dev, | 297 | struct net_device *dev, |
299 | u8 key_idx) | 298 | u8 key_idx, bool uni, |
299 | bool multi) | ||
300 | { | 300 | { |
301 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 301 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
302 | 302 | ||
303 | ieee80211_set_default_key(sdata, key_idx); | 303 | ieee80211_set_default_key(sdata, key_idx, uni, multi); |
304 | 304 | ||
305 | return 0; | 305 | return 0; |
306 | } | 306 | } |
@@ -343,8 +343,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
343 | 343 | ||
344 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || | 344 | if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || |
345 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { | 345 | (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { |
346 | sinfo->filled |= STATION_INFO_SIGNAL; | 346 | sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; |
347 | sinfo->signal = (s8)sta->last_signal; | 347 | sinfo->signal = (s8)sta->last_signal; |
348 | sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); | ||
348 | } | 349 | } |
349 | 350 | ||
350 | sinfo->txrate.flags = 0; | 351 | sinfo->txrate.flags = 0; |
@@ -983,7 +984,7 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
983 | return 0; | 984 | return 0; |
984 | } | 985 | } |
985 | 986 | ||
986 | static int ieee80211_get_mesh_params(struct wiphy *wiphy, | 987 | static int ieee80211_get_mesh_config(struct wiphy *wiphy, |
987 | struct net_device *dev, | 988 | struct net_device *dev, |
988 | struct mesh_config *conf) | 989 | struct mesh_config *conf) |
989 | { | 990 | { |
@@ -999,9 +1000,39 @@ static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask) | |||
999 | return (mask >> (parm-1)) & 0x1; | 1000 | return (mask >> (parm-1)) & 0x1; |
1000 | } | 1001 | } |
1001 | 1002 | ||
1002 | static int ieee80211_set_mesh_params(struct wiphy *wiphy, | 1003 | static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh, |
1003 | struct net_device *dev, | 1004 | const struct mesh_setup *setup) |
1004 | const struct mesh_config *nconf, u32 mask) | 1005 | { |
1006 | u8 *new_ie; | ||
1007 | const u8 *old_ie; | ||
1008 | |||
1009 | /* first allocate the new vendor information element */ | ||
1010 | new_ie = NULL; | ||
1011 | old_ie = ifmsh->vendor_ie; | ||
1012 | |||
1013 | ifmsh->vendor_ie_len = setup->vendor_ie_len; | ||
1014 | if (setup->vendor_ie_len) { | ||
1015 | new_ie = kmemdup(setup->vendor_ie, setup->vendor_ie_len, | ||
1016 | GFP_KERNEL); | ||
1017 | if (!new_ie) | ||
1018 | return -ENOMEM; | ||
1019 | } | ||
1020 | |||
1021 | /* now copy the rest of the setup parameters */ | ||
1022 | ifmsh->mesh_id_len = setup->mesh_id_len; | ||
1023 | memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len); | ||
1024 | ifmsh->mesh_pp_id = setup->path_sel_proto; | ||
1025 | ifmsh->mesh_pm_id = setup->path_metric; | ||
1026 | ifmsh->vendor_ie = new_ie; | ||
1027 | |||
1028 | kfree(old_ie); | ||
1029 | |||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | static int ieee80211_update_mesh_config(struct wiphy *wiphy, | ||
1034 | struct net_device *dev, u32 mask, | ||
1035 | const struct mesh_config *nconf) | ||
1005 | { | 1036 | { |
1006 | struct mesh_config *conf; | 1037 | struct mesh_config *conf; |
1007 | struct ieee80211_sub_if_data *sdata; | 1038 | struct ieee80211_sub_if_data *sdata; |
@@ -1024,6 +1055,8 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1024 | conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; | 1055 | conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; |
1025 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) | 1056 | if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) |
1026 | conf->dot11MeshTTL = nconf->dot11MeshTTL; | 1057 | conf->dot11MeshTTL = nconf->dot11MeshTTL; |
1058 | if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) | ||
1059 | conf->dot11MeshTTL = nconf->element_ttl; | ||
1027 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) | 1060 | if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) |
1028 | conf->auto_open_plinks = nconf->auto_open_plinks; | 1061 | conf->auto_open_plinks = nconf->auto_open_plinks; |
1029 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) | 1062 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) |
@@ -1050,6 +1083,31 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1050 | return 0; | 1083 | return 0; |
1051 | } | 1084 | } |
1052 | 1085 | ||
1086 | static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, | ||
1087 | const struct mesh_config *conf, | ||
1088 | const struct mesh_setup *setup) | ||
1089 | { | ||
1090 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1091 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
1092 | int err; | ||
1093 | |||
1094 | memcpy(&ifmsh->mshcfg, conf, sizeof(struct mesh_config)); | ||
1095 | err = copy_mesh_setup(ifmsh, setup); | ||
1096 | if (err) | ||
1097 | return err; | ||
1098 | ieee80211_start_mesh(sdata); | ||
1099 | |||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) | ||
1104 | { | ||
1105 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1106 | |||
1107 | ieee80211_stop_mesh(sdata); | ||
1108 | |||
1109 | return 0; | ||
1110 | } | ||
1053 | #endif | 1111 | #endif |
1054 | 1112 | ||
1055 | static int ieee80211_change_bss(struct wiphy *wiphy, | 1113 | static int ieee80211_change_bss(struct wiphy *wiphy, |
@@ -1108,6 +1166,12 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1108 | sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS; | 1166 | sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS; |
1109 | } | 1167 | } |
1110 | 1168 | ||
1169 | if (params->ht_opmode >= 0) { | ||
1170 | sdata->vif.bss_conf.ht_operation_mode = | ||
1171 | (u16) params->ht_opmode; | ||
1172 | changed |= BSS_CHANGED_HT; | ||
1173 | } | ||
1174 | |||
1111 | ieee80211_bss_info_change_notify(sdata, changed); | 1175 | ieee80211_bss_info_change_notify(sdata, changed); |
1112 | 1176 | ||
1113 | return 0; | 1177 | return 0; |
@@ -1299,6 +1363,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) | |||
1299 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1363 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1300 | int err; | 1364 | int err; |
1301 | 1365 | ||
1366 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { | ||
1367 | err = drv_set_frag_threshold(local, wiphy->frag_threshold); | ||
1368 | |||
1369 | if (err) | ||
1370 | return err; | ||
1371 | } | ||
1372 | |||
1302 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) { | 1373 | if (changed & WIPHY_PARAM_COVERAGE_CLASS) { |
1303 | err = drv_set_coverage_class(local, wiphy->coverage_class); | 1374 | err = drv_set_coverage_class(local, wiphy->coverage_class); |
1304 | 1375 | ||
@@ -1522,6 +1593,37 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | |||
1522 | return 0; | 1593 | return 0; |
1523 | } | 1594 | } |
1524 | 1595 | ||
1596 | static int ieee80211_remain_on_channel_hw(struct ieee80211_local *local, | ||
1597 | struct net_device *dev, | ||
1598 | struct ieee80211_channel *chan, | ||
1599 | enum nl80211_channel_type chantype, | ||
1600 | unsigned int duration, u64 *cookie) | ||
1601 | { | ||
1602 | int ret; | ||
1603 | u32 random_cookie; | ||
1604 | |||
1605 | lockdep_assert_held(&local->mtx); | ||
1606 | |||
1607 | if (local->hw_roc_cookie) | ||
1608 | return -EBUSY; | ||
1609 | /* must be nonzero */ | ||
1610 | random_cookie = random32() | 1; | ||
1611 | |||
1612 | *cookie = random_cookie; | ||
1613 | local->hw_roc_dev = dev; | ||
1614 | local->hw_roc_cookie = random_cookie; | ||
1615 | local->hw_roc_channel = chan; | ||
1616 | local->hw_roc_channel_type = chantype; | ||
1617 | local->hw_roc_duration = duration; | ||
1618 | ret = drv_remain_on_channel(local, chan, chantype, duration); | ||
1619 | if (ret) { | ||
1620 | local->hw_roc_channel = NULL; | ||
1621 | local->hw_roc_cookie = 0; | ||
1622 | } | ||
1623 | |||
1624 | return ret; | ||
1625 | } | ||
1626 | |||
1525 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, | 1627 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, |
1526 | struct net_device *dev, | 1628 | struct net_device *dev, |
1527 | struct ieee80211_channel *chan, | 1629 | struct ieee80211_channel *chan, |
@@ -1530,41 +1632,121 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy, | |||
1530 | u64 *cookie) | 1632 | u64 *cookie) |
1531 | { | 1633 | { |
1532 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1634 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1635 | struct ieee80211_local *local = sdata->local; | ||
1636 | |||
1637 | if (local->ops->remain_on_channel) { | ||
1638 | int ret; | ||
1639 | |||
1640 | mutex_lock(&local->mtx); | ||
1641 | ret = ieee80211_remain_on_channel_hw(local, dev, | ||
1642 | chan, channel_type, | ||
1643 | duration, cookie); | ||
1644 | local->hw_roc_for_tx = false; | ||
1645 | mutex_unlock(&local->mtx); | ||
1646 | |||
1647 | return ret; | ||
1648 | } | ||
1533 | 1649 | ||
1534 | return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, | 1650 | return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, |
1535 | duration, cookie); | 1651 | duration, cookie); |
1536 | } | 1652 | } |
1537 | 1653 | ||
1654 | static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local, | ||
1655 | u64 cookie) | ||
1656 | { | ||
1657 | int ret; | ||
1658 | |||
1659 | lockdep_assert_held(&local->mtx); | ||
1660 | |||
1661 | if (local->hw_roc_cookie != cookie) | ||
1662 | return -ENOENT; | ||
1663 | |||
1664 | ret = drv_cancel_remain_on_channel(local); | ||
1665 | if (ret) | ||
1666 | return ret; | ||
1667 | |||
1668 | local->hw_roc_cookie = 0; | ||
1669 | local->hw_roc_channel = NULL; | ||
1670 | |||
1671 | ieee80211_recalc_idle(local); | ||
1672 | |||
1673 | return 0; | ||
1674 | } | ||
1675 | |||
1538 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | 1676 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, |
1539 | struct net_device *dev, | 1677 | struct net_device *dev, |
1540 | u64 cookie) | 1678 | u64 cookie) |
1541 | { | 1679 | { |
1542 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1680 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1681 | struct ieee80211_local *local = sdata->local; | ||
1682 | |||
1683 | if (local->ops->cancel_remain_on_channel) { | ||
1684 | int ret; | ||
1685 | |||
1686 | mutex_lock(&local->mtx); | ||
1687 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); | ||
1688 | mutex_unlock(&local->mtx); | ||
1689 | |||
1690 | return ret; | ||
1691 | } | ||
1543 | 1692 | ||
1544 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | 1693 | return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); |
1545 | } | 1694 | } |
1546 | 1695 | ||
1696 | static enum work_done_result | ||
1697 | ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb) | ||
1698 | { | ||
1699 | /* | ||
1700 | * Use the data embedded in the work struct for reporting | ||
1701 | * here so if the driver mangled the SKB before dropping | ||
1702 | * it (which is the only way we really should get here) | ||
1703 | * then we don't report mangled data. | ||
1704 | * | ||
1705 | * If there was no wait time, then by the time we get here | ||
1706 | * the driver will likely not have reported the status yet, | ||
1707 | * so in that case userspace will have to deal with it. | ||
1708 | */ | ||
1709 | |||
1710 | if (wk->offchan_tx.wait && wk->offchan_tx.frame) | ||
1711 | cfg80211_mgmt_tx_status(wk->sdata->dev, | ||
1712 | (unsigned long) wk->offchan_tx.frame, | ||
1713 | wk->ie, wk->ie_len, false, GFP_KERNEL); | ||
1714 | |||
1715 | return WORK_DONE_DESTROY; | ||
1716 | } | ||
1717 | |||
1547 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | 1718 | static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, |
1548 | struct ieee80211_channel *chan, | 1719 | struct ieee80211_channel *chan, bool offchan, |
1549 | enum nl80211_channel_type channel_type, | 1720 | enum nl80211_channel_type channel_type, |
1550 | bool channel_type_valid, | 1721 | bool channel_type_valid, unsigned int wait, |
1551 | const u8 *buf, size_t len, u64 *cookie) | 1722 | const u8 *buf, size_t len, u64 *cookie) |
1552 | { | 1723 | { |
1553 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1724 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1554 | struct ieee80211_local *local = sdata->local; | 1725 | struct ieee80211_local *local = sdata->local; |
1555 | struct sk_buff *skb; | 1726 | struct sk_buff *skb; |
1556 | struct sta_info *sta; | 1727 | struct sta_info *sta; |
1728 | struct ieee80211_work *wk; | ||
1557 | const struct ieee80211_mgmt *mgmt = (void *)buf; | 1729 | const struct ieee80211_mgmt *mgmt = (void *)buf; |
1558 | u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | | 1730 | u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | |
1559 | IEEE80211_TX_CTL_REQ_TX_STATUS; | 1731 | IEEE80211_TX_CTL_REQ_TX_STATUS; |
1732 | bool is_offchan = false; | ||
1560 | 1733 | ||
1561 | /* Check that we are on the requested channel for transmission */ | 1734 | /* Check that we are on the requested channel for transmission */ |
1562 | if (chan != local->tmp_channel && | 1735 | if (chan != local->tmp_channel && |
1563 | chan != local->oper_channel) | 1736 | chan != local->oper_channel) |
1564 | return -EBUSY; | 1737 | is_offchan = true; |
1565 | if (channel_type_valid && | 1738 | if (channel_type_valid && |
1566 | (channel_type != local->tmp_channel_type && | 1739 | (channel_type != local->tmp_channel_type && |
1567 | channel_type != local->_oper_channel_type)) | 1740 | channel_type != local->_oper_channel_type)) |
1741 | is_offchan = true; | ||
1742 | |||
1743 | if (chan == local->hw_roc_channel) { | ||
1744 | /* TODO: check channel type? */ | ||
1745 | is_offchan = false; | ||
1746 | flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | ||
1747 | } | ||
1748 | |||
1749 | if (is_offchan && !offchan) | ||
1568 | return -EBUSY; | 1750 | return -EBUSY; |
1569 | 1751 | ||
1570 | switch (sdata->vif.type) { | 1752 | switch (sdata->vif.type) { |
@@ -1572,6 +1754,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1572 | case NL80211_IFTYPE_AP: | 1754 | case NL80211_IFTYPE_AP: |
1573 | case NL80211_IFTYPE_AP_VLAN: | 1755 | case NL80211_IFTYPE_AP_VLAN: |
1574 | case NL80211_IFTYPE_P2P_GO: | 1756 | case NL80211_IFTYPE_P2P_GO: |
1757 | case NL80211_IFTYPE_MESH_POINT: | ||
1575 | if (!ieee80211_is_action(mgmt->frame_control) || | 1758 | if (!ieee80211_is_action(mgmt->frame_control) || |
1576 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) | 1759 | mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) |
1577 | break; | 1760 | break; |
@@ -1598,12 +1781,128 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1598 | IEEE80211_SKB_CB(skb)->flags = flags; | 1781 | IEEE80211_SKB_CB(skb)->flags = flags; |
1599 | 1782 | ||
1600 | skb->dev = sdata->dev; | 1783 | skb->dev = sdata->dev; |
1601 | ieee80211_tx_skb(sdata, skb); | ||
1602 | 1784 | ||
1603 | *cookie = (unsigned long) skb; | 1785 | *cookie = (unsigned long) skb; |
1786 | |||
1787 | if (is_offchan && local->ops->remain_on_channel) { | ||
1788 | unsigned int duration; | ||
1789 | int ret; | ||
1790 | |||
1791 | mutex_lock(&local->mtx); | ||
1792 | /* | ||
1793 | * If the duration is zero, then the driver | ||
1794 | * wouldn't actually do anything. Set it to | ||
1795 | * 100 for now. | ||
1796 | * | ||
1797 | * TODO: cancel the off-channel operation | ||
1798 | * when we get the SKB's TX status and | ||
1799 | * the wait time was zero before. | ||
1800 | */ | ||
1801 | duration = 100; | ||
1802 | if (wait) | ||
1803 | duration = wait; | ||
1804 | ret = ieee80211_remain_on_channel_hw(local, dev, chan, | ||
1805 | channel_type, | ||
1806 | duration, cookie); | ||
1807 | if (ret) { | ||
1808 | kfree_skb(skb); | ||
1809 | mutex_unlock(&local->mtx); | ||
1810 | return ret; | ||
1811 | } | ||
1812 | |||
1813 | local->hw_roc_for_tx = true; | ||
1814 | local->hw_roc_duration = wait; | ||
1815 | |||
1816 | /* | ||
1817 | * queue up frame for transmission after | ||
1818 | * ieee80211_ready_on_channel call | ||
1819 | */ | ||
1820 | |||
1821 | /* modify cookie to prevent API mismatches */ | ||
1822 | *cookie ^= 2; | ||
1823 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN; | ||
1824 | local->hw_roc_skb = skb; | ||
1825 | mutex_unlock(&local->mtx); | ||
1826 | |||
1827 | return 0; | ||
1828 | } | ||
1829 | |||
1830 | /* | ||
1831 | * Can transmit right away if the channel was the | ||
1832 | * right one and there's no wait involved... If a | ||
1833 | * wait is involved, we might otherwise not be on | ||
1834 | * the right channel for long enough! | ||
1835 | */ | ||
1836 | if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) { | ||
1837 | ieee80211_tx_skb(sdata, skb); | ||
1838 | return 0; | ||
1839 | } | ||
1840 | |||
1841 | wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL); | ||
1842 | if (!wk) { | ||
1843 | kfree_skb(skb); | ||
1844 | return -ENOMEM; | ||
1845 | } | ||
1846 | |||
1847 | wk->type = IEEE80211_WORK_OFFCHANNEL_TX; | ||
1848 | wk->chan = chan; | ||
1849 | wk->sdata = sdata; | ||
1850 | wk->done = ieee80211_offchan_tx_done; | ||
1851 | wk->offchan_tx.frame = skb; | ||
1852 | wk->offchan_tx.wait = wait; | ||
1853 | wk->ie_len = len; | ||
1854 | memcpy(wk->ie, buf, len); | ||
1855 | |||
1856 | ieee80211_add_work(wk); | ||
1604 | return 0; | 1857 | return 0; |
1605 | } | 1858 | } |
1606 | 1859 | ||
1860 | static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, | ||
1861 | struct net_device *dev, | ||
1862 | u64 cookie) | ||
1863 | { | ||
1864 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1865 | struct ieee80211_local *local = sdata->local; | ||
1866 | struct ieee80211_work *wk; | ||
1867 | int ret = -ENOENT; | ||
1868 | |||
1869 | mutex_lock(&local->mtx); | ||
1870 | |||
1871 | if (local->ops->cancel_remain_on_channel) { | ||
1872 | cookie ^= 2; | ||
1873 | ret = ieee80211_cancel_remain_on_channel_hw(local, cookie); | ||
1874 | |||
1875 | if (ret == 0) { | ||
1876 | kfree_skb(local->hw_roc_skb); | ||
1877 | local->hw_roc_skb = NULL; | ||
1878 | } | ||
1879 | |||
1880 | mutex_unlock(&local->mtx); | ||
1881 | |||
1882 | return ret; | ||
1883 | } | ||
1884 | |||
1885 | list_for_each_entry(wk, &local->work_list, list) { | ||
1886 | if (wk->sdata != sdata) | ||
1887 | continue; | ||
1888 | |||
1889 | if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX) | ||
1890 | continue; | ||
1891 | |||
1892 | if (cookie != (unsigned long) wk->offchan_tx.frame) | ||
1893 | continue; | ||
1894 | |||
1895 | wk->timeout = jiffies; | ||
1896 | |||
1897 | ieee80211_queue_work(&local->hw, &local->work_work); | ||
1898 | ret = 0; | ||
1899 | break; | ||
1900 | } | ||
1901 | mutex_unlock(&local->mtx); | ||
1902 | |||
1903 | return ret; | ||
1904 | } | ||
1905 | |||
1607 | static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, | 1906 | static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, |
1608 | struct net_device *dev, | 1907 | struct net_device *dev, |
1609 | u16 frame_type, bool reg) | 1908 | u16 frame_type, bool reg) |
@@ -1621,6 +1920,23 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, | |||
1621 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); | 1920 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); |
1622 | } | 1921 | } |
1623 | 1922 | ||
1923 | static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) | ||
1924 | { | ||
1925 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1926 | |||
1927 | if (local->started) | ||
1928 | return -EOPNOTSUPP; | ||
1929 | |||
1930 | return drv_set_antenna(local, tx_ant, rx_ant); | ||
1931 | } | ||
1932 | |||
1933 | static int ieee80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) | ||
1934 | { | ||
1935 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
1936 | |||
1937 | return drv_get_antenna(local, tx_ant, rx_ant); | ||
1938 | } | ||
1939 | |||
1624 | struct cfg80211_ops mac80211_config_ops = { | 1940 | struct cfg80211_ops mac80211_config_ops = { |
1625 | .add_virtual_intf = ieee80211_add_iface, | 1941 | .add_virtual_intf = ieee80211_add_iface, |
1626 | .del_virtual_intf = ieee80211_del_iface, | 1942 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1645,8 +1961,10 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1645 | .change_mpath = ieee80211_change_mpath, | 1961 | .change_mpath = ieee80211_change_mpath, |
1646 | .get_mpath = ieee80211_get_mpath, | 1962 | .get_mpath = ieee80211_get_mpath, |
1647 | .dump_mpath = ieee80211_dump_mpath, | 1963 | .dump_mpath = ieee80211_dump_mpath, |
1648 | .set_mesh_params = ieee80211_set_mesh_params, | 1964 | .update_mesh_config = ieee80211_update_mesh_config, |
1649 | .get_mesh_params = ieee80211_get_mesh_params, | 1965 | .get_mesh_config = ieee80211_get_mesh_config, |
1966 | .join_mesh = ieee80211_join_mesh, | ||
1967 | .leave_mesh = ieee80211_leave_mesh, | ||
1650 | #endif | 1968 | #endif |
1651 | .change_bss = ieee80211_change_bss, | 1969 | .change_bss = ieee80211_change_bss, |
1652 | .set_txq_params = ieee80211_set_txq_params, | 1970 | .set_txq_params = ieee80211_set_txq_params, |
@@ -1671,6 +1989,9 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1671 | .remain_on_channel = ieee80211_remain_on_channel, | 1989 | .remain_on_channel = ieee80211_remain_on_channel, |
1672 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, | 1990 | .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, |
1673 | .mgmt_tx = ieee80211_mgmt_tx, | 1991 | .mgmt_tx = ieee80211_mgmt_tx, |
1992 | .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait, | ||
1674 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, | 1993 | .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, |
1675 | .mgmt_frame_register = ieee80211_mgmt_frame_register, | 1994 | .mgmt_frame_register = ieee80211_mgmt_frame_register, |
1995 | .set_antenna = ieee80211_set_antenna, | ||
1996 | .get_antenna = ieee80211_get_antenna, | ||
1676 | }; | 1997 | }; |