diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-12-18 20:03:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:09:38 -0500 |
commit | 5dfdaf58d61f06a458529430c24b1191ea4d1a27 (patch) | |
tree | bd3fac57f66e80bf2a31d253af19093f4020ba79 /net/mac80211/tx.c | |
parent | 51fb61e76d952e6bc2fbdd9f0d38425fbab1cf31 (diff) |
mac80211: add beacon configuration via cfg80211
This patch implements the cfg80211 hooks for configuring beaconing
on an access point interface in mac80211. While doing so, it fixes
a number of races that could badly crash the machine when the
beacon is changed while being requested by the driver.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 65 |
1 files changed, 40 insertions, 25 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 99590e4ce30b..51c0f00d02d1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1628,7 +1628,8 @@ void ieee80211_tx_pending(unsigned long data) | |||
1628 | 1628 | ||
1629 | static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | 1629 | static void ieee80211_beacon_add_tim(struct ieee80211_local *local, |
1630 | struct ieee80211_if_ap *bss, | 1630 | struct ieee80211_if_ap *bss, |
1631 | struct sk_buff *skb) | 1631 | struct sk_buff *skb, |
1632 | struct beacon_data *beacon) | ||
1632 | { | 1633 | { |
1633 | u8 *pos, *tim; | 1634 | u8 *pos, *tim; |
1634 | int aid0 = 0; | 1635 | int aid0 = 0; |
@@ -1644,7 +1645,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1644 | IEEE80211_MAX_AID+1); | 1645 | IEEE80211_MAX_AID+1); |
1645 | 1646 | ||
1646 | if (bss->dtim_count == 0) | 1647 | if (bss->dtim_count == 0) |
1647 | bss->dtim_count = bss->dtim_period - 1; | 1648 | bss->dtim_count = beacon->dtim_period - 1; |
1648 | else | 1649 | else |
1649 | bss->dtim_count--; | 1650 | bss->dtim_count--; |
1650 | 1651 | ||
@@ -1652,7 +1653,7 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
1652 | *pos++ = WLAN_EID_TIM; | 1653 | *pos++ = WLAN_EID_TIM; |
1653 | *pos++ = 4; | 1654 | *pos++ = 4; |
1654 | *pos++ = bss->dtim_count; | 1655 | *pos++ = bss->dtim_count; |
1655 | *pos++ = bss->dtim_period; | 1656 | *pos++ = beacon->dtim_period; |
1656 | 1657 | ||
1657 | if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) | 1658 | if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) |
1658 | aid0 = 1; | 1659 | aid0 = 1; |
@@ -1700,44 +1701,43 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1700 | struct ieee80211_sub_if_data *sdata = NULL; | 1701 | struct ieee80211_sub_if_data *sdata = NULL; |
1701 | struct ieee80211_if_ap *ap = NULL; | 1702 | struct ieee80211_if_ap *ap = NULL; |
1702 | struct rate_selection rsel; | 1703 | struct rate_selection rsel; |
1703 | u8 *b_head, *b_tail; | 1704 | struct beacon_data *beacon; |
1704 | int bh_len, bt_len; | 1705 | |
1706 | rcu_read_lock(); | ||
1705 | 1707 | ||
1706 | sdata = vif_to_sdata(vif); | 1708 | sdata = vif_to_sdata(vif); |
1707 | bdev = sdata->dev; | 1709 | bdev = sdata->dev; |
1708 | ap = &sdata->u.ap; | 1710 | ap = &sdata->u.ap; |
1709 | 1711 | ||
1710 | if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || | 1712 | beacon = rcu_dereference(ap->beacon); |
1711 | !ap->beacon_head) { | 1713 | |
1714 | if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) { | ||
1712 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1715 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1713 | if (net_ratelimit()) | 1716 | if (net_ratelimit()) |
1714 | printk(KERN_DEBUG "no beacon data avail for %s\n", | 1717 | printk(KERN_DEBUG "no beacon data avail for %s\n", |
1715 | bdev->name); | 1718 | bdev->name); |
1716 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 1719 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
1717 | return NULL; | 1720 | skb = NULL; |
1721 | goto out; | ||
1718 | } | 1722 | } |
1719 | 1723 | ||
1720 | /* Assume we are generating the normal beacon locally */ | 1724 | /* headroom, head length, tail length and maximum TIM length */ |
1721 | b_head = ap->beacon_head; | 1725 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + |
1722 | b_tail = ap->beacon_tail; | 1726 | beacon->tail_len + 256); |
1723 | bh_len = ap->beacon_head_len; | ||
1724 | bt_len = ap->beacon_tail_len; | ||
1725 | |||
1726 | skb = dev_alloc_skb(local->tx_headroom + | ||
1727 | bh_len + bt_len + 256 /* maximum TIM len */); | ||
1728 | if (!skb) | 1727 | if (!skb) |
1729 | return NULL; | 1728 | goto out; |
1730 | 1729 | ||
1731 | skb_reserve(skb, local->tx_headroom); | 1730 | skb_reserve(skb, local->tx_headroom); |
1732 | memcpy(skb_put(skb, bh_len), b_head, bh_len); | 1731 | memcpy(skb_put(skb, beacon->head_len), beacon->head, |
1732 | beacon->head_len); | ||
1733 | 1733 | ||
1734 | ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); | 1734 | ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); |
1735 | 1735 | ||
1736 | ieee80211_beacon_add_tim(local, ap, skb); | 1736 | ieee80211_beacon_add_tim(local, ap, skb, beacon); |
1737 | 1737 | ||
1738 | if (b_tail) { | 1738 | if (beacon->tail) |
1739 | memcpy(skb_put(skb, bt_len), b_tail, bt_len); | 1739 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, |
1740 | } | 1740 | beacon->tail_len); |
1741 | 1741 | ||
1742 | if (control) { | 1742 | if (control) { |
1743 | rate_control_get_rate(local->mdev, local->oper_hw_mode, skb, | 1743 | rate_control_get_rate(local->mdev, local->oper_hw_mode, skb, |
@@ -1749,7 +1749,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1749 | wiphy_name(local->hw.wiphy)); | 1749 | wiphy_name(local->hw.wiphy)); |
1750 | } | 1750 | } |
1751 | dev_kfree_skb(skb); | 1751 | dev_kfree_skb(skb); |
1752 | return NULL; | 1752 | skb = NULL; |
1753 | goto out; | ||
1753 | } | 1754 | } |
1754 | 1755 | ||
1755 | control->tx_rate = | 1756 | control->tx_rate = |
@@ -1764,6 +1765,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1764 | } | 1765 | } |
1765 | 1766 | ||
1766 | ap->num_beacons++; | 1767 | ap->num_beacons++; |
1768 | |||
1769 | out: | ||
1770 | rcu_read_unlock(); | ||
1767 | return skb; | 1771 | return skb; |
1768 | } | 1772 | } |
1769 | EXPORT_SYMBOL(ieee80211_beacon_get); | 1773 | EXPORT_SYMBOL(ieee80211_beacon_get); |
@@ -1815,13 +1819,24 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
1815 | struct net_device *bdev; | 1819 | struct net_device *bdev; |
1816 | struct ieee80211_sub_if_data *sdata; | 1820 | struct ieee80211_sub_if_data *sdata; |
1817 | struct ieee80211_if_ap *bss = NULL; | 1821 | struct ieee80211_if_ap *bss = NULL; |
1822 | struct beacon_data *beacon; | ||
1818 | 1823 | ||
1819 | sdata = vif_to_sdata(vif); | 1824 | sdata = vif_to_sdata(vif); |
1820 | bdev = sdata->dev; | 1825 | bdev = sdata->dev; |
1821 | 1826 | ||
1822 | if (!bss || sdata->vif.type != IEEE80211_IF_TYPE_AP || | 1827 | |
1823 | !bss->beacon_head) | 1828 | if (!bss) |
1829 | return NULL; | ||
1830 | |||
1831 | rcu_read_lock(); | ||
1832 | beacon = rcu_dereference(bss->beacon); | ||
1833 | |||
1834 | if (sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon || | ||
1835 | !beacon->head) { | ||
1836 | rcu_read_unlock(); | ||
1824 | return NULL; | 1837 | return NULL; |
1838 | } | ||
1839 | rcu_read_unlock(); | ||
1825 | 1840 | ||
1826 | if (bss->dtim_count != 0) | 1841 | if (bss->dtim_count != 0) |
1827 | return NULL; /* send buffered bc/mc only after DTIM beacon */ | 1842 | return NULL; /* send buffered bc/mc only after DTIM beacon */ |