enum ieee80211_phymode ieee80211_next_mode(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) != IFM_AUTO) { /* * Reset the scan state and indicate a wrap around * if we're running in a fixed, user-specified phy mode. */ ieee80211_reset_scan(ifp); return (IEEE80211_MODE_AUTO); } /* * Get the next supported mode */ for (++ic->ic_curmode; ic->ic_curmode <= IEEE80211_MODE_TURBO; ic->ic_curmode++) { /* Wrap around and ignore turbo mode */ if (ic->ic_curmode >= IEEE80211_MODE_TURBO) { ic->ic_curmode = IEEE80211_MODE_AUTO; break; } if (ic->ic_modecaps & (1 << ic->ic_curmode)) break; } ieee80211_setmode(ic, ic->ic_curmode); return (ic->ic_curmode); }
/* * Begin an active scan. */ void ieee80211_begin_scan(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; if (ic->ic_scan_lock & IEEE80211_SCAN_LOCKED) return; ic->ic_scan_lock |= IEEE80211_SCAN_LOCKED; /* * In all but hostap mode scanning starts off in * an active mode before switching to passive. */ #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode != IEEE80211_M_HOSTAP) #endif { ic->ic_flags |= IEEE80211_F_ASCAN; ic->ic_stats.is_scan_active++; } #ifndef IEEE80211_STA_ONLY else ic->ic_stats.is_scan_passive++; #endif if (ifp->if_flags & IFF_DEBUG) printf("%s: begin %s scan\n", ifp->if_xname, (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); /* * Flush any previously seen AP's. Note that the latter * assumes we don't act as both an AP and a station, * otherwise we'll potentially flush state of stations * associated with us. */ ieee80211_free_allnodes(ic); /* * Reset the current mode. Setting the current mode will also * reset scan state. */ if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) == IFM_AUTO) ic->ic_curmode = IEEE80211_MODE_AUTO; ieee80211_setmode(ic, ic->ic_curmode); ic->ic_scan_count = 0; /* Scan the next channel. */ ieee80211_next_scan(ifp); }
/* * Begin an active scan. */ void Voodoo80211Device:: ieee80211_begin_scan(struct ieee80211com *ic) { if (ic->ic_scan_lock & IEEE80211_SCAN_LOCKED) return; ic->ic_scan_lock |= IEEE80211_SCAN_LOCKED; /* * In all but hostap mode scanning starts off in * an active mode before switching to passive. */ { ic->ic_flags |= IEEE80211_F_ASCAN; ic->ic_stats.is_scan_active++; } if (false /* ifp->debugOn */) printf("%s: begin %s scan\n", "voodoo_wifi", (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); /* * Flush any previously seen AP's. Note that the latter * assumes we don't act as both an AP and a station, * otherwise we'll potentially flush state of stations * associated with us. */ ieee80211_free_allnodes(ic); /* * Reset the current mode. Setting the current mode will also * reset scan state. */ if (getCurrentMedium()->getType() & IFM_AUTO) ic->ic_curmode = IEEE80211_MODE_AUTO; ieee80211_setmode(ic, (enum ieee80211_phymode) ic->ic_curmode); ic->ic_scan_count = 0; /* Scan the next channel. */ ieee80211_next_scan(ic); }
int wlan_reset_end(wlan_if_t vaphandle, ieee80211_reset_request *reset_req) { struct ieee80211com *ic = vaphandle->iv_ic; int ret; ret = ic->ic_reset_end(ic, reset_req->no_flush); #if ATH_RESET_SERIAL /* Reset some MIB variables if required */ if (reset_req->set_default_mib) { struct ieee80211vap *vap = vaphandle; /* * NB: Only IEEE80211_RESET_TYPE_DOT11_INTF can reset MIB variables */ KASSERT(reset_req->type == IEEE80211_RESET_TYPE_DOT11_INTF, ("invalid reset request\n")); if (reset_req->reset_mac) { /* reset regdmn module */ ieee80211_regdmn_reset(ic); } if (reset_req->reset_phy) { /* set the desired PHY mode to 11b */ vap->iv_des_mode = reset_req->phy_mode; /* change to the default PHY mode if required */ /* set wireless mode */ ieee80211_setmode(ic, vap->iv_des_mode, vap->iv_opmode); /* set default channel */ ASSERT(vap->iv_des_chan[vap->iv_des_mode] != IEEE80211_CHAN_ANYC); ieee80211_set_channel(ic, vap->iv_des_chan[vap->iv_des_mode]); vap->iv_bsschan = ic->ic_curchan; } } #endif return ret; }
void ieee80211_ifattach(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; memcpy(((struct arpcom *)ifp)->ac_enaddr, ic->ic_myaddr, ETHER_ADDR_LEN); ether_ifattach(ifp); ifp->if_output = ieee80211_output; #if NBPFILTER > 0 bpfattach(&ic->ic_rawbpf, ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4)); #endif ieee80211_crypto_attach(ifp); ieee80211_channel_init(ifp); /* IEEE 802.11 defines a MTU >= 2290 */ ifp->if_capabilities |= IFCAP_VLAN_MTU; ieee80211_setbasicrates(ic); (void)ieee80211_setmode(ic, ic->ic_curmode); if (ic->ic_lintval == 0) ic->ic_lintval = 100; /* default sleep */ ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */ ic->ic_dtim_period = 1; /* all TIMs are DTIMs */ LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list); ieee80211_node_attach(ifp); ieee80211_proto_attach(ifp); if_addgroup(ifp, "wlan"); ifp->if_priority = IF_WIRELESS_DEFAULT_PRIORITY; }
/* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ static void ieee80211_chan_init(struct ieee80211com *ic) { #define DEFAULTRATES(m, def) do { \ if (ic->ic_sup_rates[m].rs_nrates == 0) \ ic->ic_sup_rates[m] = def; \ } while (0) struct ieee80211_channel *c; int i; KASSERT(0 < ic->ic_nchans && ic->ic_nchans <= IEEE80211_CHAN_MAX, ("invalid number of channels specified: %u", ic->ic_nchans)); memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); memset(ic->ic_modecaps, 0, sizeof(ic->ic_modecaps)); setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO); for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; KASSERT(c->ic_flags != 0, ("channel with no flags")); /* * Help drivers that work only with frequencies by filling * in IEEE channel #'s if not already calculated. Note this * mimics similar work done in ieee80211_setregdomain when * changing regulatory state. */ if (c->ic_ieee == 0) c->ic_ieee = ieee80211_mhz2ieee(c->ic_freq,c->ic_flags); if (IEEE80211_IS_CHAN_HT40(c) && c->ic_extieee == 0) c->ic_extieee = ieee80211_mhz2ieee(c->ic_freq + (IEEE80211_IS_CHAN_HT40U(c) ? 20 : -20), c->ic_flags); /* default max tx power to max regulatory */ if (c->ic_maxpower == 0) c->ic_maxpower = 2*c->ic_maxregpower; setbit(ic->ic_chan_avail, c->ic_ieee); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11A); if (IEEE80211_IS_CHAN_B(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11B); if (IEEE80211_IS_CHAN_ANYG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11G); if (IEEE80211_IS_CHAN_FHSS(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_FH); if (IEEE80211_IS_CHAN_108A(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_A); if (IEEE80211_IS_CHAN_108G(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G); if (IEEE80211_IS_CHAN_ST(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A); if (IEEE80211_IS_CHAN_HALF(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_HALF); if (IEEE80211_IS_CHAN_QUARTER(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_QUARTER); if (IEEE80211_IS_CHAN_HTA(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11NA); if (IEEE80211_IS_CHAN_HTG(c)) setbit(ic->ic_modecaps, IEEE80211_MODE_11NG); } /* initialize candidate channels to all available */ memcpy(ic->ic_chan_active, ic->ic_chan_avail, sizeof(ic->ic_chan_avail)); /* sort channel table to allow lookup optimizations */ ieee80211_sort_channels(ic->ic_channels, ic->ic_nchans); /* invalidate any previous state */ ic->ic_bsschan = IEEE80211_CHAN_ANYC; ic->ic_prevchan = NULL; ic->ic_csa_newchan = NULL; /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[0]; ic->ic_rt = ieee80211_get_ratetable(ic->ic_curchan); /* fillin well-known rate sets if driver has not specified */ DEFAULTRATES(IEEE80211_MODE_11B, ieee80211_rateset_11b); DEFAULTRATES(IEEE80211_MODE_11G, ieee80211_rateset_11g); DEFAULTRATES(IEEE80211_MODE_11A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_TURBO_A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_TURBO_G, ieee80211_rateset_11g); DEFAULTRATES(IEEE80211_MODE_STURBO_A, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_HALF, ieee80211_rateset_half); DEFAULTRATES(IEEE80211_MODE_QUARTER, ieee80211_rateset_quarter); DEFAULTRATES(IEEE80211_MODE_11NA, ieee80211_rateset_11a); DEFAULTRATES(IEEE80211_MODE_11NG, ieee80211_rateset_11g); /* * Set auto mode to reset active channel state and any desired channel. */ (void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO); #undef DEFAULTRATES }
/* * Handle a media change request. */ int ieee80211_media_change(struct ifnet *ifp) { struct ieee80211com *ic; struct ifmedia_entry *ime; enum ieee80211_opmode newopmode; enum ieee80211_phymode newphymode; int i, j, newrate, error = 0; ic = ieee80211_find_instance(ifp); if (!ic) { if_printf(ifp, "%s: no 802.11 instance!\n", __func__); return EINVAL; } ime = ic->ic_media.ifm_cur; /* * First, identify the phy mode. */ switch (IFM_MODE(ime->ifm_media)) { case IFM_IEEE80211_11A: newphymode = IEEE80211_MODE_11A; break; case IFM_IEEE80211_11B: newphymode = IEEE80211_MODE_11B; break; case IFM_IEEE80211_11G: newphymode = IEEE80211_MODE_11G; break; case IFM_IEEE80211_FH: newphymode = IEEE80211_MODE_FH; break; case IFM_AUTO: newphymode = IEEE80211_MODE_AUTO; break; default: return EINVAL; } /* * Turbo mode is an ``option''. * XXX does not apply to AUTO */ if (ime->ifm_media & IFM_IEEE80211_TURBO) { if (newphymode == IEEE80211_MODE_11A) newphymode = IEEE80211_MODE_TURBO_A; else if (newphymode == IEEE80211_MODE_11G) newphymode = IEEE80211_MODE_TURBO_G; else return EINVAL; } /* * Validate requested mode is available. */ if ((ic->ic_modecaps & (1<<newphymode)) == 0) return EINVAL; /* * Next, the fixed/variable rate. */ i = -1; if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) { /* * Convert media subtype to rate. */ newrate = ieee80211_media2rate(ime->ifm_media); if (newrate == 0) return EINVAL; /* * Check the rate table for the specified/current phy. */ if (newphymode == IEEE80211_MODE_AUTO) { /* * In autoselect mode search for the rate. */ for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) { if ((ic->ic_modecaps & (1<<j)) == 0) continue; i = findrate(ic, j, newrate); if (i != -1) { /* lock mode too */ newphymode = j; break; } } } else { i = findrate(ic, newphymode, newrate); } if (i == -1) /* mode/rate mismatch */ return EINVAL; } /* NB: defer rate setting to later */ /* * Deduce new operating mode but don't install it just yet. */ if ((ime->ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) == (IFM_IEEE80211_ADHOC|IFM_FLAG0)) newopmode = IEEE80211_M_AHDEMO; else if (ime->ifm_media & IFM_IEEE80211_HOSTAP) newopmode = IEEE80211_M_HOSTAP; else if (ime->ifm_media & IFM_IEEE80211_ADHOC) newopmode = IEEE80211_M_IBSS; else if (ime->ifm_media & IFM_IEEE80211_MONITOR) newopmode = IEEE80211_M_MONITOR; else newopmode = IEEE80211_M_STA; #ifndef IEEE80211_NO_HOSTAP /* * Autoselect doesn't make sense when operating as an AP. * If no phy mode has been selected, pick one and lock it * down so rate tables can be used in forming beacon frames * and the like. */ if (newopmode == IEEE80211_M_HOSTAP && newphymode == IEEE80211_MODE_AUTO) { for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) if (ic->ic_modecaps & (1<<j)) { newphymode = j; break; } } #endif /* !IEEE80211_NO_HOSTAP */ /* * Handle phy mode change. */ if (ic->ic_curmode != newphymode) { /* change phy mode */ error = ieee80211_setmode(ic, newphymode); if (error != 0) return error; error = ENETRESET; } /* * Committed to changes, install the rate setting. */ if (ic->ic_fixed_rate != i) { ic->ic_fixed_rate = i; /* set fixed tx rate */ error = ENETRESET; } /* * Handle operating mode change. */ if (ic->ic_opmode != newopmode) { ic->ic_opmode = newopmode; switch (newopmode) { case IEEE80211_M_AHDEMO: case IEEE80211_M_HOSTAP: case IEEE80211_M_STA: case IEEE80211_M_MONITOR: ic->ic_flags &= ~IEEE80211_F_IBSSON; break; case IEEE80211_M_IBSS: ic->ic_flags |= IEEE80211_F_IBSSON; break; } /* * Yech, slot time may change depending on the * operating mode so reset it to be sure everything * is setup appropriately. */ ieee80211_reset_erp(ic); ieee80211_wme_initparams(ic); /* after opmode change */ error = ENETRESET; } #ifdef notdef if (error == 0) ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media); #endif return error; }
void ieee80211_ifattach(struct ieee80211com *ic) { struct ifnet *ifp = ic->ic_ifp; struct ieee80211_channel *c; int i; #ifdef __NetBSD__ ieee80211_init(); #endif /* __NetBSD__ */ ether_ifattach(ifp, ic->ic_myaddr); bpf_attach2(ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); ieee80211_crypto_attach(ic); /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (c->ic_flags) { /* * Verify driver passed us valid data. */ if (i != ieee80211_chan2ieee(ic, c)) { if_printf(ifp, "bad channel ignored; " "freq %u flags %x number %u\n", c->ic_freq, c->ic_flags, i); c->ic_flags = 0; /* NB: remove */ continue; } setbit(ic->ic_chan_avail, i); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_11A; if (IEEE80211_IS_CHAN_B(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_11B; if (IEEE80211_IS_CHAN_PUREG(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_11G; if (IEEE80211_IS_CHAN_FHSS(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_FH; if (IEEE80211_IS_CHAN_T(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_A; if (IEEE80211_IS_CHAN_108G(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_G; if (ic->ic_curchan == NULL) { /* arbitrarily pick the first channel */ ic->ic_curchan = &ic->ic_channels[i]; } } } /* validate ic->ic_curmode */ if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0) ic->ic_curmode = IEEE80211_MODE_AUTO; ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ #if 0 /* * Enable WME by default if we're capable. */ if (ic->ic_caps & IEEE80211_C_WME) ic->ic_flags |= IEEE80211_F_WME; #endif (void) ieee80211_setmode(ic, ic->ic_curmode); if (ic->ic_bintval == 0) ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT; ic->ic_bmisstimeout = 7*ic->ic_bintval; /* default 7 beacons */ ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT; IEEE80211_BEACON_LOCK_INIT(ic, "beacon"); if (ic->ic_lintval == 0) ic->ic_lintval = ic->ic_bintval; ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list); ieee80211_node_attach(ic); ieee80211_proto_attach(ic); ieee80211_add_vap(ic); ieee80211_sysctl_attach(ic); /* NB: requires ic_vap */ /* * Install a default reset method for the ioctl support. * The driver is expected to fill this in before calling us. */ if (ic->ic_reset == NULL) ic->ic_reset = ieee80211_default_reset; }
static int ieee80211_vap_reset(struct ieee80211vap *vap, ieee80211_reset_request *reset_req) { struct ieee80211com *ic = vap->iv_ic; /* Cancel pending MLME requests */ wlan_mlme_cancel(vap); /* * Reset node table include all nodes. * NB: pairwise keys will be deleted during node cleanup. */ ieee80211_reset_bss(vap); /* Reset aplist configuration parameters */ ieee80211_aplist_config_init(ieee80211_vap_get_aplist_config(vap)); /* Reset RSN settings */ ieee80211_rsn_reset(vap); /* Reset statistics */ ieee80211_reset_stats(vap, reset_req->reset_hw); /* Reset some of the misc. vap settings */ vap->iv_des_modecaps = (1 << IEEE80211_MODE_AUTO); vap->iv_des_nssid = 0; OS_MEMZERO(&vap->iv_des_ssid[0], (sizeof(ieee80211_ssid) * IEEE80211_SCAN_MAX_SSID)); /* Because reset_start has graspped a mutex which chan_set *will also try to grasp, so don't call ieee80211_set_channel here. */ #if !ATH_RESET_SERIAL /* Reset some MIB variables if required */ if (reset_req->set_default_mib) { /* * NB: Only IEEE80211_RESET_TYPE_DOT11_INTF can reset MIB variables */ KASSERT(reset_req->type == IEEE80211_RESET_TYPE_DOT11_INTF, ("invalid reset request\n")); if (reset_req->reset_mac) { /* reset regdmn module */ ieee80211_regdmn_reset(ic); } if (reset_req->reset_phy) { /* set the desired PHY mode to 11b */ vap->iv_des_mode = reset_req->phy_mode; /* change to the default PHY mode if required */ /* set wireless mode */ ieee80211_setmode(ic, vap->iv_des_mode, vap->iv_opmode); /* set default channel */ ASSERT(vap->iv_des_chan[vap->iv_des_mode] != IEEE80211_CHAN_ANYC); ieee80211_set_channel(ic, vap->iv_des_chan[vap->iv_des_mode]); vap->iv_bsschan = ic->ic_curchan; } } #endif return 0; }
void ieee80211_ifattach(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; struct ieee80211_channel *c; int i; memcpy(((struct arpcom *)ifp)->ac_enaddr, ic->ic_myaddr, ETHER_ADDR_LEN); ether_ifattach(ifp); ifp->if_output = ieee80211_output; #if NBPFILTER > 0 bpfattach(&ic->ic_rawbpf, ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4)); #endif ieee80211_crypto_attach(ifp); /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (c->ic_flags) { /* * Verify driver passed us valid data. */ if (i != ieee80211_chan2ieee(ic, c)) { printf("%s: bad channel ignored; " "freq %u flags %x number %u\n", ifp->if_xname, c->ic_freq, c->ic_flags, i); c->ic_flags = 0; /* NB: remove */ continue; } setbit(ic->ic_chan_avail, i); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_11A; if (IEEE80211_IS_CHAN_B(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_11B; if (IEEE80211_IS_CHAN_PUREG(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_11G; if (IEEE80211_IS_CHAN_T(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO; } } /* validate ic->ic_curmode */ if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0) ic->ic_curmode = IEEE80211_MODE_AUTO; ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED; /* IEEE 802.11 defines a MTU >= 2290 */ ifp->if_capabilities |= IFCAP_VLAN_MTU; ieee80211_setbasicrates(ic); (void)ieee80211_setmode(ic, ic->ic_curmode); if (ic->ic_lintval == 0) ic->ic_lintval = 100; /* default sleep */ ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */ ic->ic_dtim_period = 1; /* all TIMs are DTIMs */ LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list); ieee80211_node_attach(ifp); ieee80211_proto_attach(ifp); if_addgroup(ifp, "wlan"); ifp->if_priority = IF_WIRELESS_DEFAULT_PRIORITY; }
/* * Handle a media change request. */ int ieee80211_media_change(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; struct ifmedia_entry *ime; enum ieee80211_opmode newopmode; enum ieee80211_phymode newphymode; int i, j, newrate, error = 0; ime = ic->ic_media.ifm_cur; /* * First, identify the phy mode. */ switch (IFM_MODE(ime->ifm_media)) { case IFM_IEEE80211_11A: newphymode = IEEE80211_MODE_11A; break; case IFM_IEEE80211_11B: newphymode = IEEE80211_MODE_11B; break; case IFM_IEEE80211_11G: newphymode = IEEE80211_MODE_11G; break; case IFM_IEEE80211_FH: newphymode = IEEE80211_MODE_FH; break; case IFM_AUTO: newphymode = IEEE80211_MODE_AUTO; break; default: return EINVAL; } /* * Turbo mode is an ``option''. Eventually it * needs to be applied to 11g too. */ if (ime->ifm_media & IFM_IEEE80211_TURBO) { if (newphymode != IEEE80211_MODE_11A) return EINVAL; newphymode = IEEE80211_MODE_TURBO; } /* * Validate requested mode is available. */ if ((ic->ic_modecaps & (1<<newphymode)) == 0) return EINVAL; /* * Next, the fixed/variable rate. */ i = -1; if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) { /* * Convert media subtype to rate. */ newrate = ieee80211_media2rate(ime->ifm_media); if (newrate == 0) return EINVAL; /* * Check the rate table for the specified/current phy. */ if (newphymode == IEEE80211_MODE_AUTO) { /* * In autoselect mode search for the rate. */ for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) { if ((ic->ic_modecaps & (1<<j)) == 0) continue; i = findrate(ic, j, newrate); if (i != -1) { /* lock mode too */ newphymode = j; break; } } } else { i = findrate(ic, newphymode, newrate); } if (i == -1) /* mode/rate mismatch */ return EINVAL; } /* NB: defer rate setting to later */ /* * Deduce new operating mode but don't install it just yet. */ if ((ime->ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) == (IFM_IEEE80211_ADHOC|IFM_FLAG0)) newopmode = IEEE80211_M_AHDEMO; else if (ime->ifm_media & IFM_IEEE80211_HOSTAP) newopmode = IEEE80211_M_HOSTAP; else if (ime->ifm_media & IFM_IEEE80211_ADHOC) newopmode = IEEE80211_M_IBSS; else if (ime->ifm_media & IFM_IEEE80211_MONITOR) newopmode = IEEE80211_M_MONITOR; else newopmode = IEEE80211_M_STA; /* * Autoselect doesn't make sense when operating as an AP. * If no phy mode has been selected, pick one and lock it * down so rate tables can be used in forming beacon frames * and the like. */ if (newopmode == IEEE80211_M_HOSTAP && newphymode == IEEE80211_MODE_AUTO) { for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) if (ic->ic_modecaps & (1<<j)) { newphymode = j; break; } } /* * Handle phy mode change. */ if (ic->ic_curmode != newphymode) { /* change phy mode */ error = ieee80211_setmode(ic, newphymode); if (error != 0) return error; error = ENETRESET; } /* * Committed to changes, install the rate setting. */ if (ic->ic_fixed_rate != i) { ic->ic_fixed_rate = i; /* set fixed tx rate */ error = ENETRESET; } /* * Handle operating mode change. */ if (ic->ic_opmode != newopmode) { ic->ic_opmode = newopmode; switch (newopmode) { case IEEE80211_M_AHDEMO: case IEEE80211_M_HOSTAP: case IEEE80211_M_STA: case IEEE80211_M_MONITOR: ic->ic_flags &= ~IEEE80211_F_IBSSON; break; case IEEE80211_M_IBSS: ic->ic_flags |= IEEE80211_F_IBSSON; break; } error = ENETRESET; } #ifdef notdef if (error == 0) ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media); #endif return error; }
void ieee80211_ifattach(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; struct ieee80211_channel *c; int i; ether_ifattach(ifp, ic->ic_myaddr); #if NBPFILTER > 0 bpfattach2(ifp, DLT_IEEE802_11, sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); #endif ieee80211_crypto_attach(ifp); /* * Fill in 802.11 available channel set, mark * all available channels as active, and pick * a default channel if not already specified. */ memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (c->ic_flags) { /* * Verify driver passed us valid data. */ if (i != ieee80211_chan2ieee(ic, c)) { if_printf(ifp, "bad channel ignored; " "freq %u flags %x number %u\n", c->ic_freq, c->ic_flags, i); c->ic_flags = 0; /* NB: remove */ continue; } setbit(ic->ic_chan_avail, i); /* * Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_11A; if (IEEE80211_IS_CHAN_B(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_11B; if (IEEE80211_IS_CHAN_PUREG(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_11G; if (IEEE80211_IS_CHAN_FHSS(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_FH; if (IEEE80211_IS_CHAN_T(c)) ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO; } } /* validate ic->ic_curmode */ if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0) ic->ic_curmode = IEEE80211_MODE_AUTO; ieee80211_setbasicrates(ic); (void) ieee80211_setmode(ic, ic->ic_curmode); ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ if (ic->ic_lintval == 0) ic->ic_lintval = 100; /* default sleep */ ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */ ieee80211_node_attach(ifp); ieee80211_proto_attach(ifp); }
int ieee80211_ifattach(struct ieee80211com *ic, IEEE80211_REG_PARAMETERS *ieee80211_reg_parm) { u_int8_t bcast[IEEE80211_ADDR_LEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; int error = 0; ic->ic_reg_parm = *ieee80211_reg_parm; /* set up broadcast address */ IEEE80211_ADDR_COPY(ic->ic_broadcast, bcast); /* initialize channel list */ ieee80211_update_channellist(ic, 0); /* initialize rate set */ ieee80211_init_rateset(ic); /* validate ic->ic_curmode */ if (!IEEE80211_SUPPORT_PHY_MODE(ic, ic->ic_curmode)) ic->ic_curmode = IEEE80211_MODE_AUTO; /* setup initial channel settings */ ic->ic_curchan = ieee80211_get_channel(ic, 0); /* arbitrarily pick the first channel */ /* Enable marking of dfs by default */ ic->ic_flags_ext |= IEEE80211_FEXT_MARKDFS; if (ic->ic_reg_parm.htEnableWepTkip) { ieee80211_ic_wep_tkip_htrate_set(ic); } else { ieee80211_ic_wep_tkip_htrate_clear(ic); } if (ic->ic_reg_parm.htVendorIeEnable) IEEE80211_ENABLE_HTVIE(ic); /* whether to ignore 11d beacon */ if (ic->ic_reg_parm.ignore11dBeacon) IEEE80211_ENABLE_IGNORE_11D_BEACON(ic); if (ic->ic_reg_parm.disallowAutoCCchange) { ieee80211_ic_disallowAutoCCchange_set(ic); } else { ieee80211_ic_disallowAutoCCchange_clear(ic); } (void) ieee80211_setmode(ic, ic->ic_curmode, ic->ic_opmode); ic->ic_intval = IEEE80211_BINTVAL_DEFAULT; /* beacon interval */ ic->ic_set_beacon_interval(ic); ic->ic_lintval = 1; /* listen interval */ ic->ic_lintval_assoc = IEEE80211_LINTVAL_MAX; /* listen interval to use in association */ ic->ic_bmisstimeout = IEEE80211_BMISS_LIMIT * ic->ic_intval; TAILQ_INIT(&ic->ic_vaps); ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX; /* Intialize WDS Auto Detect mode */ ic->ic_flags_ext |= IEEE80211_FEXT_WDS_AUTODETECT; /* ** Enable the 11d country code IE by default */ ic->ic_flags_ext |= IEEE80211_FEXT_COUNTRYIE; /* setup CWM configuration */ ic->ic_cwm_set_mode(ic, ic->ic_reg_parm.cwmMode); ic->ic_cwm_set_extoffset(ic, ic->ic_reg_parm.cwmExtOffset); ic->ic_cwm_set_extprotmode(ic, ic->ic_reg_parm.cwmExtProtMode); ic->ic_cwm_set_extprotspacing(ic, ic->ic_reg_parm.cwmExtProtSpacing); #if tbd /* XXX - TODO - move these into ath layer */ #else ic->ic_cwm_set_enable(ic, ic->ic_reg_parm.cwmEnable); ic->ic_cwm_set_extbusythreshold(ic, ic->ic_reg_parm.cwmExtBusyThreshold); #endif ic->ic_enable2GHzHt40Cap = ic->ic_reg_parm.enable2GHzHt40Cap; #ifdef ATH_COALESCING ic->ic_tx_coalescing = ic->ic_reg_parm.txCoalescingEnable; #endif ic->ic_ignoreDynamicHalt = ic->ic_reg_parm.ignoreDynamicHalt; /* default to auto ADDBA mode */ ic->ic_addba_mode = ADDBA_MODE_AUTO; if (ic->ic_reg_parm.ht20AdhocEnable) { /* * Support HT rates in Ad hoc connections. */ if (IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NA_HT20) || IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NG_HT20)) { ieee80211_ic_ht20Adhoc_set(ic); if (ic->ic_reg_parm.htAdhocAggrEnable) { ieee80211_ic_htAdhocAggr_set(ic); } } } if (ic->ic_reg_parm.ht40AdhocEnable) { /* * Support HT rates in Ad hoc connections. */ if (IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NA_HT40PLUS) || IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NA_HT40MINUS) || IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NG_HT40PLUS) || IEEE80211_SUPPORT_PHY_MODE(ic, IEEE80211_MODE_11NG_HT40MINUS)) { ieee80211_ic_ht40Adhoc_set(ic); if (ic->ic_reg_parm.htAdhocAggrEnable) { ieee80211_ic_htAdhocAggr_set(ic); } } } OS_INIT_TIMER(ic->ic_osdev, &(ic->ic_inact_timer), ieee80211_inact_timeout, (void *) (ic)); #if UMAC_SUPPORT_WNM OS_INIT_TIMER(ic->ic_osdev, &(ic->ic_bssload_timer), ieee80211_bssload_timeout, (void *) (ic)); #endif if (ic->ic_reg_parm.disable2040Coexist) { ic->ic_flags |= IEEE80211_F_COEXT_DISABLE; } else { ic->ic_flags &= ~IEEE80211_F_COEXT_DISABLE; } /* setup other modules */ /* The TSF Timer module is required when P2P or Off-channel support are required */ ic->ic_tsf_timer = ieee80211_tsf_timer_attach(ic); #if UMAC_SUPPORT_TDLS_CHAN_SWITCH /* TDLS off-channel support requires TSF timer */ if (ic->ic_tsf_timer) { ieee80211_ic_off_channel_support_set(ic); } else { ieee80211_ic_off_channel_support_clear(ic); } #else ieee80211_ic_off_channel_support_clear(ic); #endif ieee80211_p2p_attach(ic); ieee80211_crypto_attach(ic); ieee80211_node_attach(ic); ieee80211_proto_attach(ic); ieee80211_power_attach(ic); ieee80211_mlme_attach(ic); #if ATH_SUPPORT_DFS ieee80211_dfs_attach(ic); #endif /* ATH_SUPPORT_DFS */ if (IEEE80211_ENAB_AOW(ic)) ieee80211_aow_attach(ic); error = ieee80211_scan_table_attach(ic, &(ic->ic_scan_table), ic->ic_osdev); if (error) { ieee80211_node_detach(ic); return error; } /* * By default overwrite probe response with beacon IE in scan entry. */ ieee80211_ic_override_proberesp_ie_set(ic); error = ieee80211_scan_attach(&(ic->ic_scanner), ic, ic->ic_osdev, ieee80211_is_connected, ieee80211_is_txq_empty, ieee80211_is_sw_txq_empty); if (error) { /* detach and free already allocated memory for scan */ ieee80211_scan_table_detach(&(ic->ic_scan_table)); ieee80211_node_detach(ic); return error; } ic->ic_resmgr = ieee80211_resmgr_create(ic, IEEE80211_RESMGR_MODE_SINGLE_CHANNEL); error = ieee80211_acs_attach(&(ic->ic_acs), ic, ic->ic_osdev); if (error) { /* detach and free already allocated memory for scan */ ieee80211_scan_table_detach(&(ic->ic_scan_table)); ieee80211_scan_detach(&(ic->ic_scanner)); ieee80211_node_detach(ic); return error; } ic->ic_notify_tx_bcn_mgr = ieee80211_notify_tx_bcn_attach(ic); ieee80211_rptplacement_attach(ic); IEEE80211_TDLS_ATTACH(ic); #if UMAC_SUPPORT_VI_DBG ieee80211_vi_dbg_attach(ic); #endif ieee80211_quiet_attach(ic); ieee80211_admctl_attach(ic); /* * Perform steps that require multiple objects to be initialized. * For example, cross references between objects such as ResMgr and Scanner. */ ieee80211_scan_attach_complete(ic->ic_scanner); ieee80211_resmgr_create_complete(ic->ic_resmgr); ieee80211_smartantenna_attach(ic); ieee80211_prdperfstats_attach(ic); ic->ic_get_ext_chan_info = ieee80211_get_extchan_info; /* initialization complete */ ic->ic_initialized = 1; return 0; }