static void
tdma_beacon_miss(struct ieee80211vap *vap)
{
	struct ieee80211_tdma_state *ts = vap->iv_tdma;

	IEEE80211_LOCK_ASSERT(vap->iv_ic);

	KASSERT((vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning"));
	KASSERT(vap->iv_state == IEEE80211_S_RUN,
	    ("wrong state %d", vap->iv_state));

	IEEE80211_DPRINTF(vap,
		IEEE80211_MSG_STATE | IEEE80211_MSG_TDMA | IEEE80211_MSG_DEBUG,
		"beacon miss, mode %u state %s\n",
		vap->iv_opmode, ieee80211_state_name[vap->iv_state]);

	callout_stop(&vap->iv_swbmiss);

	if (ts->tdma_peer != NULL) {	/* XXX? can this be null? */
		ieee80211_notify_node_leave(vap->iv_bss);
		ts->tdma_peer = NULL;
		/*
		 * Treat beacon miss like an associate failure wrt the
		 * scan policy; this forces the entry in the scan cache
		 * to be ignored after several tries.
		 */
		ieee80211_scan_assoc_fail(vap, vap->iv_bss->ni_macaddr,
		    IEEE80211_STATUS_TIMEOUT);
	}
#if 0
	ts->tdma_inuse = 0;		/* clear slot usage */
#endif
	ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
}
Esempio n. 2
0
/*
 * IEEE80211_M_MONITOR vap state machine handler.
 */
static int
monitor_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
	struct ieee80211com *ic = vap->iv_ic;
	enum ieee80211_state ostate;

	IEEE80211_LOCK_ASSERT(ic);

	ostate = vap->iv_state;
	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
	    __func__, ieee80211_state_name[ostate],
	    ieee80211_state_name[nstate], arg);
	vap->iv_state = nstate;			/* state transition */
	if (nstate == IEEE80211_S_RUN) {
		switch (ostate) {
		case IEEE80211_S_INIT:
			ieee80211_create_ibss(vap, ic->ic_curchan);
			break;
		default:
			break;
		}
		/*
		 * NB: this shouldn't be here but many people use
		 * monitor mode for raw packets; once we switch
		 * them over to adhoc demo mode remove this.
		 */
		ieee80211_node_authorize(vap->iv_bss);
	}
	return 0;
}
Esempio n. 3
0
static void
scan_signal(void *arg)
{
	struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;

	IEEE80211_LOCK_ASSERT(ss->ss_ic);

	cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv);
}
Esempio n. 4
0
/*
 * Manually stop a scan that is currently running.
 * Provided for drivers that are not able to scan single channels
 * (e.g. for firmware-based devices).
 */
static void
ieee80211_swscan_scan_done(struct ieee80211vap *vap)
{
	struct ieee80211com *ic = vap->iv_ic;
	struct ieee80211_scan_state *ss = ic->ic_scan;

	IEEE80211_LOCK_ASSERT(ic);

	scan_signal_locked(ss, 0);
}
Esempio n. 5
0
static void
ieee80211_swscan_vdetach(struct ieee80211vap *vap)
{
	struct ieee80211com *ic = vap->iv_ic;
	struct ieee80211_scan_state *ss = ic->ic_scan;

	IEEE80211_LOCK_ASSERT(ic);

	if (ss != NULL && ss->ss_vap == vap &&
	    (ic->ic_flags & IEEE80211_F_SCAN))
		scan_signal_locked(ss, ISCAN_ABORT);
}
Esempio n. 6
0
/*
 * Check the scan cache for an ap/channel to use; if that
 * fails then kick off a new scan.
 *
 * Called with the comlock held.
 *
 * XXX TODO: split out!
 */
