mirror of
https://github.com/proski/madwifi
synced 2024-11-26 00:09:46 +03:00
Refcount fix for netif_rx() and friends, returning error and dropping SKB but we were not releasing our node reference.
Refcount fix for skb_clone/etc where we were not keeping reference counter matching the number of skbuff instances and were not having enough references. git-svn-id: http://madwifi-project.org/svn/madwifi/trunk@2894 0192ed92-7a03-0410-a25b-9323aeb14dbd
This commit is contained in:
parent
09b1e7bb56
commit
0c4e2a41e9
@ -707,7 +707,11 @@ ieee80211_input(struct ieee80211_node *ni,
|
||||
/* ether_type must be length as FF frames are always LLC/SNAP encap'd */
|
||||
frame_len = ntohs(eh_tmp->ether_type);
|
||||
|
||||
skb1 = skb_clone(skb, GFP_ATOMIC); /* XXX: GFP_ATOMIC is overkill? */
|
||||
skb1 = skb_clone(skb, GFP_ATOMIC);
|
||||
/* Increment reference count after copy */
|
||||
if (NULL != skb1 && SKB_CB(skb)->ni != NULL) {
|
||||
SKB_CB(skb1)->ni = ieee80211_ref_node(SKB_CB(skb)->ni);
|
||||
}
|
||||
|
||||
/* we now have 802.3 MAC hdr followed by 802.2 LLC/SNAP; convert to EthernetII.
|
||||
* Note that the frame is at least IEEE80211_MIN_LEN, due to the driver code. */
|
||||
@ -915,9 +919,12 @@ ieee80211_input_all(struct ieee80211com *ic,
|
||||
if (TAILQ_NEXT(vap, iv_next) != NULL) {
|
||||
skb1 = skb_copy(skb, GFP_ATOMIC);
|
||||
if (skb1 == NULL) {
|
||||
/* XXX stat+msg */
|
||||
continue;
|
||||
}
|
||||
/* We duplicate the reference after skb_copy */
|
||||
if (SKB_CB(skb)->ni != NULL) {
|
||||
SKB_CB(skb1)->ni = ieee80211_ref_node(SKB_CB(skb)->ni);
|
||||
}
|
||||
} else {
|
||||
skb1 = skb;
|
||||
skb = NULL;
|
||||
@ -1023,6 +1030,10 @@ ieee80211_defrag(struct ieee80211_node *ni, struct sk_buff *skb, int hdrlen)
|
||||
* assemble fragments
|
||||
*/
|
||||
ni->ni_rxfrag = skb_copy(skb, GFP_ATOMIC);
|
||||
/* We duplicate the reference after skb_copy */
|
||||
if (SKB_CB(skb)->ni != NULL) {
|
||||
SKB_CB(ni->ni_rxfrag)->ni = ieee80211_ref_node(SKB_CB(skb)->ni);
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
/*
|
||||
@ -1036,6 +1047,10 @@ ieee80211_defrag(struct ieee80211_node *ni, struct sk_buff *skb, int hdrlen)
|
||||
(ni->ni_vap->iv_dev->mtu + hdrlen) -
|
||||
(skb_end_pointer(skb) - skb->head),
|
||||
GFP_ATOMIC);
|
||||
/* We duplicate the reference after skb_copy */
|
||||
if (SKB_CB(skb)->ni != NULL && (skb != ni->ni_rxfrag)) {
|
||||
SKB_CB(ni->ni_rxfrag)->ni = ieee80211_ref_node(SKB_CB(skb)->ni);
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
@ -1077,6 +1092,7 @@ ieee80211_deliver_data(struct ieee80211_node *ni, struct sk_buff *skb)
|
||||
struct ieee80211vap *vap = ni->ni_vap;
|
||||
struct net_device *dev = vap->iv_dev;
|
||||
struct ether_header *eh = (struct ether_header *) skb->data;
|
||||
struct ieee80211_node * ni_tmp = NULL;
|
||||
|
||||
#ifdef ATH_SUPERG_XR
|
||||
/*
|
||||
@ -1094,8 +1110,13 @@ ieee80211_deliver_data(struct ieee80211_node *ni, struct sk_buff *skb)
|
||||
(vap->iv_flags & IEEE80211_F_NOBRIDGE) == 0) {
|
||||
struct sk_buff *skb1 = NULL;
|
||||
|
||||
if (ETHER_IS_MULTICAST(eh->ether_dhost))
|
||||
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
|
||||
skb1 = skb_copy(skb, GFP_ATOMIC);
|
||||
/* We duplicate the reference after skb_copy */
|
||||
if (SKB_CB(skb)->ni != NULL) {
|
||||
SKB_CB(skb1)->ni = ieee80211_ref_node(SKB_CB(skb)->ni);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Check if destination is associated with the
|
||||
@ -1124,7 +1145,19 @@ ieee80211_deliver_data(struct ieee80211_node *ni, struct sk_buff *skb)
|
||||
|
||||
skb1->protocol = __constant_htons(ETH_P_802_2);
|
||||
/* XXX insert vlan tag before queue it? */
|
||||
dev_queue_xmit(skb1);
|
||||
ni_tmp = SKB_CB(skb1)->ni; /* remember node so we can free it */
|
||||
if ( dev_queue_xmit(skb1) == NET_XMIT_DROP ) {
|
||||
/* If queue dropped the packet because device was
|
||||
* too busy */
|
||||
vap->iv_devstats.tx_dropped++;
|
||||
/* node reference was leaked */
|
||||
if (ni_tmp != NULL)
|
||||
ieee80211_unref_node(&ni_tmp);
|
||||
}
|
||||
/* skb is no longer ours, either way after dev_queue_xmit */
|
||||
skb1 = NULL;
|
||||
/* no need to free node reference */
|
||||
ni_tmp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1136,11 +1169,34 @@ ieee80211_deliver_data(struct ieee80211_node *ni, struct sk_buff *skb)
|
||||
#else
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
#endif
|
||||
vap->iv_devstats.rx_packets++;
|
||||
vap->iv_devstats.rx_bytes += skb->len;
|
||||
if (ni->ni_vlan != 0 && vap->iv_vlgrp != NULL) {
|
||||
/* attach vlan tag */
|
||||
vlan_hwaccel_receive_skb(skb, vap->iv_vlgrp, ni->ni_vlan);
|
||||
} else
|
||||
netif_rx(skb);
|
||||
struct ieee80211_node *ni_tmp = SKB_CB(skb)->ni;
|
||||
if (vlan_hwaccel_receive_skb(skb, vap->iv_vlgrp, ni->ni_vlan) == NET_RX_DROP) {
|
||||
/* If netif_rx dropped the packet because
|
||||
* device was too busy */
|
||||
if (ni_tmp != NULL) {
|
||||
/* node reference was leaked */
|
||||
ieee80211_unref_node(&ni_tmp);
|
||||
}
|
||||
vap->iv_devstats.rx_dropped++;
|
||||
}
|
||||
skb = NULL; /* SKB is no longer ours */
|
||||
} else {
|
||||
struct ieee80211_node *ni_tmp = SKB_CB(skb)->ni;
|
||||
if (netif_rx(skb) == NET_RX_DROP) {
|
||||
/* If netif_rx dropped the packet because
|
||||
* device was too busy */
|
||||
if (ni_tmp != NULL) {
|
||||
/* node reference was leaked */
|
||||
ieee80211_unref_node(&ni_tmp);
|
||||
}
|
||||
vap->iv_devstats.rx_dropped++;
|
||||
}
|
||||
skb = NULL; /* SKB is no longer ours */
|
||||
}
|
||||
dev->last_rx = jiffies;
|
||||
}
|
||||
}
|
||||
@ -1203,6 +1259,10 @@ ieee80211_decap(struct ieee80211vap *vap, struct sk_buff *skb, int hdrlen)
|
||||
|
||||
/* XXX: does this always work? */
|
||||
tskb = skb_copy(skb, GFP_ATOMIC);
|
||||
/* We duplicate the reference after skb_copy */
|
||||
if (SKB_CB(skb)->ni != NULL) {
|
||||
SKB_CB(tskb)->ni = ieee80211_ref_node(SKB_CB(skb)->ni);
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
skb = tskb;
|
||||
}
|
||||
@ -2234,10 +2294,15 @@ forward_mgmt_to_app(struct ieee80211vap *vap, int subtype, struct sk_buff *skb,
|
||||
|
||||
if (filter_type && ((vap->app_filter & filter_type) == filter_type)) {
|
||||
struct sk_buff *skb1;
|
||||
struct ieee80211_node *ni_tmp;
|
||||
|
||||
skb1 = skb_copy(skb, GFP_ATOMIC);
|
||||
if (skb1 == NULL)
|
||||
return;
|
||||
/* We duplicate the reference after skb_copy */
|
||||
if (SKB_CB(skb)->ni != NULL) {
|
||||
SKB_CB(skb1)->ni = ieee80211_ref_node(SKB_CB(skb)->ni);
|
||||
}
|
||||
skb1->dev = dev;
|
||||
skb_reset_mac_header(skb1);
|
||||
|
||||
@ -2245,7 +2310,18 @@ forward_mgmt_to_app(struct ieee80211vap *vap, int subtype, struct sk_buff *skb,
|
||||
skb1->pkt_type = PACKET_OTHERHOST;
|
||||
skb1->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */
|
||||
|
||||
netif_rx(skb1);
|
||||
ni_tmp = SKB_CB(skb1)->ni;
|
||||
if (netif_rx(skb1) == NET_RX_DROP) {
|
||||
/* If netif_rx dropped the packet because
|
||||
* device was too busy */
|
||||
if (ni_tmp != NULL) {
|
||||
/* node reference was leaked */
|
||||
ieee80211_unref_node(&ni_tmp);
|
||||
}
|
||||
vap->iv_devstats.rx_dropped++;
|
||||
}
|
||||
vap->iv_devstats.rx_packets++;
|
||||
vap->iv_devstats.rx_bytes += skb1->len;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2288,8 +2364,10 @@ ieee80211_doth_cancel_cs(struct ieee80211vap *vap)
|
||||
del_timer(&vap->iv_csa_timer);
|
||||
if (vap->iv_csa_jiffies)
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
|
||||
"channel switch canceled (was: to %u in %u "
|
||||
"tbtt, mode %u)\n", vap->iv_csa_chan->ic_ieee,
|
||||
"channel switch canceled (was: to %3d (%4d MHz) in %u "
|
||||
"TBTT, mode %u)\n",
|
||||
vap->iv_csa_chan->ic_ieee,
|
||||
vap->iv_csa_chan->ic_freq,
|
||||
vap->iv_csa_count, vap->iv_csa_mode);
|
||||
vap->iv_csa_jiffies = 0;
|
||||
}
|
||||
@ -2300,8 +2378,10 @@ ieee80211_doth_switch_channel(struct ieee80211vap *vap)
|
||||
struct ieee80211com *ic = vap->iv_ic;
|
||||
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
|
||||
"%s: Channel switch to %d NOW!\n",
|
||||
__func__, vap->iv_csa_chan->ic_ieee);
|
||||
"%s: Channel switch to %3d (%4d MHz) NOW!\n",
|
||||
__func__,
|
||||
vap->iv_csa_chan->ic_ieee,
|
||||
vap->iv_csa_chan->ic_freq);
|
||||
#if 0
|
||||
/* XXX does not belong here? */
|
||||
/* XXX doesn't stop management frames */
|
||||
@ -2384,8 +2464,10 @@ ieee80211_parse_csaie(struct ieee80211_node *ni, u_int8_t *frm,
|
||||
/* XXX abuse? */
|
||||
IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
|
||||
"%s: channel switch channel "
|
||||
"changed from %u to %u!\n", __func__,
|
||||
"changed from %3d (%4d MHz) to %u!\n",
|
||||
__func__,
|
||||
vap->iv_csa_chan->ic_ieee,
|
||||
vap->iv_csa_chan->ic_freq,
|
||||
csa_ie->csa_chan);
|
||||
|
||||
if (vap->iv_csa_count > IEEE80211_CSA_PROTECTION_PERIOD)
|
||||
@ -2497,8 +2579,7 @@ ieee80211_deliver_l2uf(struct ieee80211_node *ni)
|
||||
struct ether_header *eh;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(*l2uf));
|
||||
if (!skb) {
|
||||
printk("ieee80211_deliver_l2uf: no buf available\n");
|
||||
if (skb == NULL) {
|
||||
return;
|
||||
}
|
||||
skb_put(skb, sizeof(*l2uf));
|
||||
|
Loading…
Reference in New Issue
Block a user