diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2017-12-08 21:16:02 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2017-12-08 21:16:02 +0000 |
commit | 8dd7445ec11646a03591b357efe373d50259ad22 (patch) | |
tree | a06e8616a0dcf0a86323cc94ceccf649b81edb60 /sys/net80211 | |
parent | d1ff86bb1e72aebf0111a2f7ef8d27eafdcc16c3 (diff) |
Add support for background scanning to net80211 and iwm(4).
The iwm(4) driver will now roam between access points which share an SSID.
Use 'ifconfig iwm0 debug' and 'tail -f /var/log/messages' to watch it do so.
Tested by several people in various iterations.
As usual, let me know if you run into issues.
ok phessler deraadt
Diffstat (limited to 'sys/net80211')
-rw-r--r-- | sys/net80211/ieee80211.c | 30 | ||||
-rw-r--r-- | sys/net80211/ieee80211_input.c | 39 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 260 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 8 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.c | 9 | ||||
-rw-r--r-- | sys/net80211/ieee80211_var.h | 19 |
6 files changed, 309 insertions, 56 deletions
diff --git a/sys/net80211/ieee80211.c b/sys/net80211/ieee80211.c index ff788315911..9e92fbbae19 100644 --- a/sys/net80211/ieee80211.c +++ b/sys/net80211/ieee80211.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211.c,v 1.63 2017/09/05 12:02:21 stsp Exp $ */ +/* $OpenBSD: ieee80211.c,v 1.64 2017/12/08 21:16:01 stsp Exp $ */ /* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */ /*- @@ -72,6 +72,32 @@ void ieee80211_setbasicrates(struct ieee80211com *); int ieee80211_findrate(struct ieee80211com *, enum ieee80211_phymode, int); void +ieee80211_begin_bgscan(struct ifnet *ifp) +{ + struct ieee80211com *ic = (void *)ifp; + + if ((ic->ic_flags & IEEE80211_F_BGSCAN) || + ic->ic_state != IEEE80211_S_RUN) + return; + + if (ic->ic_bgscan_start != NULL && ic->ic_bgscan_start(ic) == 0) { + ic->ic_flags |= IEEE80211_F_BGSCAN; + if (ifp->if_flags & IFF_DEBUG) + printf("%s: begin background scan\n", ifp->if_xname); + + /* Driver calls ieee80211_end_scan() when done. */ + } +} + +void +ieee80211_bgscan_timeout(void *arg) +{ + struct ifnet *ifp = arg; + + ieee80211_begin_bgscan(ifp); +} + +void ieee80211_channel_init(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; @@ -158,6 +184,8 @@ ieee80211_ifattach(struct ifnet *ifp) ifp->if_priority = IF_WIRELESS_DEFAULT_PRIORITY; ieee80211_set_link_state(ic, LINK_STATE_DOWN); + + timeout_set(&ic->ic_bgscan_timeout, ieee80211_bgscan_timeout, ifp); } void diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index e7add1e4a75..be869244e40 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_input.c,v 1.196 2017/09/04 09:11:46 stsp Exp $ */ +/* $OpenBSD: ieee80211_input.c,v 1.197 2017/12/08 21:16:01 stsp Exp $ */ /*- * Copyright (c) 2001 Atsushi Onoe @@ -267,6 +267,14 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni, ni->ni_rssi = rxi->rxi_rssi; ni->ni_rstamp = rxi->rxi_tstamp; ni->ni_inact = 0; + + /* Cancel or start background scan based on RSSI. */ + if ((*ic->ic_node_checkrssi)(ic, ni)) + timeout_del(&ic->ic_bgscan_timeout); + else if (!timeout_pending(&ic->ic_bgscan_timeout) && + (ic->ic_flags & IEEE80211_F_BGSCAN) == 0) + timeout_add_msec(&ic->ic_bgscan_timeout, + 500 * (ic->ic_bgscan_fail + 1)); } #ifndef IEEE80211_STA_ONLY @@ -1504,7 +1512,8 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m, #ifdef IEEE80211_DEBUG if (ieee80211_debug > 1 && - (ni == NULL || ic->ic_state == IEEE80211_S_SCAN)) { + (ni == NULL || ic->ic_state == IEEE80211_S_SCAN || + (ic->ic_flags & IEEE80211_F_BGSCAN))) { printf("%s: %s%s on chan %u (bss chan %u) ", __func__, (ni == NULL ? "new " : ""), isprobe ? "probe response" : "beacon", @@ -1589,7 +1598,8 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m, * This probe response indicates the AP is still serving us * so don't allow ieee80211_watchdog() to move us into SCAN. */ - ic->ic_mgt_timer = 0; + if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0) + ic->ic_mgt_timer = 0; } /* * We do not try to update EDCA parameters if QoS was not negotiated @@ -1606,7 +1616,8 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m, ni->ni_flags &= ~IEEE80211_NODE_QOS; } - if (ic->ic_state == IEEE80211_S_SCAN) { + if (ic->ic_state == IEEE80211_S_SCAN || + (ic->ic_flags & IEEE80211_F_BGSCAN)) { struct ieee80211_rsnparams rsn, wpa; ni->ni_rsnprotos = IEEE80211_PROTO_NONE; @@ -2361,9 +2372,13 @@ ieee80211_recv_deauth(struct ieee80211com *ic, struct mbuf *m, ic->ic_stats.is_rx_deauth++; switch (ic->ic_opmode) { - case IEEE80211_M_STA: - ieee80211_new_state(ic, IEEE80211_S_AUTH, - IEEE80211_FC0_SUBTYPE_DEAUTH); + case IEEE80211_M_STA: { + int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) && + ic->ic_state == IEEE80211_S_RUN); + if (!bgscan) /* ignore deauth during bgscan */ + ieee80211_new_state(ic, IEEE80211_S_AUTH, + IEEE80211_FC0_SUBTYPE_DEAUTH); + } break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_HOSTAP: @@ -2407,9 +2422,13 @@ ieee80211_recv_disassoc(struct ieee80211com *ic, struct mbuf *m, ic->ic_stats.is_rx_disassoc++; switch (ic->ic_opmode) { - case IEEE80211_M_STA: - ieee80211_new_state(ic, IEEE80211_S_ASSOC, - IEEE80211_FC0_SUBTYPE_DISASSOC); + case IEEE80211_M_STA: { + int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) && + ic->ic_state == IEEE80211_S_RUN); + if (!bgscan) /* ignore disassoc during bgscan */ + ieee80211_new_state(ic, IEEE80211_S_ASSOC, + IEEE80211_FC0_SUBTYPE_DISASSOC); + } break; #ifndef IEEE80211_STA_ONLY case IEEE80211_M_HOSTAP: diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index aac5308668f..c0675b17958 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.c,v 1.121 2017/09/05 14:56:59 stsp Exp $ */ +/* $OpenBSD: ieee80211_node.c,v 1.122 2017/12/08 21:16:01 stsp Exp $ */ /* $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $ */ /*- @@ -65,12 +65,16 @@ void ieee80211_node_copy(struct ieee80211com *, struct ieee80211_node *, void ieee80211_choose_rsnparams(struct ieee80211com *); u_int8_t ieee80211_node_getrssi(struct ieee80211com *, const struct ieee80211_node *); +int ieee80211_node_checkrssi(struct ieee80211com *, + const struct ieee80211_node *); void ieee80211_setup_node(struct ieee80211com *, struct ieee80211_node *, const u_int8_t *); void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *); void ieee80211_ba_del(struct ieee80211_node *); struct ieee80211_node *ieee80211_alloc_node_helper(struct ieee80211com *); void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node *); +void ieee80211_node_switch_bss(struct ieee80211com *, struct ieee80211_node *); +void ieee80211_node_join_bss(struct ieee80211com *, struct ieee80211_node *); void ieee80211_needs_auth(struct ieee80211com *, struct ieee80211_node *); #ifndef IEEE80211_STA_ONLY void ieee80211_node_join_ht(struct ieee80211com *, struct ieee80211_node *); @@ -128,6 +132,7 @@ ieee80211_node_attach(struct ifnet *ifp) ic->ic_node_free = ieee80211_node_free; ic->ic_node_copy = ieee80211_node_copy; ic->ic_node_getrssi = ieee80211_node_getrssi; + ic->ic_node_checkrssi = ieee80211_node_checkrssi; ic->ic_scangen = 1; ic->ic_max_nnodes = ieee80211_cache_size; @@ -546,6 +551,113 @@ ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni) return fail; } +struct ieee80211_node_switch_bss_arg { + u_int8_t cur_macaddr[IEEE80211_ADDR_LEN]; + u_int8_t sel_macaddr[IEEE80211_ADDR_LEN]; +}; + +/* Implements ni->ni_unref_cb(). */ +void +ieee80211_node_switch_bss(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + struct ifnet *ifp = &ic->ic_if; + struct ieee80211_node_switch_bss_arg *sba = ni->ni_unref_arg; + struct ieee80211_node *curbs, *selbs; + + splassert(IPL_NET); + + if ((ic->ic_flags & IEEE80211_F_BGSCAN) == 0) { + free(sba, M_DEVBUF, sizeof(*sba)); + return; + } + + ic->ic_xflags &= ~IEEE80211_F_TX_MGMT_ONLY; + + selbs = ieee80211_find_node(ic, sba->sel_macaddr); + if (selbs == NULL) { + free(sba, M_DEVBUF, sizeof(*sba)); + ic->ic_flags &= ~IEEE80211_F_BGSCAN; + ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); + return; + } + + curbs = ieee80211_find_node(ic, sba->cur_macaddr); + if (curbs == NULL) { + free(sba, M_DEVBUF, sizeof(*sba)); + ic->ic_flags &= ~IEEE80211_F_BGSCAN; + ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); + return; + } + + if (ifp->if_flags & IFF_DEBUG) { + printf("%s: roaming from %s chan %d ", + ifp->if_xname, ether_sprintf(curbs->ni_macaddr), + ieee80211_chan2ieee(ic, curbs->ni_chan)); + printf("to %s chan %d\n", ether_sprintf(selbs->ni_macaddr), + ieee80211_chan2ieee(ic, selbs->ni_chan)); + } + ieee80211_node_newstate(curbs, IEEE80211_STA_CACHE); + ieee80211_node_join_bss(ic, selbs); /* frees arg and ic->ic_bss */ +} + +void +ieee80211_node_join_bss(struct ieee80211com *ic, struct ieee80211_node *selbs) +{ + enum ieee80211_phymode mode; + struct ieee80211_node *ni; + + /* Reinitialize media mode and channels if needed. */ + mode = ieee80211_chan2mode(ic, selbs->ni_chan); + if (mode != ic->ic_curmode) + ieee80211_setmode(ic, mode); + + (*ic->ic_node_copy)(ic, ic->ic_bss, selbs); + ni = ic->ic_bss; + + ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan); + + /* Make sure we send valid rates in an association request. */ + if (ic->ic_opmode == IEEE80211_M_STA) + ieee80211_fix_rate(ic, ni, + IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | + IEEE80211_F_DONEGO | IEEE80211_F_DODEL); + + if (ic->ic_flags & IEEE80211_F_RSNON) + ieee80211_choose_rsnparams(ic); + else if (ic->ic_flags & IEEE80211_F_WEPON) + ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP; + + ieee80211_node_newstate(selbs, IEEE80211_STA_BSS); +#ifndef IEEE80211_STA_ONLY + if (ic->ic_opmode == IEEE80211_M_IBSS) { + ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE | + IEEE80211_F_DONEGO | IEEE80211_F_DODEL); + if (ni->ni_rates.rs_nrates == 0) { + ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); + return; + } + ieee80211_new_state(ic, IEEE80211_S_RUN, -1); + } else +#endif + { + int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) && + ic->ic_opmode == IEEE80211_M_STA && + ic->ic_state == IEEE80211_S_RUN); + + timeout_del(&ic->ic_bgscan_timeout); + ic->ic_flags &= ~IEEE80211_F_BGSCAN; + + /* + * After a background scan, we have now switched APs. + * Pretend we were just de-authed, which makes + * ieee80211_new_state() try to re-auth and thus send + * an AUTH frame to our newly selected AP. + */ + ieee80211_new_state(ic, IEEE80211_S_AUTH, + bgscan ? IEEE80211_FC0_SUBTYPE_DEAUTH : -1); + } +} + /* * Complete a scan of potential channels. */ @@ -553,12 +665,16 @@ void ieee80211_end_scan(struct ifnet *ifp) { struct ieee80211com *ic = (void *)ifp; - struct ieee80211_node *ni, *nextbs, *selbs; + struct ieee80211_node *ni, *nextbs, *selbs, *curbs; + int bgscan = ((ic->ic_flags & IEEE80211_F_BGSCAN) && + ic->ic_opmode == IEEE80211_M_STA && + ic->ic_state == IEEE80211_S_RUN); if (ifp->if_flags & IFF_DEBUG) printf("%s: end %s scan\n", ifp->if_xname, - (ic->ic_flags & IEEE80211_F_ASCAN) ? - "active" : "passive"); + bgscan ? "background" : + ((ic->ic_flags & IEEE80211_F_ASCAN) ? + "active" : "passive")); if (ic->ic_scan_count) ic->ic_flags &= ~IEEE80211_F_ASCAN; @@ -634,6 +750,7 @@ ieee80211_end_scan(struct ifnet *ifp) return; } selbs = NULL; + curbs = NULL; for (; ni != NULL; ni = nextbs) { nextbs = RBT_NEXT(ieee80211_tree, ni); @@ -647,6 +764,10 @@ ieee80211_end_scan(struct ifnet *ifp) ieee80211_free_node(ic, ni); continue; } + + if (bgscan && ieee80211_node_cmp(ic->ic_bss, ni) == 0) + curbs = ni; + if (ieee80211_match_bss(ic, ni) != 0) continue; @@ -657,21 +778,17 @@ ieee80211_end_scan(struct ifnet *ifp) IEEE80211_IS_CHAN_5GHZ(selbs->ni_chan) && IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) && ni->ni_rssi > selbs->ni_rssi) { - uint8_t min_rssi = 0, max_rssi = ic->ic_max_rssi; + uint8_t min_rssi; /* * Prefer 5GHz (with reasonable RSSI) over 2GHz since * the 5GHz band is usually less saturated. */ - if (max_rssi) { - /* Driver reports RSSI relative to maximum. */ - if (ni->ni_rssi > max_rssi / 3) - min_rssi = ni->ni_rssi - (max_rssi / 3); - } else { - /* Driver reports RSSI value in dBm. */ - if (ni->ni_rssi > 10) /* XXX magic number */ - min_rssi = ni->ni_rssi - 10; - } + if (ic->ic_max_rssi) + min_rssi = IEEE80211_RSSI_THRES_RATIO_5GHZ; + else + min_rssi = (uint8_t)IEEE80211_RSSI_THRES_5GHZ; + if (selbs->ni_rssi >= min_rssi) continue; } @@ -679,35 +796,65 @@ ieee80211_end_scan(struct ifnet *ifp) if (ni->ni_rssi > selbs->ni_rssi) selbs = ni; } - if (selbs == NULL) - goto notfound; - (*ic->ic_node_copy)(ic, ic->ic_bss, selbs); - ni = ic->ic_bss; - ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan); + if (bgscan) { + struct ieee80211_node_switch_bss_arg *arg; - /* Make sure we send valid rates in an association request. */ - if (ic->ic_opmode == IEEE80211_M_STA) - ieee80211_fix_rate(ic, ni, - IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | - IEEE80211_F_DONEGO | IEEE80211_F_DODEL); + /* AP disappeared? Should not happen. */ + if (selbs == NULL || curbs == NULL) { + ic->ic_flags &= ~IEEE80211_F_BGSCAN; + goto notfound; + } - if (ic->ic_flags & IEEE80211_F_RSNON) - ieee80211_choose_rsnparams(ic); - else if (ic->ic_flags & IEEE80211_F_WEPON) - ni->ni_rsncipher = IEEE80211_CIPHER_USEGROUP; + /* + * After a background scan we might end up choosing the + * same AP again. Do not change ic->ic_bss in this case, + * and make background scans less frequent. + */ + if (selbs == curbs) { + if (ic->ic_bgscan_fail < IEEE80211_BGSCAN_FAIL_MAX) + ic->ic_bgscan_fail++; + ic->ic_flags &= ~IEEE80211_F_BGSCAN; + goto wakeup; + } + + arg = malloc(sizeof(*arg), M_DEVBUF, M_NOWAIT | M_ZERO); + if (arg == NULL) { + ic->ic_flags &= ~IEEE80211_F_BGSCAN; + goto wakeup; + } - ieee80211_node_newstate(selbs, IEEE80211_STA_BSS); -#ifndef IEEE80211_STA_ONLY - if (ic->ic_opmode == IEEE80211_M_IBSS) { - ieee80211_fix_rate(ic, ni, IEEE80211_F_DOFRATE | - IEEE80211_F_DONEGO | IEEE80211_F_DODEL); - if (ni->ni_rates.rs_nrates == 0) - goto notfound; - ieee80211_new_state(ic, IEEE80211_S_RUN, -1); - } else -#endif - ieee80211_new_state(ic, IEEE80211_S_AUTH, -1); + ic->ic_bgscan_fail = 0; + + /* + * We are going to switch APs. + * Queue a de-auth frame addressed to our current AP. + */ + if (IEEE80211_SEND_MGMT(ic, ic->ic_bss, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_AUTH_LEAVE) != 0) { + ic->ic_flags &= ~IEEE80211_F_BGSCAN; + goto wakeup; + } + + /* Prevent dispatch of additional data frames to hardware. */ + ic->ic_xflags |= IEEE80211_F_TX_MGMT_ONLY; + + /* + * Install a callback which will switch us to the new AP once + * all dispatched frames have been processed by hardware. + */ + IEEE80211_ADDR_COPY(arg->cur_macaddr, curbs->ni_macaddr); + IEEE80211_ADDR_COPY(arg->sel_macaddr, selbs->ni_macaddr); + ic->ic_bss->ni_unref_arg = arg; + ic->ic_bss->ni_unref_arg_size = sizeof(*arg); + ic->ic_bss->ni_unref_cb = ieee80211_node_switch_bss; + /* F_BGSCAN flag gets cleared in ieee80211_node_join_bss(). */ + goto wakeup; + } else if (selbs == NULL) + goto notfound; + + ieee80211_node_join_bss(ic, selbs); wakeup: if (ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) { @@ -808,6 +955,9 @@ ieee80211_node_cleanup(struct ieee80211com *ic, struct ieee80211_node *ni) ni->ni_rsnie = NULL; } ieee80211_ba_del(ni); + free(ni->ni_unref_arg, M_DEVBUF, ni->ni_unref_arg_size); + ni->ni_unref_arg = NULL; + ni->ni_unref_arg_size = 0; } void @@ -835,6 +985,25 @@ ieee80211_node_getrssi(struct ieee80211com *ic, return ni->ni_rssi; } +int +ieee80211_node_checkrssi(struct ieee80211com *ic, + const struct ieee80211_node *ni) +{ + uint8_t thres; + + if (ic->ic_max_rssi) { + thres = (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) ? + IEEE80211_RSSI_THRES_RATIO_2GHZ : + IEEE80211_RSSI_THRES_RATIO_5GHZ; + return ((ni->ni_rssi * 100) / ic->ic_max_rssi >= thres); + } + + thres = (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) ? + IEEE80211_RSSI_THRES_2GHZ : + IEEE80211_RSSI_THRES_5GHZ; + return (ni->ni_rssi >= (u_int8_t)thres); +} + void ieee80211_setup_node(struct ieee80211com *ic, struct ieee80211_node *ni, const u_int8_t *macaddr) @@ -1177,9 +1346,16 @@ ieee80211_release_node(struct ieee80211com *ic, struct ieee80211_node *ni) DPRINTF(("%s refcnt %u\n", ether_sprintf(ni->ni_macaddr), ni->ni_refcnt)); s = splnet(); - if (ieee80211_node_decref(ni) == 0 && - ni->ni_state == IEEE80211_STA_COLLECT) { - ieee80211_free_node(ic, ni); + if (ieee80211_node_decref(ni) == 0) { + if (ni->ni_unref_cb) { + (*ni->ni_unref_cb)(ic, ni); + ni->ni_unref_cb = NULL; + /* Freed by callback if necessary: */ + ni->ni_unref_arg = NULL; + ni->ni_unref_arg_size = 0; + } + if (ni->ni_state == IEEE80211_STA_COLLECT) + ieee80211_free_node(ic, ni); } splx(s); } diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index fc088b3324f..2a5b0f1f0dc 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.h,v 1.69 2017/08/17 06:01:05 stsp Exp $ */ +/* $OpenBSD: ieee80211_node.h,v 1.70 2017/12/08 21:16:01 stsp Exp $ */ /* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */ /*- @@ -297,6 +297,12 @@ struct ieee80211_node { #define IEEE80211_NODE_SA_QUERY 0x0800 /* SA Query in progress */ #define IEEE80211_NODE_SA_QUERY_FAILED 0x1000 /* last SA Query failed */ #define IEEE80211_NODE_RSN_NEW_PTK 0x2000 /* expecting a new PTK */ + + /* If not NULL, this function gets called when ni_refcnt hits zero. */ + void (*ni_unref_cb)(struct ieee80211com *, + struct ieee80211_node *); + void * ni_unref_arg; + size_t ni_unref_arg_size; }; RBT_HEAD(ieee80211_tree, ieee80211_node); diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c index c0978acfc31..8f6d804ae77 100644 --- a/sys/net80211/ieee80211_proto.c +++ b/sys/net80211/ieee80211_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_proto.c,v 1.80 2017/08/18 17:30:12 stsp Exp $ */ +/* $OpenBSD: ieee80211_proto.c,v 1.81 2017/12/08 21:16:01 stsp Exp $ */ /* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */ /*- @@ -853,6 +853,7 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, ic->ic_state = nstate; /* state transition */ ni = ic->ic_bss; /* NB: no reference held */ ieee80211_set_link_state(ic, LINK_STATE_DOWN); + ic->ic_xflags &= ~IEEE80211_F_TX_MGMT_ONLY; switch (nstate) { case IEEE80211_S_INIT: /* @@ -919,6 +920,8 @@ justcleanup: if (ic->ic_opmode == IEEE80211_M_HOSTAP) timeout_del(&ic->ic_rsn_timeout); #endif + timeout_del(&ic->ic_bgscan_timeout); + ic->ic_bgscan_fail = 0; ic->ic_mgt_timer = 0; mq_purge(&ic->ic_mgtq); mq_purge(&ic->ic_pwrsaveq); @@ -968,6 +971,8 @@ justcleanup: " rescanning\n", ifp->if_xname, ether_sprintf(ic->ic_bss->ni_bssid)); } + timeout_del(&ic->ic_bgscan_timeout); + ic->ic_bgscan_fail = 0; ieee80211_free_allnodes(ic); /* FALLTHROUGH */ case IEEE80211_S_AUTH: @@ -1008,6 +1013,8 @@ justcleanup: } break; case IEEE80211_S_RUN: + timeout_del(&ic->ic_bgscan_timeout); + ic->ic_bgscan_fail = 0; switch (mgt) { case IEEE80211_FC0_SUBTYPE_AUTH: IEEE80211_SEND_MGMT(ic, ni, diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 593860863c1..51c3c56cbf0 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_var.h,v 1.81 2017/11/06 11:34:29 phessler Exp $ */ +/* $OpenBSD: ieee80211_var.h,v 1.82 2017/12/08 21:16:01 stsp Exp $ */ /* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */ /*- @@ -57,6 +57,13 @@ #define IEEE80211_TXPOWER_MAX 100 /* max power */ #define IEEE80211_TXPOWER_MIN -50 /* kill radio (if possible) */ +#define IEEE80211_RSSI_THRES_2GHZ (-60) /* in dBm */ +#define IEEE80211_RSSI_THRES_5GHZ (-70) /* in dBm */ +#define IEEE80211_RSSI_THRES_RATIO_2GHZ 60 /* in percent */ +#define IEEE80211_RSSI_THRES_RATIO_5GHZ 50 /* in percent */ + +#define IEEE80211_BGSCAN_FAIL_MAX 360 /* units of 500 msec */ + enum ieee80211_phytype { IEEE80211_T_DS, /* direct sequence spread spectrum */ IEEE80211_T_OFDM, /* frequency division multiplexing */ @@ -220,6 +227,9 @@ struct ieee80211com { struct ieee80211_node *, u_int8_t); void (*ic_update_htprot)(struct ieee80211com *, struct ieee80211_node *); + int (*ic_bgscan_start)(struct ieee80211com *); + struct timeout ic_bgscan_timeout; + uint32_t ic_bgscan_fail; u_int8_t ic_myaddr[IEEE80211_ADDR_LEN]; struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX]; struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1]; @@ -231,6 +241,7 @@ struct ieee80211com { u_int ic_scan_lock; /* user-initiated scan */ u_int8_t ic_scan_count; /* count scans */ u_int32_t ic_flags; /* state flags */ + u_int32_t ic_xflags; /* more flags */ u_int32_t ic_caps; /* capabilities */ u_int16_t ic_modecaps; /* set of mode capabilities */ u_int16_t ic_curmode; /* current mode */ @@ -256,6 +267,8 @@ struct ieee80211com { const struct ieee80211_node *); u_int8_t (*ic_node_getrssi)(struct ieee80211com *, const struct ieee80211_node *); + int (*ic_node_checkrssi)(struct ieee80211com *, + const struct ieee80211_node *); u_int8_t ic_max_rssi; struct ieee80211_tree ic_tree; int ic_nnodes; /* length of ic_nnodes */ @@ -352,8 +365,12 @@ extern struct ieee80211com_head ieee80211com_head; #define IEEE80211_F_MFPR 0x01000000 /* CONF: MFP required */ #define IEEE80211_F_HTON 0x02000000 /* CONF: HT enabled */ #define IEEE80211_F_PBAR 0x04000000 /* CONF: PBAC required */ +#define IEEE80211_F_BGSCAN 0x08000000 /* STATUS: background scan */ #define IEEE80211_F_USERMASK 0xf0000000 /* CONF: ioctl flag mask */ +/* ic_xflags */ +#define IEEE80211_F_TX_MGMT_ONLY 0x00000001 /* leave data frames on ifq */ + /* ic_caps */ #define IEEE80211_C_WEP 0x00000001 /* CAPABILITY: WEP available */ #define IEEE80211_C_IBSS 0x00000002 /* CAPABILITY: IBSS available */ |