Esempio n. 1
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. 2
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. 3
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;

	/*
	 * 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_callout, 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 */
		dfs->newchan = ieee80211_dfs_pickchannel(ic);

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

#ifdef notyet
		if (callout_pending(&dfs->cac_timer)) {
			callout_reset(&dfs->cac_timer, 0,
					cac_timeout_callout, vap);
		}
		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*/
		}
#endif
	} 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);
		}
	}
}