Handle properly IBSS merges (works with patch from bug 199632).

PR:		kern/197143
Submitted by:	Andriy Voskoboinyk <s3erios@gmail.com>
This commit is contained in:
Adrian Chadd 2015-05-03 23:39:44 +00:00
parent 5cacb17fa2
commit a20c9aff42
2 changed files with 107 additions and 14 deletions

View File

@ -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;

View File

@ -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;