Пример #1
0
/*
 * 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;
}
Пример #2
0
/*
 * 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
}
Пример #3
0
/*
 * 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(&params, sizeof(struct vap_iter_check_state_params));
        wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, &params);

        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, &params);
        } else {
            wlan_iterate_vap_list(ic, ieee80211_vap_iter_resume_request, &params);
        }
    
        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, &notif);
        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, &notif);
        }
        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, &notif);
            }

            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(&params, sizeof(struct vap_iter_check_state_params));
                            wlan_iterate_vap_list(ic, ieee80211_vap_iter_check_state, &params);
                            
                            /* 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, &notif);
                        }
                        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;
}
Пример #5
0
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;
}
Пример #6
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;
}
Пример #7
0
/*
 * 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
}