diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 83 |
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 | ||
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 | |||
1596 | static int ieee80211_remain_on_channel(struct wiphy *wiphy, | 1627 | static 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 | ||
1653 | static 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 | |||
1609 | static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | 1675 | static 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 | ||