aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r--net/mac80211/cfg.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5892b0302454..168a6ba8fc28 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1593,6 +1593,37 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
1593 return 0; 1593 return 0;
1594} 1594}
1595 1595
1596static 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
1596static int ieee80211_remain_on_channel(struct wiphy *wiphy, 1627static int ieee80211_remain_on_channel(struct wiphy *wiphy,
1597 struct net_device *dev, 1628 struct net_device *dev,
1598 struct ieee80211_channel *chan, 1629 struct ieee80211_channel *chan,
@@ -1601,16 +1632,62 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
1601 u64 *cookie) 1632 u64 *cookie)
1602{ 1633{
1603 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 mutex_unlock(&local->mtx);
1645
1646 return ret;
1647 }
1604 1648
1605 return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, 1649 return ieee80211_wk_remain_on_channel(sdata, chan, channel_type,
1606 duration, cookie); 1650 duration, cookie);
1607} 1651}
1608 1652
1653static int ieee80211_cancel_remain_on_channel_hw(struct ieee80211_local *local,
1654 u64 cookie)
1655{
1656 int ret;
1657
1658 lockdep_assert_held(&local->mtx);
1659
1660 if (local->hw_roc_cookie != cookie)
1661 return -ENOENT;
1662
1663 ret = drv_cancel_remain_on_channel(local);
1664 if (ret)
1665 return ret;
1666
1667 local->hw_roc_cookie = 0;
1668 local->hw_roc_channel = NULL;
1669
1670 ieee80211_recalc_idle(local);
1671
1672 return 0;
1673}
1674
1609static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, 1675static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
1610 struct net_device *dev, 1676 struct net_device *dev,
1611 u64 cookie) 1677 u64 cookie)
1612{ 1678{
1613 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1679 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1680 struct ieee80211_local *local = sdata->local;
1681
1682 if (local->ops->cancel_remain_on_channel) {
1683 int ret;
1684
1685 mutex_lock(&local->mtx);
1686 ret = ieee80211_cancel_remain_on_channel_hw(local, cookie);
1687 mutex_unlock(&local->mtx);
1688
1689 return ret;
1690 }
1614 1691
1615 return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); 1692 return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
1616} 1693}
@@ -1662,6 +1739,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1662 channel_type != local->_oper_channel_type)) 1739 channel_type != local->_oper_channel_type))
1663 is_offchan = true; 1740 is_offchan = true;
1664 1741
1742 if (chan == local->hw_roc_channel) {
1743 /* TODO: check channel type? */
1744 is_offchan = false;
1745 flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
1746 }
1747
1665 if (is_offchan && !offchan) 1748 if (is_offchan && !offchan)
1666 return -EBUSY; 1749 return -EBUSY;
1667 1750