static int
ieee80211_swscan_check_scan(const struct ieee80211_scanner *scan,
    struct ieee80211vap *vap, int flags,
    u_int duration, u_int mindwell, u_int maxdwell,
    u_int nssid, const struct ieee80211_scan_ssid ssids[])
{
	struct ieee80211com *ic = vap->iv_ic;
	struct ieee80211_scan_state *ss = ic->ic_scan;
	int result;

	IEEE80211_LOCK_ASSERT(ic);

	if (ss->ss_ops != NULL) {
		/* XXX verify ss_ops matches vap->iv_opmode */
		if ((flags & IEEE80211_SCAN_NOSSID) == 0) {
			/*
			 * Update the ssid list and mark flags so if
			 * we call start_scan it doesn't duplicate work.
			 */
			ieee80211_scan_copy_ssid(vap, ss, nssid, ssids);
			flags |= IEEE80211_SCAN_NOSSID;
		}
		if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
		    (flags & IEEE80211_SCAN_FLUSH) == 0 &&
		    ieee80211_time_before(ticks, ic->ic_lastscan + vap->iv_scanvalid)) {
			/*
			 * We're not currently scanning and the cache is
			 * deemed hot enough to consult.  Lock out others
			 * by marking IEEE80211_F_SCAN while we decide if
			 * something is already in the scan cache we can
			 * use.  Also discard any frames that might come
			 * in while temporarily marked as scanning.
			 */
			SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
			ic->ic_flags |= IEEE80211_F_SCAN;

			/* NB: need to use supplied flags in check */
			ss->ss_flags = flags & 0xff;
			result = ss->ss_ops->scan_end(ss, vap);

			ic->ic_flags &= ~IEEE80211_F_SCAN;
			SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_DISCARD;
			if (result) {
				ieee80211_notify_scan_done(vap);
				return 1;
			}
		}
	}
	result = ieee80211_swscan_start_scan_locked(scan, vap, flags, duration,
	    mindwell, maxdwell, nssid, ssids);

	return result;
}
Esempio n. 7
0
static void
ieee80211_swscan_set_scan_duration(struct ieee80211vap *vap, u_int duration)
{
	struct ieee80211com *ic = vap->iv_ic;
	struct ieee80211_scan_state *ss = ic->ic_scan;

	IEEE80211_LOCK_ASSERT(ic);

	/* NB: flush frames rx'd before 1st channel change */
	SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
	SCAN_PRIVATE(ss)->ss_duration = duration;
}
Esempio n. 8
0
/*
 * Initiate the CAC timer.  The driver is responsible
 * for setting up the hardware to scan for radar on the
 * channnel, we just handle timing things out.
 */
void
ieee80211_dfs_cac_start(struct ieee80211vap *vap)
{
    struct ieee80211com *ic = vap->iv_ic;
    struct ieee80211_dfs_state *dfs = &ic->ic_dfs;

    IEEE80211_LOCK_ASSERT(ic);

    callout_reset(&dfs->cac_timer, CAC_TIMEOUT, cac_timeout, vap);
    if_printf(vap->iv_ifp, "start %d second CAC timer on channel %u (%u MHz)\n",
              ticks_to_secs(CAC_TIMEOUT),
              ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq);
    ieee80211_notify_cac(ic, ic->ic_curchan, IEEE80211_NOTIFY_CAC_START);
}
Esempio n. 9
0
static void
cac_timeout(void *arg)
{
    struct ieee80211vap *vap = arg;
    struct ieee80211com *ic = vap->iv_ic;
    struct ieee80211_dfs_state *dfs = &ic->ic_dfs;
    int i;

    IEEE80211_LOCK_ASSERT(ic);

    if (vap->iv_state != IEEE80211_S_CAC)	/* NB: just in case */
        return;
    /*
     * When radar is detected during a CAC we are woken
     * up prematurely to switch to a new channel.
     * Check the channel to decide how to act.
     */
    if (IEEE80211_IS_CHAN_RADAR(ic->ic_curchan)) {
        ieee80211_notify_cac(ic, ic->ic_curchan,
                             IEEE80211_NOTIFY_CAC_RADAR);

        if_printf(vap->iv_ifp,
                  "CAC timer on channel %u (%u MHz) stopped due to radar\n",
                  ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq);

        /* XXX clobbers any existing desired channel */
        /* NB: dfs->newchan may be NULL, that's ok */
        vap->iv_des_chan = dfs->newchan;
        /* XXX recursive lock need ieee80211_new_state_locked */
        ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
    } else {
        if_printf(vap->iv_ifp,
                  "CAC timer on channel %u (%u MHz) expired; "
                  "no radar detected\n",
                  ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq);
        /*
         * Mark all channels with the current frequency
         * as having completed CAC; this keeps us from
         * doing it again until we change channels.
         */
        for (i = 0; i < ic->ic_nchans; i++) {
            struct ieee80211_channel *c = &ic->ic_channels[i];
            if (c->ic_freq == ic->ic_curchan->ic_freq)
                c->ic_state |= IEEE80211_CHANSTATE_CACDONE;
        }
        ieee80211_notify_cac(ic, ic->ic_curchan,
                             IEEE80211_NOTIFY_CAC_EXPIRE);
        ieee80211_cac_completeswitch(vap);
    }
}
Esempio n. 10
0
static void
scan_signal_locked(struct ieee80211_scan_state *ss, int iflags)
{
	struct scan_state *ss_priv = SCAN_PRIVATE(ss);
	struct timeout_task *scan_task = &ss_priv->ss_scan_curchan;
	struct ieee80211com *ic = ss->ss_ic;

	IEEE80211_LOCK_ASSERT(ic);

	ss_priv->ss_iflags |= iflags;
	if (ss_priv->ss_iflags & ISCAN_RUNNING) {
		if (taskqueue_cancel_timeout(ic->ic_tq, scan_task, NULL) == 0)
			taskqueue_enqueue_timeout(ic->ic_tq, scan_task, 0);
	}
}
Esempio n. 11
0
/*
 * Clear the CAC timer.
 */
