Index: sys/net80211/ieee80211_ht.c =================================================================== --- sys/net80211/ieee80211_ht.c (revision 276517) +++ sys/net80211/ieee80211_ht.c (working copy) @@ -2655,6 +2655,7 @@ caps |= IEEE80211_HTCAP_CHWIDTH40; else caps &= ~IEEE80211_HTCAP_CHWIDTH40; + /* use advertised setting (XXX locally constraint) */ rxmax = MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU); density = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY); @@ -2678,6 +2679,19 @@ rxmax = vap->iv_ampdu_rxmax; density = vap->iv_ampdu_density; } + + /* + * Use the VAP configured AMPDU maximum RX size + * and RX density. + * + * XXX TODO: should check the recieved settings and + * the configured VAP settings / hardware settings + * to see what the minimum of both is and advertise + * that. + */ + rxmax = vap->iv_ampdu_rxmax; + density = vap->iv_ampdu_density; + /* adjust short GI based on channel and config */ if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0) caps &= ~IEEE80211_HTCAP_SHORTGI20; Index: sys/net80211/ieee80211_output.c =================================================================== --- sys/net80211/ieee80211_output.c (revision 276517) +++ sys/net80211/ieee80211_output.c (working copy) @@ -2322,18 +2322,33 @@ ic->ic_curchan); frm = ieee80211_add_supportedchannels(frm, ic); } + + /* + * Check the channel - we may be using an 11n NIC with an + * 11n capable station, but we're configured to be an 11b + * channel. + */ if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && + IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_ies.htcap_ie != NULL && - ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) + ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) { frm = ieee80211_add_htcap(frm, ni); + } frm = ieee80211_add_wpa(frm, vap); if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_ies.wme_ie != NULL) frm = ieee80211_add_wme_info(frm, &ic->ic_wme); + + /* + * Same deal - only send HT info if we're on an 11n + * capable channel. + */ if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && + IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_ies.htcap_ie != NULL && - ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) + ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) { frm = ieee80211_add_htcap_vendor(frm, ni); + } #ifdef IEEE80211_SUPPORT_SUPERG if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { frm = ieee80211_add_ath(frm, Index: sys/net80211/ieee80211_regdomain.h =================================================================== --- sys/net80211/ieee80211_regdomain.h (revision 276517) +++ sys/net80211/ieee80211_regdomain.h (working copy) @@ -236,6 +236,7 @@ CTRY_JAPAN22 = 4022, /* Japan (J22) */ CTRY_JAPAN23 = 4023, /* Japan (J23) */ CTRY_JAPAN24 = 4024, /* Japan (J24) */ + CTRY_JAPAN25 = 4025, /* Japan (J25) */ }; enum RegdomainCode { Index: sys/net80211/ieee80211_scan.c =================================================================== --- sys/net80211/ieee80211_scan.c (revision 276517) +++ sys/net80211/ieee80211_scan.c (working copy) @@ -46,37 +46,12 @@ #include +/* XXX until it's implemented as attach ops */ +#include + #include -struct scan_state { - struct ieee80211_scan_state base; /* public state */ - - u_int ss_iflags; /* flags used internally */ -#define ISCAN_MINDWELL 0x0001 /* min dwell time reached */ -#define ISCAN_DISCARD 0x0002 /* discard rx'd frames */ -#define ISCAN_CANCEL 0x0004 /* cancel current scan */ -#define ISCAN_ABORT 0x0008 /* end the scan immediately */ - unsigned long ss_chanmindwell; /* min dwell on curchan */ - unsigned long ss_scanend; /* time scan must stop */ - u_int ss_duration; /* duration for next scan */ - struct task ss_scan_task; /* scan execution */ - struct cv ss_scan_cv; /* scan signal */ - struct callout ss_scan_timer; /* scan timer */ -}; -#define SCAN_PRIVATE(ss) ((struct scan_state *) ss) - /* - * Amount of time to go off-channel during a background - * scan. This value should be large enough to catch most - * ap's but short enough that we can return on-channel - * before our listen interval expires. - * - * XXX tunable - * XXX check against configured listen interval - */ -#define IEEE80211_SCAN_OFFCHANNEL msecs_to_ticks(150) - -/* * Roaming-related defaults. RSSI thresholds are as returned by the * driver (.5dBm). Transmit rate thresholds are IEEE rate codes (i.e * .5M units) or MCS. @@ -93,55 +68,32 @@ #define ROAM_RATE_QUARTER_DEFAULT 2*3 /* quarter-width 11a/g bss */ #define ROAM_MCS_11N_DEFAULT (1 | IEEE80211_RATE_MCS) /* 11n bss */ -static void scan_curchan(struct ieee80211_scan_state *, unsigned long); -static void scan_mindwell(struct ieee80211_scan_state *); -static void scan_signal(void *); -static void scan_task(void *, int); - -MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state"); - void ieee80211_scan_attach(struct ieee80211com *ic) { - struct scan_state *ss; - ss = (struct scan_state *) malloc(sizeof(struct scan_state), - M_80211_SCAN, M_NOWAIT | M_ZERO); - if (ss == NULL) { - ic->ic_scan = NULL; - return; - } - callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0); - cv_init(&ss->ss_scan_cv, "scan"); - TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss); - ic->ic_scan = &ss->base; - ss->base.ss_ic = ic; - - ic->ic_scan_curchan = scan_curchan; - ic->ic_scan_mindwell = scan_mindwell; + /* + * For now, the swscan module does both the + * allocation (so it can pad it) and sets up the net80211 + * bits. + * + * I'll split this stuff later. + */ + ieee80211_swscan_attach(ic); } void ieee80211_scan_detach(struct ieee80211com *ic) { - struct ieee80211_scan_state *ss = ic->ic_scan; - if (ss != NULL) { - IEEE80211_LOCK(ic); - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; - scan_signal(ss); - IEEE80211_UNLOCK(ic); - ieee80211_draintask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); - callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer); - KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, - ("scan still running")); - if (ss->ss_ops != NULL) { - ss->ss_ops->scan_detach(ss); - ss->ss_ops = NULL; - } - ic->ic_scan = NULL; - free(SCAN_PRIVATE(ss), M_80211_SCAN); - } + /* + * Ideally we'd do the ss_ops detach call here; + * but then ieee80211_swscan_detach would need + * to be split in two. + * + * I'll do that later. + */ + ieee80211_swscan_detach(ic); } static const struct ieee80211_roamparam defroam[IEEE80211_MODE_MAX] = { @@ -176,6 +128,8 @@ vap->iv_roaming = IEEE80211_ROAMING_AUTO; memcpy(vap->iv_roamparms, defroam, sizeof(defroam)); + + ieee80211_swscan_vattach(vap); } void @@ -186,11 +140,10 @@ IEEE80211_LOCK(ic); ss = ic->ic_scan; + + ieee80211_swscan_vdetach(vap); + if (ss != NULL && ss->ss_vap == vap) { - if (ic->ic_flags & IEEE80211_F_SCAN) { - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; - scan_signal(ss); - } if (ss->ss_ops != NULL) { ss->ss_ops->scan_detach(ss); ss->ss_ops = NULL; @@ -261,8 +214,8 @@ * ensure later callbacks find ss_ops set to properly * reflect current operating mode. */ -static void -scan_update_locked(struct ieee80211vap *vap, +void +ieee80211_scan_update_locked(struct ieee80211vap *vap, const struct ieee80211_scanner *scan) { struct ieee80211com *ic = vap->iv_ic; @@ -307,6 +260,9 @@ } } +/* + * XXX TODO: should be a global method! + */ static char channel_type(const struct ieee80211_channel *c) { @@ -345,8 +301,8 @@ } #ifdef IEEE80211_DEBUG -static void -scan_dump(struct ieee80211_scan_state *ss) +void +ieee80211_scan_dump(struct ieee80211_scan_state *ss) { struct ieee80211vap *vap = ss->ss_vap; @@ -357,8 +313,8 @@ } #endif /* IEEE80211_DEBUG */ -static void -copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss, +void +ieee80211_scan_copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss, int nssid, const struct ieee80211_scan_ssid ssids[]) { if (nssid > IEEE80211_SCAN_MAX_SSID) { @@ -375,8 +331,8 @@ /* * Start a scan unless one is already going. */ -static int -start_scan_locked(const struct ieee80211_scanner *scan, +int +ieee80211_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[]) @@ -404,10 +360,10 @@ , flags & IEEE80211_SCAN_ONCE ? ", once" : "" ); - scan_update_locked(vap, scan); + ieee80211_scan_update_locked(vap, scan); if (ss->ss_ops != NULL) { if ((flags & IEEE80211_SCAN_NOSSID) == 0) - copy_ssid(vap, ss, nssid, ssids); + ieee80211_scan_copy_ssid(vap, ss, nssid, ssids); /* NB: top 4 bits for internal use */ ss->ss_flags = flags & 0xfff; @@ -420,9 +376,9 @@ if (flags & IEEE80211_SCAN_BGSCAN) ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; - /* NB: flush frames rx'd before 1st channel change */ - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; - SCAN_PRIVATE(ss)->ss_duration = duration; + /* 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; @@ -430,10 +386,12 @@ ss->ss_ops->scan_start(ss, vap); #ifdef IEEE80211_DEBUG if (ieee80211_msg_scan(vap)) - scan_dump(ss); + ieee80211_scan_dump(ss); #endif /* IEEE80211_DEBUG */ ic->ic_flags |= IEEE80211_F_SCAN; - ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); + + /* Start scan task */ + ieee80211_swscan_run_scan_task(vap); } return 1; } else { @@ -452,9 +410,7 @@ u_int duration, u_int mindwell, u_int maxdwell, u_int nssid, const struct ieee80211_scan_ssid ssids[]) { - struct ieee80211com *ic = vap->iv_ic; const struct ieee80211_scanner *scan; - int result; scan = ieee80211_scanner_get(vap->iv_opmode); if (scan == NULL) { @@ -465,12 +421,9 @@ return 0; } - IEEE80211_LOCK(ic); - result = start_scan_locked(scan, vap, flags, duration, + /* XXX ops */ + return ieee80211_swscan_start_scan(scan, vap, flags, duration, mindwell, maxdwell, nssid, ssids); - IEEE80211_UNLOCK(ic); - - return result; } /* @@ -517,49 +470,19 @@ /* XXX re-use cache contents? e.g. adhoc<->sta */ flags |= IEEE80211_SCAN_FLUSH; } - scan_update_locked(vap, scan); - 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. - */ - copy_ssid(vap, ss, nssid, ssids); - flags |= IEEE80211_SCAN_NOSSID; - } - if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 && - (flags & IEEE80211_SCAN_FLUSH) == 0 && - 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); + /* + * XXX TODO: separate things out a bit better. + * XXX TODO: ops + */ + ieee80211_scan_update_locked(vap, scan); - ic->ic_flags &= ~IEEE80211_F_SCAN; - SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_DISCARD; - if (result) { - ieee80211_notify_scan_done(vap); - IEEE80211_UNLOCK(ic); - return 1; - } - } - } - result = start_scan_locked(scan, vap, flags, duration, + result = ieee80211_swscan_check_scan(scan, vap, flags, duration, mindwell, maxdwell, nssid, ssids); + IEEE80211_UNLOCK(ic); - return result; + return (result); } /* @@ -582,10 +505,10 @@ int ieee80211_bg_scan(struct ieee80211vap *vap, int flags) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; const struct ieee80211_scanner *scan; + // IEEE80211_UNLOCK_ASSERT(sc); + scan = ieee80211_scanner_get(vap->iv_opmode); if (scan == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, @@ -595,84 +518,14 @@ return 0; } - IEEE80211_LOCK(ic); - if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { - u_int duration; - /* - * Go off-channel for a fixed interval that is large - * enough to catch most ap's but short enough that - * we can return on-channel before our listen interval - * expires. - */ - duration = IEEE80211_SCAN_OFFCHANNEL; - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: %s scan, ticks %u duration %lu\n", __func__, - ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive", - ticks, duration); - - scan_update_locked(vap, scan); - if (ss->ss_ops != NULL) { - ss->ss_vap = vap; - /* - * A background scan does not select a new sta; it - * just refreshes the scan cache. Also, indicate - * the scan logic should follow the beacon schedule: - * we go off-channel and scan for a while, then - * return to the bss channel to receive a beacon, - * then go off-channel again. All during this time - * we notify the ap we're in power save mode. When - * the scan is complete we leave power save mode. - * If any beacon indicates there are frames pending - * for us then we drop out of power save mode - * (and background scan) automatically by way of the - * usual sta power save logic. - */ - ss->ss_flags |= IEEE80211_SCAN_NOPICK - | IEEE80211_SCAN_BGSCAN - | flags - ; - /* if previous scan completed, restart */ - if (ss->ss_next >= ss->ss_last) { - if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) - vap->iv_stats.is_scan_active++; - else - vap->iv_stats.is_scan_passive++; - /* - * NB: beware of the scan cache being flushed; - * if the channel list is empty use the - * scan_start method to populate it. - */ - ss->ss_next = 0; - if (ss->ss_last != 0) - ss->ss_ops->scan_restart(ss, vap); - else { - ss->ss_ops->scan_start(ss, vap); -#ifdef IEEE80211_DEBUG - if (ieee80211_msg_scan(vap)) - scan_dump(ss); -#endif /* IEEE80211_DEBUG */ - } - } - /* NB: flush frames rx'd before 1st channel change */ - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; - SCAN_PRIVATE(ss)->ss_duration = duration; - ss->ss_maxdwell = duration; - ic->ic_flags |= IEEE80211_F_SCAN; - ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; - ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); - } else { - /* XXX msg+stat */ - } - } else { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: %s scan already in progress\n", __func__, - ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"); - } - IEEE80211_UNLOCK(ic); - - /* NB: racey, does it matter? */ - return (ic->ic_flags & IEEE80211_F_SCAN); + /* + * XXX TODO: pull apart the bgscan logic into whatever + * belongs here and whatever belongs in the software + * scanner. + * + * XXX TODO: ops + */ + return (ieee80211_swscan_bg_scan(scan, vap, flags)); } /* @@ -681,32 +534,9 @@ void ieee80211_cancel_scan(struct ieee80211vap *vap) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - IEEE80211_LOCK(ic); - if ((ic->ic_flags & IEEE80211_F_SCAN) && - ss->ss_vap == vap && - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: cancel %s scan\n", __func__, - ss->ss_flags & IEEE80211_SCAN_ACTIVE ? - "active" : "passive"); - - /* clear bg scan NOPICK and mark cancel request */ - ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL; - /* wake up the scan task */ - scan_signal(ss); - } else { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: called; F_SCAN=%d, vap=%s, CANCEL=%d\n", - __func__, - !! (ic->ic_flags & IEEE80211_F_SCAN), - (ss->ss_vap == vap ? "match" : "nomatch"), - !! (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL)); - } - IEEE80211_UNLOCK(ic); + /* XXX TODO: ops */ + ieee80211_swscan_cancel_scan(vap); } /* @@ -715,31 +545,9 @@ void ieee80211_cancel_anyscan(struct ieee80211vap *vap) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - IEEE80211_LOCK(ic); - if ((ic->ic_flags & IEEE80211_F_SCAN) && - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: cancel %s scan\n", __func__, - ss->ss_flags & IEEE80211_SCAN_ACTIVE ? - "active" : "passive"); - - /* clear bg scan NOPICK and mark cancel request */ - ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL; - /* wake up the scan task */ - scan_signal(ss); - } else { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: called; F_SCAN=%d, vap=%s, CANCEL=%d\n", - __func__, - !! (ic->ic_flags & IEEE80211_F_SCAN), - (ss->ss_vap == vap ? "match" : "nomatch"), - !! (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL)); - } - IEEE80211_UNLOCK(ic); + /* XXX TODO: ops */ + ieee80211_swscan_cancel_anyscan(vap); } /* @@ -749,15 +557,9 @@ void ieee80211_scan_next(struct ieee80211vap *vap) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: called\n", __func__); - - /* wake up the scan task */ - IEEE80211_LOCK(ic); - scan_signal(ss); - IEEE80211_UNLOCK(ic); + /* XXX TODO: ops */ + ieee80211_swscan_scan_next(vap); } /* @@ -775,7 +577,10 @@ IEEE80211_LOCK(ic); ss = ic->ic_scan; ss->ss_next = ss->ss_last; /* all channels are complete */ - scan_signal(ss); + + /* XXX TODO: ops */ + ieee80211_swscan_scan_done(vap); + IEEE80211_UNLOCK(ic); } @@ -790,330 +595,16 @@ ieee80211_probe_curchan(struct ieee80211vap *vap, int force) { struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - struct ifnet *ifp = vap->iv_ifp; - int i; if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) && !force) { ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN; return; } - /* - * Send directed probe requests followed by any - * broadcast probe request. - * XXX remove dependence on ic/vap->iv_bss - */ - for (i = 0; i < ss->ss_nssid; i++) - ieee80211_send_probereq(vap->iv_bss, - vap->iv_myaddr, ifp->if_broadcastaddr, - ifp->if_broadcastaddr, - ss->ss_ssid[i].ssid, ss->ss_ssid[i].len); - if ((ss->ss_flags & IEEE80211_SCAN_NOBCAST) == 0) - ieee80211_send_probereq(vap->iv_bss, - vap->iv_myaddr, ifp->if_broadcastaddr, - ifp->if_broadcastaddr, - "", 0); -} -/* - * Scan curchan. If this is an active scan and the channel - * is not marked passive then send probe request frame(s). - * Arrange for the channel change after maxdwell ticks. - */ -static void -scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) -{ - struct ieee80211vap *vap = ss->ss_vap; - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: calling; maxdwell=%lu\n", - __func__, - maxdwell); - IEEE80211_LOCK(vap->iv_ic); - if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) - ieee80211_probe_curchan(vap, 0); - callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, - maxdwell, scan_signal, ss); - IEEE80211_UNLOCK(vap->iv_ic); + /* XXX TODO: ops */ + ieee80211_swscan_probe_curchan(vap, force); } -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); -} - -/* - * Handle mindwell requirements completed; initiate a channel - * change to the next channel asap. - */ -static void -scan_mindwell(struct ieee80211_scan_state *ss) -{ - struct ieee80211com *ic = ss->ss_ic; - - IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN, "%s: called\n", __func__); - - IEEE80211_LOCK(ic); - scan_signal(ss); - IEEE80211_UNLOCK(ic); -} - -static void -scan_task(void *arg, int pending) -{ -#define ISCAN_REP (ISCAN_MINDWELL | ISCAN_DISCARD) - struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; - struct ieee80211vap *vap = ss->ss_vap; - struct ieee80211com *ic = ss->ss_ic; - struct ieee80211_channel *chan; - unsigned long maxdwell, scanend; - int scandone = 0; - - IEEE80211_LOCK(ic); - if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 || - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)) { - /* Cancelled before we started */ - goto done; - } - - if (ss->ss_next == ss->ss_last) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: no channels to scan\n", __func__); - scandone = 1; - goto done; - } - - if (vap->iv_opmode == IEEE80211_M_STA && - vap->iv_state == IEEE80211_S_RUN) { - if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { - /* Enable station power save mode */ - vap->iv_sta_ps(vap, 1); - /* - * Use an 1ms delay so the null data frame has a chance - * to go out. - * XXX Should use M_TXCB mechanism to eliminate this. - */ - cv_timedwait(&SCAN_PRIVATE(ss)->ss_scan_cv, - IEEE80211_LOCK_OBJ(ic), hz / 1000); - if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) - goto done; - } - } - - scanend = ticks + SCAN_PRIVATE(ss)->ss_duration; - - /* XXX scan state can change! Re-validate scan state! */ - - IEEE80211_UNLOCK(ic); - ic->ic_scan_start(ic); /* notify driver */ - IEEE80211_LOCK(ic); - - for (;;) { - - scandone = (ss->ss_next >= ss->ss_last) || - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0; - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: loop start; scandone=%d\n", - __func__, - scandone); - - if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) || - (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) || - time_after(ticks + ss->ss_mindwell, scanend)) - break; - - chan = ss->ss_chans[ss->ss_next++]; - - /* - * Watch for truncation due to the scan end time. - */ - if (time_after(ticks + ss->ss_maxdwell, scanend)) - maxdwell = scanend - ticks; - else - maxdwell = ss->ss_maxdwell; - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: chan %3d%c -> %3d%c [%s, dwell min %lums max %lums]\n", - __func__, - ieee80211_chan2ieee(ic, ic->ic_curchan), - channel_type(ic->ic_curchan), - ieee80211_chan2ieee(ic, chan), channel_type(chan), - (ss->ss_flags & IEEE80211_SCAN_ACTIVE) && - (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ? - "active" : "passive", - ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(maxdwell)); - - /* - * Potentially change channel and phy mode. - */ - ic->ic_curchan = chan; - ic->ic_rt = ieee80211_get_ratetable(chan); - IEEE80211_UNLOCK(ic); - /* - * Perform the channel change and scan unlocked so the driver - * may sleep. Once set_channel returns the hardware has - * completed the channel change. - */ - ic->ic_set_channel(ic); - ieee80211_radiotap_chan_change(ic); - - /* - * Scan curchan. Drivers for "intelligent hardware" - * override ic_scan_curchan to tell the device to do - * the work. Otherwise we manage the work outselves; - * sending a probe request (as needed), and arming the - * timeout to switch channels after maxdwell ticks. - * - * scan_curchan should only pause for the time required to - * prepare/initiate the hardware for the scan (if at all), the - * below condvar is used to sleep for the channels dwell time - * and allows it to be signalled for abort. - */ - ic->ic_scan_curchan(ss, maxdwell); - IEEE80211_LOCK(ic); - - /* XXX scan state can change! Re-validate scan state! */ - - SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell; - /* clear mindwell lock and initial channel change flush */ - SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; - - if ((SCAN_PRIVATE(ss)->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT))) - continue; - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: waiting\n", __func__); - /* Wait to be signalled to scan the next channel */ - cv_wait(&SCAN_PRIVATE(ss)->ss_scan_cv, IEEE80211_LOCK_OBJ(ic)); - } - - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: out\n", __func__); - - if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) - goto done; - - 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 occured during one of the - * driver calls (whilst unlocked), update scandone. - */ - if (scandone == 0 && - ((SCAN_PRIVATE(ss)->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 */ - SCAN_PRIVATE(ss)->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 ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 && - !ss->ss_ops->scan_end(ss, vap) && - (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 && - time_before(ticks + ss->ss_mindwell, scanend)) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: done, restart " - "[ticks %u, dwell min %lu scanend %lu]\n", - __func__, - ticks, ss->ss_mindwell, scanend); - ss->ss_next = 0; /* reset to begining */ - 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, &SCAN_PRIVATE(ss)->ss_scan_task); - 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, scanend); - - /* - * Since a cancellation may have occured during one of the - * driver calls (whilst unlocked), update scandone. - */ - if (scandone == 0 && - ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0)) { - /* XXX printf? */ - if_printf(vap->iv_ifp, - "%s: OOPS! scan cancelled during driver call (2)!\n", - __func__); - scandone = 1; - } - - /* - * 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. - */ -done: - 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; - } - } - SCAN_PRIVATE(ss)->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT); - ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST); - IEEE80211_UNLOCK(ic); -#undef ISCAN_REP -} - #ifdef IEEE80211_DEBUG static void dump_country(const uint8_t *ie) @@ -1140,8 +631,8 @@ printf("]"); } -static void -dump_probe_beacon(uint8_t subtype, int isnew, +void +ieee80211_scan_dump_probe_beacon(uint8_t subtype, int isnew, const uint8_t mac[IEEE80211_ADDR_LEN], const struct ieee80211_scanparams *sp, int rssi) { @@ -1172,45 +663,8 @@ const struct ieee80211_frame *wh, int subtype, int rssi, int noise) { - struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_scan_state *ss = ic->ic_scan; - /* XXX locking */ - /* - * Frames received during startup are discarded to avoid - * using scan state setup on the initial entry to the timer - * callback. This can occur because the device may enable - * rx prior to our doing the initial channel change in the - * timer routine. - */ - if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_DISCARD) - return; -#ifdef IEEE80211_DEBUG - if (ieee80211_msg_scan(vap) && (ic->ic_flags & IEEE80211_F_SCAN)) - dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi); -#endif - if (ss->ss_ops != NULL && - ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise)) { - /* - * If we've reached the min dwell time terminate - * the timer so we'll switch to the next channel. - */ - if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_MINDWELL) == 0 && - time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: chan %3d%c min dwell met (%u > %lu)\n", - __func__, - ieee80211_chan2ieee(ic, ic->ic_curchan), - channel_type(ic->ic_curchan), - ticks, SCAN_PRIVATE(ss)->ss_chanmindwell); - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_MINDWELL; - /* - * NB: trigger at next clock tick or wait for the - * hardware. - */ - ic->ic_scan_mindwell(ss); - } - } + return (ieee80211_swscan_add_scan(vap, sp, wh, subtype, rssi, noise)); } /* Index: sys/net80211/ieee80211_scan.h =================================================================== --- sys/net80211/ieee80211_scan.h (revision 276517) +++ sys/net80211/ieee80211_scan.h (working copy) @@ -299,4 +299,18 @@ const struct ieee80211_scanner *); void ieee80211_scanner_unregister_all(const struct ieee80211_scanner *); const struct ieee80211_scanner *ieee80211_scanner_get(enum ieee80211_opmode); +void ieee80211_scan_update_locked(struct ieee80211vap *vap, + const struct ieee80211_scanner *scan); +void ieee80211_scan_copy_ssid(struct ieee80211vap *vap, + struct ieee80211_scan_state *ss, + int nssid, const struct ieee80211_scan_ssid ssids[]); +void ieee80211_scan_dump_probe_beacon(uint8_t subtype, int isnew, + const uint8_t mac[IEEE80211_ADDR_LEN], + const struct ieee80211_scanparams *sp, int rssi); +int ieee80211_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[]); +void ieee80211_scan_dump(struct ieee80211_scan_state *ss); + #endif /* _NET80211_IEEE80211_SCAN_H_ */ Index: sys/net80211/ieee80211_scan_sw.c =================================================================== --- sys/net80211/ieee80211_scan_sw.c (revision 276517) +++ sys/net80211/ieee80211_scan_sw.c (working copy) @@ -46,6 +46,8 @@ #include +#include + #include struct scan_state { @@ -101,7 +103,7 @@ MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state"); void -ieee80211_scan_attach(struct ieee80211com *ic) +ieee80211_swscan_attach(struct ieee80211com *ic) { struct scan_state *ss; @@ -114,15 +116,20 @@ callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0); cv_init(&ss->ss_scan_cv, "scan"); TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss); + ic->ic_scan = &ss->base; ss->base.ss_ic = ic; ic->ic_scan_curchan = scan_curchan; ic->ic_scan_mindwell = scan_mindwell; + + /* + * TODO: all of the non-vap scan calls should be methods! + */ } void -ieee80211_scan_detach(struct ieee80211com *ic) +ieee80211_swscan_detach(struct ieee80211com *ic) { struct ieee80211_scan_state *ss = ic->ic_scan; @@ -135,6 +142,14 @@ callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer); KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scan still running")); + + /* + * For now, do the ss_ops detach here rather + * than ieee80211_scan_detach(). + * + * I'll figure out how to cleanly split things up + * at a later date. + */ if (ss->ss_ops != NULL) { ss->ss_ops->scan_detach(ss); ss->ss_ops = NULL; @@ -144,47 +159,23 @@ } } -static const struct ieee80211_roamparam defroam[IEEE80211_MODE_MAX] = { - [IEEE80211_MODE_11A] = { .rssi = ROAM_RSSI_11A_DEFAULT, - .rate = ROAM_RATE_11A_DEFAULT }, - [IEEE80211_MODE_11G] = { .rssi = ROAM_RSSI_11B_DEFAULT, - .rate = ROAM_RATE_11B_DEFAULT }, - [IEEE80211_MODE_11B] = { .rssi = ROAM_RSSI_11BONLY_DEFAULT, - .rate = ROAM_RATE_11BONLY_DEFAULT }, - [IEEE80211_MODE_TURBO_A]= { .rssi = ROAM_RSSI_11A_DEFAULT, - .rate = ROAM_RATE_11A_DEFAULT }, - [IEEE80211_MODE_TURBO_G]= { .rssi = ROAM_RSSI_11A_DEFAULT, - .rate = ROAM_RATE_11A_DEFAULT }, - [IEEE80211_MODE_STURBO_A]={ .rssi = ROAM_RSSI_11A_DEFAULT, - .rate = ROAM_RATE_11A_DEFAULT }, - [IEEE80211_MODE_HALF] = { .rssi = ROAM_RSSI_11A_DEFAULT, - .rate = ROAM_RATE_HALF_DEFAULT }, - [IEEE80211_MODE_QUARTER]= { .rssi = ROAM_RSSI_11A_DEFAULT, - .rate = ROAM_RATE_QUARTER_DEFAULT }, - [IEEE80211_MODE_11NA] = { .rssi = ROAM_RSSI_11A_DEFAULT, - .rate = ROAM_MCS_11N_DEFAULT }, - [IEEE80211_MODE_11NG] = { .rssi = ROAM_RSSI_11B_DEFAULT, - .rate = ROAM_MCS_11N_DEFAULT }, -}; - void -ieee80211_scan_vattach(struct ieee80211vap *vap) +ieee80211_swscan_vattach(struct ieee80211vap *vap) { - vap->iv_bgscanidle = (IEEE80211_BGSCAN_IDLE_DEFAULT*1000)/hz; - vap->iv_bgscanintvl = IEEE80211_BGSCAN_INTVAL_DEFAULT*hz; - vap->iv_scanvalid = IEEE80211_SCAN_VALID_DEFAULT*hz; + /* nothing to do for now */ + /* + * TODO: all of the vap scan calls should be methods! + */ - vap->iv_roaming = IEEE80211_ROAMING_AUTO; - memcpy(vap->iv_roamparms, defroam, sizeof(defroam)); } void -ieee80211_scan_vdetach(struct ieee80211vap *vap) +ieee80211_swscan_vdetach(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_state *ss; - IEEE80211_LOCK(ic); + IEEE80211_LOCK_ASSERT(ic); ss = ic->ic_scan; if (ss != NULL && ss->ss_vap == vap) { if (ic->ic_flags & IEEE80211_F_SCAN) { @@ -191,122 +182,10 @@ SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT; scan_signal(ss); } - if (ss->ss_ops != NULL) { - ss->ss_ops->scan_detach(ss); - ss->ss_ops = NULL; - } - ss->ss_vap = NULL; } - IEEE80211_UNLOCK(ic); } -/* - * Simple-minded scanner module support. - */ -static const char *scan_modnames[IEEE80211_OPMODE_MAX] = { - "wlan_scan_sta", /* IEEE80211_M_IBSS */ - "wlan_scan_sta", /* IEEE80211_M_STA */ - "wlan_scan_wds", /* IEEE80211_M_WDS */ - "wlan_scan_sta", /* IEEE80211_M_AHDEMO */ - "wlan_scan_ap", /* IEEE80211_M_HOSTAP */ - "wlan_scan_monitor", /* IEEE80211_M_MONITOR */ - "wlan_scan_sta", /* IEEE80211_M_MBSS */ -}; -static const struct ieee80211_scanner *scanners[IEEE80211_OPMODE_MAX]; - -const struct ieee80211_scanner * -ieee80211_scanner_get(enum ieee80211_opmode mode) -{ - if (mode >= IEEE80211_OPMODE_MAX) - return NULL; - if (scanners[mode] == NULL) - ieee80211_load_module(scan_modnames[mode]); - return scanners[mode]; -} - -void -ieee80211_scanner_register(enum ieee80211_opmode mode, - const struct ieee80211_scanner *scan) -{ - if (mode >= IEEE80211_OPMODE_MAX) - return; - scanners[mode] = scan; -} - -void -ieee80211_scanner_unregister(enum ieee80211_opmode mode, - const struct ieee80211_scanner *scan) -{ - if (mode >= IEEE80211_OPMODE_MAX) - return; - if (scanners[mode] == scan) - scanners[mode] = NULL; -} - -void -ieee80211_scanner_unregister_all(const struct ieee80211_scanner *scan) -{ - int m; - - for (m = 0; m < IEEE80211_OPMODE_MAX; m++) - if (scanners[m] == scan) - scanners[m] = NULL; -} - -/* - * 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; - } -} - +/* XXX should be a global net80211 function */ static char channel_type(const struct ieee80211_channel *c) { @@ -328,145 +207,47 @@ } void -ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss) +ieee80211_swscan_set_scan_duration(struct ieee80211vap *vap, u_int duration) { - struct ieee80211com *ic = ss->ss_ic; - const char *sep; - int i; + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_scan_state *ss = ic->ic_scan; - sep = ""; - for (i = ss->ss_next; i < ss->ss_last; i++) { - const struct ieee80211_channel *c = ss->ss_chans[i]; + IEEE80211_LOCK_ASSERT(ic); - printf("%s%u%c", sep, ieee80211_chan2ieee(ic, c), - channel_type(c)); - sep = ", "; - } + /* NB: flush frames rx'd before 1st channel change */ + SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; + SCAN_PRIVATE(ss)->ss_duration = duration; } -#ifdef IEEE80211_DEBUG -static void -scan_dump(struct ieee80211_scan_state *ss) +void +ieee80211_swscan_run_scan_task(struct ieee80211vap *vap) { - struct ieee80211vap *vap = ss->ss_vap; - - if_printf(vap->iv_ifp, "scan set "); - ieee80211_scan_dump_channels(ss); - printf(" dwell min %lums max %lums\n", - ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(ss->ss_maxdwell)); -} -#endif /* IEEE80211_DEBUG */ - -static void -copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss, - int nssid, const struct ieee80211_scan_ssid ssids[]) -{ - if (nssid > IEEE80211_SCAN_MAX_SSID) { - /* XXX printf */ - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: too many ssid %d, ignoring all of them\n", - __func__, nssid); - return; - } - memcpy(ss->ss_ssid, ssids, nssid * sizeof(ssids[0])); - ss->ss_nssid = nssid; -} - -/* - * Start a scan unless one is already going. - */ -static int -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" : "" - ); - - scan_update_locked(vap, scan); - if (ss->ss_ops != NULL) { - if ((flags & IEEE80211_SCAN_NOSSID) == 0) - 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; - - /* NB: flush frames rx'd before 1st channel change */ - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; - SCAN_PRIVATE(ss)->ss_duration = 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)) - scan_dump(ss); -#endif /* IEEE80211_DEBUG */ - ic->ic_flags |= IEEE80211_F_SCAN; - ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); - } - 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; + ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); } /* * Start a scan unless one is already going. + * + * Called without the comlock held; grab the comlock as appropriate. */ int -ieee80211_start_scan(struct ieee80211vap *vap, int flags, - u_int duration, u_int mindwell, u_int maxdwell, - u_int nssid, const struct ieee80211_scan_ssid ssids[]) +ieee80211_swscan_start_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; - const struct ieee80211_scanner *scan; int result; - scan = ieee80211_scanner_get(vap->iv_opmode); - if (scan == NULL) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: no scanner support for %s mode\n", - __func__, ieee80211_opmode_name[vap->iv_opmode]); - /* XXX stat */ - return 0; - } + IEEE80211_UNLOCK_ASSERT(ic); IEEE80211_LOCK(ic); - result = start_scan_locked(scan, vap, flags, duration, + result = ieee80211_start_scan_locked(scan, vap, flags, duration, mindwell, maxdwell, nssid, ssids); IEEE80211_UNLOCK(ic); @@ -476,48 +257,23 @@ /* * 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! */ int -ieee80211_check_scan(struct ieee80211vap *vap, int flags, - u_int duration, u_int mindwell, u_int maxdwell, - u_int nssid, const struct ieee80211_scan_ssid ssids[]) +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; - const struct ieee80211_scanner *scan; int result; - scan = ieee80211_scanner_get(vap->iv_opmode); - if (scan == NULL) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: no scanner support for %s mode\n", - __func__, vap->iv_opmode); - /* XXX stat */ - return 0; - } + IEEE80211_LOCK_ASSERT(ic); - /* - * Check if there's a list of scan candidates already. - * XXX want more than the ap we're currently associated with - */ - - IEEE80211_LOCK(ic); - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: %s scan, %s%s%s%s%s\n" - , __func__ - , flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive" - , flags & IEEE80211_SCAN_FLUSH ? "flush" : "append" - , flags & IEEE80211_SCAN_NOPICK ? ", nopick" : "" - , flags & IEEE80211_SCAN_NOJOIN ? ", nojoin" : "" - , flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : "" - , flags & IEEE80211_SCAN_ONCE ? ", once" : "" - ); - - if (ss->ss_ops != scan) { - /* XXX re-use cache contents? e.g. adhoc<->sta */ - flags |= IEEE80211_SCAN_FLUSH; - } - scan_update_locked(vap, scan); if (ss->ss_ops != NULL) { /* XXX verify ss_ops matches vap->iv_opmode */ if ((flags & IEEE80211_SCAN_NOSSID) == 0) { @@ -525,7 +281,7 @@ * Update the ssid list and mark flags so if * we call start_scan it doesn't duplicate work. */ - copy_ssid(vap, ss, nssid, ssids); + ieee80211_scan_copy_ssid(vap, ss, nssid, ssids); flags |= IEEE80211_SCAN_NOSSID; } if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 && @@ -550,50 +306,29 @@ SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_DISCARD; if (result) { ieee80211_notify_scan_done(vap); - IEEE80211_UNLOCK(ic); return 1; } } } - result = start_scan_locked(scan, vap, flags, duration, + result = ieee80211_start_scan_locked(scan, vap, flags, duration, mindwell, maxdwell, nssid, ssids); - IEEE80211_UNLOCK(ic); return result; } /* - * Check the scan cache for an ap/channel to use; if that fails - * then kick off a scan using the current settings. - */ -int -ieee80211_check_scan_current(struct ieee80211vap *vap) -{ - return ieee80211_check_scan(vap, - IEEE80211_SCAN_ACTIVE, - IEEE80211_SCAN_FOREVER, 0, 0, - vap->iv_des_nssid, vap->iv_des_ssid); -} - -/* * Restart a previous scan. If the previous scan completed * then we start again using the existing channel list. */ int -ieee80211_bg_scan(struct ieee80211vap *vap, int flags) +ieee80211_swscan_bg_scan(const struct ieee80211_scanner *scan, + struct ieee80211vap *vap, int flags) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_state *ss = ic->ic_scan; - const struct ieee80211_scanner *scan; - scan = ieee80211_scanner_get(vap->iv_opmode); - if (scan == NULL) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, - "%s: no scanner support for %s mode\n", - __func__, vap->iv_opmode); - /* XXX stat */ - return 0; - } + /* XXX assert unlocked? */ + // IEEE80211_UNLOCK_ASSERT(ic); IEEE80211_LOCK(ic); if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { @@ -611,7 +346,7 @@ ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive", ticks, duration); - scan_update_locked(vap, scan); + ieee80211_scan_update_locked(vap, scan); if (ss->ss_ops != NULL) { ss->ss_vap = vap; /* @@ -650,13 +385,11 @@ ss->ss_ops->scan_start(ss, vap); #ifdef IEEE80211_DEBUG if (ieee80211_msg_scan(vap)) - scan_dump(ss); + ieee80211_scan_dump(ss); #endif /* IEEE80211_DEBUG */ } } - /* NB: flush frames rx'd before 1st channel change */ - SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD; - SCAN_PRIVATE(ss)->ss_duration = duration; + ieee80211_swscan_set_scan_duration(vap, duration); ss->ss_maxdwell = duration; ic->ic_flags |= IEEE80211_F_SCAN; ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN; @@ -679,7 +412,7 @@ * Cancel any scan currently going on for the specified vap. */ void -ieee80211_cancel_scan(struct ieee80211vap *vap) +ieee80211_swscan_cancel_scan(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_state *ss = ic->ic_scan; @@ -713,7 +446,7 @@ * Cancel any scan currently going on. */ void -ieee80211_cancel_anyscan(struct ieee80211vap *vap) +ieee80211_swscan_cancel_anyscan(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_state *ss = ic->ic_scan; @@ -747,7 +480,7 @@ * scanning themselves (e.g. for firmware-based devices). */ void -ieee80211_scan_next(struct ieee80211vap *vap) +ieee80211_swscan_scan_next(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_state *ss = ic->ic_scan; @@ -765,18 +498,15 @@ * channels (e.g. for firmware-based devices). */ void -ieee80211_scan_done(struct ieee80211vap *vap) +ieee80211_swscan_scan_done(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_state *ss; - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: called\n", __func__); + IEEE80211_LOCK_ASSERT(ic); - IEEE80211_LOCK(ic); ss = ic->ic_scan; - ss->ss_next = ss->ss_last; /* all channels are complete */ scan_signal(ss); - IEEE80211_UNLOCK(ic); } /* @@ -787,7 +517,7 @@ * then we'll transmit a probe request. */ void -ieee80211_probe_curchan(struct ieee80211vap *vap, int force) +ieee80211_swscan_probe_curchan(struct ieee80211vap *vap, int force) { struct ieee80211com *ic = vap->iv_ic; struct ieee80211_scan_state *ss = ic->ic_scan; @@ -794,10 +524,6 @@ struct ifnet *ifp = vap->iv_ifp; int i; - if ((ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) && !force) { - ic->ic_flags_ext |= IEEE80211_FEXT_PROBECHAN; - return; - } /* * Send directed probe requests followed by any * broadcast probe request. @@ -1114,60 +840,11 @@ #undef ISCAN_REP } -#ifdef IEEE80211_DEBUG -static void -dump_country(const uint8_t *ie) -{ - const struct ieee80211_country_ie *cie = - (const struct ieee80211_country_ie *) ie; - int i, nbands, schan, nchan; - - if (cie->len < 3) { - printf(" ", cie->len); - return; - } - printf(" country [%c%c%c", cie->cc[0], cie->cc[1], cie->cc[2]); - nbands = (cie->len - 3) / sizeof(cie->band[0]); - for (i = 0; i < nbands; i++) { - schan = cie->band[i].schan; - nchan = cie->band[i].nchan; - if (nchan != 1) - printf(" %u-%u,%u", schan, schan + nchan-1, - cie->band[i].maxtxpwr); - else - printf(" %u,%u", schan, cie->band[i].maxtxpwr); - } - printf("]"); -} - -static void -dump_probe_beacon(uint8_t subtype, int isnew, - const uint8_t mac[IEEE80211_ADDR_LEN], - const struct ieee80211_scanparams *sp, int rssi) -{ - - printf("[%s] %s%s on chan %u (bss chan %u) ", - ether_sprintf(mac), isnew ? "new " : "", - ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], - sp->chan, sp->bchan); - ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]); - printf(" rssi %d\n", rssi); - - if (isnew) { - printf("[%s] caps 0x%x bintval %u erp 0x%x", - ether_sprintf(mac), sp->capinfo, sp->bintval, sp->erp); - if (sp->country != NULL) - dump_country(sp->country); - printf("\n"); - } -} -#endif /* IEEE80211_DEBUG */ - /* * Process a beacon or probe response frame. */ void -ieee80211_add_scan(struct ieee80211vap *vap, +ieee80211_swscan_add_scan(struct ieee80211vap *vap, const struct ieee80211_scanparams *sp, const struct ieee80211_frame *wh, int subtype, int rssi, int noise) @@ -1187,7 +864,7 @@ return; #ifdef IEEE80211_DEBUG if (ieee80211_msg_scan(vap) && (ic->ic_flags & IEEE80211_F_SCAN)) - dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi); + ieee80211_scan_dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi); #endif if (ss->ss_ops != NULL && ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise)) { @@ -1213,97 +890,3 @@ } } -/* - * Timeout/age scan cache entries; called from sta timeout - * timer (XXX should be self-contained). - */ -void -ieee80211_scan_timeout(struct ieee80211com *ic) -{ - struct ieee80211_scan_state *ss = ic->ic_scan; - - if (ss->ss_ops != NULL) - ss->ss_ops->scan_age(ss); -} - -/* - * Mark a scan cache entry after a successful associate. - */ -void -ieee80211_scan_assoc_success(struct ieee80211vap *vap, const uint8_t mac[]) -{ - struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan; - - if (ss->ss_ops != NULL) { - IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_SCAN, - mac, "%s", __func__); - ss->ss_ops->scan_assoc_success(ss, mac); - } -} - -/* - * Demerit a scan cache entry after failing to associate. - */ -void -ieee80211_scan_assoc_fail(struct ieee80211vap *vap, - const uint8_t mac[], int reason) -{ - struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan; - - if (ss->ss_ops != NULL) { - IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_SCAN, mac, - "%s: reason %u", __func__, reason); - ss->ss_ops->scan_assoc_fail(ss, mac, reason); - } -} - -/* - * Iterate over the contents of the scan cache. - */ -void -ieee80211_scan_iterate(struct ieee80211vap *vap, - ieee80211_scan_iter_func *f, void *arg) -{ - struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan; - - if (ss->ss_ops != NULL) - ss->ss_ops->scan_iterate(ss, f, arg); -} - -/* - * Flush the contents of the scan cache. - */ -void -ieee80211_scan_flush(struct ieee80211vap *vap) -{ - struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan; - - if (ss->ss_ops != NULL && ss->ss_vap == vap) { - IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", __func__); - ss->ss_ops->scan_flush(ss); - } -} - -/* - * 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); -} Index: sys/net80211/ieee80211_scan_sw.h =================================================================== --- sys/net80211/ieee80211_scan_sw.h (revision 0) +++ sys/net80211/ieee80211_scan_sw.h (working copy) @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2015 Adrian Chadd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ +#ifndef __NET80211_IEEE80211_SCAN_SW_H__ +#define __NET80211_IEEE80211_SCAN_SW_H__ + +extern void ieee80211_swscan_attach(struct ieee80211com *ic); +extern void ieee80211_swscan_detach(struct ieee80211com *ic); + +extern void ieee80211_swscan_vattach(struct ieee80211vap *vap); +extern void ieee80211_swscan_vdetach(struct ieee80211vap *vap); + +extern int ieee80211_swscan_start_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[]); +extern void ieee80211_swscan_set_scan_duration(struct ieee80211vap *vap, + u_int duration); +extern void ieee80211_swscan_run_scan_task(struct ieee80211vap *vap); +extern 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[]); +extern int ieee80211_swscan_bg_scan(const struct ieee80211_scanner *scan, + struct ieee80211vap *vap, int flags); +extern void ieee80211_swscan_cancel_scan(struct ieee80211vap *vap); +extern void ieee80211_swscan_cancel_anyscan(struct ieee80211vap *vap); +extern void ieee80211_swscan_scan_next(struct ieee80211vap *vap); +extern void ieee80211_swscan_scan_done(struct ieee80211vap *vap); +extern void ieee80211_swscan_probe_curchan(struct ieee80211vap *vap, + int force); +extern void ieee80211_swscan_add_scan(struct ieee80211vap *vap, + const struct ieee80211_scanparams *sp, + const struct ieee80211_frame *wh, + int subtype, int rssi, int noise); + +#endif /* __NET80211_IEEE80211_SCAN_SW_H__ */ Property changes on: sys/net80211/ieee80211_scan_sw.h ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property