In some parts of Madwifi, SKBs are dispatched from the VAP device to the physical device using Linux kernel queuing, which does not understand our node reference system, so node references are carefully cleaned up if the packet is dropped.

However, the netif_rx and vlan_hwaccel_receive_skb functions dispatch the SKB to the higher networking levels, out of our domain.

Therefore, handle node references as appropriate.


git-svn-id: http://madwifi-project.org/svn/madwifi/trunk@3708 0192ed92-7a03-0410-a25b-9323aeb14dbd
This commit is contained in:
mentor 2008-06-06 19:21:33 +00:00
parent 1b5e6019b1
commit f259deab93
2 changed files with 23 additions and 30 deletions

View File

@ -1103,7 +1103,7 @@ ieee80211_deliver_data(struct ieee80211_node *ni, struct sk_buff *skb)
{ {
struct ieee80211vap *vap = ni->ni_vap; struct ieee80211vap *vap = ni->ni_vap;
struct net_device *dev = vap->iv_dev; struct net_device *dev = vap->iv_dev;
struct ether_header *eh = (struct ether_header *) skb->data; struct ether_header *eh = (struct ether_header *)skb->data;
struct ieee80211_node *tni; struct ieee80211_node *tni;
int ret; int ret;
@ -1149,19 +1149,21 @@ ieee80211_deliver_data(struct ieee80211_node *ni, struct sk_buff *skb)
} }
} }
if (skb1 != NULL) { if (skb1 != NULL) {
struct ieee80211_node *tni;
skb1->dev = dev; skb1->dev = dev;
skb_reset_mac_header(skb1); skb_reset_mac_header(skb1);
skb_set_network_header(skb1, sizeof(struct ether_header)); skb_set_network_header(skb1, sizeof(struct ether_header));
skb1->protocol = __constant_htons(ETH_P_802_2); skb1->protocol = __constant_htons(ETH_P_802_2);
/* This SKB is being emitted to the physical/parent
* device, which maintains node references. However,
* there is kernel code in between which does not.
* Therefore, the ref. is cleaned if the SKB is
* dropped. */
tni = SKB_NI(skb1);
/* XXX: Insert vlan tag before queuing it? */ /* XXX: Insert vlan tag before queuing it? */
tni = SKB_NI(skb1); /* Remember node so we can free it. */
if (dev_queue_xmit(skb1) == NET_XMIT_DROP) { if (dev_queue_xmit(skb1) == NET_XMIT_DROP) {
/* If queue dropped the packet because device
* was too busy */
vap->iv_devstats.tx_dropped++; vap->iv_devstats.tx_dropped++;
/* node reference was leaked */
if (tni != NULL) if (tni != NULL)
ieee80211_unref_node(&tni); ieee80211_unref_node(&tni);
} }
@ -1188,12 +1190,10 @@ ieee80211_deliver_data(struct ieee80211_node *ni, struct sk_buff *skb)
vap->iv_vlgrp, ni->ni_vlan); vap->iv_vlgrp, ni->ni_vlan);
else else
ret = netif_rx(skb); ret = netif_rx(skb);
if (ret == NET_RX_DROP) { if (ret == NET_RX_DROP)
/* Cleanup if passing SKB to ourselves failed. */
if (tni != NULL)
ieee80211_unref_node(&tni);
vap->iv_devstats.rx_dropped++; vap->iv_devstats.rx_dropped++;
} if (tni != NULL)
ieee80211_unref_node(&tni);
skb = NULL; /* SKB is no longer ours */ skb = NULL; /* SKB is no longer ours */
} }
} }
@ -2285,18 +2285,13 @@ forward_mgmt_to_app(struct ieee80211vap *vap, int subtype, struct sk_buff *skb,
skb1->pkt_type = PACKET_OTHERHOST; skb1->pkt_type = PACKET_OTHERHOST;
skb1->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */ skb1->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */
tni = SKB_NI(skb1);
if (netif_rx(skb1) == NET_RX_DROP) {
/* If netif_rx dropped the packet because
* device was too busy */
if (tni != NULL) {
/* node reference was leaked */
ieee80211_unref_node(&tni);
}
vap->iv_devstats.rx_dropped++;
}
vap->iv_devstats.rx_packets++; vap->iv_devstats.rx_packets++;
vap->iv_devstats.rx_bytes += skb1->len; vap->iv_devstats.rx_bytes += skb1->len;
if (SKB_NI(skb1) != NULL)
ieee80211_unref_node(&SKB_NI(skb1));
if (netif_rx(skb1) == NET_RX_DROP)
vap->iv_devstats.rx_dropped++;
} }
} }

View File

@ -302,6 +302,7 @@ ieee80211_input_monitor(struct ieee80211com *ic, struct sk_buff *skb,
int noise = 0, antenna = 0, ieeerate = 0; int noise = 0, antenna = 0, ieeerate = 0;
u_int32_t rssi = 0; u_int32_t rssi = 0;
u_int8_t pkttype = 0; u_int8_t pkttype = 0;
if (tx) { if (tx) {
rssi = bf->bf_dsstatus.ds_txstat.ts_rssi; rssi = bf->bf_dsstatus.ds_txstat.ts_rssi;
antenna = bf->bf_dsstatus.ds_txstat.ts_antenna; antenna = bf->bf_dsstatus.ds_txstat.ts_antenna;
@ -574,17 +575,14 @@ ieee80211_input_monitor(struct ieee80211com *ic, struct sk_buff *skb,
skb1->protocol = skb1->protocol =
__constant_htons(0x0019); /* ETH_P_80211_RAW */ __constant_htons(0x0019); /* ETH_P_80211_RAW */
if (netif_rx(skb1) == NET_RX_DROP) {
/* If netif_rx dropped the packet because
* device was too busy, reclaim the ref. in
* the skb. */
if (SKB_NI(skb1) != NULL)
ieee80211_unref_node(&SKB_NI(skb1));
vap->iv_devstats.rx_dropped++;
}
vap->iv_devstats.rx_packets++; vap->iv_devstats.rx_packets++;
vap->iv_devstats.rx_bytes += skb1->len; vap->iv_devstats.rx_bytes += skb1->len;
if (SKB_NI(skb1) != NULL)
ieee80211_unref_node(&SKB_NI(skb1));
if (netif_rx(skb1) == NET_RX_DROP)
vap->iv_devstats.rx_dropped++;
skb1 = NULL;
} }
} }
} }