void
ieee80211_dfs_cac_stop(struct ieee80211vap *vap)
{
    struct ieee80211com *ic = vap->iv_ic;
    struct ieee80211_dfs_state *dfs = &ic->ic_dfs;

    IEEE80211_LOCK_ASSERT(ic);

    /* NB: racey but not important */
    if (callout_pending(&dfs->cac_timer)) {
        if_printf(vap->iv_ifp, "stop CAC timer on channel %u (%u MHz)\n",
                  ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq);
        ieee80211_notify_cac(ic, ic->ic_curchan,
                             IEEE80211_NOTIFY_CAC_STOP);
    }
    callout_stop(&dfs->cac_timer);
}
Esempio n. 12
0
/*
 * Update common scanner state to reflect the current
 * operating mode.  This is called when the state machine
 * is transitioned to RUN state w/o scanning--e.g. when
 * operating in monitor mode.  The purpose of this is to
 * ensure later callbacks find ss_ops set to properly
 * reflect current operating mode.
 */
static void
scan_update_locked(struct ieee80211vap *vap,
	const struct ieee80211_scanner *scan)
{
	struct ieee80211com *ic = vap->iv_ic;
	struct ieee80211_scan_state *ss = ic->ic_scan;

	IEEE80211_LOCK_ASSERT(ic);

#ifdef IEEE80211_DEBUG
	if (ss->ss_vap != vap || ss->ss_ops != scan) {
		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
		    "%s: current scanner is <%s:%s>, switch to <%s:%s>\n",
		    __func__,
		    ss->ss_vap != NULL ?
			ss->ss_vap->iv_ifp->if_xname : "none",
		    ss->ss_vap != NULL ?
			ieee80211_opmode_name[ss->ss_vap->iv_opmode] : "none",
		    vap->iv_ifp->if_xname,
		    ieee80211_opmode_name[vap->iv_opmode]);
	}
#endif
	ss->ss_vap = vap;
	if (ss->ss_ops != scan) {
		/*
		 * Switch scanners; detach old, attach new.  Special
		 * case where a single scan module implements multiple
		 * policies by using different scan ops but a common
		 * core.  We assume if the old and new attach methods
		 * are identical then it's ok to just change ss_ops
		 * and not flush the internal state of the module.
		 */
		if (scan == NULL || ss->ss_ops == NULL ||
		    ss->ss_ops->scan_attach != scan->scan_attach) {
			if (ss->ss_ops != NULL)
				ss->ss_ops->scan_detach(ss);
			if (scan != NULL && !scan->scan_attach(ss)) {
				/* XXX attach failure */
				/* XXX stat+msg */
				scan = NULL;
			}
		}
		ss->ss_ops = scan;
	}
}
Esempio n. 13
0
/*
 * Synchronize flags_ext bit state in the com structure
 * according to the state of all vap's.  This is used,
 * for example, to handle state changes via ioctls.
 */
static void
ieee80211_syncflag_ext_locked(struct ieee80211com *ic, int flag)
{
	struct ieee80211vap *vap;
	int bit;

	IEEE80211_LOCK_ASSERT(ic);

	bit = 0;
	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
		if (vap->iv_flags_ext & flag) {
			bit = 1;
			break;
		}
	if (bit)
		ic->ic_flags_ext |= flag;
	else
		ic->ic_flags_ext &= ~flag;
}
Esempio n. 14
0
/*
 * Check the scan cache for an ap/channel to use; if that
 * fails then kick off a new scan.
 */
