diff options
| author | Adrian Chadd <adrian@FreeBSD.org> | 2015-05-03 23:39:44 +0000 |
|---|---|---|
| committer | Adrian Chadd <adrian@FreeBSD.org> | 2015-05-03 23:39:44 +0000 |
| commit | a20c9aff424ac6c93e268dca47b13117d54d711d (patch) | |
| tree | 2bca9b36b2c3aba8a88d5663d77aa09fad6331fd /sys/dev/wpi | |
| parent | 5cacb17fa2852bc270e220da829328e5f4eacd3b (diff) | |
Notes
Diffstat (limited to 'sys/dev/wpi')
| -rw-r--r-- | sys/dev/wpi/if_wpi.c | 102 | ||||
| -rw-r--r-- | sys/dev/wpi/if_wpivar.h | 19 |
2 files changed, 107 insertions, 14 deletions
diff --git a/sys/dev/wpi/if_wpi.c b/sys/dev/wpi/if_wpi.c index 7447ef20261b..320961d73c3e 100644 --- a/sys/dev/wpi/if_wpi.c +++ b/sys/dev/wpi/if_wpi.c @@ -174,9 +174,13 @@ static int wpi_setregdomain(struct ieee80211com *, struct ieee80211_channel[]); static int wpi_read_eeprom_group(struct wpi_softc *, int); static int wpi_add_node_entry_adhoc(struct wpi_softc *); -static void wpi_node_free(struct ieee80211_node *); static struct ieee80211_node *wpi_node_alloc(struct ieee80211vap *, const uint8_t mac[IEEE80211_ADDR_LEN]); +static void wpi_node_free(struct ieee80211_node *); +static void wpi_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, int, + int); +static void wpi_restore_node(void *, struct ieee80211_node *); +static void wpi_restore_node_table(struct wpi_softc *, struct wpi_vap *); static int wpi_newstate(struct ieee80211vap *, enum ieee80211_state, int); static void wpi_calib_timeout(void *); static void wpi_rx_done(struct wpi_softc *, struct wpi_rx_desc *, @@ -654,6 +658,8 @@ wpi_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, /* Override with driver methods. */ vap->iv_key_set = wpi_key_set; vap->iv_key_delete = wpi_key_delete; + wvp->wv_recv_mgmt = vap->iv_recv_mgmt; + vap->iv_recv_mgmt = wpi_recv_mgmt; wvp->wv_newstate = vap->iv_newstate; vap->iv_newstate = wpi_newstate; vap->iv_update_beacon = wpi_update_beacon; @@ -1685,6 +1691,66 @@ wpi_check_bss_filter(struct wpi_softc *sc) return (sc->rxon.filter & htole32(WPI_FILTER_BSS)) != 0; } +static void +wpi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, int rssi, + int nf) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct wpi_softc *sc = vap->iv_ic->ic_ifp->if_softc; + struct wpi_vap *wvp = WPI_VAP(vap); + uint64_t ni_tstamp, rx_tstamp; + + wvp->wv_recv_mgmt(ni, m, subtype, rssi, nf); + + if (vap->iv_opmode == IEEE80211_M_IBSS && + vap->iv_state == IEEE80211_S_RUN && + (subtype == IEEE80211_FC0_SUBTYPE_BEACON || + subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { + ni_tstamp = le64toh(ni->ni_tstamp.tsf); + rx_tstamp = le64toh(sc->rx_tstamp); + + if (ni_tstamp >= rx_tstamp) { + DPRINTF(sc, WPI_DEBUG_STATE, + "ibss merge, tsf %ju tstamp %ju\n", + (uintmax_t)rx_tstamp, (uintmax_t)ni_tstamp); + (void) ieee80211_ibss_merge(ni); + } + } +} + +static void +wpi_restore_node(void *arg, struct ieee80211_node *ni) +{ + struct wpi_softc *sc = arg; + struct wpi_node *wn = WPI_NODE(ni); + int error; + + WPI_NT_LOCK(sc); + if (wn->id != WPI_ID_UNDEFINED) { + wn->id = WPI_ID_UNDEFINED; + if ((error = wpi_add_ibss_node(sc, ni)) != 0) { + device_printf(sc->sc_dev, + "%s: could not add IBSS node, error %d\n", + __func__, error); + } + } + WPI_NT_UNLOCK(sc); +} + +static void +wpi_restore_node_table(struct wpi_softc *sc, struct wpi_vap *wvp) +{ + struct ieee80211com *ic = sc->sc_ifp->if_l2com; + + /* Set group keys once. */ + WPI_NT_LOCK(sc); + wvp->wv_gtk = 0; + WPI_NT_UNLOCK(sc); + + ieee80211_iterate_nodes(&ic->ic_sta, wpi_restore_node, sc); + ieee80211_crypto_reload_keys(ic); +} + /** * Called by net80211 when ever there is a change to 80211 state machine */ @@ -1751,13 +1817,36 @@ wpi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) case IEEE80211_S_RUN: /* - * RUN -> RUN transition; Just restart the timers. + * RUN -> RUN transition: + * STA mode: Just restart the timers. + * IBSS mode: Process IBSS merge. */ if (vap->iv_state == IEEE80211_S_RUN) { - WPI_RXON_LOCK(sc); - wpi_calib_timeout(sc); - WPI_RXON_UNLOCK(sc); - break; + if (vap->iv_opmode != IEEE80211_M_IBSS) { + WPI_RXON_LOCK(sc); + wpi_calib_timeout(sc); + WPI_RXON_UNLOCK(sc); + break; + } else { + /* + * Drop the BSS_FILTER bit + * (there is no another way to change bssid). + */ + WPI_RXON_LOCK(sc); + sc->rxon.filter &= ~htole32(WPI_FILTER_BSS); + if ((error = wpi_send_rxon(sc, 0, 1)) != 0) { + device_printf(sc->sc_dev, + "%s: could not send RXON\n", + __func__); + } + WPI_RXON_UNLOCK(sc); + + /* Restore all what was lost. */ + wpi_restore_node_table(sc, wvp); + + /* XXX set conditionally? */ + wpi_updateedca(ic); + } } /* @@ -1945,6 +2034,7 @@ wpi_rx_done(struct wpi_softc *sc, struct wpi_rx_desc *desc, } ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); + sc->rx_tstamp = tail->tstamp; if (ieee80211_radiotap_active(ic)) { struct wpi_rx_radiotap_header *tap = &sc->sc_rxtap; diff --git a/sys/dev/wpi/if_wpivar.h b/sys/dev/wpi/if_wpivar.h index c20732fb021f..7a65b721f6c4 100644 --- a/sys/dev/wpi/if_wpivar.h +++ b/sys/dev/wpi/if_wpivar.h @@ -121,17 +121,19 @@ struct wpi_buf { }; struct wpi_vap { - struct ieee80211vap wv_vap; + struct ieee80211vap wv_vap; - struct wpi_buf wv_bcbuf; - struct ieee80211_beacon_offsets wv_boff; - struct mtx wv_mtx; + struct wpi_buf wv_bcbuf; + struct ieee80211_beacon_offsets wv_boff; + struct mtx wv_mtx; - uint32_t wv_gtk; -#define WPI_VAP_KEY(kid) (1 << kid) + uint32_t wv_gtk; +#define WPI_VAP_KEY(kid) (1 << kid) - int (*wv_newstate)(struct ieee80211vap *, - enum ieee80211_state, int); + int (*wv_newstate)(struct ieee80211vap *, + enum ieee80211_state, int); + void (*wv_recv_mgmt)(struct ieee80211_node *, + struct mbuf *, int, int, int); }; #define WPI_VAP(vap) ((struct wpi_vap *)(vap)) @@ -180,6 +182,7 @@ struct wpi_softc { uint32_t txq_active; struct wpi_rx_ring rxq; + uint64_t rx_tstamp; /* TX Thermal Callibration. */ struct callout calib_to; |
