int an_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { struct an_softc *sc = ic->ic_softc; struct ieee80211_node *ni = ic->ic_bss; enum ieee80211_state ostate; int buflen; ostate = ic->ic_state; DPRINTF(("an_newstate: %s -> %s\n", ieee80211_state_name[ostate], ieee80211_state_name[nstate])); switch (nstate) { case IEEE80211_S_INIT: ic->ic_flags &= ~IEEE80211_F_IBSSON; return (*sc->sc_newstate)(ic, nstate, arg); case IEEE80211_S_RUN: buflen = sizeof(sc->sc_buf); an_read_rid(sc, AN_RID_STATUS, &sc->sc_buf, &buflen); an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_cur_bssid, 3); an_swap16((u_int16_t *)&sc->sc_buf.sc_status.an_ssid, 16); IEEE80211_ADDR_COPY(ni->ni_bssid, sc->sc_buf.sc_status.an_cur_bssid); IEEE80211_ADDR_COPY(ni->ni_macaddr, ni->ni_bssid); ni->ni_chan = &ic->ic_channels[ sc->sc_buf.sc_status.an_cur_channel]; ni->ni_esslen = sc->sc_buf.sc_status.an_ssidlen; if (ni->ni_esslen > IEEE80211_NWID_LEN) ni->ni_esslen = IEEE80211_NWID_LEN; /*XXX*/ memcpy(ni->ni_essid, sc->sc_buf.sc_status.an_ssid, ni->ni_esslen); ni->ni_rates = ic->ic_sup_rates[IEEE80211_MODE_11B]; /*XXX*/ if (ic->ic_if.if_flags & IFF_DEBUG) { printf("%s: ", sc->sc_dev.dv_xname); if (ic->ic_opmode == IEEE80211_M_STA) printf("associated "); else printf("synchronized "); printf("with %s ssid ", ether_sprintf(ni->ni_bssid)); ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); printf(" channel %u start %uMb\n", sc->sc_buf.sc_status.an_cur_channel, sc->sc_buf.sc_status.an_current_tx_rate/2); } break; default: break; } ic->ic_state = nstate; /* skip standard ieee80211 handling */ return 0; }
void ieee80211_scan_dump_probe_beacon(uint8_t subtype, int isnew, const uint8_t mac[IEEE80211_ADDR_LEN], const struct ieee80211_scanparams *sp, int rssi) { printf("[%s] %s%s on chan %u (bss chan %u) ", ether_sprintf(mac), isnew ? "new " : "", ieee80211_mgt_subtype_name(subtype), sp->chan, sp->bchan); ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]); printf(" rssi %d\n", rssi); if (isnew) { printf("[%s] caps 0x%x bintval %u erp 0x%x", ether_sprintf(mac), sp->capinfo, sp->bintval, sp->erp); if (sp->country != NULL) dump_country(sp->country); printf("\n"); } }
/* * 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; }
int ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni) { u_int8_t rate; int fail; fail = 0; if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) fail |= 0x01; if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && ni->ni_chan != ic->ic_des_chan) fail |= 0x01; #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) fail |= 0x02; } else #endif { if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) fail |= 0x02; } if (ic->ic_flags & (IEEE80211_F_WEPON | IEEE80211_F_RSNON)) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) fail |= 0x04; } else { if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) fail |= 0x04; } rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO); if (rate & IEEE80211_RATE_BASIC) fail |= 0x08; if (ic->ic_des_esslen != 0 && (ni->ni_esslen != ic->ic_des_esslen || memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) fail |= 0x10; if ((ic->ic_flags & IEEE80211_F_DESBSSID) && !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) fail |= 0x20; if (ic->ic_flags & IEEE80211_F_RSNON) { /* * If at least one RSN IE field from the AP's RSN IE fails * to overlap with any value the STA supports, the STA shall * decline to associate with that AP. */ if ((ni->ni_rsnprotos & ic->ic_rsnprotos) == 0) fail |= 0x40; if ((ni->ni_rsnakms & ic->ic_rsnakms) == 0) fail |= 0x40; if ((ni->ni_rsnakms & ic->ic_rsnakms & ~(IEEE80211_AKM_PSK | IEEE80211_AKM_SHA256_PSK)) == 0) { /* AP only supports PSK AKMPs */ if (!(ic->ic_flags & IEEE80211_F_PSK)) fail |= 0x40; } if (ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP40 && ni->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP && ni->ni_rsngroupcipher != IEEE80211_CIPHER_CCMP && ni->ni_rsngroupcipher != IEEE80211_CIPHER_WEP104) fail |= 0x40; if ((ni->ni_rsnciphers & ic->ic_rsnciphers) == 0) fail |= 0x40; /* we only support BIP as the IGTK cipher */ if ((ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC) && ni->ni_rsngroupmgmtcipher != IEEE80211_CIPHER_BIP) fail |= 0x40; /* we do not support MFP but AP requires it */ if (!(ic->ic_caps & IEEE80211_C_MFP) && (ni->ni_rsncaps & IEEE80211_RSNCAP_MFPR)) fail |= 0x40; /* we require MFP but AP does not support it */ if ((ic->ic_caps & IEEE80211_C_MFP) && (ic->ic_flags & IEEE80211_F_MFPR) && !(ni->ni_rsncaps & IEEE80211_RSNCAP_MFPC)) fail |= 0x40; } #ifdef IEEE80211_DEBUG if (ic->ic_if.if_flags & IFF_DEBUG) { printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr)); printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' '); printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' '); printf(" %+4d", ni->ni_rssi); printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, fail & 0x08 ? '!' : ' '); printf(" %4s%c", (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : "????", fail & 0x02 ? '!' : ' '); printf(" %7s%c ", (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "privacy" : "no", fail & 0x04 ? '!' : ' '); printf(" %3s%c ", (ic->ic_flags & IEEE80211_F_RSNON) ? "rsn" : "no", fail & 0x40 ? '!' : ' '); ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); printf("%s\n", fail & 0x10 ? "!" : ""); } #endif return fail; }
int ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni) { u_int8_t rate; int fail; fail = 0; if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan))) fail |= 0x01; if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && ni->ni_chan != ic->ic_des_chan) fail |= 0x01; if (ic->ic_opmode == IEEE80211_M_IBSS) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) fail |= 0x02; } else { if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) fail |= 0x02; } if (ic->ic_flags & IEEE80211_F_WEPON) { if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) fail |= 0x04; } else { /* XXX does this mean privacy is supported or required? */ if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) fail |= 0x04; } rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO); if (rate & IEEE80211_RATE_BASIC) fail |= 0x08; if (ic->ic_des_esslen != 0 && (ni->ni_esslen != ic->ic_des_esslen || memcmp(ni->ni_essid, ic->ic_des_essid, ic->ic_des_esslen) != 0)) fail |= 0x10; if ((ic->ic_flags & IEEE80211_F_DESBSSID) && !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) fail |= 0x20; #ifdef IEEE80211_DEBUG if (ic->ic_if.if_flags & IFF_DEBUG) { printf(" %c %s", fail ? '-' : '+', ether_sprintf(ni->ni_macaddr)); printf(" %s%c", ether_sprintf(ni->ni_bssid), fail & 0x20 ? '!' : ' '); printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), fail & 0x01 ? '!' : ' '); printf(" %+4d", ni->ni_rssi); printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2, fail & 0x08 ? '!' : ' '); printf(" %4s%c", (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : "????", fail & 0x02 ? '!' : ' '); printf(" %3s%c ", (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? "wep" : "no", fail & 0x04 ? '!' : ' '); ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); printf("%s\n", fail & 0x10 ? "!" : ""); } #endif return fail; }
int ieee80211_elements(struct ieee80211_frame *wh) { u_int8_t *frm; u_int8_t *tstamp, *bintval, *capinfo; int i; frm = (u_int8_t *)&wh[1]; tstamp = frm; TCHECK2(*tstamp, 8); frm += 8; bintval = frm; TCHECK2(*bintval, 2); frm += 2; if (vflag) PRINTF(", interval %u", letoh16(*(u_int16_t *)bintval)); capinfo = frm; TCHECK2(*capinfo, 2); frm += 2; #if 0 if (vflag) printb(", caps", letoh16(*(u_int16_t *)capinfo), IEEE80211_CAPINFO_BITS); #endif while (TTEST2(*frm, 2)) { u_int len = frm[1]; u_int8_t *data = frm + 2; if (!TTEST2(*data, len)) break; #define ELEM_CHECK(l) if (len != l) break switch (*frm) { case IEEE80211_ELEMID_SSID: PRINTF(", ssid"); ieee80211_print_essid(data, len); break; case IEEE80211_ELEMID_RATES: if (!vflag) break; PRINTF(", rates"); for (i = len; i > 0; i--, data++) PRINTF(" %uM", (data[0] & IEEE80211_RATE_VAL) / 2); break; case IEEE80211_ELEMID_FHPARMS: ELEM_CHECK(5); PRINTF(", fh (dwell %u, chan %u, index %u)", (data[1] << 8) | data[0], (data[2] - 1) * 80 + data[3], /* FH_CHAN */ data[4]); break; case IEEE80211_ELEMID_DSPARMS: ELEM_CHECK(1); if (!vflag) break; PRINTF(", ds"); PRINTF(" (chan %u)", data[0]); break; case IEEE80211_ELEMID_CFPARMS: if (!vflag) break; PRINTF(", cf"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_TIM: if (!vflag) break; PRINTF(", tim"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_IBSSPARMS: if (!vflag) break; PRINTF(", ibss"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_COUNTRY: if (!vflag) break; PRINTF(", country"); for (i = len; i > 0; i--, data++) PRINTF(" %u", data[0]); break; case IEEE80211_ELEMID_CHALLENGE: if (!vflag) break; PRINTF(", challenge"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_ERP: if (!vflag) break; PRINTF(", erp"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_RSN: if (!vflag) break; PRINTF(", rsn"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_XRATES: if (!vflag) break; PRINTF(", xrates"); for (i = len; i > 0; i--, data++) PRINTF(" %uM", (data[0] & IEEE80211_RATE_VAL) / 2); break; case IEEE80211_ELEMID_TPC: if (!vflag) break; PRINTF(", tpc"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_CCKM: if (!vflag) break; PRINTF(", cckm"); ieee80211_print_element(data, len); break; case IEEE80211_ELEMID_VENDOR: if (!vflag) break; PRINTF(", vendor"); ieee80211_print_element(data, len); break; default: if (!vflag) break; PRINTF(", %u:%u", (u_int) *frm, len); ieee80211_print_element(data, len); break; } frm += len + 2; if (frm >= snapend) break; } #undef ELEM_CHECK return (0); trunc: /* Truncated elements in frame */ return (1); }