struct ieee80211_channel *
ieee80211_scan_pickchannel(struct ieee80211com *ic, int flags)
{
	struct ieee80211_scan_state *ss = ic->ic_scan;

	IEEE80211_LOCK_ASSERT(ic);

	if (ss == NULL || ss->ss_ops == NULL || ss->ss_vap == NULL) {
		/* XXX printf? */
		return NULL;
	}
	if (ss->ss_ops->scan_pickchan == NULL) {
		IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN,
		    "%s: scan module does not support picking a channel, "
		    "opmode %s\n", __func__, ss->ss_vap->iv_opmode);
		return NULL;
	}
	return ss->ss_ops->scan_pickchan(ss, flags);
}
Esempio n. 15
0
/*
 * Synchronize flag bit state in the parent ifnet structure
 * according to the state of all vap ifnet's.  This is used,
 * for example, to handle IFF_PROMISC and IFF_ALLMULTI.
 */
void
ieee80211_syncifflag_locked(struct ieee80211com *ic, int flag)
{
	struct ifnet *ifp = ic->ic_ifp;
	struct ieee80211vap *vap;
	int bit, oflags;

	IEEE80211_LOCK_ASSERT(ic);

	bit = 0;
	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
		if (vap->iv_ifp->if_flags & flag) {
			/*
			 * XXX the bridge sets PROMISC but we don't want to
			 * enable it on the device, discard here so all the
			 * drivers don't need to special-case it
			 */
			if (flag == IFF_PROMISC &&
			    !(vap->iv_opmode == IEEE80211_M_MONITOR ||
			      (vap->iv_opmode == IEEE80211_M_AHDEMO &&
			       (vap->iv_caps & IEEE80211_C_TDMA) == 0)))
				continue;
			bit = 1;
			break;
		}
	oflags = ifp->if_flags;
	if (bit)
		ifp->if_flags |= flag;
	else
		ifp->if_flags &= ~flag;
	if ((ifp->if_flags ^ oflags) & flag) {
		/* XXX should we return 1/0 and let caller do this? */
		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
			if (flag == IFF_PROMISC)
				ieee80211_runtask(ic, &ic->ic_promisc_task);
			else if (flag == IFF_ALLMULTI)
				ieee80211_runtask(ic, &ic->ic_mcast_task);
		}
	}
}
Esempio n. 16
0
static void
dfs_timeout(void *arg)
{
	struct ieee80211com *ic = arg;
	struct ieee80211_dfs_state *dfs = &ic->ic_dfs;
	struct ieee80211_channel *c;
	int i, oldest, now;

	IEEE80211_LOCK_ASSERT(ic);

	now = oldest = ticks;
	for (i = 0; i < ic->ic_nchans; i++) {
		c = &ic->ic_channels[i];
		if (IEEE80211_IS_CHAN_RADAR(c)) {
			if (time_after_eq(now, dfs->nol_event[i]+NOL_TIMEOUT)) {
				c->ic_state &= ~IEEE80211_CHANSTATE_RADAR;
				if (c->ic_state & IEEE80211_CHANSTATE_NORADAR) {
					/*
					 * NB: do this here so we get only one
					 * msg instead of one for every channel
					 * table entry.
					 */
					if_printf(ic->ic_ifp, "radar on channel"
					    " %u (%u MHz) cleared after timeout\n",
					    c->ic_ieee, c->ic_freq);
					/* notify user space */
					c->ic_state &=
					    ~IEEE80211_CHANSTATE_NORADAR;
					ieee80211_notify_radar(ic, c);
				}
			} else if (dfs->nol_event[i] < oldest)
				oldest = dfs->nol_event[i];
		}
	}
	if (oldest != now) {
		/* arrange to process next channel up for a status change */
		callout_schedule_dfly(&dfs->nol_timer, oldest + NOL_TIMEOUT - now,
				dfs_timeout, ic);
	}
}
Esempio n. 17
0
static void
scan_done(struct ieee80211_scan_state *ss, int scandone)
{
	struct scan_state *ss_priv = SCAN_PRIVATE(ss);
	struct ieee80211com *ic = ss->ss_ic;
	struct ieee80211vap *vap = ss->ss_vap;

	IEEE80211_LOCK_ASSERT(ic);

	/*
	 * Clear the SCAN bit first in case frames are
	 * pending on the station power save queue.  If
	 * we defer this then the dispatch of the frames
	 * may generate a request to cancel scanning.
	 */
	ic->ic_flags &= ~IEEE80211_F_SCAN;

	/*
	 * Drop out of power save mode when a scan has
	 * completed.  If this scan was prematurely terminated
	 * because it is a background scan then don't notify
	 * the ap; we'll either return to scanning after we
	 * receive the beacon frame or we'll drop out of power
	 * save mode because the beacon indicates we have frames
	 * waiting for us.
	 */
	if (scandone) {
		vap->iv_sta_ps(vap, 0);
		if (ss->ss_next >= ss->ss_last) {
			ieee80211_notify_scan_done(vap);
			ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
		}
	}
	ss_priv->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT);
	ss_priv->ss_scanend = 0;
	ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST);
	IEEE80211_UNLOCK(ic);
