ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen)
{
const u_int align = sizeof(u_int32_t);
- struct ieee80211_cb *cb;
struct sk_buff *skb;
u_int len;
if (off != 0)
skb_reserve(skb, align - off);
- cb = (struct ieee80211_cb *)skb->cb;
- cb->ni = NULL;
- cb->flags = 0;
- cb->next = NULL;
+ SKB_CB(skb)->ni = NULL;
+ SKB_CB(skb)->flags = 0;
+ SKB_CB(skb)->next = NULL;
skb_reserve(skb, sizeof(struct ieee80211_frame));
*frm = skb_put(skb, pktlen);
return skb;
}
-#if 0
-/*
- * Drain a queue of sk_buffs.
- */
-void
-__skb_queue_drain(struct sk_buff_head *q)
-{
- struct sk_buff *skb;
-
- while ((skb = __skb_dequeue(q)) != NULL)
- dev_kfree_skb(skb);
-}
-#endif
-
#if IEEE80211_VLAN_TAG_USED
/*
* VLAN support.
/* 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);
+ }
if (vap->iv_monitor_txf_len && tx) {
/* truncate transmit feedback packets */
skb_trim(skb1, vap->iv_monitor_txf_len);
default:
break;
}
- if (skb1) {
+ if (skb1 != NULL) {
+ struct ieee80211_node *ni_tmp;
if (!tx && (vap->iv_dev->type != ARPHRD_IEEE80211_RADIOTAP) && (skb1->len >= IEEE80211_CRC_LEN)) {
/* Remove FCS from end of rx frames when
* delivering to non-Radiotap VAPs */
skb1->pkt_type = pkttype;
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;
}