mac80211: use nullfunc frames for 4-addr sta detection
PATCH 1/3 mac80211: use nullfunc frames for 4-addr sta detection
To detect incoming 4-addr stations, hostapd needs to receive a 4-addr data frame from the remote station, so that it can create the AP VLAN for it. With this patch, the mlme code emits a 4-addr nullfunc frame immediately after assoc. On the AP side it also drops 4-addr nullfunc frames to the cooked monitor mode interface, if the interface hasn't been fully set up to receive 4-addr data frames yet.
---
net/mac80211/mlme.c +39 -0
@@ -312,6 +312,38 @@ void ieee80211_send_nullfunc(struct ieeeieee80211_tx_skb (sdata, skb); } +static void ieee80211_send_4addr_nullfunc (struct ieee80211_local *local, +struct ieee80211_sub_if_data *sdata) +{ +struct sk_buff *skb; +struct ieee80211_hdr *nullfunc; +__le16 fc; + +if (WARN_ON (sdata->vif.type !=NL80211_IFTYPE_STATION )) +return ; + + skb =dev_alloc_skb (local->hw.extra_tx_headroom +30 ); +if (!skb) { +printk (KERN_DEBUG "%s: failed to allocate buffer for 4addr " +"nullfunc frame\n" , sdata->name); +return ; + } +skb_reserve (skb, local->hw.extra_tx_headroom); + + nullfunc = (struct ieee80211_hdr *)skb_put (skb,30 ); +memset (nullfunc,0 ,30 ); + fc =cpu_to_le16 (IEEE80211_FTYPE_DATA |IEEE80211_STYPE_NULLFUNC | +IEEE80211_FCTL_FROMDS |IEEE80211_FCTL_TODS ); + nullfunc->frame_control = fc; +memcpy (nullfunc->addr1, sdata->u.mgd.bssid,ETH_ALEN ); +memcpy (nullfunc->addr2, sdata->vif.addr,ETH_ALEN ); +memcpy (nullfunc->addr3, sdata->u.mgd.bssid,ETH_ALEN ); +memcpy (nullfunc->addr4, sdata->vif.addr,ETH_ALEN ); + +IEEE80211_SKB_CB (skb)->flags |=IEEE80211_TX_INTFL_DONT_ENCRYPT ; +ieee80211_tx_skb (sdata, skb); +} +/* spectrum management related things */ static void ieee80211_chswitch_work (struct work_struct *work) {
@@ -1120,6 +1152,13 @@ static bool ieee80211_assoc_success(struieee80211_set_associated (sdata, cbss, changed);/* +* If we're using 4-addr mode, let the AP know that we're +* doing so, so that it can create the STA VLAN on its side +*/ +if (ifmgd->use_4addr) +ieee80211_send_4addr_nullfunc (local, sdata); + +/* * Start timer to probe the connection to the AP now. * Also start the timer that will detect beacon loss. */
net/mac80211/rx.c +12 -0
@@ -1111,6 +1111,18 @@ ieee80211_rx_h_sta_process(struct ieee80if (ieee80211_is_nullfunc (hdr->frame_control) ||ieee80211_is_qos_nullfunc (hdr->frame_control)) {I802_DEBUG_INC (rx->local->rx_handlers_drop_nullfunc); + +/* +* If we receive a 4-addr nullfunc frame from a STA +* that was not moved to a 4-addr STA vlan yet, drop +* the frame to the monitor interface, to make sure +* that hostapd sees it +*/ +if (ieee80211_has_a4 (hdr->frame_control) && + (rx->sdata->vif.type ==NL80211_IFTYPE_AP || + (rx->sdata->vif.type ==NL80211_IFTYPE_AP_VLAN && + !rx->sdata->u.vlan.sta))) +return RX_DROP_MONITOR ;/* * Update counter and free packet here to avoid * counting this as a dropped packed.
PATCH 2/3 mac80211: allow station updates on ap interfaces for vlan stations
Since the per-vif station changes, sta_info_get on the ap sdata no longer returns entries for stations on ap vlans. This causes issues with hostapd, which currently always passes the ap interface name to nl80211 calls. This patch provides bug compatibility with the earlier versions until hostapd is fixed.
---
net/mac80211/sta_info.c +21 -0
@@ -119,6 +119,27 @@ struct sta_info *sta_info_get(struct ieereturn sta; } +/* +* Get sta info either from the specified interface +* or from one of its vlans +*/ +struct sta_info *sta_info_get_bss (struct ieee80211_sub_if_data *sdata, +const u8 *addr) +{ +struct ieee80211_local *local = sdata->local; +struct sta_info *sta; + + sta =rcu_dereference (local->sta_hash[STA_HASH (addr)]); +while (sta) { +if ((sta->sdata == sdata || + sta->sdata->bss == sdata->bss) && +memcmp (sta->sta.addr, addr,ETH_ALEN ) ==0 ) +break ; + sta =rcu_dereference (sta->hnext); + } +return sta; +} +struct sta_info *sta_info_get_by_idx (struct ieee80211_sub_if_data *sdata,int idx) {
net/mac80211/sta_info.h +3 -0
@@ -408,6 +408,9 @@ static inline u32 get_sta_flags(struct sstruct sta_info *sta_info_get (struct ieee80211_sub_if_data *sdata,const u8 *addr); +struct sta_info *sta_info_get_bss (struct ieee80211_sub_if_data *sdata, +const u8 *addr); + static inline void for_each_sta_info_type_check(struct ieee80211_local *local, const u8 *addr,
net/mac80211/cfg.c +6 -6
@@ -148,7 +148,7 @@ static int ieee80211_add_key(struct wiphrcu_read_lock ();if (mac_addr) { - sta =sta_info_get (sdata, mac_addr); + sta =sta_info_get_bss (sdata, mac_addr);if (!sta) {ieee80211_key_free (key); err = -ENOENT ;
@@ -179,7 +179,7 @@ static int ieee80211_del_key(struct wiphif (mac_addr) { ret = -ENOENT ; - sta =sta_info_get (sdata, mac_addr); + sta =sta_info_get_bss (sdata, mac_addr);if (!sta) goto out_unlock;
@@ -226,7 +226,7 @@ static int ieee80211_get_key(struct wiphrcu_read_lock ();if (mac_addr) { - sta =sta_info_get (sdata, mac_addr); + sta =sta_info_get_bss (sdata, mac_addr);if (!sta) goto out;
@@ -419,7 +419,7 @@ static int ieee80211_get_station(structrcu_read_lock (); - sta =sta_info_get (sdata, mac); + sta =sta_info_get_bss (sdata, mac);if (sta) { ret =0 ;sta_set_sinfo (sta, sinfo);
@@ -775,7 +775,7 @@ static int ieee80211_del_station(structif (mac) {rcu_read_lock (); - sta =sta_info_get (sdata, mac); + sta =sta_info_get_bss (sdata, mac);if (!sta) {rcu_read_unlock ();return -ENOENT ;
@@ -803,7 +803,7 @@ static int ieee80211_change_station(strurcu_read_lock (); - sta =sta_info_get (sdata, mac); + sta =sta_info_get_bss (sdata, mac);if (!sta) {rcu_read_unlock ();return -ENOENT ;
PATCH 3/3 mac80211: do not transmit frames on unconfigured 4-addr vlan interfaces
If frames are transmitted on 4-addr ap vlan interfaces with no station, they end up being transmitted unencrypted, even if the ap interface uses WPA. This patch add some sanity checking to make sure that this does not happen.
---
net/mac80211/tx.c +4 -1
@@ -1051,8 +1051,11 @@ ieee80211_tx_prepare(struct ieee80211_su hdr = (struct ieee80211_hdr *) skb->data; -if (sdata->vif.type ==NL80211_IFTYPE_AP_VLAN ) +if (sdata->vif.type ==NL80211_IFTYPE_AP_VLAN ) { tx->sta =rcu_dereference (sdata->u.vlan.sta); +if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) +return TX_DROP ; + }if (!tx->sta) tx->sta =sta_info_get (sdata, hdr->addr1);