#undef ISCAN_REP
}
Esempio n. 18
0
static void
scan_end(struct ieee80211_scan_state *ss, int scandone)
{
	struct scan_state *ss_priv = SCAN_PRIVATE(ss);
	struct ieee80211vap *vap = ss->ss_vap;
	struct ieee80211com *ic = ss->ss_ic;

	IEEE80211_LOCK_ASSERT(ic);

	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: out\n", __func__);

	if (ss_priv->ss_iflags & ISCAN_ABORT) {
		scan_done(ss, scandone);
		return;
	}

	IEEE80211_UNLOCK(ic);
	ic->ic_scan_end(ic);		/* notify driver */
	IEEE80211_LOCK(ic);
	/* XXX scan state can change! Re-validate scan state! */

	/*
	 * Since a cancellation may have occurred during one of the
	 * driver calls (whilst unlocked), update scandone.
	 */
	if (scandone == 0 && (ss_priv->ss_iflags & ISCAN_CANCEL) != 0) {
		/* XXX printf? */
		if_printf(vap->iv_ifp,
		    "%s: OOPS! scan cancelled during driver call (1)!\n",
		    __func__);
		scandone = 1;
	}

	/*
	 * Record scan complete time.  Note that we also do
	 * this when canceled so any background scan will
	 * not be restarted for a while.
	 */
	if (scandone)
		ic->ic_lastscan = ticks;
	/* return to the bss channel */
	if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
	    ic->ic_curchan != ic->ic_bsschan) {
		ieee80211_setupcurchan(ic, ic->ic_bsschan);
		IEEE80211_UNLOCK(ic);
		ic->ic_set_channel(ic);
		ieee80211_radiotap_chan_change(ic);
		IEEE80211_LOCK(ic);
	}
	/* clear internal flags and any indication of a pick */
	ss_priv->ss_iflags &= ~ISCAN_REP;
	ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK;

	/*
	 * If not canceled and scan completed, do post-processing.
	 * If the callback function returns 0, then it wants to
	 * continue/restart scanning.  Unfortunately we needed to
	 * notify the driver to end the scan above to avoid having
	 * rx frames alter the scan candidate list.
	 */
	if ((ss_priv->ss_iflags & ISCAN_CANCEL) == 0 &&
	    !ss->ss_ops->scan_end(ss, vap) &&
	    (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
	    ieee80211_time_before(ticks + ss->ss_mindwell, ss_priv->ss_scanend)) {
		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
		    "%s: done, restart "
		    "[ticks %u, dwell min %lu scanend %lu]\n",
		    __func__,
		    ticks, ss->ss_mindwell, ss_priv->ss_scanend);
		ss->ss_next = 0;	/* reset to beginning */
		if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
			vap->iv_stats.is_scan_active++;
		else
			vap->iv_stats.is_scan_passive++;

		ss->ss_ops->scan_restart(ss, vap);	/* XXX? */
		ieee80211_runtask(ic, &ss_priv->ss_scan_start);
		IEEE80211_UNLOCK(ic);
		return;
	}

	/* past here, scandone is ``true'' if not in bg mode */
	if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0)
		scandone = 1;

	IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
	    "%s: %s, [ticks %u, dwell min %lu scanend %lu]\n",
	    __func__, scandone ? "done" : "stopped",
	    ticks, ss->ss_mindwell, ss_priv->ss_scanend);

	/*
	 * Since a cancellation may have occurred during one of the
	 * driver calls (whilst unlocked), update scandone.
	 */
	if (scandone == 0 && (ss_priv->ss_iflags & ISCAN_CANCEL) != 0) {
		/* XXX printf? */
		if_printf(vap->iv_ifp,
		    "%s: OOPS! scan cancelled during driver call (2)!\n",
		    __func__);
		scandone = 1;
	}

	scan_done(ss, scandone);
}
Esempio n. 19
0
/*
 * IEEE80211_M_IBSS+IEEE80211_M_AHDEMO vap state machine handler.
 */
