* [PATCH 0/4] d80211: fix receiving
@ 2006-07-03 17:24 Jiri Benc
2006-07-03 17:24 ` [PATCH 1/4] d80211: better deallocation of mdev Jiri Benc
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw)
To: netdev
This patch series fixes receiving when multiple virtual interfaces are
active.
It is also available in a 'devel' branch of git tree at
git://git.kernel.org/pub/scm/linux/kernel/git/jbenc/dscape.git
--
Jiri Benc
SUSE Labs
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 1/4] d80211: better deallocation of mdev 2006-07-03 17:24 [PATCH 0/4] d80211: fix receiving Jiri Benc @ 2006-07-03 17:24 ` Jiri Benc 2006-07-03 17:24 ` [PATCH 2/4] d80211: fix receiving through virtual interfaces Jiri Benc ` (2 subsequent siblings) 3 siblings, 0 replies; 6+ messages in thread From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw) To: netdev Master device and ieee80211_local are allocated separately now, so master device can be freed by the same function as other virtual interfaces. Signed-off-by: Jiri Benc <jbenc@suse.cz> --- net/d80211/ieee80211.c | 2 +- net/d80211/ieee80211_iface.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) de609aa3e039b91ebebbec45d4bddd1134a71948 diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c index f1e42d4..fe1003b 100644 --- a/net/d80211/ieee80211.c +++ b/net/d80211/ieee80211.c @@ -4536,7 +4536,7 @@ void ieee80211_free_hw(struct net_device { struct ieee80211_local *local = dev->ieee80211_ptr; - free_netdev(dev); + ieee80211_if_free(dev); ieee80211_dev_free(local); } diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c index 5abd713..566bb36 100644 --- a/net/d80211/ieee80211_iface.c +++ b/net/d80211/ieee80211_iface.c @@ -337,7 +337,8 @@ void ieee80211_if_free(struct net_device { struct ieee80211_local *local = dev->ieee80211_ptr; - BUG_ON(dev == local->mdev || dev == local->apdev); + /* local->apdev must be NULL when freeing management interface */ + BUG_ON(dev == local->apdev); free_netdev(dev); } -- 1.3.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/4] d80211: fix receiving through virtual interfaces 2006-07-03 17:24 [PATCH 0/4] d80211: fix receiving Jiri Benc 2006-07-03 17:24 ` [PATCH 1/4] d80211: better deallocation of mdev Jiri Benc @ 2006-07-03 17:24 ` Jiri Benc 2006-07-04 18:05 ` Jiri Benc 2006-07-03 17:24 ` [PATCH 3/4] d80211: fix defragmentation Jiri Benc 2006-07-03 17:24 ` [PATCH 4/4] d80211: optimize defragmentation Jiri Benc 3 siblings, 1 reply; 6+ messages in thread From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw) To: netdev This fixes several problems with receiving when multiple interfaces are present or when some interface is in promiscious mode: - Packet type (PACKET_HOST and PACKET_OTHER_HOST) is set correctly now. - Failed decryption of a frame is reported only once for each frame. - Failed decryption of a frame not destined to the interface (e.g. when the interface is in promisc mode) is not reported. - Channel utilization is counted correctly (i.e. once for each frame only, independently on number of active virtual interfaces). To achieve this, ieee80211_rx_handlers needed to be separated into new ieee80211_rx_handlers and ieee80211_rx_pre_handlers structures. Defragmentation still doesn't work correctly in promisc mode. This is fixed by subsequent patches. Signed-off-by: Jiri Benc <jbenc@suse.cz> --- net/d80211/ieee80211.c | 171 +++++++++++++++++++++++++++++++--------------- net/d80211/ieee80211_i.h | 5 + net/d80211/wpa.c | 4 + 3 files changed, 124 insertions(+), 56 deletions(-) 6cc76c3c2c5de4e1ad40a8b82201eff5eab81939 diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c index fe1003b..52316f9 100644 --- a/net/d80211/ieee80211.c +++ b/net/d80211/ieee80211.c @@ -2463,27 +2463,15 @@ ieee80211_rx_h_data(struct ieee80211_txr memcpy(ehdr->h_source, src, ETH_ALEN); ehdr->h_proto = len; } - - if (rx->sta && !rx->sta->assoc_ap && - !(rx->sta && (rx->sta->flags & WLAN_STA_WDS))) - skb->dev = rx->sta->dev; - else - skb->dev = dev; + skb->dev = dev; skb2 = NULL; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - /* - * don't count the master since the low level code - * counts it already for us. - */ - if (skb->dev != sdata->master) { - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; - } + sdata->stats.rx_packets++; + sdata->stats.rx_bytes += skb->len; if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP - || sdata->type == IEEE80211_IF_TYPE_VLAN)) { + || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) { if (is_multicast_ether_addr(skb->data)) { /* send multicast frames both to higher layers in * local net stack and back to the wireless media */ @@ -2760,13 +2748,14 @@ #endif /* IEEE80211_VERBOSE_DEBUG_PS */ static ieee80211_txrx_result -ieee80211_rx_h_ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) { struct sk_buff *skb; int no_pending_pkts; if (likely(!rx->sta || WLAN_FC_GET_TYPE(rx->fc) != WLAN_FC_TYPE_CTRL || - WLAN_FC_GET_STYPE(rx->fc) != WLAN_FC_STYPE_PSPOLL)) + WLAN_FC_GET_STYPE(rx->fc) != WLAN_FC_STYPE_PSPOLL || + !rx->u.rx.ra_match)) return TXRX_CONTINUE; skb = skb_dequeue(&rx->sta->tx_filtered); @@ -3042,8 +3031,10 @@ ieee80211_rx_h_check(struct ieee80211_tx if (unlikely(rx->fc & WLAN_FC_RETRY && rx->sta->last_seq_ctrl[rx->u.rx.queue] == hdr->seq_ctrl)) { - rx->local->dot11FrameDuplicateCount++; - rx->sta->num_duplicates++; + if (rx->u.rx.ra_match) { + rx->local->dot11FrameDuplicateCount++; + rx->sta->num_duplicates++; + } return TXRX_DROP; } else rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; @@ -3057,7 +3048,9 @@ ieee80211_rx_h_check(struct ieee80211_tx return TXRX_DROP; } - if (memcmp(rx->dev->dev_addr, hdr->addr1, ETH_ALEN) == 0) + if (rx->fc & WLAN_FC_TODS) + rx->skb->pkt_type = PACKET_OTHERHOST; + else if (memcmp(rx->dev->dev_addr, hdr->addr1, ETH_ALEN) == 0) rx->skb->pkt_type = PACKET_HOST; else if (is_multicast_ether_addr(hdr->addr1)) { if (is_broadcast_ether_addr(hdr->addr1)) @@ -3080,8 +3073,10 @@ ieee80211_rx_h_check(struct ieee80211_tx WLAN_FC_GET_STYPE(rx->fc) == WLAN_FC_STYPE_PSPOLL)) && rx->sdata->type != IEEE80211_IF_TYPE_IBSS && (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { - if (!(rx->fc & WLAN_FC_FROMDS) && !(rx->fc & WLAN_FC_TODS)) { - /* Drop IBSS frames silently. */ + if ((!(rx->fc & WLAN_FC_FROMDS) && !(rx->fc & WLAN_FC_TODS)) || + !rx->u.rx.ra_match) { + /* Drop IBSS frames and frames for other hosts + * silently. */ return TXRX_DROP; } @@ -3113,6 +3108,8 @@ ieee80211_rx_h_check(struct ieee80211_tx rx->key = rx->sdata->keys[keyidx]; } if (!rx->key) { + if (!rx->u.rx.ra_match) + return TXRX_DROP; printk(KERN_DEBUG "%s: RX WEP frame with " "unknown keyidx %d (A1=" MACSTR " A2=" MACSTR " A3=" MACSTR ")\n", @@ -3128,7 +3125,7 @@ ieee80211_rx_h_check(struct ieee80211_tx } } - if (rx->fc & WLAN_FC_ISWEP && rx->key) { + if (rx->fc & WLAN_FC_ISWEP && rx->key && rx->u.rx.ra_match) { rx->key->tx_rx_count++; if (unlikely(rx->local->key_tx_rx_threshold && rx->key->tx_rx_count > @@ -3168,6 +3165,10 @@ ieee80211_rx_h_sta_process(struct ieee80 */ sta->last_rx = jiffies; } + + if (!rx->u.rx.ra_match) + return TXRX_CONTINUE; + sta->rx_fragments++; sta->rx_bytes += rx->skb->len; sta->last_rssi = rx->u.rx.status->ssi; @@ -3203,7 +3204,7 @@ ieee80211_rx_h_wep_weak_iv_detection(str { if (!rx->sta || !(rx->fc & WLAN_FC_ISWEP) || WLAN_FC_GET_TYPE(rx->fc) != WLAN_FC_TYPE_DATA || !rx->key || - rx->key->alg != ALG_WEP) + rx->key->alg != ALG_WEP || !rx->u.rx.ra_match) return TXRX_CONTINUE; /* Check for weak IVs, if hwaccel did not remove IV from the frame */ @@ -3260,7 +3261,7 @@ static ieee80211_txrx_result ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) { if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && - rx->sdata->type != IEEE80211_IF_TYPE_STA) { + rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) { /* Pass both encrypted and unencrypted EAPOL frames to user * space for processing. */ ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status, @@ -3313,6 +3314,10 @@ static ieee80211_txrx_result ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) { struct ieee80211_sub_if_data *sdata; + + if (!rx->u.rx.ra_match) + return TXRX_DROP; + sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if ((sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) && @@ -3351,7 +3356,8 @@ ieee80211_rx_h_passive_scan(struct ieee8 fc = le16_to_cpu(hdr->frame_control); if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) { + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON && + rx->dev == local->mdev) { local->scan.rx_beacon++; /* Need to trim FCS here because it is normally * removed only after this passive scan handler. */ @@ -3502,14 +3508,16 @@ static void ieee80211_rx_michael_mic_rep rx->skb = NULL; } -static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) +static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( + struct ieee80211_local *local, + ieee80211_rx_handler *handlers, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) { ieee80211_rx_handler *handler; ieee80211_txrx_result res = TXRX_DROP; - for (handler = local->rx_handlers; *handler != NULL; handler++) { + for (handler = handlers; *handler != NULL; handler++) { res = (*handler)(rx); if (res != TXRX_CONTINUE) { if (res == TXRX_DROP) { @@ -3523,8 +3531,19 @@ static inline void ieee80211_invoke_rx_h } } + if (res == TXRX_DROP) { + dev_kfree_skb(rx->skb); + } + return res; +} - if (res == TXRX_DROP || *handler == NULL) +static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, + ieee80211_rx_handler *handlers, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) +{ + if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == + TXRX_CONTINUE) dev_kfree_skb(rx->skb); } @@ -3568,37 +3587,57 @@ void __ieee80211_rx(struct net_device *d if (unlikely(local->sta_scanning || local->scan.in_scan)) rx.u.rx.in_scan = 1; + if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, + sta) != TXRX_CONTINUE) + goto end; + skb = rx.skb; + if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) && !local->iff_promiscs && !multicast) { rx.dev = sta->dev; rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); - ieee80211_invoke_rx_handlers(local, &rx, sta); + rx.u.rx.ra_match = 1; + ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, + sta); } else { struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; u8 *bssid = ieee80211_get_bssid(hdr, skb->len); list_for_each_entry(sdata, &local->sub_if_list, list) { + rx.u.rx.ra_match = 1; switch (sdata->type) { case IEEE80211_IF_TYPE_STA: - if (!bssid || memcmp(sdata->u.sta.bssid, - bssid, ETH_ALEN) != 0) - continue; - if (!multicast && !sdata->promisc && - memcmp(sdata->dev->dev_addr, hdr->addr1, - ETH_ALEN) != 0) + if (!bssid) continue; + if (!ieee80211_bssid_match(bssid, + sdata->u.sta.bssid)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } else if (!multicast && + memcmp(sdata->dev->dev_addr, + hdr->addr1, ETH_ALEN) != 0) { + if (!sdata->promisc) + continue; + rx.u.rx.ra_match = 0; + } break; case IEEE80211_IF_TYPE_IBSS: - if (!bssid || - !ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) - continue; - if (!multicast && !sdata->promisc && - memcmp(sdata->dev->dev_addr, hdr->addr1, - ETH_ALEN) != 0) + if (!bssid) continue; - if (sta == NULL) { + if (!ieee80211_bssid_match(bssid, + sdata->u.sta.bssid)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } else if (!multicast && + memcmp(sdata->dev->dev_addr, + hdr->addr1, ETH_ALEN) != 0) { + if (!sdata->promisc) + continue; + rx.u.rx.ra_match = 0; + } else if (sta == NULL) { sta = rx.sta = ieee80211_ibss_add_sta(dev, skb, bssid, hdr->addr2); @@ -3610,10 +3649,12 @@ void __ieee80211_rx(struct net_device *d if (memcmp(sdata->dev->dev_addr, hdr->addr1, ETH_ALEN) != 0) continue; - } else if (!rx.u.rx.in_scan && - !ieee80211_bssid_match(bssid, - sdata->dev->dev_addr)) - continue; + } else if (!ieee80211_bssid_match(bssid, + sdata->dev->dev_addr)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } if (sdata->dev == sdata->master && !rx.u.rx.in_scan) /* do not receive anything via @@ -3643,7 +3684,9 @@ void __ieee80211_rx(struct net_device *d rx.skb = skb_new; rx.dev = prev->dev; rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, &rx, sta); + ieee80211_invoke_rx_handlers(local, + local->rx_handlers, + &rx, sta); } prev = sdata; } @@ -3651,7 +3694,8 @@ void __ieee80211_rx(struct net_device *d rx.skb = skb; rx.dev = prev->dev; rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, &rx, sta); + ieee80211_invoke_rx_handlers(local, local->rx_handlers, + &rx, sta); } else dev_kfree_skb(skb); } @@ -3765,11 +3809,17 @@ ieee80211_rx_h_load_stats(struct ieee802 local->channel_use_raw += load; if (rx->sta) rx->sta->channel_use_raw += load; - rx->sdata->channel_use_raw += load; + rx->u.rx.load = load; return TXRX_CONTINUE; } +static ieee80211_txrx_result +ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) +{ + rx->sdata->channel_use_raw += rx->u.rx.load; + return TXRX_CONTINUE; +} static void ieee80211_stat_refresh(unsigned long data) { @@ -4113,10 +4163,18 @@ #endif /* IEEE80211_LEDS */ /* TODO: implement register/unregister functions for adding TX/RX handlers * into ordered list */ -static ieee80211_rx_handler ieee80211_rx_handlers[] = +/* rx_pre handlers don't have dev and sdata fields available in + * ieee80211_txrx_data */ +static ieee80211_rx_handler ieee80211_rx_pre_handlers[] = { ieee80211_rx_h_parse_qos, ieee80211_rx_h_load_stats, + NULL +}; + +static ieee80211_rx_handler ieee80211_rx_handlers[] = +{ + ieee80211_rx_h_if_stats, ieee80211_rx_h_monitor, ieee80211_rx_h_passive_scan, ieee80211_rx_h_check, @@ -4126,7 +4184,7 @@ static ieee80211_rx_handler ieee80211_rx ieee80211_rx_h_wep_weak_iv_detection, ieee80211_rx_h_wep_decrypt, ieee80211_rx_h_defragment, - ieee80211_rx_h_ieee80211_rx_h_ps_poll, + ieee80211_rx_h_ps_poll, ieee80211_rx_h_michael_mic_verify, /* this must be after decryption - so header is counted in MPDU mic * must be before pae and data, so QOS_DATA format frames @@ -4284,6 +4342,7 @@ struct net_device *ieee80211_alloc_hw(si NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); local->mdev = mdev; + local->rx_pre_handlers = ieee80211_rx_pre_handlers; local->rx_handlers = ieee80211_rx_handlers; local->tx_handlers = ieee80211_tx_handlers; diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h index 7ffeae2..3f4d00e 100644 --- a/net/d80211/ieee80211_i.h +++ b/net/d80211/ieee80211_i.h @@ -137,7 +137,11 @@ struct ieee80211_txrx_data { struct ieee80211_rx_status *status; int sent_ps_buffered; int queue; + int load; int in_scan:1; + int ra_match:1; /* frame is destined to interface + * currently processed (including + * multicast frames) */ } rx; } u; #ifdef CONFIG_HOSTAPD_WPA_TESTING @@ -413,6 +417,7 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12 struct ieee80211_passive_scan scan; + ieee80211_rx_handler *rx_pre_handlers; ieee80211_rx_handler *rx_handlers; ieee80211_tx_handler *tx_handlers; diff --git a/net/d80211/wpa.c b/net/d80211/wpa.c index 04856a9..37f5af4 100644 --- a/net/d80211/wpa.c +++ b/net/d80211/wpa.c @@ -235,6 +235,10 @@ #endif /* CONFIG_HOSTAPD_WPA_TESTING */ #ifdef CONFIG_HOSTAPD_WPA_TESTING int i; #endif /* CONFIG_HOSTAPD_WPA_TESTING */ + + if (!rx->u.rx.ra_match) + return TXRX_DROP; + printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " MACSTR "\n", rx->dev->name, MAC2STR(sa)); #ifdef CONFIG_HOSTAPD_WPA_TESTING -- 1.3.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/4] d80211: fix receiving through virtual interfaces 2006-07-03 17:24 ` [PATCH 2/4] d80211: fix receiving through virtual interfaces Jiri Benc @ 2006-07-04 18:05 ` Jiri Benc 0 siblings, 0 replies; 6+ messages in thread From: Jiri Benc @ 2006-07-04 18:05 UTC (permalink / raw) To: netdev On Mon, 3 Jul 2006 19:24:08 +0200 (CEST), Jiri Benc wrote: > - Packet type (PACKET_HOST and PACKET_OTHER_HOST) is set correctly now. Uhm, not really. > @@ -3057,7 +3048,9 @@ ieee80211_rx_h_check(struct ieee80211_tx > return TXRX_DROP; > } > > - if (memcmp(rx->dev->dev_addr, hdr->addr1, ETH_ALEN) == 0) > + if (rx->fc & WLAN_FC_TODS) > + rx->skb->pkt_type = PACKET_OTHERHOST; I'm not sure how something so obviously wrong slipped there. The corrected version of the patch follows. --- net/d80211/ieee80211.c | 171 +++++++++++++++++++++++++++++++---------------- net/d80211/ieee80211_i.h | 5 + net/d80211/wpa.c | 4 + 3 files changed, 124 insertions(+), 56 deletions(-) --- dscape.orig/net/d80211/ieee80211.c +++ dscape/net/d80211/ieee80211.c @@ -2463,27 +2463,15 @@ ieee80211_rx_h_data(struct ieee80211_txr memcpy(ehdr->h_source, src, ETH_ALEN); ehdr->h_proto = len; } - - if (rx->sta && !rx->sta->assoc_ap && - !(rx->sta && (rx->sta->flags & WLAN_STA_WDS))) - skb->dev = rx->sta->dev; - else - skb->dev = dev; + skb->dev = dev; skb2 = NULL; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - /* - * don't count the master since the low level code - * counts it already for us. - */ - if (skb->dev != sdata->master) { - sdata->stats.rx_packets++; - sdata->stats.rx_bytes += skb->len; - } + sdata->stats.rx_packets++; + sdata->stats.rx_bytes += skb->len; if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP - || sdata->type == IEEE80211_IF_TYPE_VLAN)) { + || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) { if (is_multicast_ether_addr(skb->data)) { /* send multicast frames both to higher layers in * local net stack and back to the wireless media */ @@ -2760,13 +2748,14 @@ static int ap_sta_ps_end(struct net_devi static ieee80211_txrx_result -ieee80211_rx_h_ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) { struct sk_buff *skb; int no_pending_pkts; if (likely(!rx->sta || WLAN_FC_GET_TYPE(rx->fc) != WLAN_FC_TYPE_CTRL || - WLAN_FC_GET_STYPE(rx->fc) != WLAN_FC_STYPE_PSPOLL)) + WLAN_FC_GET_STYPE(rx->fc) != WLAN_FC_STYPE_PSPOLL || + !rx->u.rx.ra_match)) return TXRX_CONTINUE; skb = skb_dequeue(&rx->sta->tx_filtered); @@ -3042,8 +3031,10 @@ ieee80211_rx_h_check(struct ieee80211_tx if (unlikely(rx->fc & WLAN_FC_RETRY && rx->sta->last_seq_ctrl[rx->u.rx.queue] == hdr->seq_ctrl)) { - rx->local->dot11FrameDuplicateCount++; - rx->sta->num_duplicates++; + if (rx->u.rx.ra_match) { + rx->local->dot11FrameDuplicateCount++; + rx->sta->num_duplicates++; + } return TXRX_DROP; } else rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; @@ -3057,7 +3048,9 @@ ieee80211_rx_h_check(struct ieee80211_tx return TXRX_DROP; } - if (memcmp(rx->dev->dev_addr, hdr->addr1, ETH_ALEN) == 0) + if (!rx->u.rx.ra_match) + rx->skb->pkt_type = PACKET_OTHERHOST; + else if (memcmp(rx->dev->dev_addr, hdr->addr1, ETH_ALEN) == 0) rx->skb->pkt_type = PACKET_HOST; else if (is_multicast_ether_addr(hdr->addr1)) { if (is_broadcast_ether_addr(hdr->addr1)) @@ -3080,8 +3073,10 @@ ieee80211_rx_h_check(struct ieee80211_tx WLAN_FC_GET_STYPE(rx->fc) == WLAN_FC_STYPE_PSPOLL)) && rx->sdata->type != IEEE80211_IF_TYPE_IBSS && (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) { - if (!(rx->fc & WLAN_FC_FROMDS) && !(rx->fc & WLAN_FC_TODS)) { - /* Drop IBSS frames silently. */ + if ((!(rx->fc & WLAN_FC_FROMDS) && !(rx->fc & WLAN_FC_TODS)) || + !rx->u.rx.ra_match) { + /* Drop IBSS frames and frames for other hosts + * silently. */ return TXRX_DROP; } @@ -3113,6 +3108,8 @@ ieee80211_rx_h_check(struct ieee80211_tx rx->key = rx->sdata->keys[keyidx]; } if (!rx->key) { + if (!rx->u.rx.ra_match) + return TXRX_DROP; printk(KERN_DEBUG "%s: RX WEP frame with " "unknown keyidx %d (A1=" MACSTR " A2=" MACSTR " A3=" MACSTR ")\n", @@ -3128,7 +3125,7 @@ ieee80211_rx_h_check(struct ieee80211_tx } } - if (rx->fc & WLAN_FC_ISWEP && rx->key) { + if (rx->fc & WLAN_FC_ISWEP && rx->key && rx->u.rx.ra_match) { rx->key->tx_rx_count++; if (unlikely(rx->local->key_tx_rx_threshold && rx->key->tx_rx_count > @@ -3168,6 +3165,10 @@ ieee80211_rx_h_sta_process(struct ieee80 */ sta->last_rx = jiffies; } + + if (!rx->u.rx.ra_match) + return TXRX_CONTINUE; + sta->rx_fragments++; sta->rx_bytes += rx->skb->len; sta->last_rssi = rx->u.rx.status->ssi; @@ -3203,7 +3204,7 @@ ieee80211_rx_h_wep_weak_iv_detection(str { if (!rx->sta || !(rx->fc & WLAN_FC_ISWEP) || WLAN_FC_GET_TYPE(rx->fc) != WLAN_FC_TYPE_DATA || !rx->key || - rx->key->alg != ALG_WEP) + rx->key->alg != ALG_WEP || !rx->u.rx.ra_match) return TXRX_CONTINUE; /* Check for weak IVs, if hwaccel did not remove IV from the frame */ @@ -3260,7 +3261,7 @@ static ieee80211_txrx_result ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) { if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && - rx->sdata->type != IEEE80211_IF_TYPE_STA) { + rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) { /* Pass both encrypted and unencrypted EAPOL frames to user * space for processing. */ ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status, @@ -3313,6 +3314,10 @@ static ieee80211_txrx_result ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) { struct ieee80211_sub_if_data *sdata; + + if (!rx->u.rx.ra_match) + return TXRX_DROP; + sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if ((sdata->type == IEEE80211_IF_TYPE_STA || sdata->type == IEEE80211_IF_TYPE_IBSS) && @@ -3351,7 +3356,8 @@ ieee80211_rx_h_passive_scan(struct ieee8 fc = le16_to_cpu(hdr->frame_control); if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) { + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON && + rx->dev == local->mdev) { local->scan.rx_beacon++; /* Need to trim FCS here because it is normally * removed only after this passive scan handler. */ @@ -3502,14 +3508,16 @@ static void ieee80211_rx_michael_mic_rep rx->skb = NULL; } -static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) +static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( + struct ieee80211_local *local, + ieee80211_rx_handler *handlers, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) { ieee80211_rx_handler *handler; ieee80211_txrx_result res = TXRX_DROP; - for (handler = local->rx_handlers; *handler != NULL; handler++) { + for (handler = handlers; *handler != NULL; handler++) { res = (*handler)(rx); if (res != TXRX_CONTINUE) { if (res == TXRX_DROP) { @@ -3523,8 +3531,19 @@ static inline void ieee80211_invoke_rx_h } } + if (res == TXRX_DROP) { + dev_kfree_skb(rx->skb); + } + return res; +} - if (res == TXRX_DROP || *handler == NULL) +static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, + ieee80211_rx_handler *handlers, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) +{ + if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == + TXRX_CONTINUE) dev_kfree_skb(rx->skb); } @@ -3568,37 +3587,57 @@ void __ieee80211_rx(struct net_device *d if (unlikely(local->sta_scanning || local->scan.in_scan)) rx.u.rx.in_scan = 1; + if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, + sta) != TXRX_CONTINUE) + goto end; + skb = rx.skb; + if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) && !local->iff_promiscs && !multicast) { rx.dev = sta->dev; rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); - ieee80211_invoke_rx_handlers(local, &rx, sta); + rx.u.rx.ra_match = 1; + ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, + sta); } else { struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; u8 *bssid = ieee80211_get_bssid(hdr, skb->len); list_for_each_entry(sdata, &local->sub_if_list, list) { + rx.u.rx.ra_match = 1; switch (sdata->type) { case IEEE80211_IF_TYPE_STA: - if (!bssid || memcmp(sdata->u.sta.bssid, - bssid, ETH_ALEN) != 0) - continue; - if (!multicast && !sdata->promisc && - memcmp(sdata->dev->dev_addr, hdr->addr1, - ETH_ALEN) != 0) + if (!bssid) continue; + if (!ieee80211_bssid_match(bssid, + sdata->u.sta.bssid)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } else if (!multicast && + memcmp(sdata->dev->dev_addr, + hdr->addr1, ETH_ALEN) != 0) { + if (!sdata->promisc) + continue; + rx.u.rx.ra_match = 0; + } break; case IEEE80211_IF_TYPE_IBSS: - if (!bssid || - !ieee80211_bssid_match(bssid, - sdata->u.sta.bssid)) + if (!bssid) continue; - if (!multicast && !sdata->promisc && - memcmp(sdata->dev->dev_addr, hdr->addr1, - ETH_ALEN) != 0) - continue; - if (sta == NULL) { + if (!ieee80211_bssid_match(bssid, + sdata->u.sta.bssid)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } else if (!multicast && + memcmp(sdata->dev->dev_addr, + hdr->addr1, ETH_ALEN) != 0) { + if (!sdata->promisc) + continue; + rx.u.rx.ra_match = 0; + } else if (sta == NULL) { sta = rx.sta = ieee80211_ibss_add_sta(dev, skb, bssid, hdr->addr2); @@ -3610,10 +3649,12 @@ void __ieee80211_rx(struct net_device *d if (memcmp(sdata->dev->dev_addr, hdr->addr1, ETH_ALEN) != 0) continue; - } else if (!rx.u.rx.in_scan && - !ieee80211_bssid_match(bssid, - sdata->dev->dev_addr)) - continue; + } else if (!ieee80211_bssid_match(bssid, + sdata->dev->dev_addr)) { + if (!rx.u.rx.in_scan) + continue; + rx.u.rx.ra_match = 0; + } if (sdata->dev == sdata->master && !rx.u.rx.in_scan) /* do not receive anything via @@ -3643,7 +3684,9 @@ void __ieee80211_rx(struct net_device *d rx.skb = skb_new; rx.dev = prev->dev; rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, &rx, sta); + ieee80211_invoke_rx_handlers(local, + local->rx_handlers, + &rx, sta); } prev = sdata; } @@ -3651,7 +3694,8 @@ void __ieee80211_rx(struct net_device *d rx.skb = skb; rx.dev = prev->dev; rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, &rx, sta); + ieee80211_invoke_rx_handlers(local, local->rx_handlers, + &rx, sta); } else dev_kfree_skb(skb); } @@ -3765,11 +3809,17 @@ ieee80211_rx_h_load_stats(struct ieee802 local->channel_use_raw += load; if (rx->sta) rx->sta->channel_use_raw += load; - rx->sdata->channel_use_raw += load; + rx->u.rx.load = load; return TXRX_CONTINUE; } +static ieee80211_txrx_result +ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) +{ + rx->sdata->channel_use_raw += rx->u.rx.load; + return TXRX_CONTINUE; +} static void ieee80211_stat_refresh(unsigned long data) { @@ -4113,10 +4163,18 @@ void ieee80211_tx_status(struct net_devi /* TODO: implement register/unregister functions for adding TX/RX handlers * into ordered list */ -static ieee80211_rx_handler ieee80211_rx_handlers[] = +/* rx_pre handlers don't have dev and sdata fields available in + * ieee80211_txrx_data */ +static ieee80211_rx_handler ieee80211_rx_pre_handlers[] = { ieee80211_rx_h_parse_qos, ieee80211_rx_h_load_stats, + NULL +}; + +static ieee80211_rx_handler ieee80211_rx_handlers[] = +{ + ieee80211_rx_h_if_stats, ieee80211_rx_h_monitor, ieee80211_rx_h_passive_scan, ieee80211_rx_h_check, @@ -4126,7 +4184,7 @@ static ieee80211_rx_handler ieee80211_rx ieee80211_rx_h_wep_weak_iv_detection, ieee80211_rx_h_wep_decrypt, ieee80211_rx_h_defragment, - ieee80211_rx_h_ieee80211_rx_h_ps_poll, + ieee80211_rx_h_ps_poll, ieee80211_rx_h_michael_mic_verify, /* this must be after decryption - so header is counted in MPDU mic * must be before pae and data, so QOS_DATA format frames @@ -4284,6 +4342,7 @@ struct net_device *ieee80211_alloc_hw(si NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); local->mdev = mdev; + local->rx_pre_handlers = ieee80211_rx_pre_handlers; local->rx_handlers = ieee80211_rx_handlers; local->tx_handlers = ieee80211_tx_handlers; --- dscape.orig/net/d80211/ieee80211_i.h +++ dscape/net/d80211/ieee80211_i.h @@ -137,7 +137,11 @@ struct ieee80211_txrx_data { struct ieee80211_rx_status *status; int sent_ps_buffered; int queue; + int load; int in_scan:1; + int ra_match:1; /* frame is destined to interface + * currently processed (including + * multicast frames) */ } rx; } u; #ifdef CONFIG_HOSTAPD_WPA_TESTING @@ -413,6 +417,7 @@ struct ieee80211_local { struct ieee80211_passive_scan scan; + ieee80211_rx_handler *rx_pre_handlers; ieee80211_rx_handler *rx_handlers; ieee80211_tx_handler *tx_handlers; --- dscape.orig/net/d80211/wpa.c +++ dscape/net/d80211/wpa.c @@ -235,6 +235,10 @@ ieee80211_rx_h_michael_mic_verify(struct #ifdef CONFIG_HOSTAPD_WPA_TESTING int i; #endif /* CONFIG_HOSTAPD_WPA_TESTING */ + + if (!rx->u.rx.ra_match) + return TXRX_DROP; + printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " MACSTR "\n", rx->dev->name, MAC2STR(sa)); #ifdef CONFIG_HOSTAPD_WPA_TESTING -- Jiri Benc SUSE Labs ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/4] d80211: fix defragmentation 2006-07-03 17:24 [PATCH 0/4] d80211: fix receiving Jiri Benc 2006-07-03 17:24 ` [PATCH 1/4] d80211: better deallocation of mdev Jiri Benc 2006-07-03 17:24 ` [PATCH 2/4] d80211: fix receiving through virtual interfaces Jiri Benc @ 2006-07-03 17:24 ` Jiri Benc 2006-07-03 17:24 ` [PATCH 4/4] d80211: optimize defragmentation Jiri Benc 3 siblings, 0 replies; 6+ messages in thread From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw) To: netdev When multiple virtual interfaces are active and some of them is in promisc mode, defragmentation does not work. Fix it by introducing separate fragment table for each virtual interface. Signed-off-by: Jiri Benc <jbenc@suse.cz> --- net/d80211/ieee80211.c | 26 +++++++++++--------------- net/d80211/ieee80211_i.h | 8 ++++---- net/d80211/ieee80211_iface.c | 5 +++++ 3 files changed, 20 insertions(+), 19 deletions(-) 9b8e66f2aee1f620da25453255cf58e8744519a6 diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c index 52316f9..7b0b4c1 100644 --- a/net/d80211/ieee80211.c +++ b/net/d80211/ieee80211.c @@ -2812,17 +2812,17 @@ #endif /* IEEE80211_VERBOSE_DEBUG_PS */ static inline struct ieee80211_fragment_entry * -ieee80211_reassemble_add(struct ieee80211_local *local, +ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, unsigned int frag, unsigned int seq, int rx_queue, struct sk_buff **skb) { struct ieee80211_fragment_entry *entry; int idx; - idx = local->fragment_next; - entry = &local->fragments[local->fragment_next++]; - if (local->fragment_next >= IEEE80211_FRAGMENT_MAX) - local->fragment_next = 0; + idx = sdata->fragment_next; + entry = &sdata->fragments[sdata->fragment_next++]; + if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) + sdata->fragment_next = 0; if (entry->skb) { #ifdef CONFIG_D80211_DEBUG @@ -2831,7 +2831,7 @@ #ifdef CONFIG_D80211_DEBUG printk(KERN_DEBUG "%s: RX reassembly removed oldest " "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " "addr1=" MACSTR " addr2=" MACSTR "\n", - local->mdev->name, idx, + sdata->dev->name, idx, jiffies - entry->first_frag_time, entry->seq, entry->last_frag, MAC2STR(hdr->addr1), MAC2STR(hdr->addr2)); @@ -2852,14 +2852,14 @@ #endif /* CONFIG_D80211_DEBUG */ static inline struct ieee80211_fragment_entry * -ieee80211_reassemble_find(struct ieee80211_local *local, +ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, u16 fc, unsigned int frag, unsigned int seq, int rx_queue, struct ieee80211_hdr *hdr) { struct ieee80211_fragment_entry *entry; int i, idx; - idx = local->fragment_next; + idx = sdata->fragment_next; for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { struct ieee80211_hdr *f_hdr; u16 f_fc; @@ -2868,7 +2868,7 @@ ieee80211_reassemble_find(struct ieee802 if (idx < 0) idx = IEEE80211_FRAGMENT_MAX - 1; - entry = &local->fragments[idx]; + entry = &sdata->fragments[idx]; if (!entry->skb || entry->seq != seq || entry->rx_queue != rx_queue || entry->last_frag + 1 != frag) @@ -2918,7 +2918,7 @@ ieee80211_rx_h_defragment(struct ieee802 if (frag == 0) { /* This is the first fragment of a new frame. */ - entry = ieee80211_reassemble_add(rx->local, frag, seq, + entry = ieee80211_reassemble_add(rx->sdata, frag, seq, rx->u.rx.queue, &(rx->skb)); if (rx->key && rx->key->alg == ALG_CCMP && (rx->fc & WLAN_FC_ISWEP)) { @@ -2935,7 +2935,7 @@ ieee80211_rx_h_defragment(struct ieee802 /* This is a fragment for a frame that should already be pending in * fragment cache. Add this fragment to the end of the pending entry. */ - entry = ieee80211_reassemble_find(rx->local, rx->fc, frag, seq, + entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq, rx->u.rx.queue, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); @@ -4573,10 +4573,6 @@ void ieee80211_unregister_hw(struct net_ &local->class_dev.kobj); ieee80211_dev_sysfs_del(local); - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) - if (local->fragments[i].skb) - dev_kfree_skb(local->fragments[i].skb); - for (i = 0; i < NUM_IEEE80211_MODES; i++) { kfree(local->supp_rates[i]); kfree(local->basic_rates[i]); diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h index 3f4d00e..6a952bd 100644 --- a/net/d80211/ieee80211_i.h +++ b/net/d80211/ieee80211_i.h @@ -307,6 +307,10 @@ struct ieee80211_sub_if_data { int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized * port */ + /* Fragment table for host-based reassembly */ + struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; + unsigned int fragment_next; + #define NUM_DEFAULT_KEYS 4 struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; struct ieee80211_key *default_key; @@ -406,10 +410,6 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12 * or RX before generating a rekey * notification; 0 = notification disabled. */ - /* Fragment table for host-based reassembly */ - struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX]; - unsigned int fragment_next; - int bridge_packets; /* bridge packets between associated stations and * deliver multicast frames both back to wireless * media and to the local net stack */ diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c index 566bb36..f49ce8a 100644 --- a/net/d80211/ieee80211_iface.c +++ b/net/d80211/ieee80211_iface.c @@ -336,9 +336,14 @@ int ieee80211_if_remove(struct net_devic void ieee80211_if_free(struct net_device *dev) { struct ieee80211_local *local = dev->ieee80211_ptr; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int i; /* local->apdev must be NULL when freeing management interface */ BUG_ON(dev == local->apdev); + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) + if (sdata->fragments[i].skb) + dev_kfree_skb(sdata->fragments[i].skb); free_netdev(dev); } -- 1.3.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/4] d80211: optimize defragmentation 2006-07-03 17:24 [PATCH 0/4] d80211: fix receiving Jiri Benc ` (2 preceding siblings ...) 2006-07-03 17:24 ` [PATCH 3/4] d80211: fix defragmentation Jiri Benc @ 2006-07-03 17:24 ` Jiri Benc 3 siblings, 0 replies; 6+ messages in thread From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw) To: netdev Optimize defragmentation by storing all fragments in skb queue and reallocating skb only once all fragments are received. Signed-off-by: Jiri Benc <jbenc@suse.cz> --- net/d80211/ieee80211.c | 46 ++++++++++++++++++++++-------------------- net/d80211/ieee80211_i.h | 3 ++- net/d80211/ieee80211_iface.c | 19 ++++++++++++++--- 3 files changed, 41 insertions(+), 27 deletions(-) 240090e43ed16ad95dd2c7865a681b26f739efc0 diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c index 7b0b4c1..1494603 100644 --- a/net/d80211/ieee80211.c +++ b/net/d80211/ieee80211.c @@ -2824,10 +2824,10 @@ ieee80211_reassemble_add(struct ieee8021 if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) sdata->fragment_next = 0; - if (entry->skb) { + if (!skb_queue_empty(&entry->skb_list)) { #ifdef CONFIG_D80211_DEBUG struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) entry->skb->data; + (struct ieee80211_hdr *) entry->skb_list.next->data; printk(KERN_DEBUG "%s: RX reassembly removed oldest " "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " "addr1=" MACSTR " addr2=" MACSTR "\n", @@ -2836,16 +2836,17 @@ #ifdef CONFIG_D80211_DEBUG entry->last_frag, MAC2STR(hdr->addr1), MAC2STR(hdr->addr2)); #endif /* CONFIG_D80211_DEBUG */ - dev_kfree_skb(entry->skb); + __skb_queue_purge(&entry->skb_list); } - entry->skb = *skb; + __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ *skb = NULL; entry->first_frag_time = jiffies; entry->seq = seq; entry->rx_queue = rx_queue; entry->last_frag = frag; entry->ccmp = 0; + entry->extra_len = 0; return entry; } @@ -2869,12 +2870,12 @@ ieee80211_reassemble_find(struct ieee802 idx = IEEE80211_FRAGMENT_MAX - 1; entry = &sdata->fragments[idx]; - if (!entry->skb || entry->seq != seq || + if (skb_queue_empty(&entry->skb_list) || entry->seq != seq || entry->rx_queue != rx_queue || entry->last_frag + 1 != frag) continue; - f_hdr = (struct ieee80211_hdr *) entry->skb->data; + f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; f_fc = le16_to_cpu(f_hdr->frame_control); if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_GET_TYPE(f_fc) || @@ -2883,8 +2884,7 @@ ieee80211_reassemble_find(struct ieee802 continue; if (entry->first_frag_time + 2 * HZ < jiffies) { - dev_kfree_skb(entry->skb); - entry->skb = NULL; + __skb_queue_purge(&entry->skb_list); continue; } return entry; @@ -2901,6 +2901,7 @@ ieee80211_rx_h_defragment(struct ieee802 u16 sc; unsigned int frag, seq; struct ieee80211_fragment_entry *entry; + struct sk_buff *skb; hdr = (struct ieee80211_hdr *) rx->skb->data; sc = le16_to_cpu(hdr->seq_ctrl); @@ -2968,30 +2969,30 @@ ieee80211_rx_h_defragment(struct ieee802 memcpy(entry->last_pn, pn, CCMP_PN_LEN); } - /* TODO: could gather list of skb's and reallocate data buffer only - * after finding out the total length of the frame */ skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc)); - if (skb_tailroom(entry->skb) < rx->skb->len) { + __skb_queue_tail(&entry->skb_list, rx->skb); + entry->last_frag = frag; + entry->extra_len += rx->skb->len; + if (rx->fc & WLAN_FC_MOREFRAG) { + rx->skb = NULL; + return TXRX_QUEUED; + } + + rx->skb = __skb_dequeue(&entry->skb_list); + if (skb_tailroom(rx->skb) < entry->extra_len) { I802_DEBUG_INC(rx->local->rx_expand_skb_head2); - if (unlikely(pskb_expand_head(entry->skb, 0, rx->skb->len, + if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len, GFP_ATOMIC))) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); + __skb_queue_purge(&entry->skb_list); return TXRX_DROP; } } - memcpy(skb_put(entry->skb, rx->skb->len), rx->skb->data, rx->skb->len); - entry->last_frag = frag; - dev_kfree_skb(rx->skb); - - if (rx->fc & WLAN_FC_MOREFRAG) { - rx->skb = NULL; - return TXRX_QUEUED; - } + while ((skb = __skb_dequeue(&entry->skb_list))) + memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len); /* Complete frame has been reassembled - process it now */ - rx->skb = entry->skb; rx->fragmented = 1; - entry->skb = NULL; out: if (rx->sta) @@ -4392,6 +4393,7 @@ struct net_device *ieee80211_alloc_hw(si sdata->dev = mdev; sdata->master = mdev; sdata->local = local; + ieee80211_if_sdata_init(sdata); list_add_tail(&sdata->list, &local->sub_if_list); tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h index 6a952bd..b4e294c 100644 --- a/net/d80211/ieee80211_i.h +++ b/net/d80211/ieee80211_i.h @@ -62,7 +62,8 @@ struct ieee80211_fragment_entry { unsigned int seq; unsigned int rx_queue; unsigned int last_frag; - struct sk_buff *skb; + unsigned int extra_len; + struct sk_buff_head skb_list; int ccmp; /* Whether fragments were encrypted with CCMP */ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ }; diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c index f49ce8a..f64b4de 100644 --- a/net/d80211/ieee80211_iface.c +++ b/net/d80211/ieee80211_iface.c @@ -18,9 +18,22 @@ #include "sta_info.h" void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) { + int i; + /* Default values for sub-interface parameters */ sdata->drop_unencrypted = 0; sdata->eapol = 1; + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) + skb_queue_head_init(&sdata->fragments[i].skb_list); +} + +static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) +{ + int i; + + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { + __skb_queue_purge(&sdata->fragments[i].skb_list); + } } /* Must be called with rtnl lock held. */ @@ -212,6 +225,7 @@ void ieee80211_if_reinit(struct net_devi int i; ASSERT_RTNL(); + ieee80211_if_sdata_deinit(sdata); for (i = 0; i < NUM_DEFAULT_KEYS; i++) { if (!sdata->keys[i]) continue; @@ -337,13 +351,10 @@ void ieee80211_if_free(struct net_device { struct ieee80211_local *local = dev->ieee80211_ptr; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int i; /* local->apdev must be NULL when freeing management interface */ BUG_ON(dev == local->apdev); - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) - if (sdata->fragments[i].skb) - dev_kfree_skb(sdata->fragments[i].skb); + ieee80211_if_sdata_deinit(sdata); free_netdev(dev); } -- 1.3.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2006-07-04 18:05 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-07-03 17:24 [PATCH 0/4] d80211: fix receiving Jiri Benc 2006-07-03 17:24 ` [PATCH 1/4] d80211: better deallocation of mdev Jiri Benc 2006-07-03 17:24 ` [PATCH 2/4] d80211: fix receiving through virtual interfaces Jiri Benc 2006-07-04 18:05 ` Jiri Benc 2006-07-03 17:24 ` [PATCH 3/4] d80211: fix defragmentation Jiri Benc 2006-07-03 17:24 ` [PATCH 4/4] d80211: optimize defragmentation Jiri Benc
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).