/* * BSS channel request. (Scan Module) */ int ieee80211_resmgr_request_bsschan(ieee80211_resmgr_t resmgr, u_int16_t reqid) { struct ieee80211_resmgr_sm_event event; struct vap_iter_check_state_params params; struct ieee80211com *ic = resmgr->ic; event.vap = NULL; event.chan = NULL; if (ieee80211_resmgr_active(ic)) { /* ResMgr SM active, check for active VAPs */ OS_MEMZERO(¶ms, sizeof(struct vap_iter_check_state_params)); wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, ¶ms); /* If there are no VAPs active, there is no BSS channel. Scanner can continueously scan all channels */ if (!params.vaps_running && !params.vap_starting) { return EINVAL; } } /* Post event to ResMgr SM */ if (ieee80211_resmgr_sm_dispatch(resmgr, IEEE80211_RESMGR_EVENT_BSSCHAN_REQUEST, &event) == EOK){ return EBUSY; /* processing req asynchronously */ } else { return EOK; /* caller can change channel */ } }
static void ieee80211_resmgr_reset_power_state(ieee80211_resmgr_t resmgr) { int pm_state; struct ieee80211com *ic = resmgr->ic; ieee80211_resmgr_vap_pmstate_t combined_state = VAP_PM_FULL_SLEEP; IEEE80211_RESMGR_LOCK(resmgr); if (resmgr->is_scan_in_progress) { combined_state = VAP_PM_ACTIVE; } else { wlan_iterate_vap_list(ic, ieee80211_vap_iter_pm_state, (void *)&combined_state); } switch(combined_state) { case VAP_PM_FULL_SLEEP: pm_state = IEEE80211_PWRSAVE_FULL_SLEEP; break; case VAP_PM_NW_SLEEP: pm_state = IEEE80211_PWRSAVE_NETWORK_SLEEP; break; default: pm_state = IEEE80211_PWRSAVE_AWAKE; break; } if (pm_state != resmgr->pm_state) { IEEE80211_DPRINTF_IC(ic, IEEE80211_MSG_POWER, IEEE80211_VERBOSE_LOUD, "%s: changing chip power state from %s to %s \n", __func__, state_to_name[resmgr->pm_state], state_to_name[pm_state]); resmgr->pm_state = pm_state; ic->ic_pwrsave_set_state(ic, pm_state); } IEEE80211_RESMGR_UNLOCK(resmgr); }
/* * returns number of vaps ready. */ u_int16_t ieee80211_vaps_ready(struct ieee80211com *ic, enum ieee80211_opmode opmode) { struct ieee80211_iter_vaps_ready_arg params; u_int16_t nready = 0; OS_MEMZERO(¶ms, sizeof(params)); wlan_iterate_vap_list(ic,ieee80211_vap_iter_ready_vaps,(void *) ¶ms); switch(opmode) { case IEEE80211_M_HOSTAP: case IEEE80211_M_BTAMP: nready = params.num_ap_vaps_ready; break; case IEEE80211_M_IBSS: nready = params.num_ibss_vaps_ready; break; case IEEE80211_M_STA: nready = params.num_sta_vaps_ready; break; default: break; } return nready; }
/* * returns number of vaps active. */ u_int16_t ieee80211_vaps_active(struct ieee80211com *ic) { u_int16_t nactive=0; wlan_iterate_vap_list(ic,ieee80211_vap_iter_active_vaps,(void *) &nactive); return nactive; }
/* * State PAUSING */ static void ieee80211_resmgr_state_multichan_pausing_entry(void *ctx) { ieee80211_resmgr_t resmgr = (ieee80211_resmgr_t) ctx; struct ieee80211com *ic = resmgr->ic; /* Send Pause request to all active VAPs */ wlan_iterate_vap_list(ic, ieee80211_vap_iter_pause_request, NULL); }
systime_t ieee80211com_get_traffic_indication_timestamp(struct ieee80211com *ic) { systime_t traffic_timestamp = 0; wlan_iterate_vap_list(ic, ieee80211_vap_iter_last_traffic_timestamp,(void *) &traffic_timestamp); return traffic_timestamp; }
/* * Per-ieee80211com inactivity timer callback. * used for checking any kind of inactivity in the * COM device. */ static OS_TIMER_FUNC(ieee80211_inact_timeout) { struct ieee80211com *ic; OS_GET_TIMER_ARG(ic, struct ieee80211com *); ieee80211_timeout_stations(&ic->ic_sta); ieee80211_timeout_fragments(ic, IEEE80211_FRAG_TIMEOUT*1000); wlan_iterate_vap_list(ic,ieee80211_vap_iter_mlme_inact_timeout,NULL); OS_SET_TIMER(&ic->ic_inact_timer, IEEE80211_INACT_WAIT*1000); }
void ieee80211_beacon_miss(struct ieee80211com *ic) { /* * Do not ignore a beacon miss during scan now that the scan algorithm * has frequent returns to the home channel, */ if (IEEE80211_IS_RADAR_ENABLED(ic)) return; wlan_iterate_vap_list(ic, ieee80211_vap_iter_beacon_miss, NULL); }
/* * State RESUMING */ static void ieee80211_resmgr_state_multichan_chanswitch_entry(void *ctx) { ieee80211_resmgr_t resmgr = (ieee80211_resmgr_t) ctx; struct ieee80211com *ic = resmgr->ic; struct vap_iter_unpause_params params = {0, 0}; /* Set required channel */ ic->ic_curchan = resmgr->scandata.chan; ic->ic_scan_end(ic); ic->ic_set_channel(ic); /* Unpause VAPs operating on selected BSS channel */ params.chan = ic->ic_curchan; wlan_iterate_vap_list(ic, ieee80211_vap_iter_unpause_request, ¶ms); }
/* * Set country code */ int ieee80211_set_country_code(struct ieee80211com *ic, char *isoName, u_int16_t cc, enum ieee80211_clist_cmd cmd) { int error; if (!cc) { if (isoName == NULL) { if (!IEEE80211_IS_11D_ENABLED(ic)) return 0; } else if((ic->ic_country_iso[0] == isoName[0]) && (ic->ic_country_iso[1] == isoName[1]) && (ic->ic_country_iso[2] == isoName[2])) { return 0; } } IEEE80211_DISABLE_11D(ic); error = ic->ic_set_country(ic, isoName, cc, cmd); if (error) return error; /* update the country information for 11D */ ic->ic_get_currentCountry(ic, &ic->ic_country); /* update channel list */ ieee80211_update_channellist(ic, 1); ic->ic_country_iso[0] = ic->ic_country.iso[0]; ic->ic_country_iso[1] = ic->ic_country.iso[1]; ic->ic_country_iso[2] = ic->ic_country.iso[2]; ieee80211_build_countryie_all(ic); if (IEEE80211_IS_COUNTRYIE_ENABLED(ic)) { IEEE80211_ENABLE_11D(ic); } /* notify all vaps that the country changed */ wlan_iterate_vap_list(ic, wlan_notify_country_changed, (void *)ic->ic_country.iso); return 0; }
static bool ieee80211_resmgr_state_multichan_chanswitch_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; struct ieee80211com *ic = resmgr->ic; ieee80211_resmgr_vap_priv_t resmgr_vap = NULL; ieee80211_resmgr_sm_event_t event = (ieee80211_resmgr_sm_event_t)event_data; ieee80211_vap_t vap = event->vap; ieee80211_resmgr_notification notif; bool retVal = true; if (vap) { resmgr_vap = ieee80211vap_get_resmgr(vap); } switch (event_type) { case IEEE80211_RESMGR_EVENT_VAP_START_REQUEST: { if (!resmgr_vap) break; ieee80211_resmgr_defer_event(resmgr, resmgr_vap, event, event_type); 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); 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) { ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_IDLE); } break; } case IEEE80211_RESMGR_EVENT_OFFCHAN_REQUEST: /* Store ? */ break; case IEEE80211_RESMGR_EVENT_VAP_RESUME_COMPLETE: { struct vap_iter_check_state_params params; resmgr_vap->state = VAP_ACTIVE; /* Check if all the VAPs on the channel have been unpaused */ OS_MEMZERO(¶ms, sizeof(struct vap_iter_check_state_params)); params.chan = ic->ic_curchan; wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, ¶ms); /* Intimate request completion to VAP module */ if (!params.vaps_paused) { notif.type = IEEE80211_RESMGR_BSSCHAN_SWITCH_COMPLETE; notif.req_id = IEEE80211_RESMGR_REQID; notif.status = 0; notif.vap = NULL; IEEE80211_RESMGR_NOTIFICATION(resmgr, ¬if); ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_BSSCHAN); } 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); break; default: retVal = false; break; } return retVal; }
static bool ieee80211_resmgr_state_multichan_pausing_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; struct ieee80211com *ic = resmgr->ic; bool retVal=true; ieee80211_resmgr_notification notif; if (vap) { resmgr_vap = ieee80211vap_get_resmgr(vap); } switch (event_type) { case IEEE80211_RESMGR_EVENT_VAP_START_REQUEST: { if (resmgr_vap) break; /* Store and change state after all the vaps are paused */ ieee80211_resmgr_defer_event(resmgr, resmgr_vap, event, event_type); 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); 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) { ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_IDLE); } break; } case IEEE80211_RESMGR_EVENT_VAP_PAUSE_COMPLETE: { struct vap_iter_check_state_params params; if (resmgr_vap->state != VAP_STOPPED) { /* If VAP is already stopped, don't update state */ resmgr_vap->state = VAP_PAUSED; } /* Check if all the VAPs are paused */ OS_MEMZERO(¶ms, sizeof(struct vap_iter_check_state_params)); wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, ¶ms); if (!params.vaps_active) { if (resmgr->cancel_pause) { /* Pending pause cancel */ resmgr->scandata.chan = ic->ic_curchan; resmgr->cancel_pause = false; ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_RESUMING); } else { ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_OFFCHAN); } } else if (params.vaps_active == 1 && resmgr->pause_failed) { if (resmgr->cancel_pause) { /* Pending pause cancel */ resmgr->scandata.chan = ic->ic_curchan; resmgr->cancel_pause = false; ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_RESUMING); } else { struct vap_iter_unpause_params unpause_params = {0, 0}; /* Unpause VAPs on channel */ unpause_params.chan = ic->ic_curchan; wlan_iterate_vap_list(ic, ieee80211_vap_iter_unpause_request, &unpause_params); resmgr->pause_failed = false; } } break; } case IEEE80211_RESMGR_EVENT_VAP_PAUSE_FAIL: { struct vap_iter_check_state_params params; /* Unpause VAPs operating on channel */ OS_MEMZERO(¶ms, sizeof(struct vap_iter_check_state_params)); params.chan = ic->ic_curchan; wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, ¶ms); if (params.vaps_active > 1) { /* VAPs still in the process of pausing, need to unpaused them after they are paused */ resmgr->pause_failed = true; } else if (params.vaps_paused) { if (resmgr->cancel_pause) { /* Pending pause cancel */ resmgr->scandata.chan = ic->ic_curchan; resmgr->cancel_pause = false; ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_RESUMING); } else { struct vap_iter_unpause_params unpause_params = {0, 0}; /* Unpause VAPs on channel */ unpause_params.chan = ic->ic_curchan; wlan_iterate_vap_list(ic, ieee80211_vap_iter_unpause_request, &unpause_params); } } else { /* Check if there is a cancel pending */ if (resmgr->cancel_pause) { resmgr->cancel_pause = false; notif.type = IEEE80211_RESMGR_BSSCHAN_SWITCH_COMPLETE; notif.status = EOK; } else { notif.type = IEEE80211_RESMGR_OFFCHAN_SWITCH_COMPLETE; notif.status = EIO; } notif.req_id = IEEE80211_RESMGR_REQID; notif.vap = NULL; IEEE80211_RESMGR_NOTIFICATION(resmgr, ¬if); ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_BSSCHAN); } break; } case IEEE80211_RESMGR_EVENT_BSSCHAN_REQUEST: { /* Equivalent to cancelling the off channel request */ struct vap_iter_check_state_params params; /* Unpause VAPs operating on channel */ OS_MEMZERO(¶ms, sizeof(struct vap_iter_check_state_params)); params.chan = ic->ic_curchan; wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, ¶ms); if (params.vaps_active) { /* VAPs still in the process of pausing, unpause them after pause completion */ resmgr->cancel_pause = true; } else if (params.vaps_paused) { resmgr->scandata.chan = ic->ic_curchan; ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_RESUMING); } else { resmgr->scandata.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); ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_BSSCHAN); } break; } case IEEE80211_RESMGR_EVENT_VAP_RESUME_COMPLETE: { struct vap_iter_check_state_params params; resmgr_vap->state = VAP_ACTIVE; /* Check if all the VAPs on the channel have been unpaused */ OS_MEMZERO(¶ms, sizeof(struct vap_iter_check_state_params)); params.chan = ic->ic_curchan; wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, ¶ms); /* Intimate Pause failure to Scan Module */ if (!params.vaps_paused) { if (resmgr->cancel_pause) { resmgr->cancel_pause = false; notif.type = IEEE80211_RESMGR_BSSCHAN_SWITCH_COMPLETE; notif.status = EOK; } else { notif.type = IEEE80211_RESMGR_OFFCHAN_SWITCH_COMPLETE; notif.status = EIO; } notif.req_id = IEEE80211_RESMGR_REQID; notif.vap = NULL; IEEE80211_RESMGR_NOTIFICATION(resmgr, ¬if); ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_BSSCHAN); } 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); break; default: retVal = false; break; } return retVal; }
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 void ieee80211_resmgr_process_deferred_events(ieee80211_resmgr_t resmgr) { ieee80211_vap_t vap = NULL; ieee80211_resmgr_sm_event_t event = NULL; u_int16_t event_type = 0; ieee80211_resmgr_vap_priv_t resmgr_vap = NULL; struct ieee80211com *ic = resmgr->ic; bool dispatch_event = false; /* * This is a stable state, process deferred events if any ... * Preference goes to deferred events from VAP first and then to SCAn */ wlan_iterate_vap_list(ic, ieee80211_vap_iter_get_def_event, &vap); if (vap) { resmgr_vap = ieee80211vap_get_resmgr(vap); event = &resmgr_vap->def_event; event_type = resmgr_vap->def_event_type; } if (event_type) { switch(event_type) { case IEEE80211_RESMGR_EVENT_VAP_START_REQUEST: { dispatch_event = true; #if 0 struct vap_iter_check_state_params params; resmgr_vap->state = VAP_STARTING; resmgr_vap->chan = event->chan; /* Check for other active VAPs */ OS_MEMZERO(¶ms, sizeof(struct vap_iter_check_state_params)); wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, ¶ms); /* Clear deferred event before changing state */ resmgr_vap->def_event = NULL; resmgr_vap->def_event_type = 0; if (params.vaps_active) { if (resmgr->mode == IEEE80211_RESMGR_MODE_SINGLE_CHANNEL) { /* Single Channel Operation * New STA Vap - Switch other vaps to its channel * New non-STA Vap - Start on channel being used */ if (vap->iv_opmode == IEEE80211_M_STA) { /* Send channel switch request to active VAPs on different channels */ wlan_iterate_vap_list(ic, ieee80211_vap_iter_chanswitch_request, resmgr_vap->chan); ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_VAP_PRESTART); } else { resmgr_vap->chan = ic->ic_curchan; ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_VAP_STARTING); } } } else { ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_VAP_STARTING); } #endif break; } default: break; } if (dispatch_event) { ieee80211_resmgr_sm_dispatch(resmgr, event_type, sizeof(struct ieee80211_resmgr_sm_event), (void *)event); dispatch_event = false; } /* Clear deferred event */ ieee80211_resmgr_clear_event(resmgr, resmgr_vap); } if (resmgr->scandata.def_event_type) { event = &resmgr->scandata.def_event; event_type = resmgr->scandata.def_event_type; switch(event_type) { case IEEE80211_RESMGR_EVENT_OFFCHAN_REQUEST: dispatch_event = true; #if 0 /* Setup channel to be set after VAPs are paused */ resmgr->scandata.chan = event->chan; resmgr->scandata.canpause_timeout = event->max_time ? event->max_time: CANPAUSE_INFINITE_WAIT; /* Clear deferred event before changing state */ resmgr->scandata.def_event = NULL; resmgr->scandata.def_event_type = 0; ieee80211_sm_transition_to(resmgr->hsm_handle, IEEE80211_RESMGR_STATE_CANPAUSE); #endif break; default: break; } if (dispatch_event) { ieee80211_resmgr_sm_dispatch(resmgr, event_type, sizeof(struct ieee80211_resmgr_sm_event), (void *)event); } ieee80211_resmgr_clear_event(resmgr, NULL); } }
void ieee80211_get_vap_opmode_count(struct ieee80211com *ic, struct ieee80211_vap_opmode_count *vap_opmode_count) { wlan_iterate_vap_list(ic, ieee80211_iter_vap_opmode, (void *) vap_opmode_count); }