static int
adhoc_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
	struct ieee80211com *ic = vap->iv_ic;
	struct ieee80211_node *ni;
	enum ieee80211_state ostate;

	IEEE80211_LOCK_ASSERT(vap->iv_ic);

	ostate = vap->iv_state;
	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
	    __func__, ieee80211_state_name[ostate],
	    ieee80211_state_name[nstate], arg);
	vap->iv_state = nstate;			/* state transition */
	if (ostate != IEEE80211_S_SCAN)
		ieee80211_cancel_scan(vap);	/* background scan */
	ni = vap->iv_bss;			/* NB: no reference held */
	switch (nstate) {
	case IEEE80211_S_INIT:
		switch (ostate) {
		case IEEE80211_S_SCAN:
			ieee80211_cancel_scan(vap);
			break;
		default:
			break;
		}
		if (ostate != IEEE80211_S_INIT) {
			/* NB: optimize INIT -> INIT case */
			ieee80211_reset_bss(vap);
		}
		break;
	case IEEE80211_S_SCAN:
		switch (ostate) {
		case IEEE80211_S_RUN:		/* beacon miss */
			/* purge station table; entries are stale */
			ieee80211_iterate_nodes(&ic->ic_sta, sta_leave, vap);
			/* fall thru... */
		case IEEE80211_S_INIT:
			if (vap->iv_des_chan != IEEE80211_CHAN_ANYC &&
			    !IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) {
				/*
				 * Already have a channel; bypass the
				 * scan and startup immediately.
				 */
				ieee80211_create_ibss(vap,
				    ieee80211_ht_adjust_channel(ic,
				    vap->iv_des_chan, vap->iv_flags_ht));
				break;
			}
			/*
			 * Initiate a scan.  We can come here as a result
			 * of an IEEE80211_IOC_SCAN_REQ too in which case
			 * the vap will be marked with IEEE80211_FEXT_SCANREQ
			 * and the scan request parameters will be present
			 * in iv_scanreq.  Otherwise we do the default.
			 */
			if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
				ieee80211_check_scan(vap,
				    vap->iv_scanreq_flags,
				    vap->iv_scanreq_duration,
				    vap->iv_scanreq_mindwell,
				    vap->iv_scanreq_maxdwell,
				    vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
				vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
			} else
				ieee80211_check_scan_current(vap);
			break;
		case IEEE80211_S_SCAN:
			/*
			 * This can happen because of a change in state
			 * that requires a reset.  Trigger a new scan
			 * unless we're in manual roaming mode in which
			 * case an application must issue an explicit request.
			 */
			if (vap->iv_roaming == IEEE80211_ROAMING_AUTO)
				ieee80211_check_scan_current(vap);
			break;
		default:
			goto invalid;
		}
		break;
	case IEEE80211_S_RUN:
		if (vap->iv_flags & IEEE80211_F_WPA) {
			/* XXX validate prerequisites */
		}
		switch (ostate) {
		case IEEE80211_S_SCAN:
#ifdef IEEE80211_DEBUG
			if (ieee80211_msg_debug(vap)) {
				ieee80211_note(vap,
				    "synchronized with %s ssid ",
				    ether_sprintf(ni->ni_bssid));
				ieee80211_print_essid(vap->iv_bss->ni_essid,
				    ni->ni_esslen);
				/* XXX MCS/HT */
				printf(" channel %d start %uMb\n",
				    ieee80211_chan2ieee(ic, ic->ic_curchan),
				    IEEE80211_RATE2MBS(ni->ni_txrate));
			}
#endif
			break;
		case IEEE80211_S_RUN:	/* IBSS merge */
			break;
		default:
			goto invalid;
		}
		/*
		 * When 802.1x is not in use mark the port authorized
		 * at this point so traffic can flow.
		 */
		if (ni->ni_authmode != IEEE80211_AUTH_8021X)
			ieee80211_node_authorize(ni);
		/*
		 * Fake association when joining an existing bss.
		 */
		if (!IEEE80211_ADDR_EQ(ni->ni_macaddr, vap->iv_myaddr) &&
		    ic->ic_newassoc != NULL)
			ic->ic_newassoc(ni, ostate != IEEE80211_S_RUN);
		break;
	case IEEE80211_S_SLEEP:
		vap->iv_sta_ps(vap, 0);
		break;
	default:
	invalid:
		IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE,
		    "%s: unexpected state transition %s -> %s\n", __func__,
		    ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
		break;
	}
	return 0;
}
Esempio n. 20
0
/*
 * Handle a radar detection event on a channel. The channel is
 * added to the NOL list and we record the time of the event.
 * Entries are aged out after NOL_TIMEOUT.  If radar was
 * detected while doing CAC we force a state/channel change.
 * Otherwise radar triggers a channel switch using the CSA
 * mechanism (when the channel is the bss channel).
 */
