/* * 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; }
/* * Set the current phy mode and recalculate the active channel * set based on the available channels for this mode. Also * select a new default/current channel if the current one is * inappropriate for this mode. */ int ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) { #define N(a) (sizeof(a) / sizeof(a[0])) static const u_int chanflags[] = { 0, /* IEEE80211_MODE_AUTO */ IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */ IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO_A */ IEEE80211_CHAN_108G, /* IEEE80211_MODE_TURBO_G */ }; struct ieee80211_channel *c; u_int modeflags; int i; /* validate new mode */ if ((ic->ic_modecaps & (1<<mode)) == 0) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "%s: mode %u not supported (caps 0x%x)\n", __func__, mode, ic->ic_modecaps); return EINVAL; } /* * Verify at least one channel is present in the available * channel list before committing to the new mode. */ IASSERT(mode < N(chanflags), ("Unexpected mode %u", mode)); modeflags = chanflags[mode]; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (c->ic_flags == 0) continue; if (mode == IEEE80211_MODE_AUTO) { /* ignore turbo channels for autoselect */ if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) break; } else { if ((c->ic_flags & modeflags) == modeflags) break; } } if (i > IEEE80211_CHAN_MAX) { IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, "%s: no channels found for mode %u\n", __func__, mode); return EINVAL; } /* * Calculate the active channel set. */ memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active)); for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (c->ic_flags == 0) continue; if (mode == IEEE80211_MODE_AUTO) { /* take anything but pure turbo channels */ if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0) setbit(ic->ic_chan_active, i); } else { if ((c->ic_flags & modeflags) == modeflags) setbit(ic->ic_chan_active, i); } } /* * If no current/default channel is setup or the current * channel is wrong for the mode then pick the first * available channel from the active list. This is likely * not the right one. */ if (ic->ic_ibss_chan == NULL || isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { for (i = 0; i <= IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i)) { ic->ic_ibss_chan = &ic->ic_channels[i]; break; } IASSERT(ic->ic_ibss_chan != NULL && isset(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan)), ("Bad IBSS channel %u", ieee80211_chan2ieee(ic, ic->ic_ibss_chan))); } /* * If the desired channel is set but no longer valid then reset it. */ if (ic->ic_des_chan != IEEE80211_CHAN_ANYC && isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_des_chan))) ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* * Do mode-specific rate setup. */ if (mode == IEEE80211_MODE_11G) { /* * Use a mixed 11b/11g rate set. */ ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], IEEE80211_MODE_11G); } else if (mode == IEEE80211_MODE_11B) { /* * Force pure 11b rate set. */ ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], IEEE80211_MODE_11B); } /* * Setup an initial rate set according to the * current/default channel selected above. This * will be changed when scanning but must exist * now so driver have a consistent state of ic_ibss_chan. */ if (ic->ic_bss) /* NB: can be called before lateattach */ ic->ic_bss->ni_rates = ic->ic_sup_rates[mode]; ic->ic_curmode = mode; ieee80211_reset_erp(ic); /* reset ERP state */ ieee80211_wme_initparams(ic); /* reset WME stat */ return 0; #undef N }
/* * Complete a scan of potential channels. */ void ieee80211_end_scan(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; struct ieee80211_node *ni, *nextbs, *selbs; if (ifp->if_flags & IFF_DEBUG) printf("%s: end %s scan\n", ifp->if_xname, (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); if (ic->ic_scan_count) ic->ic_flags &= ~IEEE80211_F_ASCAN; ni = RB_MIN(ieee80211_tree, &ic->ic_tree); #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* XXX off stack? */ u_char occupied[howmany(IEEE80211_CHAN_MAX, NBBY)]; int i, fail; /* * The passive scan to look for existing AP's completed, * select a channel to camp on. Identify the channels * that already have one or more AP's and try to locate * an unnoccupied one. If that fails, pick a random * channel from the active set. */ memset(occupied, 0, sizeof(occupied)); RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan)); for (i = 0; i < IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i) && isclr(occupied, i)) break; if (i == IEEE80211_CHAN_MAX) { fail = arc4random() & 3; /* random 0-3 */ for (i = 0; i < IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i) && fail-- == 0) break; } ieee80211_create_ibss(ic, &ic->ic_channels[i]); goto wakeup; } #endif if (ni == NULL) { DPRINTF(("no scan candidate\n")); notfound: #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS && (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen != 0) { ieee80211_create_ibss(ic, ic->ic_ibss_chan); goto wakeup; } #endif /* * Scan the next mode if nothing has been found. This * is necessary if the device supports different * incompatible modes in the same channel range, like * like 11b and "pure" 11G mode. This will loop * forever except for user-initiated scans. */ if (ieee80211_next_mode(ifp) == IEEE80211_MODE_AUTO) { if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST && ic->ic_scan_lock & IEEE80211_SCAN_RESUME) { ic->ic_scan_lock = IEEE80211_SCAN_LOCKED; /* Return from an user-initiated scan */ wakeup(&ic->ic_scan_lock); } else if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) goto wakeup; ic->ic_scan_count++; } /* * Reset the list of channels to scan and start again. */ ieee80211_next_scan(ifp); return; } selbs = NULL; for (; ni != NULL; ni = nextbs) { nextbs = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); if (ni->ni_fails) { /* * The configuration of the access points may change * during my scan. So delete the entry for the AP * and retry to associate if there is another beacon. */ if (ni->ni_fails++ > 2) ieee80211_free_node(ic, ni); continue; } if (ieee80211_match_bss(ic, ni) == 0) { if (selbs == NULL) selbs = ni; else if (ni->ni_rssi > selbs->ni_rssi) selbs = ni; } } if (selbs == NULL) goto notfound; (*ic->ic_node_copy)(ic, ic->ic_bss, selbs); ni = ic->ic_bss; /* * Set the erp state (mostly the slot time) to deal with * the auto-select case; this should be redundant if the * mode is locked. */ ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan); ieee80211_reset_erp(ic); if (ic->ic_flags & IEEE80211_F_RSNON) ieee80211_choose_rsnparams(ic); else if (ic->ic_flags & IEEE80211_F_WEPON) ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP; ieee80211_node_newstate(selbs, IEEE80211_STA_BSS); #ifndef IEEE80211_STA_ONLY if (ic->ic_opmode == IEEE80211_M_IBSS) { ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); if (ni->ni_rates.rs_nrates == 0) goto notfound; ieee80211_new_state(ic, IEEE80211_S_RUN, -1); } else #endif ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); wakeup: if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) { /* Return from an user-initiated scan */ wakeup(&ic->ic_scan_lock); } ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED; }
static bool ieee80211_resmgr_state_multichan_idle_event(void *ctx, u_int16_t event_type, u_int16_t event_data_len, void *event_data) { ieee80211_resmgr_t resmgr = (ieee80211_resmgr_t)ctx; ieee80211_resmgr_sm_event_t event = (ieee80211_resmgr_sm_event_t)event_data; ieee80211_vap_t vap = event->vap; ieee80211_resmgr_vap_priv_t resmgr_vap = NULL; bool retVal = true; struct ieee80211com *ic = resmgr->ic; ieee80211_resmgr_oc_scheduler_operation_data_t next_scheduled_operation = {OC_SCHED_OP_NONE, NULL}; ieee80211_vap_t curr_vap, next_vap; bool transition_vap = false; bool transition_scan = false; bool check_scheduled_operation = false; if (vap) { resmgr_vap = ieee80211vap_get_resmgr(vap); } switch (event_type) { case IEEE80211_RESMGR_EVENT_VAP_START_REQUEST: { if (!resmgr_vap) break; ieee80211_resmgr_oc_sched_set_state(resmgr, OC_SCHEDULER_ON); /* Turn scheduler on before invoking next routine */ ieee80211_resmgr_oc_sched_vap_transition(resmgr, vap, resmgr_vap, OFF_CHAN_SCHED_VAP_START); resmgr_vap->state = VAP_STARTING; resmgr_vap->chan = event->chan; DBG_PRINTK("VAP_STARTING: resmgr_vap->chan = 0x%08x\n", resmgr_vap->chan); check_scheduled_operation = true; break; } case IEEE80211_RESMGR_EVENT_VAP_STOPPED: { struct vap_iter_check_state_params params; if (!resmgr_vap) break; /* Stop associated VAP */ resmgr_vap->state = VAP_STOPPED; ieee80211_resmgr_oc_sched_vap_transition(resmgr, vap, resmgr_vap, OFF_CHAN_SCHED_VAP_STOPPED); /* Check if any other vaps exist */ OS_MEMZERO(¶ms, sizeof(struct vap_iter_check_state_params)); wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, ¶ms); if (!params.vaps_running && !params.vap_starting) { ieee80211_resmgr_oc_sched_set_state(resmgr, OC_SCHEDULER_OFF); } else { check_scheduled_operation = true; } break; } case IEEE80211_RESMGR_EVENT_VAP_UP: { struct vap_iter_unpause_params params = {0, 0}; resmgr_vap->state = VAP_ACTIVE; ieee80211_resmgr_oc_sched_vap_transition(resmgr, vap, resmgr_vap, OFF_CHAN_SCHED_VAP_UP); /* Unpause VAP's on same channel */ params.chan = resmgr_vap->chan; if (resmgr->mode == IEEE80211_RESMGR_MODE_MULTI_CHANNEL) { wlan_iterate_vap_list(ic, ieee80211_vap_iter_unpause_request, ¶ms); } else { wlan_iterate_vap_list(ic, ieee80211_vap_iter_resume_request, ¶ms); } break; } case IEEE80211_RESMGR_EVENT_VAP_PAUSE_COMPLETE: case IEEE80211_RESMGR_EVENT_VAP_PAUSE_FAIL: case IEEE80211_RESMGR_EVENT_VAP_RESUME_COMPLETE: case IEEE80211_RESMGR_EVENT_CHAN_SWITCH_REQUEST: case IEEE80211_RESMGR_EVENT_CSA_COMPLETE: case IEEE80211_RESMGR_EVENT_SCHED_BSS_REQUEST: DBG_PRINTK("%s : [*** WARNING ***] Encountered unhandled event_type!!\n", __func__); ASSERT(0); break; case IEEE80211_RESMGR_EVENT_BSSCHAN_REQUEST: { ieee80211_resmgr_notification notif; /* Is Off-Channel Scheduler active? */ if (ieee80211_resmgr_oc_sched_get_state(resmgr) != OC_SCHEDULER_ON) { /* Set home channel */ ASSERT(resmgr->scandata.chan); /* scanner should go to foreign first? */ if (resmgr->scandata.chan) ic->ic_curchan = resmgr->scandata.chan; ic->ic_set_channel(ic); } resmgr->scandata.chan = NULL; resmgr->scandata.scan_chan = NULL; /* Intimate request completion */ notif.type = IEEE80211_RESMGR_BSSCHAN_SWITCH_COMPLETE; notif.req_id = IEEE80211_RESMGR_REQID; notif.status = 0; notif.vap = NULL; IEEE80211_RESMGR_NOTIFICATION(resmgr, ¬if); break; } case IEEE80211_RESMGR_EVENT_OFFCHAN_REQUEST: { ieee80211_resmgr_notification notif; /* Store current channel as home channel */ resmgr->scandata.chan = ic->ic_curchan; resmgr->scandata.scan_chan = event->chan; /* Is Off-Channel Scheduler active? */ if (ieee80211_resmgr_oc_sched_get_state(resmgr) != OC_SCHEDULER_ON) { /* Set desired channel */ ic->ic_curchan = event->chan; ic->ic_scan_start(ic); ic->ic_set_channel(ic); /* Intimate request completion */ notif.type = IEEE80211_RESMGR_OFFCHAN_SWITCH_COMPLETE; notif.req_id = IEEE80211_RESMGR_REQID; notif.status = EOK; notif.vap = NULL; IEEE80211_RESMGR_NOTIFICATION(resmgr, ¬if); } else { DBG_PRINTK("%s : OFFCHAN_REQ - max_dwell_time = %d\n", __func__, event->max_dwell_time); ieee80211_resmgr_oc_sched_req_duration_usec_set(resmgr->scandata.oc_sched_req, event->max_dwell_time * 1000); ieee80211_resmgr_oc_sched_req_start(resmgr, resmgr->scandata.oc_sched_req); ieee80211_resmgr_off_chan_scheduler(resmgr, IEEE80211_RESMGR_EVENT_OFF_CHAN_SCHED_START_REQUEST); } break; } case IEEE80211_RESMGR_EVENT_TSF_TIMER_EXPIRED: case IEEE80211_RESMGR_EVENT_TSF_TIMER_CHANGED: case IEEE80211_RESMGR_EVENT_OFF_CHAN_SCHED_START_REQUEST: case IEEE80211_RESMGR_EVENT_OFF_CHAN_SCHED_STOP_REQUEST: ieee80211_resmgr_off_chan_scheduler(resmgr, event_type); check_scheduled_operation = true; break; default: retVal = false; break; } if (ieee80211_resmgr_oc_sched_get_state(resmgr) == OC_SCHEDULER_ON) { if (check_scheduled_operation == true) { /* Fetch next scheduled operation */ ieee80211_resmgr_oc_sched_get_scheduled_operation(resmgr, &next_scheduled_operation); next_vap = next_scheduled_operation.vap; /* Take care of post operation cleanup */ switch (next_scheduled_operation.operation_type) { case OC_SCHED_OP_VAP: if (resmgr->current_scheduled_operation.operation_type == OC_SCHED_OP_VAP) { curr_vap = resmgr->current_scheduled_operation.vap; resmgr_vap = ieee80211vap_get_resmgr(curr_vap); if (next_vap != curr_vap) { DBG_PRINTK("OP_VAP: vap_force_pause curr_vap = 0x%08x\n", curr_vap); /* Force pause the currently active VAP */ curr_vap->iv_ic->ic_vap_pause_control(curr_vap->iv_ic,curr_vap,true); //ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_PAUSING); resmgr_vap->state = VAP_PAUSED; transition_vap = true; } } else { transition_vap = true; } break; case OC_SCHED_OP_SCAN: transition_scan = true; /* Falling through INTENTIONALLY */ case OC_SCHED_OP_SLEEP: if (resmgr->current_scheduled_operation.operation_type == OC_SCHED_OP_VAP) { curr_vap = resmgr->current_scheduled_operation.vap; resmgr_vap = ieee80211vap_get_resmgr(curr_vap); DBG_PRINTK("OP_SCAN: vap_force_pause curr_vap = 0x%08x\n", curr_vap); /* Force pause the current VAP */ curr_vap->iv_ic->ic_vap_pause_control(curr_vap->iv_ic,curr_vap,true); //ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_PAUSING); resmgr_vap->state = VAP_PAUSED; } break; case OC_SCHED_OP_NOP: case OC_SCHED_OP_NONE: default: break; } /* Initiate the next operation */ if (transition_scan == true) { DBG_PRINTK("%s : transition_scan == true\n", __func__); ieee80211_resmgr_notification notif; /* Set desired channel */ ic->ic_curchan = resmgr->scandata.scan_chan; ic->ic_scan_start(ic); ic->ic_set_channel(ic); /* Intimate request completion */ notif.type = IEEE80211_RESMGR_OFFCHAN_SWITCH_COMPLETE; notif.req_id = IEEE80211_RESMGR_REQID; notif.status = EOK; notif.vap = NULL; IEEE80211_RESMGR_NOTIFICATION(resmgr, ¬if); } if (transition_vap == true) { if (next_vap != NULL) { DBG_PRINTK("%s : transition_vap == true\n", __func__); resmgr_vap = ieee80211vap_get_resmgr(next_vap); switch (resmgr_vap->state) { case VAP_STARTING: { ieee80211_resmgr_notification notif; struct vap_iter_check_state_params params; /* Check if this is the first VAP starting */ OS_MEMZERO(¶ms, sizeof(struct vap_iter_check_state_params)); wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, ¶ms); /* Set the requested channel */ if (resmgr_vap && (!params.vaps_active || !IS_CHAN_EQUAL(ic->ic_curchan, resmgr_vap->chan))) { ic->ic_curchan = resmgr_vap->chan; ic->ic_bsschan = ic->ic_curchan; ic->ic_set_channel(ic); ieee80211_reset_erp(ic, ic->ic_curmode, next_vap->iv_opmode); ieee80211_wme_initparams(next_vap); } /* Set passed channel as BSS channel */ ic->ic_bsschan = ic->ic_curchan; /* Intimate start completion to VAP module */ notif.type = IEEE80211_RESMGR_VAP_START_COMPLETE; notif.req_id = IEEE80211_RESMGR_REQID; notif.status = 0; notif.vap = next_vap; IEEE80211_RESMGR_NOTIFICATION(resmgr, ¬if); } break; case VAP_PAUSED: DBG_PRINTK("%s : vap_force_unpause; next_vap\n", __func__); next_vap->iv_ic->ic_vap_pause_control(next_vap->iv_ic, next_vap, false); resmgr_vap->state = VAP_ACTIVE; break; default: if (ic->ic_curchan != resmgr_vap->chan) { /* Set home channel */ DBG_PRINTK("%s : resmgr_vap->chan = 0x%08x\n", __func__, resmgr_vap->chan); ic->ic_curchan = resmgr_vap->chan; ic->ic_set_channel(ic); } break; } } } } } return retVal; }
static int ol_vdev_wmi_event_handler(ol_scn_t scn, u_int8_t *data, u_int16_t datalen, void *context) { ieee80211_resmgr_t resmgr = (ieee80211_resmgr_t )context; wmi_vdev_start_response_event *wmi_vdev_start_resp_ev = (wmi_vdev_start_response_event *)data; wlan_if_t vaphandle; struct ieee80211com *ic = resmgr->ic; struct ieee80211_channel *chan = NULL; struct ieee80211_node *ni; u_int8_t numvaps, actidx = 0; struct ol_ath_vap_net80211 *avn; bool do_notify = true; vaphandle = ol_ath_vap_get(scn, wmi_vdev_start_resp_ev->vdev_id); if (NULL == vaphandle) { printk("Event received for Invalid/Deleted vap handle\n"); return 0; } avn = OL_ATH_VAP_NET80211(vaphandle); printk("ol_vdev_start_resp_ev for vap %d (%p)\n", wmi_vdev_start_resp_ev->vdev_id, scn->wmi_handle); spin_lock(&vaphandle->init_lock); switch (vaphandle->iv_opmode) { case IEEE80211_M_MONITOR: /* Handle same as HOSTAP */ case IEEE80211_M_HOSTAP: /* If vap is not waiting for the WMI event from target return here */ if(avn->av_ol_resmgr_wait == FALSE) { spin_unlock(&vaphandle->init_lock); return 0; } /* Resetting the ol_resmgr_wait flag*/ avn->av_ol_resmgr_wait = FALSE; numvaps = ieee80211_vaps_active(ic); chan = vaphandle->iv_des_chan[vaphandle->iv_des_mode]; /* * if there is a vap already running. * ignore the desired channel and use the * operating channel of the other vap. */ /* so that cwm can do its own crap. need to untie from state */ /* vap join is called here to wake up the chip if it is in sleep state */ ieee80211_vap_join(vaphandle); if (numvaps == 0) { //AP_DFS: ieee80211_set_channel(ic, chan); if (wmi_vdev_start_resp_ev->resp_type != WMI_VDEV_RESTART_RESP_EVENT) { /* 20/40 Mhz coexistence handler */ if ((avn->av_ol_resmgr_chan != NULL) && (chan != avn->av_ol_resmgr_chan)) { chan = avn->av_ol_resmgr_chan; } ic->ic_prevchan = ic->ic_curchan; ic->ic_curchan = chan; /*update channel history*/ actidx = ic->ic_chanidx; ic->ic_chanhist[actidx].chanid = (ic->ic_curchan)->ic_ieee; ic->ic_chanhist[actidx].chanjiffies = OS_GET_TIMESTAMP(); ic->ic_chanidx == (IEEE80211_CHAN_MAXHIST - 1) ? ic->ic_chanidx = 0 : ++(ic->ic_chanidx); /* update max channel power to max regpower of current channel */ ieee80211com_set_curchanmaxpwr(ic, chan->ic_maxregpower); ieee80211_wme_initparams(vaphandle); } /* ieee80211 Layer - Default Configuration */ vaphandle->iv_bsschan = ic->ic_curchan; /* XXX reset erp state */ ieee80211_reset_erp(ic, ic->ic_curmode, vaphandle->iv_opmode); } else { /* ieee80211 Layer - Default Configuration */ vaphandle->iv_bsschan = ic->ic_curchan; } /* use the vap bsschan for dfs configure */ if ( IEEE80211_IS_CHAN_DFS(vaphandle->iv_bsschan)) { extern void ol_if_dfs_configure(struct ieee80211com *ic); ol_if_dfs_configure(ic); } break; case IEEE80211_M_STA: ni = vaphandle->iv_bss; chan = ni->ni_chan; vaphandle->iv_bsschan = chan; ic->ic_prevchan = ic->ic_curchan; ic->ic_curchan = chan; /* update max channel power to max regpower of current channel */ ieee80211com_set_curchanmaxpwr(ic, chan->ic_maxregpower); /* ieee80211 Layer - Default Configuration */ vaphandle->iv_bsschan = ic->ic_curchan; /* XXX reset erp state */ ieee80211_reset_erp(ic, ic->ic_curmode, vaphandle->iv_opmode); ieee80211_wme_initparams(vaphandle); if (wmi_vdev_start_resp_ev->resp_type == WMI_VDEV_RESTART_RESP_EVENT) { do_notify = false; } break; default: break; } vaphandle->init_in_progress = false; spin_unlock(&vaphandle->init_lock); /* Intimate start completion to VAP module */ /* if STA, bypass notification for RESTERT EVENT */ if (do_notify) ieee80211_notify_vap_start_complete(resmgr, vaphandle, IEEE80211_RESMGR_STATUS_SUCCESS); return 0; }
/* * Complete a scan of potential channels. */ void Voodoo80211Device:: ieee80211_end_scan(struct ieee80211com *ic) { struct ieee80211_node *ni, *nextbs, *selbs; /* TODO if (ifp->if_flags & IFF_DEBUG) printf("%s: end %s scan\n", ifp->if_xname, (ic->ic_flags & IEEE80211_F_ASCAN) ? "active" : "passive"); */ if (ic->ic_scan_count) ic->ic_flags &= ~IEEE80211_F_ASCAN; ni = RB_MIN(ieee80211_tree, &ic->ic_tree); if (ni == NULL) { DPRINTF(("no scan candidate\n")); notfound: /* * Scan the next mode if nothing has been found. This * is necessary if the device supports different * incompatible modes in the same channel range, like * like 11b and "pure" 11G mode. This will loop * forever except for user-initiated scans. */ if (ieee80211_next_mode(ic) == IEEE80211_MODE_AUTO) { if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST && ic->ic_scan_lock & IEEE80211_SCAN_RESUME) { ic->ic_scan_lock = IEEE80211_SCAN_LOCKED; /* Return from an user-initiated scan */ wakeupOn(&ic->ic_scan_lock); // XXX: pvaibhav: do this here? fInterface->postMessage(APPLE80211_M_SCAN_DONE); } else if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) goto wakeup; ic->ic_scan_count++; } /* * Reset the list of channels to scan and start again. */ ieee80211_next_scan(ic); return; } selbs = NULL; for (; ni != NULL; ni = nextbs) { nextbs = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni); if (ni->ni_fails) { /* * The configuration of the access points may change * during my scan. So delete the entry for the AP * and retry to associate if there is another beacon. */ if (ni->ni_fails++ > 2) ieee80211_free_node(ic, ni); continue; } if (ieee80211_match_bss(ic, ni) == 0) { if (selbs == NULL) selbs = ni; else if (ni->ni_rssi > selbs->ni_rssi) selbs = ni; } } if (selbs == NULL) goto notfound; ieee80211_node_copy(ic, ic->ic_bss, selbs); ni = ic->ic_bss; /* * Set the erp state (mostly the slot time) to deal with * the auto-select case; this should be redundant if the * mode is locked. */ ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan); ieee80211_reset_erp(ic); if (ic->ic_flags & IEEE80211_F_RSNON) ieee80211_choose_rsnparams(ic); else if (ic->ic_flags & IEEE80211_F_WEPON) ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP; ieee80211_node_newstate(selbs, IEEE80211_STA_BSS); ieee80211_newstate(ic, IEEE80211_S_AUTH, -1); wakeup: if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) { /* Return from an user-initiated scan */ wakeupOn(&ic->ic_scan_lock); // XXX: pvaibhav: do this here? fInterface->postMessage(APPLE80211_M_SCAN_DONE); } ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED; }
/* * Set the current phy mode and recalculate the active channel * set based on the available channels for this mode. Also * select a new default/current channel if the current one is * inappropriate for this mode. */ int ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) { #define N(a) (sizeof(a) / sizeof(a[0])) struct ifnet *ifp = &ic->ic_if; static const u_int chanflags[] = { 0, /* IEEE80211_MODE_AUTO */ IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO */ }; const struct ieee80211_channel *c; u_int modeflags; int i; /* validate new mode */ if ((ic->ic_modecaps & (1<<mode)) == 0) { DPRINTF(("mode %u not supported (caps 0x%x)\n", mode, ic->ic_modecaps)); return EINVAL; } /* * Verify at least one channel is present in the available * channel list before committing to the new mode. */ if (mode >= N(chanflags)) panic("Unexpected mode %u", mode); modeflags = chanflags[mode]; for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (mode == IEEE80211_MODE_AUTO) { /* ignore turbo channels for autoselect */ if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) break; } else { if ((c->ic_flags & modeflags) == modeflags) break; } } if (i > IEEE80211_CHAN_MAX) { DPRINTF(("no channels found for mode %u\n", mode)); return EINVAL; } /* * Calculate the active channel set. */ memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active)); for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { c = &ic->ic_channels[i]; if (mode == IEEE80211_MODE_AUTO) { /* take anything but pure turbo channels */ if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) setbit(ic->ic_chan_active, i); } else { if ((c->ic_flags & modeflags) == modeflags) setbit(ic->ic_chan_active, i); } } /* * If no current/default channel is setup or the current * channel is wrong for the mode then pick the first * available channel from the active list. This is likely * not the right one. */ if (ic->ic_ibss_chan == NULL || isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { for (i = 0; i <= IEEE80211_CHAN_MAX; i++) if (isset(ic->ic_chan_active, i)) { ic->ic_ibss_chan = &ic->ic_channels[i]; break; } if ((ic->ic_ibss_chan == NULL) || isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) panic("Bad IBSS channel %u", ieee80211_chan2ieee(ic, ic->ic_ibss_chan)); } /* * Reset the scan state for the new mode. This avoids scanning * of invalid channels, ie. 5GHz channels in 11b mode. */ ieee80211_reset_scan(ifp); ic->ic_curmode = mode; ieee80211_reset_erp(ic); /* reset ERP state */ return 0; #undef N }