diff -ur madwifi.old/ath/if_ath.c madwifi.dev/ath/if_ath.c --- madwifi.old/ath/if_ath.c 2007-05-18 13:19:16.000000000 +0200 +++ madwifi.dev/ath/if_ath.c 2007-05-21 08:10:46.864754176 +0200 @@ -158,8 +158,7 @@ static int ath_desc_alloc(struct ath_softc *); static void ath_desc_free(struct ath_softc *); static void ath_desc_swap(struct ath_desc *); -static struct ieee80211_node *ath_node_alloc(struct ieee80211_node_table *, - struct ieee80211vap *); +static struct ieee80211_node *ath_node_alloc(struct ieee80211vap *); static void ath_node_cleanup(struct ieee80211_node *); static void ath_node_free(struct ieee80211_node *); static u_int8_t ath_node_getrssi(const struct ieee80211_node *); @@ -2385,7 +2384,7 @@ if (ath_tx_start(sc->sc_dev, ni, bf_ff, bf_ff->bf_skb, 0) == 0) continue; bad: - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); if (bf_ff->bf_skb != NULL) { dev_kfree_skb(bf_ff->bf_skb); bf_ff->bf_skb = NULL; @@ -2525,8 +2524,10 @@ skb = bf->bf_skb; ATH_FF_MAGIC_PUT(skb); +#if 0 /* decrement extra node reference made when an_tx_ffbuf[] was set */ - //ieee80211_free_node(ni); /* XXX where was it set ? */ + ieee80211_unref_node(&ni); /* XXX where was it set ? */ +#endif DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF, "%s: aggregating fast-frame\n", __func__); @@ -2585,7 +2586,7 @@ ff_flushbad: DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF, "%s: ff stageq flush failure\n", __func__); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); if (bf_ff->bf_skb) { dev_kfree_skb(bf_ff->bf_skb); bf_ff->bf_skb = NULL; @@ -2707,7 +2708,7 @@ tbf->bf_node = NULL; if (ni != NULL) - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); STAILQ_INSERT_TAIL(&sc->sc_txbuf, tbf, bf_list); } @@ -2789,7 +2790,7 @@ /* fall thru... */ bad: if (ni != NULL) - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); if (bf != NULL) { bf->bf_skb = NULL; bf->bf_node = NULL; @@ -3178,7 +3179,7 @@ */ ni = sc->sc_keyixmap[keyix]; if (ni != NULL) { - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); sc->sc_keyixmap[keyix] = NULL; } /* @@ -3189,7 +3190,7 @@ ath_hal_keyreset(ah, keyix + 32); /* RX key */ ni = sc->sc_keyixmap[keyix + 32]; if (ni != NULL) { /* as above... */ - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); sc->sc_keyixmap[keyix + 32] = NULL; } } @@ -3202,7 +3203,7 @@ ath_hal_keyreset(ah, keyix + rxkeyoff); ni = sc->sc_keyixmap[keyix + rxkeyoff]; if (ni != NULL) { /* as above... */ - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); sc->sc_keyixmap[keyix + rxkeyoff] = NULL; } } @@ -3764,10 +3765,8 @@ dev_kfree_skb(bf->bf_skb); bf->bf_skb = NULL; } - if (bf->bf_node != NULL) { - ieee80211_free_node(bf->bf_node); - bf->bf_node = NULL; - } + if (bf->bf_node != NULL) + ieee80211_unref_node(&bf->bf_node); /* * NB: the beacon data buffer must be 32-bit aligned; @@ -3808,7 +3807,7 @@ DPRINTF(sc, ATH_DEBUG_BEACON, "%s: %s beacons, bslot %d intval %u tsfadjust(Kus) %llu\n", __func__, sc->sc_stagbeacons ? "stagger" : "burst", - avp->av_bslot, ni->ni_intval, (unsigned long long) tuadjust); + avp->av_bslot, ni->ni_intval, (long long) tuadjust); wh = (struct ieee80211_frame *) skb->data; memcpy(&wh[1], &tsfadjust, sizeof(tsfadjust)); @@ -4128,7 +4127,7 @@ vap = sc->sc_bslot[(slot + 1) % ATH_BCBUF]; DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: slot %d [tsf %llu tsftu %u intval %u] vap %p\n", - __func__, slot, (unsigned long long) tsf, tsftu, ic->ic_lintval, vap); + __func__, slot, (long long) tsf, tsftu, ic->ic_lintval, vap); bfaddr = 0; if (vap != NULL) { bf = ath_beacon_generate(sc, vap, needmark); @@ -4309,10 +4308,8 @@ dev_kfree_skb(bf->bf_skb); bf->bf_skb = NULL; } - if (bf->bf_node != NULL) { - ieee80211_free_node(bf->bf_node); - bf->bf_node = NULL; - } + if (bf->bf_node != NULL) + ieee80211_unref_node(&bf->bf_node); STAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list); } @@ -4331,10 +4328,8 @@ dev_kfree_skb(bf->bf_skb); bf->bf_skb = NULL; } - if (bf->bf_node != NULL) { - ieee80211_free_node(bf->bf_node); - bf->bf_node = NULL; - } + if (bf->bf_node != NULL) + ieee80211_unref_node(&bf->bf_node); } } @@ -4620,7 +4615,7 @@ /* * Reclaim node reference. */ - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); } } @@ -4679,37 +4674,39 @@ } static struct ieee80211_node * -ath_node_alloc(struct ieee80211_node_table *nt,struct ieee80211vap *vap) +ath_node_alloc(struct ieee80211vap *vap) { - struct ath_softc *sc = nt->nt_ic->ic_dev->priv; + struct ath_softc *sc = vap->iv_ic->ic_dev->priv; const size_t space = sizeof(struct ath_node) + sc->sc_rc->arc_space; struct ath_node *an; an = kmalloc(space, GFP_ATOMIC); - if (an == NULL) - return NULL; - memset(an, 0, space); - an->an_decomp_index = INVALID_DECOMP_INDEX; - an->an_avgrssi = ATH_RSSI_DUMMY_MARKER; - an->an_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - an->an_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - an->an_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - /* - * ath_rate_node_init needs a VAP pointer in node - * to decide which mgt rate to use - */ - an->an_node.ni_vap = vap; - sc->sc_rc->ops->node_init(sc, an); - - /* U-APSD init */ - STAILQ_INIT(&an->an_uapsd_q); - an->an_uapsd_qdepth = 0; - STAILQ_INIT(&an->an_uapsd_overflowq); - an->an_uapsd_overflowqdepth = 0; - ATH_NODE_UAPSD_LOCK_INIT(an); + if (an != NULL) { + memset(an, 0, space); + an->an_decomp_index = INVALID_DECOMP_INDEX; + an->an_avgrssi = ATH_RSSI_DUMMY_MARKER; + an->an_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; + an->an_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; + an->an_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + /* + * ath_rate_node_init needs a vap pointer in node + * to decide which mgt rate to use + */ + an->an_node.ni_vap = vap; + sc->sc_rc->ops->node_init(sc, an); - DPRINTF(sc, ATH_DEBUG_NODE, "%s: an %p\n", __func__, an); - return &an->an_node; + /* U-APSD init */ + STAILQ_INIT(&an->an_uapsd_q); + an->an_uapsd_qdepth = 0; + STAILQ_INIT(&an->an_uapsd_overflowq); + an->an_uapsd_overflowqdepth = 0; + ATH_NODE_UAPSD_LOCK_INIT(an); + + DPRINTF(sc, ATH_DEBUG_NODE, "%s: an %p\n", __func__, an); + return &an->an_node; + } else { + return NULL; + } } static void @@ -4719,6 +4716,7 @@ struct ath_softc *sc = ni->ni_ic->ic_dev->priv; struct ath_node *an = ATH_NODE(ni); struct ath_buf *bf; + struct ieee80211_cb *cb = NULL; /* * U-APSD cleanup @@ -4733,15 +4731,18 @@ while (an->an_uapsd_qdepth) { bf = STAILQ_FIRST(&an->an_uapsd_q); STAILQ_REMOVE_HEAD(&an->an_uapsd_q, bf_list); - bf->bf_desc->ds_link = 0; + cb = (struct ieee80211_cb *) bf->bf_skb->cb; + ieee80211_unref_node(&cb->ni); dev_kfree_skb_any(bf->bf_skb); + + bf->bf_desc->ds_link = 0; bf->bf_skb = NULL; bf->bf_node = NULL; + ATH_TXBUF_LOCK_IRQ(sc); STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); ATH_TXBUF_UNLOCK_IRQ(sc); - ieee80211_free_node(ni); an->an_uapsd_qdepth--; } @@ -4749,19 +4750,25 @@ while (an->an_uapsd_overflowqdepth) { bf = STAILQ_FIRST(&an->an_uapsd_overflowq); STAILQ_REMOVE_HEAD(&an->an_uapsd_overflowq, bf_list); - bf->bf_desc->ds_link = 0; + cb = (struct ieee80211_cb *) bf->bf_skb->cb; + ieee80211_unref_node(&cb->ni); dev_kfree_skb_any(bf->bf_skb); + bf->bf_skb = NULL; bf->bf_node = NULL; + bf->bf_desc->ds_link = 0; + ATH_TXBUF_LOCK_IRQ(sc); STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); ATH_TXBUF_UNLOCK_IRQ(sc); - ieee80211_free_node(ni); an->an_uapsd_overflowqdepth--; } + /* Clean up node-specific rate things - this currently appears to always be a no-op */ + sc->sc_rc->ops->node_cleanup(sc, ATH_NODE(ni)); + ATH_NODE_UAPSD_LOCK_IRQ(an); sc->sc_node_cleanup(ni); ATH_NODE_UAPSD_UNLOCK_IRQ(an); @@ -4772,7 +4779,6 @@ { struct ath_softc *sc = ni->ni_ic->ic_dev->priv; - sc->sc_rc->ops->node_cleanup(sc, ATH_NODE(ni)); sc->sc_node_free(ni); #ifdef ATH_SUPERG_XR ath_grppoll_period_update(sc); @@ -5660,7 +5666,7 @@ an = ATH_NODE(ieee80211_ref_node(ni)); ATH_RSSI_LPF(an->an_avgrssi, rs->rs_rssi); type = ieee80211_input(ni, skb, rs->rs_rssi, rs->rs_tstamp); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); } else { /* * No key index or no entry, do a lookup and @@ -5682,7 +5688,7 @@ if (keyix != IEEE80211_KEYIX_NONE && sc->sc_keyixmap[keyix] == NULL) sc->sc_keyixmap[keyix] = ieee80211_ref_node(ni); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); } else type = ieee80211_input_all(ic, skb, rs->rs_rssi, rs->rs_tstamp); @@ -6478,8 +6484,7 @@ STAILQ_REMOVE_HEAD(&an->an_uapsd_q, bf_list); dev_kfree_skb(lastbuf->bf_skb); lastbuf->bf_skb = NULL; - ieee80211_free_node(lastbuf->bf_node); - lastbuf->bf_node = NULL; + ieee80211_unref_node(&lastbuf->bf_node); ATH_TXBUF_LOCK_IRQ(sc); STAILQ_INSERT_TAIL(&sc->sc_txbuf, lastbuf, bf_list); ATH_TXBUF_UNLOCK_IRQ(sc); @@ -7229,7 +7234,7 @@ * this is a DEAUTH message that was sent and the * node was timed out due to inactivity. */ - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); } bus_unmap_single(sc->sc_bdev, bf->bf_skbaddr, @@ -7474,7 +7479,7 @@ } #endif /* ATH_SUPERG_FF */ if (bf->bf_node) - ieee80211_free_node(bf->bf_node); + ieee80211_unref_node(&bf->bf_node); bf->bf_skb = NULL; bf->bf_node = NULL; diff -ur madwifi.old/net80211/ieee80211_input.c madwifi.dev/net80211/ieee80211_input.c --- madwifi.old/net80211/ieee80211_input.c 2007-05-18 13:19:16.000000000 +0200 +++ madwifi.dev/net80211/ieee80211_input.c 2007-05-21 08:10:46.865754024 +0200 @@ -489,7 +489,7 @@ nt = &ic->ic_sta; ni_wds = ieee80211_find_wds_node(nt, wh->i_addr3); if (ni_wds) { - ieee80211_free_node(ni_wds); /* Decr ref count */ + ieee80211_unref_node(&ni_wds); /* Decr ref count */ IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, NULL, "%s", "multicast echo originated from node behind me"); @@ -543,10 +543,12 @@ * the node table for the packet source address (addr4). * If not, add one. */ + /* XXX: Useless node mgmt API; make better */ if (dir == IEEE80211_FC1_DIR_DSTODS) { struct ieee80211_node_table *nt; struct ieee80211_frame_addr4 *wh4; struct ieee80211_node *ni_wds; + if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) { IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, "data", "%s", "4 addr not allowed"); @@ -569,7 +571,7 @@ if (ni_wds == NULL) ieee80211_add_wds_addr(nt, ni, wh4->i_addr4, 0); else - ieee80211_free_node(ni_wds); /* Decr ref count */ + ieee80211_unref_node(&ni_wds); /* Decr. ref count */ } /* @@ -936,7 +938,7 @@ } ni = ieee80211_ref_node(vap->iv_bss); type = ieee80211_input(ni, skb1, rssi, rstamp); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); } if (skb != NULL) /* no vaps, reclaim skb */ dev_kfree_skb(skb); @@ -986,22 +988,14 @@ } /* - * Use this lock to make sure ni->ni_rxfrag is - * not freed by the timer process while we use it. - * XXX bogus - */ - IEEE80211_NODE_LOCK_IRQ(ni->ni_table); - - /* * Update the time stamp. As a side effect, it * also makes sure that the timer will not change * ni->ni_rxfrag for at least 1 second, or in * other words, for the remaining of this function. + * XXX HUGE HORRIFIC HACK */ ni->ni_rxfragstamp = jiffies; - IEEE80211_NODE_UNLOCK_IRQ(ni->ni_table); - /* * Validate that fragment is in order and * related to the previous ones. @@ -1130,7 +1124,7 @@ skb = NULL; } /* XXX statistic? */ - ieee80211_free_node(ni1); + ieee80211_unref_node(&ni1); } } if (skb1 != NULL) { @@ -1265,6 +1259,7 @@ int rssi, u_int32_t rstamp, u_int16_t seq, u_int16_t status) { struct ieee80211vap *vap = ni->ni_vap; + unsigned int tmpnode = 0; if (ni->ni_authmode == IEEE80211_AUTH_SHARED) { IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, @@ -1272,22 +1267,21 @@ "bad sta auth mode %u", ni->ni_authmode); vap->iv_stats.is_rx_bad_auth++; /* XXX maybe a unique error? */ if (vap->iv_opmode == IEEE80211_M_HOSTAP) { - /* XXX hack to workaround calling convention */ - - /* XXX To send the frame to the requesting STA, we have to - * create a node for the station that we're going to reject. - * The node will be freed automatically */ if (ni == vap->iv_bss) { - ni = ieee80211_dup_bss(vap, wh->i_addr2); + ni = ieee80211_dup_bss(vap, wh->i_addr2, 0); if (ni == NULL) return; IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "%s: %p<%s> refcnt %d\n", __func__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); + tmpnode = 1; } IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, (seq + 1) | (IEEE80211_STATUS_ALG << 16)); + + if (tmpnode) + ieee80211_unref_node(&ni); return; } } @@ -1315,23 +1309,16 @@ } /* always accept open authentication requests */ if (ni == vap->iv_bss) { - ni = ieee80211_dup_bss(vap, wh->i_addr2); + ni = ieee80211_dup_bss(vap, wh->i_addr2, 0); if (ni == NULL) return; IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "%s: %p<%s> refcnt %d\n", __func__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); - - } else if ((ni->ni_flags & IEEE80211_NODE_AREF) == 0) - (void) ieee80211_ref_node(ni); - /* - * Mark the node as referenced to reflect that it's - * reference count has been bumped to ensure it remains - * after the transaction completes. - */ - ni->ni_flags |= IEEE80211_NODE_AREF; - + tmpnode = 1; + } + IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, seq + 1); IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, ni, "station authenticated (%s)", "open"); @@ -1341,6 +1328,8 @@ */ if (ni->ni_authmode != IEEE80211_AUTH_8021X) ieee80211_node_authorize(ni); + if (tmpnode) + ieee80211_unref_node(&ni); break; case IEEE80211_M_STA: @@ -1379,7 +1368,7 @@ int istmp; if (ni == vap->iv_bss) { - ni = ieee80211_tmp_node(vap, mac); + ni = ieee80211_dup_bss(vap, mac, 1); if (ni == NULL) { /* XXX msg */ return; @@ -1389,7 +1378,7 @@ istmp = 0; IEEE80211_SEND_MGMT(ni, subtype, arg); if (istmp) - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); } static int @@ -1505,7 +1494,7 @@ switch (seq) { case IEEE80211_AUTH_SHARED_REQUEST: if (ni == vap->iv_bss) { - ni = ieee80211_dup_bss(vap, wh->i_addr2); + ni = ieee80211_dup_bss(vap, wh->i_addr2, 0); if (ni == NULL) { /* NB: no way to return an error */ return; @@ -1516,17 +1505,8 @@ ieee80211_node_refcnt(ni)); allocbs = 1; - } else { - if ((ni->ni_flags & IEEE80211_NODE_AREF) == 0) - (void) ieee80211_ref_node(ni); - allocbs = 0; } - /* - * Mark the node as referenced to reflect that it's - * reference count has been bumped to ensure it remains - * after the transaction completes. - */ - ni->ni_flags |= IEEE80211_NODE_AREF; + ni->ni_rssi = rssi; ni->ni_rstamp = rstamp; ni->ni_last_rx = jiffies; @@ -1620,14 +1600,13 @@ } return; bad: - /* - * Send an error response; but only when operating as an AP. - */ + /* Send an error response; but only when operating as an AP. */ if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* XXX hack to workaround calling convention */ ieee80211_send_error(ni, wh->i_addr2, IEEE80211_FC0_SUBTYPE_AUTH, (seq + 1) | (estatus<<16)); + ieee80211_node_leave(ni); } else if (vap->iv_opmode == IEEE80211_M_STA) { /* * Kick the state machine. This short-circuits @@ -2600,7 +2579,7 @@ u_int8_t *frm, *efrm; u_int8_t *ssid, *rates, *xrates, *wpa, *rsn, *wme, *ath; u_int8_t rate; - int reassoc, resp, allocbs; + int reassoc, resp, allocbs = 0; u_int8_t qosinfo; wh = (struct ieee80211_frame *) skb->data; @@ -3008,13 +2987,13 @@ ni = ieee80211_fakeup_adhoc_node(vap, wh->i_addr2); } else { - ni = ieee80211_tmp_node(vap, wh->i_addr2); + ni = ieee80211_dup_bss(vap, wh->i_addr2, 1); } if (ni == NULL) return; allocbs = 1; - } else - allocbs = 0; + } + IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr2, "%s", "recv probe req"); ni->ni_rssi = rssi; @@ -3037,7 +3016,7 @@ * Temporary node created just to send a * response, reclaim immediately */ - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); } else if (ath != NULL) ieee80211_saveath(ni, ath); break; @@ -3067,6 +3046,9 @@ ni = vap->iv_xrvap->iv_bss; else { ieee80211_node_leave(ni); + /* This would be a stupid place to add a node to the table + * XR stuff needs work anyway + */ ieee80211_node_reset(ni, vap->iv_xrvap); } vap = vap->iv_xrvap; diff -ur madwifi.old/net80211/ieee80211_linux.c madwifi.dev/net80211/ieee80211_linux.c --- madwifi.old/net80211/ieee80211_linux.c 2007-05-18 13:19:16.000000000 +0200 +++ madwifi.dev/net80211/ieee80211_linux.c 2007-05-21 08:10:46.866753872 +0200 @@ -358,7 +358,7 @@ struct ieee80211_node *ni; struct ieee80211_node_table *nt = (struct ieee80211_node_table *) &vap->iv_ic->ic_sta; - //IEEE80211_NODE_LOCK(nt); + /* IEEE80211_NODE_LOCK(nt); */ TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { /* Assume each node needs 500 bytes */ if (buf + space < p + 500) @@ -376,7 +376,7 @@ } } - //IEEE80211_NODE_UNLOCK(nt); + /* IEEE80211_NODE_UNLOCK(nt); */ return (p - buf); } diff -ur madwifi.old/net80211/ieee80211_linux.h madwifi.dev/net80211/ieee80211_linux.h --- madwifi.old/net80211/ieee80211_linux.h 2007-05-04 15:45:58.000000000 +0200 +++ madwifi.dev/net80211/ieee80211_linux.h 2007-05-21 08:10:46.867753720 +0200 @@ -63,6 +63,12 @@ #define IEEE80211_RESCHEDULE schedule +/* Locking */ +/* NB: beware, spin_is_locked() is not usefully defined for !(DEBUG || SMP) + * because spinlocks do not exist in this configuration. Instead IRQs + * or pre-emption are simply disabled, as this is all that is needed. + */ + /* * Beacon handler locking definitions. * Beacon locking @@ -85,14 +91,14 @@ #define IEEE80211_LOCK(_ic) spin_lock(&(_ic)->ic_comlock) #define IEEE80211_UNLOCK(_ic) spin_unlock(&(_ic)->ic_comlock) -/* NB: beware, spin_is_locked() is unusable for !SMP */ -#if defined(CONFIG_SMP) +#if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked) #define IEEE80211_LOCK_ASSERT(_ic) \ KASSERT(spin_is_locked(&(_ic)->ic_comlock),("ieee80211com not locked!")) #else #define IEEE80211_LOCK_ASSERT(_ic) #endif + #define IEEE80211_VAPS_LOCK_INIT(_ic, _name) \ spin_lock_init(&(_ic)->ic_vapslock) #define IEEE80211_VAPS_LOCK_DESTROY(_ic) @@ -108,11 +114,10 @@ } while (0) #define IEEE80211_VAPS_UNLOCK_IRQ_EARLY(_ic) spin_unlock_irqrestore(&(_ic)->ic_vapslock, _vaps_lockflags) - -/* NB: beware, spin_is_locked() is unusable for !SMP */ -#if defined(CONFIG_SMP) +#if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked) #define IEEE80211_VAPS_LOCK_ASSERT(_ic) \ - KASSERT(spin_is_locked(&(_ic)->ic_vapslock),("ieee80211com_vaps not locked!")) + KASSERT(spin_is_locked(&(_ic)->ic_vapslock), \ + ("ieee80211com_vaps not locked!")) #else #define IEEE80211_VAPS_LOCK_ASSERT(_ic) #endif @@ -121,29 +126,63 @@ /* * Node locking definitions. */ +#if 0 + typedef spinlock_t ieee80211_node_lock_t; -#define IEEE80211_NODE_LOCK_INIT(_nt, _name) spin_lock_init(&(_nt)->nt_nodelock) -#define IEEE80211_NODE_LOCK_DESTROY(_nt) -#define IEEE80211_NODE_LOCK(_nt) spin_lock(&(_nt)->nt_nodelock) -#define IEEE80211_NODE_UNLOCK(_nt) spin_unlock(&(_nt)->nt_nodelock) -#define IEEE80211_NODE_LOCK_BH(_nt) spin_lock_bh(&(_nt)->nt_nodelock) -#define IEEE80211_NODE_UNLOCK_BH(_nt) spin_unlock_bh(&(_nt)->nt_nodelock) -#define IEEE80211_NODE_LOCK_IRQ(_nt) do { \ +#define IEEE80211_NODE_LOCK_INIT(_ni, _name) spin_lock_init(&(_ni)->ni_nodelock) +#define IEEE80211_NODE_LOCK_DESTROY(_ni) +#if 0 /* We should always be contesting in the same contexts */ +#define IEEE80211_NODE_LOCK(_ni) spin_lock(&(_ni)->ni_nodelock) +#define IEEE80211_NODE_UNLOCK(_ni) spin_unlock(&(_ni)->ni_nodelock) +#define IEEE80211_NODE_LOCK_BH(_ni) spin_lock_bh(&(_ni)->ni_nodelock) +#define IEEE80211_NODE_UNLOCK_BH(_ni) spin_unlock_bh(&(_ni)->ni_nodelock) +#endif +#define IEEE80211_NODE_LOCK_IRQ(_ni) do { \ + unsigned long __node_lockflags; \ + spin_lock_irqsave(&(_ni)->ni_nodelock, __node_lockflags); +#define IEEE80211_NODE_UNLOCK_IRQ(_ni) \ + spin_unlock_irqrestore(&(_ni)->ni_nodelock, __node_lockflags); \ +} while(0) +#define IEEE80211_NODE_UNLOCK_IRQ_EARLY(_ni) \ + spin_unlock_irqrestore(&(_ni)->ni_nodelock, __node_lockflags); + +#if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked) +#define IEEE80211_NODE_LOCK_ASSERT(_nt) \ + KASSERT(spin_is_locked(&(_ni)->ni_nodelock), \ + ("802.11 node not locked!")) +#else +#define IEEE80211_NODE_LOCK_ASSERT(_ni) +#endif + +#endif /* node lock */ + +/* + * Node table locking definitions. + */ +typedef spinlock_t ieee80211_node_table_lock_t; +#define IEEE80211_NODE_TABLE_LOCK_INIT(_nt, _name) spin_lock_init(&(_nt)->nt_nodelock) +#define IEEE80211_NODE_TABLE_LOCK_DESTROY(_nt) +#if 0 /* We should always be contesting in the same contexts */ +#define IEEE80211_NODE_TABLE_LOCK(_nt) spin_lock(&(_nt)->nt_nodelock) +#define IEEE80211_NODE_TABLE_UNLOCK(_nt) spin_unlock(&(_nt)->nt_nodelock) +#define IEEE80211_NODE_TABLE_LOCK_BH(_nt) spin_lock_bh(&(_nt)->nt_nodelock) +#define IEEE80211_NODE_TABLE_UNLOCK_BH(_nt) spin_unlock_bh(&(_nt)->nt_nodelock) +#endif +#define IEEE80211_NODE_TABLE_LOCK_IRQ(_nt) do { \ unsigned long __node_lockflags; \ spin_lock_irqsave(&(_nt)->nt_nodelock, __node_lockflags); -#define IEEE80211_NODE_UNLOCK_IRQ(_nt) \ +#define IEEE80211_NODE_TABLE_UNLOCK_IRQ(_nt) \ spin_unlock_irqrestore(&(_nt)->nt_nodelock, __node_lockflags); \ } while(0) -#define IEEE80211_NODE_UNLOCK_IRQ_EARLY(_nt) \ +#define IEEE80211_NODE_TABLE_UNLOCK_IRQ_EARLY(_nt) \ spin_unlock_irqrestore(&(_nt)->nt_nodelock, __node_lockflags); -/* NB: beware, *_is_locked() are bogusly defined for UP+!PREEMPT */ -#if (defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)) && defined(spinlock_is_locked) -#define IEEE80211_NODE_LOCK_ASSERT(_nt) \ - KASSERT(spinlock_is_locked(&(_nt)->nt_nodelock), \ +#if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked) +#define IEEE80211_NODE_TABLE_LOCK_ASSERT(_nt) \ + KASSERT(spin_is_locked(&(_nt)->nt_nodelock), \ ("802.11 node table not locked!")) #else -#define IEEE80211_NODE_LOCK_ASSERT(_nt) +#define IEEE80211_NODE_TABLE_LOCK_ASSERT(_nt) #endif /* @@ -163,8 +202,7 @@ #define IEEE80211_SCAN_UNLOCK_IRQ_EARLY(_nt) \ spin_unlock_irqrestore(&(_nt)->nt_scanlock, __scan_lockflags); -/* NB: beware, spin_is_locked() is unusable for !SMP */ -#if defined(CONFIG_SMP) +#if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked) #define IEEE80211_SCAN_LOCK_ASSERT(_nt) \ KASSERT(spin_is_locked(&(_nt)->nt_scanlock), ("scangen not locked!")) #else @@ -182,8 +220,7 @@ #define ACL_LOCK_BH(_as) spin_lock_bh(&(_as)->as_lock) #define ACL_UNLOCK_BH(_as) spin_unlock_bh(&(_as)->as_lock) -/* NB: beware, spin_is_locked() is unusable for !SMP */ -#if defined(CONFIG_SMP) +#if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked) #define ACL_LOCK_ASSERT(_as) \ KASSERT(spin_is_locked(&(_as)->as_lock), ("ACL not locked!")) #else @@ -299,6 +336,7 @@ * is the last reference, otherwise 0 * ieee80211_node_refcnt reference count for printing (only) */ +typedef atomic_t ieee80211_node_ref_count_t; #define ieee80211_node_initref(_ni) atomic_set(&(_ni)->ni_refcnt, 1) #define ieee80211_node_incref(_ni) atomic_inc(&(_ni)->ni_refcnt) #define ieee80211_node_decref(_ni) atomic_dec(&(_ni)->ni_refcnt) @@ -379,8 +417,8 @@ /* msecs_to_jiffies appeared in 2.6.7 and 2.4.29 */ #include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)) || \ - LINUX_VERSION_CODE < KERNEL_VERSION(2,4,29) + LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)) || \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,4,29) /* The following definitions and inline functions are * copied from the kernel src, include/linux/jiffies.h */ diff -ur madwifi.old/net80211/ieee80211_node.c madwifi.dev/net80211/ieee80211_node.c --- madwifi.old/net80211/ieee80211_node.c 2007-05-18 13:19:16.000000000 +0200 +++ madwifi.dev/net80211/ieee80211_node.c 2007-05-21 08:10:46.868753568 +0200 @@ -65,16 +65,17 @@ #define IEEE80211_AID_ISSET(_vap, _b) \ ((_vap)->iv_aid_bitmap[IEEE80211_AID(_b) / 32] & (1 << (IEEE80211_AID(_b) % 32))) +static struct ieee80211_node *ieee80211_alloc_node(struct ieee80211vap *, const u_int8_t *); + static int ieee80211_sta_join1(struct ieee80211_node *); -static struct ieee80211_node *node_alloc(struct ieee80211_node_table *, - struct ieee80211vap *); +static struct ieee80211_node *node_alloc(struct ieee80211vap *); static void node_cleanup(struct ieee80211_node *); static void node_free(struct ieee80211_node *); static u_int8_t node_getrssi(const struct ieee80211_node *); -static void _ieee80211_free_node(struct ieee80211_node *); -static void node_reclaim(struct ieee80211_node_table *, struct ieee80211_node*); +static void _node_table_leave(struct ieee80211_node_table *, struct ieee80211_node *); +static void _node_table_join(struct ieee80211_node_table *, struct ieee80211_node *); static void ieee80211_node_timeout(unsigned long); @@ -194,8 +195,7 @@ ieee80211_node_table_reset(&ic->ic_sta, vap); if (vap->iv_bss != NULL) { - ieee80211_free_node(vap->iv_bss); - vap->iv_bss = NULL; + ieee80211_unref_node(&vap->iv_bss); } if (vap->iv_aid_bitmap != NULL) { FREE(vap->iv_aid_bitmap, M_DEVBUF); @@ -250,6 +250,7 @@ nbss->ni_txpower = obss->ni_txpower; nbss->ni_vlan = obss->ni_vlan; nbss->ni_rsn = obss->ni_rsn; + nbss->ni_rates = obss->ni_rates; /* XXX statistics? */ } @@ -263,17 +264,17 @@ "%s: creating ibss on channel %u\n", __func__, ieee80211_chan2ieee(ic, chan)); - /* Check to see if we already have a node for this mac */ + /* Check to see if we already have a node for this mac + * NB: we gain a node reference here + */ ni = ieee80211_find_node(&ic->ic_sta, vap->iv_myaddr); if (ni == NULL) { - ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); + ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr); if (ni == NULL) { /* XXX recovery? */ return; } } - else - ieee80211_free_node(ni); IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "%s: %p<%s> refcnt %d\n", __func__, vap->iv_bss, ether_sprintf(vap->iv_bss->ni_macaddr), @@ -339,7 +340,7 @@ else if (IEEE80211_IS_CHAN_QUARTER(chan)) ni->ni_rates = ic->ic_sup_quarter_rates; - (void) ieee80211_sta_join1(ieee80211_ref_node(ni)); + (void) ieee80211_sta_join1(PASS_NODE(ni)); } EXPORT_SYMBOL(ieee80211_create_ibss); @@ -363,9 +364,10 @@ /* XXX multi-bss wrong */ ieee80211_reset_erp(ic, ic->ic_curmode); - ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr); + ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr); KASSERT(ni != NULL, ("unable to setup inital BSS node")); obss = vap->iv_bss; + /* New reference for caller */ vap->iv_bss = ieee80211_ref_node(ni); IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "%s: new bss %p<%s> refcnt %d\n", @@ -375,7 +377,8 @@ if (obss != NULL) { copy_bss(ni, obss); ni->ni_intval = ic->ic_lintval; - ieee80211_free_node(obss); + /* Caller's reference */ + ieee80211_unref_node(&obss); } } @@ -581,7 +584,7 @@ vap->iv_state == IEEE80211_S_RUN && ssid_equal(obss, selbs)); vap->iv_bss = selbs; if (obss != NULL) - ieee80211_free_node(obss); + ieee80211_unref_node(&obss); ic->ic_bsschan = selbs->ni_chan; ic->ic_curchan = ic->ic_bsschan; ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan); @@ -638,21 +641,20 @@ ni = ieee80211_find_node(&ic->ic_sta, se->se_macaddr); if (ni == NULL) { - ni = ieee80211_alloc_node(&ic->ic_sta, vap, se->se_macaddr); + ni = ieee80211_alloc_node_table(vap, se->se_macaddr); if (ni == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "%s: Unable to allocate node for BSS: %s\n", __func__, ether_sprintf(ni->ni_macaddr)); return 0; } - } else - ieee80211_free_node(ni); + } /* * Expand scan state into node's format. * XXX may not need all this stuff */ - ni->ni_authmode = vap->iv_bss->ni_authmode; /* inherit authmode from iv_bss */ + ni->ni_authmode = vap->iv_bss->ni_authmode; /* inherit authmode from iv_bss */ /* inherit the WPA setup as well (structure copy!) */ ni->ni_rsn = vap->iv_bss->ni_rsn; IEEE80211_ADDR_COPY(ni->ni_bssid, se->se_bssid); @@ -686,9 +688,9 @@ IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "%s: %p<%s> refcnt %d\n", __func__, ni, ether_sprintf(ni->ni_macaddr), - ieee80211_node_refcnt(ni)+1); + ieee80211_node_refcnt(ni)); - return ieee80211_sta_join1(ieee80211_ref_node(ni)); + return ieee80211_sta_join1(PASS_NODE(ni)); } EXPORT_SYMBOL(ieee80211_sta_join); @@ -700,15 +702,13 @@ ieee80211_sta_leave(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = vap->iv_ic; /* WDS/Repeater: Stop software beacon timer for STA */ if (vap->iv_opmode == IEEE80211_M_STA && vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) { del_timer(&vap->iv_swbmiss); } - - ic->ic_node_cleanup(ni); + ieee80211_notify_node_leave(ni); } @@ -717,11 +717,11 @@ */ static void -ieee80211_node_table_init(struct ieee80211com *ic, - struct ieee80211_node_table *nt, const char *name, int inact) +ieee80211_node_table_init(struct ieee80211com *ic, struct ieee80211_node_table *nt, + const char *name, int inact) { nt->nt_ic = ic; - IEEE80211_NODE_LOCK_INIT(nt, ic->ic_dev->name); + IEEE80211_NODE_TABLE_LOCK_INIT(nt, ic->ic_dev->name); IEEE80211_SCAN_LOCK_INIT(nt, ic->ic_dev->name); TAILQ_INIT(&nt->nt_node); nt->nt_name = name; @@ -733,11 +733,31 @@ mod_timer(&nt->nt_wds_aging_timer, jiffies + HZ * WDS_AGING_TIMER_VAL); } +static __inline void _node_table_join(struct ieee80211_node_table *nt, struct ieee80211_node *ni) { + IEEE80211_NODE_TABLE_LOCK_ASSERT(nt); + + ni->ni_table = nt; + TAILQ_INSERT_TAIL(&nt->nt_node, ieee80211_ref_node(ni), ni_list); + LIST_INSERT_HEAD(&nt->nt_hash[IEEE80211_NODE_HASH(ni->ni_macaddr)], ni, ni_hash); +} + +static __inline void _node_table_leave(struct ieee80211_node_table *nt, struct ieee80211_node *ni) { + struct ieee80211_node *hni; + IEEE80211_NODE_TABLE_LOCK_ASSERT(nt); + + TAILQ_REMOVE(&nt->nt_node, ni, ni_list); + LIST_FOREACH(hni, &nt->nt_hash[IEEE80211_NODE_HASH(ni->ni_macaddr)], ni_hash) { + LIST_REMOVE(ni, ni_hash); + } + ni->ni_table = NULL; + _ieee80211_unref_node(ni); +} + /* This is overridden by ath_node_alloc in ath/if_ath.c, and so - * should never get called + * should never get called. */ static struct ieee80211_node * -node_alloc(struct ieee80211_node_table *nt, struct ieee80211vap *vap) +node_alloc(struct ieee80211vap *vap) { struct ieee80211_node *ni; @@ -776,13 +796,6 @@ IEEE80211_UNLOCK_IRQ(ni->ni_ic); } } - /* - * Clear AREF flag that marks the authorization refcnt bump - * has happened. This is probably not needed as the node - * should always be removed from the table so not found but - * do it just in case. - */ - ni->ni_flags &= ~IEEE80211_NODE_AREF; /* * Drain power save queue and, if needed, clear TIM. @@ -791,10 +804,7 @@ vap->iv_set_tim(ni, 0); ni->ni_associd = 0; - if (ni->ni_challenge != NULL) { - FREE(ni->ni_challenge, M_DEVBUF); - ni->ni_challenge = NULL; - } + /* * Preserve SSID, WPA, and WME ie's so the bss node is * reusable during a re-auth/re-assoc state transition. @@ -819,9 +829,16 @@ static void node_free(struct ieee80211_node *ni) { +#if 0 + /* We should 'cleanup' and then free'ing should be done automatically on decref */ struct ieee80211com *ic = ni->ni_ic; ic->ic_node_cleanup(ni); +#endif + KASSERT(ieee80211_node_refcnt(ni) == 0, ("node being free whilst still referenced")); + + if (ni->ni_challenge != NULL) + FREE(ni->ni_challenge, M_DEVBUF); if (ni->ni_wpa_ie != NULL) FREE(ni->ni_wpa_ie, M_DEVBUF); if (ni->ni_rsn_ie != NULL) @@ -831,6 +848,7 @@ if (ni->ni_ath_ie != NULL) FREE(ni->ni_ath_ie, M_DEVBUF); IEEE80211_NODE_SAVEQ_DESTROY(ni); + FREE(ni, M_80211_NODE); } @@ -847,55 +865,70 @@ * This interface is not intended for general use, it is * used by the routines below to create entries with a * specific purpose. + * Dont assume a BSS? */ struct ieee80211_node * -ieee80211_alloc_node(struct ieee80211_node_table *nt, - struct ieee80211vap *vap, const u_int8_t *macaddr) +ieee80211_alloc_node_table(struct ieee80211vap *vap, + const u_int8_t *macaddr) { - struct ieee80211com *ic = nt->nt_ic; + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_node_table *nt = &ic->ic_sta; struct ieee80211_node *ni; - int hash; - ni = ic->ic_node_alloc(nt, vap); - if (ni == NULL) { - /* XXX msg */ - vap->iv_stats.is_rx_nodealloc++; - return NULL; - } + ni = ieee80211_alloc_node(vap, macaddr); + if (ni != NULL) { + ni->ni_inact = ni->ni_inact_reload = nt->nt_inact_init; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, - "%s: %p<%s> in %s table, refcnt %d\n", __func__, ni, - ether_sprintf(macaddr), nt->nt_name, - ieee80211_node_refcnt(ni)+1); + WME_UAPSD_NODE_TRIGSEQINIT(ni); + IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); - IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); - hash = IEEE80211_NODE_HASH(macaddr); - ieee80211_node_initref(ni); /* mark referenced */ - ni->ni_chan = IEEE80211_CHAN_ANYC; - ni->ni_authmode = IEEE80211_AUTH_OPEN; - ni->ni_txpower = ic->ic_txpowlimit; /* max power */ - ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, IEEE80211_KEYIX_NONE); - ni->ni_inact_reload = nt->nt_inact_init; - ni->ni_inact = ni->ni_inact_reload; - ni->ni_ath_defkeyindex = IEEE80211_INVAL_DEFKEY; - ni->ni_rxkeyoff = 0; - IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); + _node_table_join(nt, ni); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); + } - IEEE80211_NODE_LOCK_IRQ(nt); - ni->ni_vap = vap; - ni->ni_ic = ic; - ni->ni_table = nt; - TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); - LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); - ni->ni_rxfrag = NULL; - ni->ni_challenge = NULL; - IEEE80211_NODE_UNLOCK_IRQ(nt); + return ni; +} +EXPORT_SYMBOL(ieee80211_alloc_node_table); + +/* Allocate a node structure and initialise specialised structures + * This function does not add the node to the node table, thus this + * node will not be found using ieee80211_find_*node. + * This is useful when sending one off errors or request denials. + */ +static struct ieee80211_node * +ieee80211_alloc_node(struct ieee80211vap *vap, const u_int8_t *macaddr) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_node *ni; + + /* This always allocates zeroed memoery */ + ni = ic->ic_node_alloc(vap); + if (ni != NULL) { + IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, + "%s: %p<%s> refcnt %d\n", __func__, ni, ether_sprintf(macaddr), + ieee80211_node_refcnt(ni)+1); - WME_UAPSD_NODE_TRIGSEQINIT(ni); + ieee80211_node_initref(ni); /* mark referenced */ + + IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); + + ni->ni_chan = IEEE80211_CHAN_ANYC; + ni->ni_authmode = IEEE80211_AUTH_OPEN; + ni->ni_txpower = ic->ic_txpowlimit; + + ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, + IEEE80211_KEYIX_NONE); + ni->ni_ath_defkeyindex = IEEE80211_INVAL_DEFKEY; + ni->ni_vap = vap; + ni->ni_ic = ic; + } else { + /* XXX msg */ + vap->iv_stats.is_rx_nodealloc++; + } return ni; } -EXPORT_SYMBOL(ieee80211_alloc_node); /* Add wds address to the node table */ int @@ -917,11 +950,11 @@ wds->wds_agingcount = WDS_AGING_COUNT; hash = IEEE80211_NODE_HASH(macaddr); IEEE80211_ADDR_COPY(wds->wds_macaddr, macaddr); - ieee80211_ref_node(ni); /* Reference node */ - wds->wds_ni = ni; - IEEE80211_NODE_LOCK_IRQ(nt); + + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); + wds->wds_ni = ieee80211_ref_node(ni); LIST_INSERT_HEAD(&nt->nt_wds_hash[hash], wds, wds_hash); - IEEE80211_NODE_UNLOCK_IRQ(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); return 0; } EXPORT_SYMBOL(ieee80211_add_wds_addr); @@ -934,22 +967,19 @@ struct ieee80211_wds_addr *wds, *twds; hash = IEEE80211_NODE_HASH(macaddr); - IEEE80211_NODE_LOCK_IRQ(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); LIST_FOREACH_SAFE(wds, &nt->nt_wds_hash[hash], wds_hash, twds) { if (IEEE80211_ADDR_EQ(wds->wds_macaddr, macaddr)) { - if (ieee80211_node_dectestref(wds->wds_ni)) { - _ieee80211_free_node(wds->wds_ni); - LIST_REMOVE(wds, wds_hash); - FREE(wds, M_80211_WDS); - break; - } + LIST_REMOVE(wds, wds_hash); + ieee80211_unref_node(&wds->wds_ni); + FREE(wds, M_80211_WDS); + break; } } - IEEE80211_NODE_UNLOCK_IRQ(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); } EXPORT_SYMBOL(ieee80211_remove_wds_addr); - /* Remove node references from wds table */ void ieee80211_del_wds_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni) @@ -957,19 +987,17 @@ int hash; struct ieee80211_wds_addr *wds, *twds; - IEEE80211_NODE_LOCK_IRQ(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); for (hash = 0; hash < IEEE80211_NODE_HASHSIZE; hash++) { LIST_FOREACH_SAFE(wds, &nt->nt_wds_hash[hash], wds_hash, twds) { if (wds->wds_ni == ni) { - if (ieee80211_node_dectestref(ni)) { - _ieee80211_free_node(ni); - LIST_REMOVE(wds, wds_hash); - FREE(wds, M_80211_WDS); - } + LIST_REMOVE(wds, wds_hash); + ieee80211_unref_node(&wds->wds_ni); + FREE(wds, M_80211_WDS); } } } - IEEE80211_NODE_UNLOCK_IRQ(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); } EXPORT_SYMBOL(ieee80211_del_wds_node); @@ -980,88 +1008,46 @@ int hash; struct ieee80211_wds_addr *wds, *twds; - IEEE80211_NODE_LOCK_IRQ(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); for (hash = 0; hash < IEEE80211_NODE_HASHSIZE; hash++) { LIST_FOREACH_SAFE(wds, &nt->nt_wds_hash[hash], wds_hash, twds) { if (wds->wds_agingcount != WDS_AGING_STATIC) { if (!wds->wds_agingcount) { - if (ieee80211_node_dectestref(wds->wds_ni)) { - _ieee80211_free_node(wds->wds_ni); - LIST_REMOVE(wds, wds_hash); - FREE(wds, M_80211_WDS); - } + LIST_REMOVE(wds, wds_hash); + ieee80211_unref_node(&wds->wds_ni); + FREE(wds, M_80211_WDS); } else wds->wds_agingcount--; } } } - IEEE80211_NODE_UNLOCK_IRQ(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); mod_timer(&nt->nt_wds_aging_timer, jiffies + HZ * WDS_AGING_TIMER_VAL); } /* - * Craft a temporary node suitable for sending a management frame - * to the specified station. We craft only as much state as we - * need to do the work since the node will be immediately reclaimed - * once the send completes. - */ -struct ieee80211_node * -ieee80211_tmp_node(struct ieee80211vap *vap, const u_int8_t *macaddr) -{ - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_node *ni; - - ni = ic->ic_node_alloc(&ic->ic_sta,vap); - if (ni != NULL) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, - "%s: %p<%s> refcnt %d\n", __func__, ni, ether_sprintf(macaddr), - ieee80211_node_refcnt(ni)+1); - - IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); - IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_bss->ni_bssid); - ieee80211_node_initref(ni); /* mark referenced */ - ni->ni_txpower = vap->iv_bss->ni_txpower; - ni->ni_vap = vap; - /* NB: required by ieee80211_fix_rate */ - ieee80211_node_set_chan(ic, ni); - ieee80211_crypto_resetkey(vap, &ni->ni_ucastkey, - IEEE80211_KEYIX_NONE); - /* XXX optimize away */ - IEEE80211_NODE_SAVEQ_INIT(ni, "unknown"); - - ni->ni_table = NULL; /* NB: pedantic */ - ni->ni_ic = ic; - ni->ni_rxfrag = NULL; - ni->ni_challenge = NULL; - } else { - /* XXX msg */ - vap->iv_stats.is_rx_nodealloc++; - } - return ni; -} - -/* * Add the specified station to the station table. */ struct ieee80211_node * -ieee80211_dup_bss(struct ieee80211vap *vap, const u_int8_t *macaddr) +ieee80211_dup_bss(struct ieee80211vap *vap, const u_int8_t *macaddr, + unsigned char tmp) { - struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; + + /* FIXME: Hack */ + if (tmp) + ni = ieee80211_alloc_node(vap, macaddr); + else + ni = ieee80211_alloc_node_table(vap, macaddr); - ni = ieee80211_alloc_node(&ic->ic_sta, vap, macaddr); if (ni != NULL) { - /* - * Inherit from iv_bss. - */ - ni->ni_authmode = vap->iv_bss->ni_authmode; - ni->ni_txpower = vap->iv_bss->ni_txpower; - ni->ni_vlan = vap->iv_bss->ni_vlan; /* XXX?? */ + copy_bss(ni, vap->iv_bss); IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_bss->ni_bssid); - ieee80211_node_set_chan(ic, ni); - ni->ni_rsn = vap->iv_bss->ni_rsn; - ni->ni_rxfrag = NULL; + /* Do this only for nodes that already have a BSS. Otherwise + * ic_bsschan is not set and we get a KASSERT failure. + * Required by ieee80211_fix_rate */ + ieee80211_node_set_chan(vap->iv_ic, ni); } return ni; } @@ -1069,19 +1055,16 @@ static struct ieee80211_node * _ieee80211_find_wds_node(struct ieee80211_node_table *nt, const u_int8_t *macaddr) { - struct ieee80211_node *ni; struct ieee80211_wds_addr *wds; int hash; - IEEE80211_NODE_LOCK_ASSERT(nt); + IEEE80211_NODE_TABLE_LOCK_ASSERT(nt); hash = IEEE80211_NODE_HASH(macaddr); LIST_FOREACH(wds, &nt->nt_wds_hash[hash], wds_hash) { if (IEEE80211_ADDR_EQ(wds->wds_macaddr, macaddr)) { - ni = wds->wds_ni; if (wds->wds_agingcount != WDS_AGING_STATIC) wds->wds_agingcount = WDS_AGING_COUNT; /* reset the aging count */ - ieee80211_ref_node(ni); - return ni; + return ieee80211_ref_node(wds->wds_ni); } } return NULL; @@ -1099,7 +1082,7 @@ int hash; struct ieee80211_wds_addr *wds; - IEEE80211_NODE_LOCK_ASSERT(nt); + IEEE80211_NODE_TABLE_LOCK_ASSERT(nt); hash = IEEE80211_NODE_HASH(macaddr); LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) { @@ -1120,9 +1103,7 @@ nodes. */ LIST_FOREACH(wds, &nt->nt_wds_hash[hash], wds_hash) { if (IEEE80211_ADDR_EQ(wds->wds_macaddr, macaddr)) { - ni = wds->wds_ni; - ieee80211_ref_node(ni); - return ni; + return ieee80211_ref_node(wds->wds_ni); } } return NULL; @@ -1137,9 +1118,9 @@ { struct ieee80211_node *ni; - IEEE80211_NODE_LOCK_IRQ(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); ni = _ieee80211_find_wds_node(nt, macaddr); - IEEE80211_NODE_UNLOCK_IRQ(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); return ni; } EXPORT_SYMBOL(ieee80211_find_wds_node); @@ -1154,9 +1135,9 @@ { struct ieee80211_node *ni; - IEEE80211_NODE_LOCK_IRQ(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); ni = _ieee80211_find_node(nt, macaddr); - IEEE80211_NODE_UNLOCK_IRQ(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); return ni; } #ifdef IEEE80211_DEBUG_REFCNT @@ -1179,7 +1160,7 @@ { struct ieee80211_node *ni; - ni = ieee80211_dup_bss(vap, macaddr); + ni = ieee80211_dup_bss(vap, macaddr, 0); if (ni != NULL) { /* XXX no rate negotiation; just dup */ ni->ni_rates = vap->iv_bss->ni_rates; @@ -1202,14 +1183,13 @@ * driver has an opportunity to setup it's private state. */ struct ieee80211_node * -ieee80211_add_neighbor(struct ieee80211vap *vap, const struct ieee80211_frame *wh, +ieee80211_add_neighbor(struct ieee80211vap *vap, const struct ieee80211_frame *wh, const struct ieee80211_scanparams *sp) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; - ni = ieee80211_dup_bss(vap, wh->i_addr2); /* XXX alloc_node? */ - /* TODO: not really putting itself in a table */ + ni = ieee80211_dup_bss(vap, wh->i_addr2, 1); if (ni != NULL) { ni->ni_esslen = sp->ssid[1]; memcpy(ni->ni_essid, sp->ssid + 2, sp->ssid[1]); @@ -1284,12 +1264,12 @@ /* XXX check ic_bss first in station mode */ /* XXX 4-address frames? */ nt = &ic->ic_sta; - IEEE80211_NODE_LOCK_IRQ(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) ni = _ieee80211_find_node(nt, wh->i_addr1); else ni = _ieee80211_find_node(nt, wh->i_addr2); - IEEE80211_NODE_UNLOCK_IRQ(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); return ni; #undef IS_PSPOLL @@ -1326,9 +1306,9 @@ /* XXX can't hold lock across dup_bss due to recursive locking */ nt = &vap->iv_ic->ic_sta; - IEEE80211_NODE_LOCK_IRQ(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); ni = _ieee80211_find_node(nt, mac); - IEEE80211_NODE_UNLOCK_IRQ(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); if (ni == NULL) { if (vap->iv_opmode == IEEE80211_M_IBSS || @@ -1355,11 +1335,9 @@ EXPORT_SYMBOL(ieee80211_find_txnode); #endif -/* Caller must lock the IEEE80211_NODE_LOCK - * - * Context: hwIRQ, softIRQ and process context +/* Context: hwIRQ, softIRQ and process context */ -static void +void _ieee80211_free_node(struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; @@ -1373,117 +1351,36 @@ if (vap->iv_aid_bitmap != NULL) IEEE80211_AID_CLR(vap, ni->ni_associd); - if (nt != NULL) { - TAILQ_REMOVE(&nt->nt_node, ni, ni_list); - LIST_REMOVE(ni, ni_hash); - } + vap->iv_ic->ic_node_free(ni); } +EXPORT_SYMBOL(_ieee80211_free_node); -void -#ifdef IEEE80211_DEBUG_REFCNT -ieee80211_free_node_debug(struct ieee80211_node *ni, const char *func, int line) -#else -ieee80211_free_node(struct ieee80211_node *ni) -#endif +static void _reset_node(void *arg, struct ieee80211_node *ni) { - struct ieee80211_node_table *nt = ni->ni_table; - struct ieee80211com *ic = ni->ni_ic; + if (ni->ni_associd != 0) { + struct ieee80211vap *vap = ni->ni_vap; -#ifdef IEEE80211_DEBUG_REFCNT - IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, - "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni, - ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni) - 1); -#endif - /* - * XXX: may need to lock out the following race. we dectestref - * and determine it's time to free the node. between the if() - * and lock, we take an rx intr to receive a frame from this - * node. the rx path (tasklet or intr) bumps this node's - * refcnt and xmits a response frame. eventually that response - * will get reaped, and the reaping code will attempt to use - * the node. the code below will delete the node prior - * to the reap and we could get a crash. - * - * as a stopgap before delving deeper, lock intrs to - * prevent this case. - */ - IEEE80211_LOCK_IRQ(ic); - if (ieee80211_node_dectestref(ni)) { - /* - * Beware; if the node is marked gone then it's already - * been removed from the table and we cannot assume the - * table still exists. Regardless, there's no need to lock - * the table. - */ - if (ni->ni_table != NULL) { - IEEE80211_NODE_LOCK(nt); - _ieee80211_free_node(ni); - IEEE80211_NODE_UNLOCK(nt); - } else - _ieee80211_free_node(ni); + if (vap->iv_auth->ia_node_leave != NULL) + vap->iv_auth->ia_node_leave(ni); + if (vap->iv_aid_bitmap != NULL) + IEEE80211_AID_CLR(vap, ni->ni_associd); } - IEEE80211_UNLOCK_IRQ(ic); -} -#ifdef IEEE80211_DEBUG_REFCNT -EXPORT_SYMBOL(ieee80211_free_node_debug); -#else -EXPORT_SYMBOL(ieee80211_free_node); -#endif - -/* - * Reclaim a node. If this is the last reference count then - * do the normal free work. Otherwise remove it from the node - * table and mark it gone by clearing the back-reference. - */ -static void -node_reclaim(struct ieee80211_node_table *nt, struct ieee80211_node *ni) -{ - IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, - "%s: remove %p<%s> from %s table, refcnt %d\n", - __func__, ni, ether_sprintf(ni->ni_macaddr), - nt->nt_name, ieee80211_node_refcnt(ni)-1); - if (!ieee80211_node_dectestref(ni)) { - /* - * Other references are present, just remove the - * node from the table so it cannot be found. When - * the references are dropped storage will be - * reclaimed. This normally only happens for ic_bss. - */ - TAILQ_REMOVE(&nt->nt_node, ni, ni_list); - LIST_REMOVE(ni, ni_hash); - ni->ni_table = NULL; /* clear reference */ - } else - _ieee80211_free_node(ni); + ieee80211_node_leave(ni); } static void ieee80211_node_table_reset(struct ieee80211_node_table *nt, - struct ieee80211vap *match) + struct ieee80211vap *vap) { - struct ieee80211_node *ni, *next; - - IEEE80211_NODE_LOCK_IRQ(nt); - TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) { - if (match != NULL && ni->ni_vap != match) - continue; - if (ni->ni_associd != 0) { - struct ieee80211vap *vap = ni->ni_vap; - - if (vap->iv_auth->ia_node_leave != NULL) - vap->iv_auth->ia_node_leave(ni); - if (vap->iv_aid_bitmap != NULL) - IEEE80211_AID_CLR(vap, ni->ni_associd); - } - node_reclaim(nt, ni); - } - IEEE80211_NODE_UNLOCK_IRQ(nt); + ieee80211_iterate_dev_nodes(vap->iv_dev, nt, _reset_node, NULL); } static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt) { + struct ieee80211com *ic = nt->nt_ic; struct ieee80211_node *ni, *next; TAILQ_FOREACH_SAFE(ni, &nt->nt_node, ni_list, next) { @@ -1495,11 +1392,11 @@ if (vap->iv_aid_bitmap != NULL) IEEE80211_AID_CLR(vap, ni->ni_associd); } - node_reclaim(nt, ni); + ic->ic_node_cleanup(ni); } del_timer(&nt->nt_wds_aging_timer); IEEE80211_SCAN_LOCK_DESTROY(nt); - IEEE80211_NODE_LOCK_DESTROY(nt); + IEEE80211_NODE_TABLE_LOCK_DESTROY(nt); } /* @@ -1527,19 +1424,22 @@ IEEE80211_SCAN_LOCK_IRQ(nt); gen = ++nt->nt_scangen; restart: - IEEE80211_NODE_LOCK_IRQ(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { if (ni->ni_scangen == gen) /* previously handled */ continue; + /* Temporary entries should no longer be in the node table */ /* * Ignore entries for which have yet to receive an * authentication frame. These are transient and * will be reclaimed when the last reference to them * goes away (when frame xmits complete). */ - if (ic->ic_opmode == IEEE80211_M_HOSTAP && - (ni->ni_flags & IEEE80211_NODE_AREF) == 0) - continue; + /* + *if (ic->ic_opmode == IEEE80211_M_HOSTAP && + * (ni->ni_flags & IEEE80211_NODE_AREF) == 0) + * continue; + */ ni->ni_scangen = gen; /* * Free fragment if not needed anymore @@ -1591,7 +1491,7 @@ * ref for us as needed. */ ieee80211_ref_node(ni); - IEEE80211_NODE_UNLOCK_IRQ_EARLY(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ_EARLY(nt); ieee80211_send_nulldata(ni); /* XXX stat? */ goto restart; @@ -1614,18 +1514,18 @@ */ ni->ni_vap->iv_stats.is_node_timeout++; ieee80211_ref_node(ni); - IEEE80211_NODE_UNLOCK_IRQ_EARLY(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ_EARLY(nt); if (ni->ni_associd != 0) { IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH, IEEE80211_REASON_AUTH_EXPIRE); } ieee80211_node_leave(ni); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); goto restart; } } - IEEE80211_NODE_UNLOCK_IRQ(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); IEEE80211_SCAN_UNLOCK_IRQ(nt); } @@ -1660,21 +1560,23 @@ IEEE80211_SCAN_LOCK_IRQ(nt); gen = ++nt->nt_scangen; + restart: - IEEE80211_NODE_LOCK(nt); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { if (dev != NULL && ni->ni_vap->iv_dev != dev) continue; /* skip node not for this vap */ if (ni->ni_scangen != gen) { ni->ni_scangen = gen; (void) ieee80211_ref_node(ni); - IEEE80211_NODE_UNLOCK(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ_EARLY(nt); (*f)(arg, ni); - ieee80211_free_node(ni); + + ieee80211_unref_node(&ni); goto restart; } } - IEEE80211_NODE_UNLOCK(nt); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); IEEE80211_SCAN_UNLOCK_IRQ(nt); } @@ -1948,9 +1850,20 @@ "station with aid %d leaves (refcnt %u)", IEEE80211_NODE_AID(ni), ieee80211_node_refcnt(ni)); + /* From this point onwards we can no longer find the node, + * so no more references are generated + */ + ieee80211_remove_wds_addr(nt, ni->ni_macaddr); + ieee80211_del_wds_node(nt, ni); + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); + _node_table_leave(nt, ni); + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); + /* * If node wasn't previously associated all * we need to do is reclaim the reference. + * This also goes for nodes that are auth'ed but + * not associated. */ /* XXX ibss mode bypasses 11g and notification */ if (ni->ni_associd == 0) @@ -1968,9 +1881,11 @@ IEEE80211_LOCK_IRQ(ic); if (vap->iv_aid_bitmap != NULL) IEEE80211_AID_CLR(vap, ni->ni_associd); + ni->ni_associd = 0; vap->iv_sta_assoc--; ic->ic_sta_assoc--; + #ifdef ATH_SUPERG_XR if (ni->ni_vap->iv_flags & IEEE80211_F_XR) ic->ic_xr_sta_assoc--; @@ -1981,6 +1896,7 @@ if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) ieee80211_node_leave_11g(ni); IEEE80211_UNLOCK_IRQ(ic); + /* * Cleanup station state. In particular clear various * state that might otherwise be reused if the node @@ -1990,19 +1906,10 @@ ieee80211_sta_leave(ni); done: /* - * Remove the node from any table it's recorded in and - * drop the caller's reference. Removal from the table - * is important to ensure the node is not reprocessed - * for inactivity. - */ - if (nt != NULL) { - IEEE80211_NODE_LOCK_IRQ(nt); - node_reclaim(nt, ni); - IEEE80211_NODE_UNLOCK_IRQ(nt); - ieee80211_remove_wds_addr(nt,ni->ni_macaddr); - ieee80211_del_wds_node(nt,ni); - } else - ieee80211_free_node(ni); + * Run a cleanup and then drop the caller's reference + */ + ic->ic_node_cleanup(ni); + ieee80211_unref_node(&ni); } EXPORT_SYMBOL(ieee80211_node_leave); @@ -2062,25 +1969,8 @@ void ieee80211_node_reset(struct ieee80211_node *ni, struct ieee80211vap *vap) { - if (ni != NULL) { - struct ieee80211_node_table *nt = ni->ni_table; - if (!nt) - nt = &vap->iv_ic->ic_sta; - IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_bss->ni_bssid); - ni->ni_prev_vap = ni->ni_vap; - ni->ni_vap = vap; - ni->ni_ic = vap->iv_ic; - /* - * if node not found in the node table - * add it to the node table . - */ - if(nt && ieee80211_find_node(nt, ni->ni_macaddr) != ni) { - int hash = IEEE80211_NODE_HASH(ni->ni_macaddr); - IEEE80211_NODE_LOCK_IRQ(nt); - TAILQ_INSERT_TAIL(&nt->nt_node, ni, ni_list); - LIST_INSERT_HEAD(&nt->nt_hash[hash], ni, ni_hash); - ni->ni_table = nt; - IEEE80211_NODE_UNLOCK_IRQ(nt); - } - } + IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_bss->ni_bssid); + ni->ni_prev_vap = ni->ni_vap; + ni->ni_vap = vap; + ni->ni_ic = vap->iv_ic; } diff -ur madwifi.old/net80211/ieee80211_node.h madwifi.dev/net80211/ieee80211_node.h --- madwifi.old/net80211/ieee80211_node.h 2007-03-06 11:59:28.000000000 +0100 +++ madwifi.dev/net80211/ieee80211_node.h 2007-05-21 08:10:46.869753416 +0200 @@ -52,14 +52,14 @@ * authorized. The latter timeout is shorter to more aggressively * reclaim nodes that leave part way through the 802.1x exchange. */ -#define IEEE80211_INACT_WAIT 15 /* inactivity interval (secs) */ +#define IEEE80211_INACT_WAIT 15 /* inactivity interval (secs) */ #define IEEE80211_INACT_INIT (30/IEEE80211_INACT_WAIT) /* initial */ #define IEEE80211_INACT_AUTH (180/IEEE80211_INACT_WAIT) /* associated but not authorized */ #define IEEE80211_INACT_RUN (300/IEEE80211_INACT_WAIT) /* authorized */ #define IEEE80211_INACT_PROBE (30/IEEE80211_INACT_WAIT) /* probe */ #define IEEE80211_INACT_SCAN (300/IEEE80211_INACT_WAIT) /* scanned */ -#define IEEE80211_TRANS_WAIT 5 /* mgt frame tx timer (secs) */ +#define IEEE80211_TRANS_WAIT 5 /* mgt frame tx timer (secs) */ #define IEEE80211_NODE_HASHSIZE 32 /* simple hash is enough for variation of macaddr */ @@ -94,7 +94,8 @@ struct ieee80211_node_table *ni_table; TAILQ_ENTRY(ieee80211_node) ni_list; LIST_ENTRY(ieee80211_node) ni_hash; - atomic_t ni_refcnt; + // ieee80211_node_lock_t ni_nodelock; /* on node - notably for ref counting */ + ieee80211_node_ref_count_t ni_refcnt; u_int ni_scangen; /* gen# for timeout scan */ u_int8_t ni_authmode; /* authentication algorithm */ u_int16_t ni_flags; /* special-purpose state */ @@ -121,13 +122,13 @@ u_int16_t ni_associd; /* assoc response */ u_int16_t ni_txpower; /* current transmit power (in 0.5 dBm) */ u_int16_t ni_vlan; /* vlan tag */ - u_int32_t *ni_challenge; /* shared-key challenge */ + u_int32_t *ni_challenge; /* shared-key challenge */ u_int8_t *ni_wpa_ie; /* captured WPA ie */ u_int8_t *ni_rsn_ie; /* captured RSN ie */ u_int8_t *ni_wme_ie; /* captured WME ie */ u_int8_t *ni_ath_ie; /* captured Atheros ie */ - u_int16_t ni_txseqs[17]; /* tx seq per-tid */ - u_int16_t ni_rxseqs[17]; /* rx seq previous per-tid*/ + u_int16_t ni_txseqs[17]; /* tx seq per-tid */ + u_int16_t ni_rxseqs[17]; /* rx seq previous per-tid*/ u_int32_t ni_rxfragstamp; /* time stamp of last rx frag */ struct sk_buff *ni_rxfrag; /* rx frag reassembly */ struct ieee80211_rsnparms ni_rsn; /* RSN/WPA parameters */ @@ -156,7 +157,7 @@ struct ieee80211_channel *ni_chan; u_int16_t ni_fhdwell; /* FH only */ u_int8_t ni_fhindex; /* FH only */ - u_int8_t ni_erp; /* ERP from beacon/probe resp */ + u_int8_t ni_erp; /* ERP from beacon/probe resp */ u_int16_t ni_timoff; /* byte offset to TIM ie */ /* others */ @@ -168,7 +169,7 @@ struct ieee80211vap *ni_prev_vap; /* previously associated vap */ u_int8_t ni_uapsd; /* U-APSD per-node flags matching WMM STA Qos Info field */ u_int8_t ni_uapsd_maxsp; /* maxsp from flags above */ - u_int16_t ni_uapsd_trigseq[WME_NUM_AC]; /* trigger suppression on retry */ + u_int16_t ni_uapsd_trigseq[WME_NUM_AC]; /* trigger suppression on retry */ __le16 ni_pschangeseq; }; MALLOC_DECLARE(M_80211_NODE); @@ -186,20 +187,6 @@ #define WME_UAPSD_NODE_INVALIDSEQ 0xffff #define WME_UAPSD_NODE_TRIGSEQINIT(_ni) (memset(&(_ni)->ni_uapsd_trigseq[0], 0xff, sizeof((_ni)->ni_uapsd_trigseq))) -static __inline struct ieee80211_node * -ieee80211_ref_node(struct ieee80211_node *ni) -{ - ieee80211_node_incref(ni); - return ni; -} - -static __inline void -ieee80211_unref_node(struct ieee80211_node **ni) -{ - ieee80211_node_decref(*ni); - *ni = NULL; /* guard against use */ -} - void ieee80211_node_attach(struct ieee80211com *); void ieee80211_node_detach(struct ieee80211com *); void ieee80211_node_vattach(struct ieee80211vap *); @@ -242,43 +229,39 @@ * is a second table for associated stations or neighbors. */ struct ieee80211_node_table { + const char *nt_name; /* for debugging */ struct ieee80211com *nt_ic; /* back reference */ - ieee80211_node_lock_t nt_nodelock; /* on node table */ + ieee80211_node_table_lock_t nt_nodelock; /* on node table */ TAILQ_HEAD(, ieee80211_node) nt_node; /* information of all nodes */ ATH_LIST_HEAD(, ieee80211_node) nt_hash[IEEE80211_NODE_HASHSIZE]; ATH_LIST_HEAD(, ieee80211_wds_addr) nt_wds_hash[IEEE80211_NODE_HASHSIZE]; - const char *nt_name; /* for debugging */ ieee80211_scan_lock_t nt_scanlock; /* on nt_scangen */ u_int nt_scangen; /* gen# for timeout scan */ int nt_inact_init; /* initial node inact setting */ struct timer_list nt_wds_aging_timer; /* timer to age out wds entries */ }; -struct ieee80211_node *ieee80211_alloc_node(struct ieee80211_node_table *, - struct ieee80211vap *, const u_int8_t *); -struct ieee80211_node *ieee80211_tmp_node(struct ieee80211vap *, - const u_int8_t *); -struct ieee80211_node *ieee80211_dup_bss(struct ieee80211vap *, +struct ieee80211_node *ieee80211_alloc_node_table(struct ieee80211vap *, const u_int8_t *); +struct ieee80211_node *ieee80211_dup_bss(struct ieee80211vap *, + const u_int8_t *, unsigned char); void ieee80211_node_reset(struct ieee80211_node *, struct ieee80211vap *); #ifdef IEEE80211_DEBUG_REFCNT -void ieee80211_free_node_debug(struct ieee80211_node *, const char *, int); struct ieee80211_node *ieee80211_find_node_debug(struct ieee80211_node_table *, const u_int8_t *, const char *, int); struct ieee80211_node *ieee80211_find_rxnode_debug(struct ieee80211com *, const struct ieee80211_frame_min *, const char *, int); struct ieee80211_node *ieee80211_find_txnode_debug(struct ieee80211vap *, const u_int8_t *, const char *, int); -#define ieee80211_free_node(ni) \ - ieee80211_free_node_debug(ni, __func__, __LINE__) -#define ieee80211_find_node(nt, mac) \ - ieee80211_find_node_debug(nt, mac, __func__, __LINE__) -#define ieee80211_find_rxnode(nt, wh) \ - ieee80211_find_rxnode_debug(nt, wh, __func__, __LINE__) -#define ieee80211_find_txnode(nt, mac) \ - ieee80211_find_txnode_debug(nt, mac, __func__, __LINE__) +#define ieee80211_unref_node(_ni) \ + ieee80211_unref_node_debug(_ni, __func__, __LINE__) +#define ieee80211_find_node(_nt, _mac) \ + ieee80211_find_node_debug(_nt, _mac, __func__, __LINE__) +#define ieee80211_find_rxnode(_nt, _wh) \ + ieee80211_find_rxnode_debug(_nt, _wh, __func__, __LINE__) +#define ieee80211_find_txnode(_nt, _mac) \ + ieee80211_find_txnode_debug(_nt, _mac, __func__, __LINE__) #else -void ieee80211_free_node(struct ieee80211_node *); struct ieee80211_node *ieee80211_find_node(struct ieee80211_node_table *, const u_int8_t *); @@ -287,6 +270,53 @@ struct ieee80211_node *ieee80211_find_txnode(struct ieee80211vap *, const u_int8_t *); #endif + +void _ieee80211_free_node(struct ieee80211_node *); + +static __inline struct ieee80211_node * +ieee80211_ref_node(struct ieee80211_node *ni) +{ + ieee80211_node_incref(ni); + return ni; +} + +static __inline struct ieee80211_node * +_ieee80211_pass_node(struct ieee80211_node **pni) { + struct ieee80211_node *tmp = *pni; + *pni = NULL; + return (tmp); +} + +#define PASS_NODE(_ni) \ + _ieee80211_pass_node(&_ni) + +static __inline int +_ieee80211_unref_node(struct ieee80211_node *ni) { + if (ieee80211_node_dectestref(ni)) { + _ieee80211_free_node(ni); + return 1; + } else { + return 0; + } +} + +static __inline void +#ifdef IEEE80211_DEBUG_REFCNT +ieee80211_unref_node_debug(struct ieee80211_node **pni, const char *func, int line) +#else +ieee80211_unref_node(struct ieee80211_node **pni) +#endif +{ + struct ieee80211_node *ni = *pni; +#ifdef IEEE80211_DEBUG_REFCNT + IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_NODE, + "%s (%s:%u) %p<%s> refcnt %d\n", __func__, func, line, ni, + ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni) - 1); +#endif + _ieee80211_unref_node(ni); + *pni = NULL; /* guard against use */ +} + int ieee80211_add_wds_addr(struct ieee80211_node_table *, struct ieee80211_node *, const u_int8_t *, u_int8_t); void ieee80211_remove_wds_addr(struct ieee80211_node_table *, const u_int8_t *); diff -ur madwifi.old/net80211/ieee80211_output.c madwifi.dev/net80211/ieee80211_output.c --- madwifi.old/net80211/ieee80211_output.c 2007-05-18 13:19:16.000000000 +0200 +++ madwifi.dev/net80211/ieee80211_output.c 2007-05-21 08:10:46.870753264 +0200 @@ -254,7 +254,7 @@ goto bad; } - cb->ni = ni; + cb->ni = ieee80211_ref_node(ni); /* power-save checks */ if (WME_UAPSD_AC_CAN_TRIGGER(skb->priority, ni)) { @@ -293,13 +293,14 @@ } #endif ieee80211_parent_queue_xmit(skb); + ieee80211_unref_node(&ni); return 0; bad: if (skb != NULL) dev_kfree_skb(skb); if (ni != NULL) - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); return 0; } @@ -453,7 +454,7 @@ if (skb == NULL) { /* XXX debug msg */ vap->iv_stats.is_tx_nobuf++; - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); return -ENOMEM; } cb = (struct ieee80211_cb *)skb->cb; @@ -507,16 +508,14 @@ u_int8_t *frm; int tid; - ieee80211_ref_node(ni); skb = ieee80211_getmgtframe(&frm, 2); if (skb == NULL) { /* XXX debug msg */ vap->iv_stats.is_tx_nobuf++; - ieee80211_free_node(ni); return -ENOMEM; } cb = (struct ieee80211_cb *)skb->cb; - cb->ni = ni; + cb->ni = ieee80211_ref_node(ni); skb->priority = ac; qwh = (struct ieee80211_qosframe *)skb_push(skb, sizeof(struct ieee80211_qosframe)); @@ -865,7 +864,7 @@ nt = &ic->ic_sta; ni_wds = ieee80211_find_wds_node(nt, eh.ether_shost); if (ni_wds) - ieee80211_free_node(ni_wds); /* Decr ref count */ + ieee80211_unref_node(&ni_wds); /* Decr ref count */ else ieee80211_add_wds_addr(nt, ni, eh.ether_shost, 0); } @@ -1719,7 +1718,6 @@ __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni) + 1); - ieee80211_ref_node(ni); /* * prreq frame format @@ -1735,7 +1733,6 @@ vap->app_ie[IEEE80211_APPIE_FRAME_PROBE_REQ].length); if (skb == NULL) { vap->iv_stats.is_tx_nobuf++; - ieee80211_free_node(ni); return -ENOMEM; } @@ -1758,7 +1755,7 @@ skb_trim(skb, frm - skb->data); cb = (struct ieee80211_cb *)skb->cb; - cb->ni = ni; + cb->ni = ieee80211_ref_node(ni); wh = (struct ieee80211_frame *) skb_push(skb, sizeof(struct ieee80211_frame)); @@ -2234,7 +2231,7 @@ mod_timer(&vap->iv_mgtsend, jiffies + timer * HZ); return 0; bad: - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); return ret; #undef senderr } diff -ur madwifi.old/net80211/ieee80211_power.c madwifi.dev/net80211/ieee80211_power.c --- madwifi.old/net80211/ieee80211_power.c 2007-05-18 13:19:16.000000000 +0200 +++ madwifi.dev/net80211/ieee80211_power.c 2007-05-21 08:10:46.870753264 +0200 @@ -109,13 +109,15 @@ int ieee80211_node_saveq_drain(struct ieee80211_node *ni) { + struct ieee80211_cb *cb = NULL; struct sk_buff *skb; int qlen; IEEE80211_NODE_SAVEQ_LOCK(ni); qlen = skb_queue_len(&ni->ni_savedq); while ((skb = __skb_dequeue(&ni->ni_savedq)) != NULL) { - ieee80211_free_node(ni); + cb = (struct ieee80211_cb *) skb->cb; + ieee80211_unref_node(&cb->ni); dev_kfree_skb_any(skb); } IEEE80211_NODE_SAVEQ_UNLOCK(ni); diff -ur madwifi.old/net80211/ieee80211_proto.c madwifi.dev/net80211/ieee80211_proto.c --- madwifi.old/net80211/ieee80211_proto.c 2006-12-08 18:20:08.000000000 +0100 +++ madwifi.dev/net80211/ieee80211_proto.c 2007-05-21 08:10:46.871753112 +0200 @@ -1456,7 +1456,7 @@ */ if (vap->iv_opmode == IEEE80211_M_WDS) { struct ieee80211_node *wds_ni; - wds_ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->wds_mac); + wds_ni = ieee80211_alloc_node_table(vap, vap->wds_mac); if (wds_ni != NULL) { if (ieee80211_add_wds_addr(&ic->ic_sta, wds_ni, vap->wds_mac, 1) == 0) { ieee80211_node_authorize(wds_ni); diff -ur madwifi.old/net80211/ieee80211_var.h madwifi.dev/net80211/ieee80211_var.h --- madwifi.old/net80211/ieee80211_var.h 2007-05-18 13:19:16.000000000 +0200 +++ madwifi.dev/net80211/ieee80211_var.h 2007-05-21 08:12:01.499407984 +0200 @@ -44,6 +44,8 @@ #include +struct ieee80211vap; + #include #include #include @@ -115,7 +117,6 @@ * the underlying device and the net80211 layer is exposed here; * e.g. device-specific callbacks. */ -struct ieee80211vap; struct ieee80211com { struct net_device *ic_dev; /* associated device */ @@ -236,8 +237,7 @@ /* new station association callback/notification */ void (*ic_newassoc)(struct ieee80211_node *, int); /* node state management */ - struct ieee80211_node *(*ic_node_alloc)(struct ieee80211_node_table *, - struct ieee80211vap *); + struct ieee80211_node *(*ic_node_alloc)(struct ieee80211vap *); void (*ic_node_free)(struct ieee80211_node *); void (*ic_node_cleanup)(struct ieee80211_node *); u_int8_t (*ic_node_getrssi)(const struct ieee80211_node *); diff -ur madwifi.old/net80211/ieee80211_wireless.c madwifi.dev/net80211/ieee80211_wireless.c --- madwifi.old/net80211/ieee80211_wireless.c 2007-05-18 13:19:16.000000000 +0200 +++ madwifi.dev/net80211/ieee80211_wireless.c 2007-05-21 08:10:46.874752656 +0200 @@ -3186,7 +3186,7 @@ error = -ENXIO; ieee80211_key_update_end(vap); if (ni != NULL) - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); #ifdef ATH_SUPERG_XR /* set the same params on the xr vap device if exists */ if (vap->iv_xrvap && !(vap->iv_flags & IEEE80211_F_XR)) @@ -3246,7 +3246,7 @@ memset(ik.ik_keydata, 0, sizeof(ik.ik_keydata)); } if (ni != NULL) - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); return (copy_to_user(iwr->u.data.pointer, &ik, sizeof(ik)) ? -EFAULT : 0); } @@ -3271,7 +3271,7 @@ return -ENOENT; /* No such entity is a more appropriate error */ /* XXX error return */ ieee80211_crypto_delkey(vap, &ni->ni_ucastkey, ni); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); } else { if (kix >= IEEE80211_WEP_NKID) return -EINVAL; @@ -3382,7 +3382,7 @@ return -EINVAL; if (dev == ni->ni_vap->iv_dev) domlme(mlme, ni); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); } else ieee80211_iterate_dev_nodes(dev, &ic->ic_sta, domlme, mlme); break; @@ -3401,7 +3401,7 @@ ieee80211_node_authorize(ni); else ieee80211_node_unauthorize(ni); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); break; case IEEE80211_MLME_CLEAR_STATS: if (vap->iv_opmode != IEEE80211_M_HOSTAP) @@ -3412,7 +3412,7 @@ /* clear statistics */ memset(&ni->ni_stats, 0, sizeof(struct ieee80211_nodestats)); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); break; default: return -EINVAL; @@ -3785,7 +3785,7 @@ ielen = sizeof(wpaie.rsn_ie); memcpy(wpaie.rsn_ie, ni->ni_rsn_ie, ielen); } - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); return (copy_to_user(iwr->u.data.pointer, &wpaie, sizeof(wpaie)) ? -EFAULT : 0); } @@ -3813,7 +3813,7 @@ /* NB: copy out only the statistics */ error = copy_to_user(iwr->u.data.pointer + off, &ni->ni_stats, iwr->u.data.length - off); - ieee80211_free_node(ni); + ieee80211_unref_node(&ni); return (error ? -EFAULT : 0); }