void
ieee80211_dfs_notify_radar(struct ieee80211com *ic, struct ieee80211_channel *chan)
{
    struct ieee80211_dfs_state *dfs = &ic->ic_dfs;
    int i, now;

    IEEE80211_LOCK_ASSERT(ic);

    /*
     * If doing DFS debugging (mode 2), don't bother
     * running the rest of this function.
     *
     * Simply announce the presence of the radar and continue
     * along merrily.
     */
    if (ieee80211_dfs_debug == DFS_DBG_NOCSANOL) {
        announce_radar(ic->ic_ifp, chan, chan);
        ieee80211_notify_radar(ic, chan);
        return;
    }

    /*
     * Don't mark the channel and don't put it into NOL
     * if we're doing DFS debugging.
     */
    if (ieee80211_dfs_debug == DFS_DBG_NONE) {
        /*
         * Mark all entries with this frequency.  Notify user
         * space and arrange for notification when the radar
         * indication is cleared.  Then kick the NOL processing
         * thread if not already running.
         */
        now = ticks;
        for (i = 0; i < ic->ic_nchans; i++) {
            struct ieee80211_channel *c = &ic->ic_channels[i];
            if (c->ic_freq == chan->ic_freq) {
                c->ic_state &= ~IEEE80211_CHANSTATE_CACDONE;
                c->ic_state |= IEEE80211_CHANSTATE_RADAR;
                dfs->nol_event[i] = now;
            }
        }
        ieee80211_notify_radar(ic, chan);
        chan->ic_state |= IEEE80211_CHANSTATE_NORADAR;
        if (!callout_pending(&dfs->nol_timer))
            callout_reset(&dfs->nol_timer, NOL_TIMEOUT,
                          dfs_timeout, ic);
    }

    /*
     * If radar is detected on the bss channel while
     * doing CAC; force a state change by scheduling the
     * callout to be dispatched asap.  Otherwise, if this
     * event is for the bss channel then we must quiet
     * traffic and schedule a channel switch.
     *
     * Note this allows us to receive notification about
     * channels other than the bss channel; not sure
     * that can/will happen but it's simple to support.
     */
    if (chan == ic->ic_bsschan) {
        /* XXX need a way to defer to user app */

        /*
         * Don't flip over to a new channel if
         * we are currently doing DFS debugging.
         */
        if (ieee80211_dfs_debug == DFS_DBG_NONE)
            dfs->newchan = ieee80211_dfs_pickchannel(ic);
        else
            dfs->newchan = chan;

        announce_radar(ic->ic_ifp, chan, dfs->newchan);

        if (callout_pending(&dfs->cac_timer))
            callout_schedule(&dfs->cac_timer, 0);
        else if (dfs->newchan != NULL) {
            /* XXX mode 1, switch count 2 */
            /* XXX calculate switch count based on max
              switch time and beacon interval? */
            ieee80211_csa_startswitch(ic, dfs->newchan, 1, 2);
        } else {
            /*
             * Spec says to stop all transmissions and
             * wait on the current channel for an entry
             * on the NOL to expire.
             */
            /*XXX*/
            if_printf(ic->ic_ifp, "%s: No free channels; waiting for entry "
                      "on NOL to expire\n", __func__);
        }
    } else {
        /*
         * Issue rate-limited console msgs.
         */
        if (dfs->lastchan != chan) {
            dfs->lastchan = chan;
            dfs->cureps = 0;
            announce_radar(ic->ic_ifp, chan, NULL);
        } else if (ppsratecheck(&dfs->lastevent, &dfs->cureps, 1)) {
            announce_radar(ic->ic_ifp, chan, NULL);
        }
    }
}
Esempio n. 21
0
/*
 * TDMA state machine handler.
 */
