void ieee80211_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int resp) { int newassoc; if (ni->ni_associd == 0) { u_int16_t aid; /* * It would be clever to search the bitmap * more efficiently, but this will do for now. */ for (aid = 1; aid < ic->ic_max_aid; aid++) { if (!IEEE80211_AID_ISSET(aid, ic->ic_aid_bitmap)) break; } if (aid >= ic->ic_max_aid) { IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_REASON_ASSOC_TOOMANY); ieee80211_node_leave(ic, ni); return; } ni->ni_associd = aid | 0xc000; IEEE80211_AID_SET(ni->ni_associd, ic->ic_aid_bitmap); newassoc = 1; if (ic->ic_curmode == IEEE80211_MODE_11G) ieee80211_node_join_11g(ic, ni); } else newassoc = 0; IEEE80211_DPRINTF(("station %s %s associated at aid %d\n", ether_sprintf(ni->ni_macaddr), (newassoc ? "newly" : "already"), ni->ni_associd & ~0xc000)); /* give driver a chance to setup state like ni_txrate */ if (ic->ic_newassoc) (*ic->ic_newassoc)(ic, ni, newassoc); IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS); ieee80211_node_newstate(ni, IEEE80211_STA_ASSOC); #if NBRIDGE > 0 /* * If the parent interface belongs to a bridge, learn * the node's address dynamically on this interface. */ if (ic->ic_if.if_bridge != NULL) bridge_update(&ic->ic_if, (struct ether_addr *)ni->ni_macaddr, 0); #endif }
/* * function to handle station joining infrastructure network. * used for AP mode vap only. */ int ieee80211_node_join(struct ieee80211_node *ni) { struct ieee80211com *ic = ni->ni_ic; struct ieee80211vap *vap = ni->ni_vap; IEEE80211_NODE_STATE_LOCK(ni); if (ni->ni_associd == 0) { u_int16_t aid; if (vap->iv_aid_bitmap == NULL || IEEE80211_IS_TDLS_NODE(ni)) { IEEE80211_NODE_STATE_UNLOCK(ni); return -1; /* vap is being deleted */ } /* * It would be good to search the bitmap * more efficiently, but this will do for now. */ if (!IEEE80211_IS_TDLS_NODE(ni)) { for (aid = 1; aid < vap->iv_max_aid; aid++) { if (!IEEE80211_AID_ISSET(vap, aid)) break; } if (aid >= vap->iv_max_aid) { /* * Keep stats on this situation. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC, "aid (%d)" " greater than max aid (%d)\n", aid, vap->iv_max_aid); IEEE80211_NODE_STATE_UNLOCK(ni); IEEE80211_NODE_LEAVE(ni); return -1; } ni->ni_associd = aid | 0xc000; IEEE80211_AID_SET(vap, ni->ni_associd); } else { /* To keep the other parts of code happy. Otherwise the code assumes * node disconnected and tries to delete it.There are no associd for * TDLS nodes. */ ni->ni_associd = vap->iv_bss->ni_associd; } vap->iv_sta_assoc++; ic->ic_sta_assoc++; /* Update bss load element in beacon */ ieee80211_vap_bssload_update_set(vap); if ((ni->ni_flags & IEEE80211_NODE_HT) && (ni->ni_flags & IEEE80211_NODE_40_INTOLERANT)) { ieee80211_change_cw(ic); } if (IEEE80211_IS_AMPDU_ENABLED(ic)) { ieee80211node_clear_flag(ni, IEEE80211_NODE_NOAMPDU); } else { ieee80211node_set_flag(ni, IEEE80211_NODE_NOAMPDU); } if (IEEE80211_NODE_USEAMPDU(ni)) { ic->ic_ht_sta_assoc++; if (ni->ni_htcap & IEEE80211_HTCAP_C_GREENFIELD) 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_join_11g(ni); } #if ATH_SUPPORT_WIFIPOS // Time stamp to send in status response ni->last_rx_desc_tsf = ic->ic_get_TSF32(ic); #endif ni->ni_inact_reload = ni->ni_vap->iv_inact_auth; ni->ni_inact = ni->ni_inact_reload; /* 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: add the node entity to the table * for HBR purpose */ if (vap->iv_ique_ops.hbr_nodejoin) { vap->iv_ique_ops.hbr_nodejoin(vap, ni); } IEEE80211_NODE_STATE_UNLOCK(ni); IEEE80211_ADD_NODE_TARGET(ni, ni->ni_vap, 0); return 0; }