/* * Initialize the tables for a node. */ static void ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) { #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) #define MCS(_ix) (ni->ni_htrates.rs_rates[_ix] | IEEE80211_RATE_MCS) struct ath_node *an = ATH_NODE(ni); struct sample_node *sn = ATH_NODE_SAMPLE(an); const HAL_RATE_TABLE *rt = sc->sc_currates; int x, y, rix; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, ("curmode %u", sc->sc_curmode)); sn->sched = mrr_schedules[sc->sc_curmode]; KASSERT(sn->sched != NULL, ("no mrr schedule for mode %u", sc->sc_curmode)); sn->static_rix = -1; ath_rate_update_static_rix(sc, ni); /* * Construct a bitmask of usable rates. This has all * negotiated rates minus those marked by the hal as * to be ignored for doing rate control. */ sn->ratemask = 0; /* MCS rates */ if (ni->ni_flags & IEEE80211_NODE_HT) { for (x = 0; x < ni->ni_htrates.rs_nrates; x++) { rix = sc->sc_rixmap[MCS(x)]; if (rix == 0xff) continue; /* skip rates marked broken by hal */ if (!rt->info[rix].valid) continue; KASSERT(rix < SAMPLE_MAXRATES, ("mcs %u has rix %d", MCS(x), rix)); sn->ratemask |= 1<<rix; } } /* Legacy rates */ for (x = 0; x < ni->ni_rates.rs_nrates; x++) { rix = sc->sc_rixmap[RATE(x)]; if (rix == 0xff) continue; /* skip rates marked broken by hal */ if (!rt->info[rix].valid) continue; KASSERT(rix < SAMPLE_MAXRATES, ("rate %u has rix %d", RATE(x), rix)); sn->ratemask |= 1<<rix; } #ifdef IEEE80211_DEBUG if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { uint32_t mask; ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt", ni->ni_macaddr, ":", __func__); for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { if ((mask & 1) == 0) continue; printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix), calc_usecs_unicast_packet(sc, 1600, rix, 0,0, (ni->ni_chw == 40))); } printf("\n"); }
/* * Initialize the tables for a node. */ static void ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) { #define RATE(_ix) (ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL) #define DOT11RATE(_ix) (rt->info[(_ix)].dot11Rate & IEEE80211_RATE_VAL) struct ath_node *an = ATH_NODE(ni); const struct ieee80211_txparam *tp = ni->ni_txparms; struct sample_node *sn = ATH_NODE_SAMPLE(an); const HAL_RATE_TABLE *rt = sc->sc_currates; #ifdef IEEE80211_DEBUG char ethstr[ETHER_ADDRSTRLEN + 1]; #endif int x, y, srate, rix; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2, ("curmode %u", sc->sc_curmode)); sn->sched = mrr_schedules[sc->sc_curmode]; KASSERT(sn->sched != NULL, ("no mrr schedule for mode %u", sc->sc_curmode)); sn->static_rix = -1; if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { /* * A fixed rate is to be used; ucastrate is the IEEE code * for this rate (sans basic bit). Check this against the * negotiated rate set for the node. Note the fixed rate * may not be available for various reasons so we only * setup the static rate index if the lookup is successful. * XXX handle MCS */ for (srate = ni->ni_rates.rs_nrates - 1; srate >= 0; srate--) if (RATE(srate) == tp->ucastrate) { sn->static_rix = sc->sc_rixmap[tp->ucastrate]; break; } #ifdef IEEE80211_DEBUG if (sn->static_rix == -1) { IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "%s: ucastrate %u not found, nrates %u", __func__, tp->ucastrate, ni->ni_rates.rs_nrates); } #endif } /* * Construct a bitmask of usable rates. This has all * negotiated rates minus those marked by the hal as * to be ignored for doing rate control. */ sn->ratemask = 0; for (x = 0; x < ni->ni_rates.rs_nrates; x++) { rix = sc->sc_rixmap[RATE(x)]; if (rix == 0xff) continue; /* skip rates marked broken by hal */ if (!rt->info[rix].valid) continue; KASSERT(rix < SAMPLE_MAXRATES, ("rate %u has rix %d", RATE(x), rix)); sn->ratemask |= 1<<rix; } #ifdef IEEE80211_DEBUG if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) { uint32_t mask; ieee80211_note(ni->ni_vap, "[%s] %s: size 1600 rate/tt", kether_ntoa(ni->ni_macaddr, ethstr), __func__); for (mask = sn->ratemask, rix = 0; mask != 0; mask >>= 1, rix++) { if ((mask & 1) == 0) continue; kprintf(" %d/%d", DOT11RATE(rix) / 2, calc_usecs_unicast_packet(sc, 1600, rix, 0,0)); } kprintf("\n"); }
int wlan_mlme_deauth_request(wlan_if_t vaphandle, u_int8_t *macaddr, IEEE80211_REASON_CODE reason) { struct ieee80211vap *vap = vaphandle; struct ieee80211_node *ni; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); /* * if a node exist with the given address already , use it. * if not use bss node. */ ni = ieee80211_vap_find_node(vap, macaddr); if (ni == NULL) { if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) ni = ieee80211_ref_node(vap->iv_bss); else{ error = -EIO; goto exit; } } /* Send deauth frame */ error = ieee80211_send_deauth(ni, reason); /* Node needs to be removed from table as well, do it only for AP/IBSS now */ #if ATH_SUPPORT_IBSS if ((vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS) && ni != vap->iv_bss) { #else if (vap->iv_opmode == IEEE80211_M_HOSTAP && ni != vap->iv_bss) { #if ATH_SUPPORT_AOW ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni); #endif /* ATH_SUPPORT_AOW */ #endif /* ATH_SUPPORT_IBSS */ IEEE80211_NODE_LEAVE(ni); } /* claim node immediately */ ieee80211_free_node(ni); if (error) { goto exit; } /* * Call MLME confirmation handler => mlme_deauth_complete * This should reflect the tx completion status of the deauth frame, * but since we don't have per frame completion, we'll always indicate success here. */ IEEE80211_DELIVER_EVENT_MLME_DEAUTH_COMPLETE(vap,macaddr, IEEE80211_STATUS_SUCCESS); exit: return error; } int wlan_mlme_disassoc_request(wlan_if_t vaphandle, u_int8_t *macaddr, IEEE80211_REASON_CODE reason) { struct ieee80211vap *vap = vaphandle; struct ieee80211_node *ni; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); /* Broadcast Addr - disassociate all stations */ if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) { if (vap->iv_opmode == IEEE80211_M_STA) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: unexpected station vap with all 0xff mac address", __func__); ASSERT(0); goto exit; } else { /* Iterate station list only when PMF is not enabled */ if (!wlan_vap_is_pmf_enabled(vap)) { wlan_iterate_station_list(vap, sta_disassoc, NULL); goto exit; } } } /* * if a node exist with the given address already , use it. * if not use bss node. */ ni = ieee80211_vap_find_node(vap, macaddr); if (ni == NULL) { if (IEEE80211_ADDR_EQ(macaddr, IEEE80211_GET_BCAST_ADDR(vap->iv_ic))) ni = ieee80211_ref_node(vap->iv_bss); else{ error = -EIO; goto exit; } } /* Send disassoc frame */ error = ieee80211_send_disassoc(ni, reason); /* Node needs to be removed from table as well, do it only for AP now */ if (vap->iv_opmode == IEEE80211_M_HOSTAP && ni != vap->iv_bss) { #if ATH_SUPPORT_AOW ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni); #endif /* ATH_SUPPORT_AOW */ IEEE80211_NODE_LEAVE(ni); } /* claim node immediately */ ieee80211_free_node(ni); if (error) { goto exit; } /* * Call MLME confirmation handler => mlme_disassoc_complete * This should reflect the tx completion status of the disassoc frame, * but since we don't have per frame completion, we'll always indicate success here. */ IEEE80211_DELIVER_EVENT_MLME_DISASSOC_COMPLETE(vap, macaddr, reason, IEEE80211_STATUS_SUCCESS); exit: return error; } int wlan_mlme_start_bss(wlan_if_t vaphandle) { struct ieee80211vap *vap = vaphandle; struct ieee80211_mlme_priv *mlme_priv = vap->iv_mlme_priv; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s\n", __func__); switch(vap->iv_opmode) { case IEEE80211_M_IBSS: IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Create adhoc bss\n", __func__); /* Reset state */ mlme_priv->im_connection_up = 0; error = mlme_create_adhoc_bss(vap); break; case IEEE80211_M_MONITOR: case IEEE80211_M_HOSTAP: case IEEE80211_M_BTAMP: /* * start the AP . the channel/ssid should have been setup already. */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: Create infrastructure(AP) bss\n", __func__); error = mlme_create_infra_bss(vap); break; default: ASSERT(0); } return error; } bool wlan_coext_enabled(wlan_if_t vaphandle) { struct ieee80211com *ic = vaphandle->iv_ic; return (ic->ic_flags & IEEE80211_F_COEXT_DISABLE) ? FALSE : TRUE; } void wlan_determine_cw(wlan_if_t vaphandle, wlan_chan_t channel) { struct ieee80211com *ic = vaphandle->iv_ic; int is_chan_ht40 = channel->ic_flags & (IEEE80211_CHAN_11NG_HT40PLUS | IEEE80211_CHAN_11NG_HT40MINUS); if (is_chan_ht40 && (channel->ic_flags & IEEE80211_CHAN_HT40INTOL)) { ic->ic_bss_to20(ic); } } static void sta_deauth(void *arg, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; u_int8_t macaddr[6]; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: deauth station %s \n", __func__,ether_sprintf(ni->ni_macaddr)); IEEE80211_ADDR_COPY(macaddr, ni->ni_macaddr); if (ni->ni_associd) { /* * if it is associated, then send disassoc. */ ieee80211_send_deauth(ni, IEEE80211_REASON_AUTH_LEAVE); } IEEE80211_NODE_LEAVE(ni); IEEE80211_DELIVER_EVENT_MLME_DEAUTH_INDICATION(vap, macaddr, IEEE80211_REASON_AUTH_LEAVE); } static void sta_disassoc(void *arg, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; u_int8_t macaddr[6]; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: disassoc station %s \n", __func__,ether_sprintf(ni->ni_macaddr)); IEEE80211_ADDR_COPY(macaddr, ni->ni_macaddr); if (ni->ni_associd) { /* * if it is associated, then send disassoc. */ ieee80211_send_disassoc(ni, IEEE80211_REASON_ASSOC_LEAVE); #if ATH_SUPPORT_AOW ieee80211_aow_join_indicate(ni->ni_ic, AOW_STA_DISCONNECTED, ni); #endif /* ATH_SUPPORT_AOW */ } IEEE80211_NODE_LEAVE(ni); IEEE80211_DELIVER_EVENT_MLME_DISASSOC_COMPLETE(vap, macaddr, IEEE80211_REASON_ASSOC_LEAVE, IEEE80211_STATUS_SUCCESS); } int wlan_mlme_stop_bss(wlan_if_t vaphandle, int flags) { #define WAIT_RX_INTERVAL 10000 u_int32_t elapsed_time = 0; struct ieee80211vap *vap = vaphandle; struct ieee80211_mlme_priv *mlme_priv = vap->iv_mlme_priv; int error = 0; IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s flags = 0x%x\n", __func__, flags); /* * Wait for current rx path to finish. Assume only one rx thread. */ if (flags & WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE) { do { if (OS_ATOMIC_CMPXCHG(&vap->iv_rx_gate, 0, 1) == 0) { break; } OS_SLEEP(WAIT_RX_INTERVAL); elapsed_time += WAIT_RX_INTERVAL; if (elapsed_time > (100 * WAIT_RX_INTERVAL)) ieee80211_note (vap,"%s: Rx pending count stuck. Investigate!!!\n", __func__); } while (1); } switch(vap->iv_opmode) { #if UMAC_SUPPORT_IBSS case IEEE80211_M_IBSS: mlme_stop_adhoc_bss(vap, flags); break; #endif case IEEE80211_M_HOSTAP: case IEEE80211_M_BTAMP: /* disassoc/deauth all stations */ IEEE80211_DPRINTF(vap, IEEE80211_MSG_MLME, "%s: dsassocing/deauth all stations \n", __func__); if(vap->iv_send_deauth) wlan_iterate_station_list(vap, sta_deauth, NULL); else wlan_iterate_station_list(vap, sta_disassoc, NULL); break; case IEEE80211_M_STA: /* There should be no mlme requests pending */ ASSERT(vap->iv_mlme_priv->im_request_type == MLME_REQ_NONE); /* Reset state variables */ mlme_priv->im_connection_up = 0; mlme_sta_swbmiss_timer_stop(vap); ieee80211_sta_leave(vap->iv_bss); break; default: break; } if (flags & WLAN_MLME_STOP_BSS_F_FORCE_STOP_RESET) { /* put vap in init state */ ieee80211_vap_stop(vap, TRUE); } else { /* put vap in stopping state */ if (flags & WLAN_MLME_STOP_BSS_F_STANDBY) ieee80211_vap_standby(vap); else ieee80211_vap_stop(vap, FALSE); } if (!(flags & WLAN_MLME_STOP_BSS_F_NO_RESET)) error = ieee80211_reset_bss(vap); /* * Release the rx mutex. */ if (flags & WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE) { (void) OS_ATOMIC_CMPXCHG(&vap->iv_rx_gate, 1, 0); } return error; #undef WAIT_RX_INTERVAL }
/* * IEEE80211_M_IBSS+IEEE80211_M_AHDEMO vap state machine handler. */ static int adhoc_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; enum ieee80211_state ostate; IEEE80211_LOCK_ASSERT(vap->iv_ic); ostate = vap->iv_state; IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n", __func__, ieee80211_state_name[ostate], ieee80211_state_name[nstate], arg); vap->iv_state = nstate; /* state transition */ if (ostate != IEEE80211_S_SCAN) ieee80211_cancel_scan(vap); /* background scan */ ni = vap->iv_bss; /* NB: no reference held */ switch (nstate) { case IEEE80211_S_INIT: switch (ostate) { case IEEE80211_S_SCAN: ieee80211_cancel_scan(vap); break; default: break; } if (ostate != IEEE80211_S_INIT) { /* NB: optimize INIT -> INIT case */ ieee80211_reset_bss(vap); } break; case IEEE80211_S_SCAN: switch (ostate) { case IEEE80211_S_RUN: /* beacon miss */ /* purge station table; entries are stale */ ieee80211_iterate_nodes(&ic->ic_sta, sta_leave, vap); /* fall thru... */ case IEEE80211_S_INIT: if (vap->iv_des_chan != IEEE80211_CHAN_ANYC && !IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) { /* * Already have a channel; bypass the * scan and startup immediately. */ ieee80211_create_ibss(vap, ieee80211_ht_adjust_channel(ic, vap->iv_des_chan, vap->iv_flags_ht)); break; } /* * Initiate a scan. We can come here as a result * of an IEEE80211_IOC_SCAN_REQ too in which case * the vap will be marked with IEEE80211_FEXT_SCANREQ * and the scan request parameters will be present * in iv_scanreq. Otherwise we do the default. */ if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) { ieee80211_check_scan(vap, vap->iv_scanreq_flags, vap->iv_scanreq_duration, vap->iv_scanreq_mindwell, vap->iv_scanreq_maxdwell, vap->iv_scanreq_nssid, vap->iv_scanreq_ssid); vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ; } else ieee80211_check_scan_current(vap); break; case IEEE80211_S_SCAN: /* * This can happen because of a change in state * that requires a reset. Trigger a new scan * unless we're in manual roaming mode in which * case an application must issue an explicit request. */ if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) ieee80211_check_scan_current(vap); break; default: goto invalid; } break; case IEEE80211_S_RUN: if (vap->iv_flags & IEEE80211_F_WPA) { /* XXX validate prerequisites */ } switch (ostate) { case IEEE80211_S_SCAN: #ifdef IEEE80211_DEBUG if (ieee80211_msg_debug(vap)) { ieee80211_note(vap, "synchronized with %s ssid ", ether_sprintf(ni->ni_bssid)); ieee80211_print_essid(vap->iv_bss->ni_essid, ni->ni_esslen); /* XXX MCS/HT */ printf(" channel %d start %uMb\n", ieee80211_chan2ieee(ic, ic->ic_curchan), IEEE80211_RATE2MBS(ni->ni_txrate)); } #endif break; case IEEE80211_S_RUN: /* IBSS merge */ break; default: goto invalid; } /* * When 802.1x is not in use mark the port authorized * at this point so traffic can flow. */ if (ni->ni_authmode != IEEE80211_AUTH_8021X) ieee80211_node_authorize(ni); /* * Fake association when joining an existing bss. */ if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, vap->iv_myaddr) && ic->ic_newassoc != NULL) ic->ic_newassoc(ni, ostate != IEEE80211_S_RUN); break; case IEEE80211_S_SLEEP: vap->iv_sta_ps(vap, 0); break; default: invalid: IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: unexpected state transition %s -> %s\n", __func__, ieee80211_state_name[ostate], ieee80211_state_name[nstate]); break; } return 0; }
/* * 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; }