static int
tdma_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
	struct ieee80211_tdma_state *ts = vap->iv_tdma;
	struct ieee80211com *ic = vap->iv_ic;
	enum ieee80211_state ostate;
	int status;

	IEEE80211_LOCK_ASSERT(ic);

	ostate = vap->iv_state;
	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n",
	    __func__, ieee80211_state_name[ostate],
	    ieee80211_state_name[nstate], arg);

	if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)
		callout_stop(&vap->iv_swbmiss);
	if (nstate == IEEE80211_S_SCAN &&
	    (ostate == IEEE80211_S_INIT || ostate == IEEE80211_S_RUN) &&
	    ts->tdma_slot != 0) {
		/*
		 * Override adhoc behaviour when operating as a slave;
		 * we need to scan even if the channel is locked.
		 */
		vap->iv_state = nstate;			/* state transition */
		ieee80211_cancel_scan(vap);		/* background scan */
		if (ostate == IEEE80211_S_RUN) {
			/* purge station table; entries are stale */
			ieee80211_iterate_nodes(&ic->ic_sta, sta_leave, vap);
		}
		if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) {
			ieee80211_check_scan(vap,
			    vap->iv_scanreq_flags,
			    vap->iv_scanreq_duration,
			    vap->iv_scanreq_mindwell,
			    vap->iv_scanreq_maxdwell,
			    vap->iv_scanreq_nssid, vap->iv_scanreq_ssid);
			vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
		} else
			ieee80211_check_scan_current(vap);
		status = 0;
	} else {
		status = ts->tdma_newstate(vap, nstate, arg);
	}
	if (status == 0 && 
	    nstate == IEEE80211_S_RUN && ostate != IEEE80211_S_RUN &&
	    (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) &&
	    ts->tdma_slot != 0 &&
	    vap->iv_des_chan == IEEE80211_CHAN_ANYC) {
		/*
		 * Start s/w beacon miss timer for slave devices w/o
		 * hardware support.  Note we do this only if we're
		 * not locked to a channel (i.e. roam to follow the
		 * master). The 2x is a fudge for our doing this in
		 * software.
		 */
		vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS(
		    2 * vap->iv_bmissthreshold * ts->tdma_bintval *
		    ((ts->tdma_slotcnt * ts->tdma_slotlen) / 1024));
		vap->iv_swbmiss_count = 0;
		callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period,
			ieee80211_swbmiss, vap);
	}
	return status;
}
Esempio n. 22
0
/*
 * Start a scan unless one is already going.
 */
static int
ieee80211_swscan_start_scan_locked(const struct ieee80211_scanner *scan,
	struct ieee80211vap *vap, int flags, u_int duration,
	u_int mindwell, u_int maxdwell,
	u_int nssid, const struct ieee80211_scan_ssid ssids[])
{
	struct ieee80211com *ic = vap->iv_ic;
	struct ieee80211_scan_state *ss = ic->ic_scan;

	IEEE80211_LOCK_ASSERT(ic);

	if (ic->ic_flags & IEEE80211_F_CSAPENDING) {
		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
		    "%s: scan inhibited by pending channel change\n", __func__);
	} else if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
		    "%s: %s scan, duration %u mindwell %u maxdwell %u, desired mode %s, %s%s%s%s%s%s\n"
		    , __func__
		    , flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"
		    , duration, mindwell, maxdwell
		    , ieee80211_phymode_name[vap->iv_des_mode]
		    , flags & IEEE80211_SCAN_FLUSH ? "flush" : "append"
		    , flags & IEEE80211_SCAN_NOPICK ? ", nopick" : ""
		    , flags & IEEE80211_SCAN_NOJOIN ? ", nojoin" : ""
		    , flags & IEEE80211_SCAN_NOBCAST ? ", nobcast" : ""
		    , flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : ""
		    , flags & IEEE80211_SCAN_ONCE ? ", once" : ""
		);

		ieee80211_scan_update_locked(vap, scan);
		if (ss->ss_ops != NULL) {
			if ((flags & IEEE80211_SCAN_NOSSID) == 0)
				ieee80211_scan_copy_ssid(vap, ss, nssid, ssids);

			/* NB: top 4 bits for internal use */
			ss->ss_flags = flags & 0xfff;
			if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
				vap->iv_stats.is_scan_active++;
			else
				vap->iv_stats.is_scan_passive++;
			if (flags & IEEE80211_SCAN_FLUSH)
				ss->ss_ops->scan_flush(ss);
			if (flags & IEEE80211_SCAN_BGSCAN)
				ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;

			/* Set duration for this particular scan */
			ieee80211_swscan_set_scan_duration(vap, duration);

			ss->ss_next = 0;
			ss->ss_mindwell = mindwell;
			ss->ss_maxdwell = maxdwell;
			/* NB: scan_start must be before the scan runtask */
			ss->ss_ops->scan_start(ss, vap);
#ifdef IEEE80211_DEBUG
			if (ieee80211_msg_scan(vap))
				ieee80211_scan_dump(ss);
#endif /* IEEE80211_DEBUG */
			ic->ic_flags |= IEEE80211_F_SCAN;

			/* Start scan task */
			ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_start);
		}
		return 1;
	} else {
		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
		    "%s: %s scan already in progress\n", __func__,
		    ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");
	}
	return 0;
}