static void wlan_node_dec_free(bss_t *ni) { ieee80211_node_decref(ni); if (ieee80211_node_refcnt(ni) == 0) { wlan_node_free(ni); } }
void wlan_node_ret_n_remove(struct ieee80211_node_table *nt, bss_t *ni) { IEEE80211_NODE_LOCK(nt); ieee80211_node_decref(ni); if (ieee80211_node_refcnt(ni) == 0) { wlan_node_free(ni); } else { wlan_node_reclaim(nt, ni); } IEEE80211_NODE_UNLOCK(nt); }
bool _ieee80211_node_leave(struct ieee80211_node *ni) #endif { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; bool retval = false; #ifdef IEEE80211_DEBUG_REFCNT TRACENODE(ni, func, line); #endif IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni, "station with aid %d leaves (refcnt %u) \n", IEEE80211_NODE_AID(ni), ieee80211_node_refcnt(ni)); #ifdef ATH_SWRETRY (ni->ni_ic)->ic_reset_pause_tid(ni->ni_ic, ni); #endif if (!IEEE80211_IS_TDLS_NODE(ni)) KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_WDS || vap->iv_opmode == IEEE80211_M_BTAMP, ("unexpected operating mode %u", vap->iv_opmode)); /* Multicast enhancement: If the entry with the node's address exists in * the snoop table, it should be removed. */ if (vap->iv_ique_ops.me_clean) { vap->iv_ique_ops.me_clean(ni); } /* * HBR / headline block removal: delete the node entity from the table * for HBR purpose */ if (vap->iv_ique_ops.hbr_nodeleave) { vap->iv_ique_ops.hbr_nodeleave(vap, ni); } /* * If node wasn't previously associated all * we need to do is reclaim the reference. */ /* XXX ibss mode bypasses 11g and notification */ IEEE80211_NODE_STATE_LOCK(ni); if (ni->ni_associd) { vap->iv_sta_assoc--; ic->ic_sta_assoc--; /* Update bss load element in beacon */ ieee80211_vap_bssload_update_set(vap); if (IEEE80211_NODE_USEAMPDU(ni)) { ic->ic_ht_sta_assoc--; if (ni->ni_htcap & IEEE80211_HTCAP_C_GREENFIELD) { ASSERT(ic->ic_ht_gf_sta_assoc > 0); ic->ic_ht_gf_sta_assoc--; } } if (ni->ni_chwidth == IEEE80211_CWM_WIDTH40) ic->ic_ht40_sta_assoc--; if ((IEEE80211_IS_CHAN_ANYG(vap->iv_bsschan) || IEEE80211_IS_CHAN_11NG(vap->iv_bsschan)) && !IEEE80211_IS_TDLS_NODE(ni)) ieee80211_node_leave_11g(ni); IEEE80211_NODE_STATE_UNLOCK(ni); IEEE80211_DELETE_NODE_TARGET(ni, ic, vap, 0); } else { IEEE80211_NODE_STATE_UNLOCK(ni); } ieee80211_admctl_node_leave(vap, ni); /* * Cleanup station state. In particular clear various state that * might otherwise be reused if the node is reused before the * reference count goes to zero (and memory is reclaimed). * * If ni is not in node table, it has been reclaimed in another thread. */ retval = ieee80211_sta_leave(ni); if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_flags & IEEE80211_NODE_40_INTOLERANT)) { ieee80211_change_cw(ic); } return retval; }
/* * Join an infrastructure network */ int ieee80211_sta_join(struct ieee80211vap *vap, ieee80211_scan_entry_t scan_entry) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node_table *nt = &ic->ic_sta; struct ieee80211_node *ni = NULL; const u_int8_t *macaddr = ieee80211_scan_entry_macaddr(scan_entry); int error = 0; ASSERT(vap->iv_opmode == IEEE80211_M_STA); ni = ieee80211_find_node(nt, macaddr); if (ni) { /* * reusing old node has a potential for several bugs . The old node may have some state info from previous association. * get rid of the old bss node and create a new bss node. */ ieee80211_sta_leave(ni); ieee80211_free_node(ni); } /* * Create a BSS node. */ ni = ieee80211_alloc_node(nt, vap, macaddr); if (ni == NULL) return -ENOMEM; /* set the maximum number frmaes to be queued when the vap is in fake sleep */ ieee80211_node_saveq_set_param(ni,IEEE80211_NODE_SAVEQ_DATA_Q_LEN,IEE80211_STA_MAX_NODE_SAVEQ_LEN); /* To become a bss node, a node need an extra reference count, which alloc node already gives */ #ifdef IEEE80211_DEBUG_REFCNT ieee80211_note(ni->ni_vap,"%s ,line %u: increase node %p <%s> refcnt to %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); #endif /* setup the bss node for association */ error = ieee80211_setup_node(ni, scan_entry); if (error != 0) { ieee80211_free_node(ni); return error; } /* copy the beacon timestamp */ OS_MEMCPY(ni->ni_tstamp.data, ieee80211_scan_entry_tsf(scan_entry), sizeof(ni->ni_tstamp)); /* * Join the BSS represented by this new node. * This function will free up the old BSS node * and use this one as the new BSS node. */ ieee80211_sta_join_bss(ni); IEEE80211_ADD_NODE_TARGET(ni, ni->ni_vap, 0); /* Save our home channel */ vap->iv_bsschan = ni->ni_chan; vap->iv_cur_mode = ieee80211_chan2mode(ni->ni_chan); /* Update the DotH falg */ ieee80211_update_spectrumrequirement(vap); /* * The OS will control our security keys. * If clear, keys will be cleared. * If static WEP, keys will be plumbed before JoinInfra. * If WPA/WPA2, ciphers will be setup, but no keys will be plumbed until * after they are negotiated. * XXX We should ASSERT that all of the foregoing is true. */ return 0; }
static int hwmp_send_action(struct ieee80211_node *ni, const uint8_t sa[IEEE80211_ADDR_LEN], const uint8_t da[IEEE80211_ADDR_LEN], uint8_t *ie, size_t len) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_bpf_params params; struct mbuf *m; uint8_t *frm; #ifdef IEEE80211_DEBUG_REFCNT char ethstr[ETHER_ADDRSTRLEN + 1]; #endif if (vap->iv_state == IEEE80211_S_CAC) { IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, "block %s frame in CAC state", "HWMP action"); vap->iv_stats.is_tx_badstate++; return EIO; /* XXX */ } KASSERT(ni != NULL, ("null node")); /* * Hold a reference on the node so it doesn't go away until after * the xmit is complete all the way in the driver. On error we * will remove our reference. */ #ifdef IEEE80211_DEBUG_REFCNT IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__, ni, kether_ntoa(ni->ni_macaddr, ethstr), ieee80211_node_refcnt(ni)+1); #endif ieee80211_ref_node(ni); m = ieee80211_getmgtframe(&frm, ic->ic_headroom + sizeof(struct ieee80211_frame), sizeof(struct ieee80211_action) + len ); if (m == NULL) { ieee80211_free_node(ni); vap->iv_stats.is_tx_nobuf++; return ENOMEM; } *frm++ = IEEE80211_ACTION_CAT_MESHPATH; *frm++ = IEEE80211_ACTION_MESHPATH_SEL; switch (*ie) { case IEEE80211_ELEMID_MESHPREQ: frm = hwmp_add_meshpreq(frm, (struct ieee80211_meshpreq_ie *)ie); break; case IEEE80211_ELEMID_MESHPREP: frm = hwmp_add_meshprep(frm, (struct ieee80211_meshprep_ie *)ie); break; case IEEE80211_ELEMID_MESHPERR: frm = hwmp_add_meshperr(frm, (struct ieee80211_meshperr_ie *)ie); break; case IEEE80211_ELEMID_MESHRANN: frm = hwmp_add_meshrann(frm, (struct ieee80211_meshrann_ie *)ie); break; } m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); M_PREPEND(m, sizeof(struct ieee80211_frame), MB_DONTWAIT); if (m == NULL) { ieee80211_free_node(ni); vap->iv_stats.is_tx_nobuf++; return ENOMEM; } ieee80211_send_setup(ni, m, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION, IEEE80211_NONQOS_TID, sa, da, sa); m->m_flags |= M_ENCAP; /* mark encapsulated */ IEEE80211_NODE_STAT(ni, tx_mgmt); memset(¶ms, 0, sizeof(params)); params.ibp_pri = WME_AC_VO; params.ibp_rate0 = ni->ni_txparms->mgmtrate; if (IEEE80211_IS_MULTICAST(da)) params.ibp_try0 = 1; else params.ibp_try0 = ni->ni_txparms->maxretry; params.ibp_power = ni->ni_txpower; return ic->ic_raw_xmit(ni, m, ¶ms); }
/* * Send a probe response frame. * NB: for probe response, the node may not represent the peer STA. * We could use BSS node to reduce the memory usage from temporary node. */ int ieee80211_send_proberesp(struct ieee80211_node *ni, u_int8_t *macaddr, const void *optie, const size_t optielen) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ieee80211_rsnparms *rsn = &vap->iv_rsn; wbuf_t wbuf; struct ieee80211_frame *wh; u_int8_t *frm; u_int16_t capinfo; int enable_htrates; bool add_wpa_ie = true; ASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS || vap->iv_opmode == IEEE80211_M_BTAMP); wbuf = wbuf_alloc(ic->ic_osdev, WBUF_TX_MGMT, MAX_TX_RX_PACKET_SIZE); if (wbuf == NULL) return -ENOMEM; #ifdef IEEE80211_DEBUG_REFCNT printk("%s ,line %u: increase node %p <%s> refcnt to %d\n", __func__, __LINE__, ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)); #endif /* setup the wireless header */ wh = (struct ieee80211_frame *)wbuf_header(wbuf); ieee80211_send_setup(vap, ni, wh, IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, vap->iv_myaddr, macaddr, ieee80211_node_get_bssid(ni)); frm = (u_int8_t *)&wh[1]; /* * probe response frame format * [8] time stamp * [2] beacon interval * [2] cabability information * [tlv] ssid * [tlv] supported rates * [tlv] parameter set (FH/DS) * [tlv] parameter set (IBSS) * [tlv] extended rate phy (ERP) * [tlv] extended supported rates * [tlv] country (if present) * [3] power constraint * [tlv] WPA * [tlv] WME * [tlv] HT Capabilities * [tlv] HT Information * [tlv] Atheros Advanced Capabilities */ OS_MEMZERO(frm, 8); /* timestamp should be filled later */ frm += 8; *(u_int16_t *)frm = htole16(vap->iv_bss->ni_intval); frm += 2; if (vap->iv_opmode == IEEE80211_M_IBSS) capinfo = IEEE80211_CAPINFO_IBSS; else capinfo = IEEE80211_CAPINFO_ESS; if (IEEE80211_VAP_IS_PRIVACY_ENABLED(vap)) capinfo |= IEEE80211_CAPINFO_PRIVACY; if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; if (ic->ic_flags & IEEE80211_F_SHSLOT) capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; if (ieee80211_ic_doth_is_set(ic) && ieee80211_vap_doth_is_set(vap)) capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; *(u_int16_t *)frm = htole16(capinfo); frm += 2; frm = ieee80211_add_ssid(frm, vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen); frm = ieee80211_add_rates(frm, &vap->iv_bss->ni_rates, ic); if (!IEEE80211_IS_CHAN_FHSS(vap->iv_bsschan)) { *frm++ = IEEE80211_ELEMID_DSPARMS; *frm++ = 1; *frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan); } if (vap->iv_opmode == IEEE80211_M_IBSS) { *frm++ = IEEE80211_ELEMID_IBSSPARMS; *frm++ = 2; *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ } if (IEEE80211_IS_COUNTRYIE_ENABLED(ic)) { frm = ieee80211_add_country(frm, vap); } if (ieee80211_ic_doth_is_set(ic) && ieee80211_vap_doth_is_set(vap)) { *frm++ = IEEE80211_ELEMID_PWRCNSTR; *frm++ = 1; *frm++ = IEEE80211_PWRCONSTRAINT_VAL(vap); } #if ATH_SUPPORT_IBSS_DFS if (vap->iv_opmode == IEEE80211_M_IBSS) { frm = ieee80211_add_ibss_dfs(frm,vap); } #endif if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) || IEEE80211_IS_CHAN_11NG(ic->ic_curchan)) { frm = ieee80211_add_erp(frm, ic); } /* * check if os shim has setup RSN IE it self. */ IEEE80211_VAP_LOCK(vap); if (vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length) { add_wpa_ie = ieee80211_check_wpaie(vap, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length); } if (vap->iv_opt_ie.length) { add_wpa_ie = ieee80211_check_wpaie(vap, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); } IEEE80211_VAP_UNLOCK(vap); if (add_wpa_ie) { if (RSN_AUTH_IS_RSNA(rsn)) frm = ieee80211_setup_rsn_ie(vap, frm); } #if ATH_SUPPORT_WAPI if (RSN_AUTH_IS_WAI(rsn)) frm = ieee80211_setup_wapi_ie(vap, frm); #endif frm = ieee80211_add_xrates(frm, &vap->iv_bss->ni_rates, ic); enable_htrates = ieee80211vap_htallowed(vap); if (IEEE80211_IS_CHAN_11N(ic->ic_curchan) && enable_htrates) { frm = ieee80211_add_htcap(frm, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP); if (!IEEE80211_IS_HTVIE_ENABLED(ic)) frm = ieee80211_add_htcap_pre_ana(frm, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP); frm = ieee80211_add_htinfo(frm, ni); if (!IEEE80211_IS_HTVIE_ENABLED(ic)) frm = ieee80211_add_htinfo_pre_ana(frm, ni); if (!(ic->ic_flags & IEEE80211_F_COEXT_DISABLE)) { frm = ieee80211_add_obss_scan(frm, ni); frm = ieee80211_add_extcap(frm, ni); } } if (add_wpa_ie) { if (RSN_AUTH_IS_WPA(rsn)) frm = ieee80211_setup_wpa_ie(vap, frm); } if (ieee80211_vap_wme_is_set(vap) && (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_BTAMP)) /* don't support WMM in ad-hoc for now */ frm = ieee80211_add_wme_param(frm, &ic->ic_wme, IEEE80211_VAP_IS_UAPSD_ENABLED(vap)); if ((IEEE80211_IS_CHAN_11N(ic->ic_curchan)) && (IEEE80211_IS_HTVIE_ENABLED(ic)) && enable_htrates) { frm = ieee80211_add_htcap_vendor_specific(frm, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP); frm = ieee80211_add_htinfo_vendor_specific(frm, ni); } if (vap->iv_bss->ni_ath_flags) { frm = ieee80211_add_athAdvCap(frm, vap->iv_bss->ni_ath_flags, vap->iv_bss->ni_ath_defkeyindex); } else { frm = ieee80211_add_athAdvCap(frm, 0, IEEE80211_INVAL_DEFKEY); } /* Insert ieee80211_ie_ath_extcap IE to beacon */ if (ic->ic_ath_extcap) frm = ieee80211_add_athextcap(frm, ic->ic_ath_extcap, ic->ic_weptkipaggr_rxdelim); #ifdef notyet if (ni->ni_ath_ie != NULL) /* XXX */ frm = ieee80211_add_ath(frm, ni); #endif IEEE80211_VAP_LOCK(vap); if (vap->iv_opt_ie.length) { OS_MEMCPY(frm, vap->iv_opt_ie.ie, vap->iv_opt_ie.length); frm += vap->iv_opt_ie.length; } if (vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length) { OS_MEMCPY(frm, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].ie, vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length); frm += vap->iv_app_ie[IEEE80211_FRAME_TYPE_PROBERESP].length; } /* Add the Application IE's */ frm = ieee80211_mlme_app_ie_append(vap, IEEE80211_FRAME_TYPE_PROBERESP, frm); IEEE80211_VAP_UNLOCK(vap); if (optie != NULL && optielen != 0) { OS_MEMCPY(frm, optie, optielen); frm += optielen; } wbuf_set_pktlen(wbuf, (frm - (u_int8_t *)wbuf_header(wbuf))); return ieee80211_send_mgmt(vap,ni, wbuf,true); }