summaryrefslogtreecommitdiff
path: root/sys/dev/wpi
diff options
context:
space:
mode:
authorAdrian Chadd <adrian@FreeBSD.org>2015-05-03 23:39:44 +0000
committerAdrian Chadd <adrian@FreeBSD.org>2015-05-03 23:39:44 +0000
commita20c9aff424ac6c93e268dca47b13117d54d711d (patch)
tree2bca9b36b2c3aba8a88d5663d77aa09fad6331fd /sys/dev/wpi
parent5cacb17fa2852bc270e220da829328e5f4eacd3b (diff)
Notes
Diffstat (limited to 'sys/dev/wpi')
-rw-r--r--sys/dev/wpi/if_wpi.c102
-rw-r--r--sys/dev/wpi/if_wpivar.h19
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;