Author: adrian
Date: Sun May  3 23:39:44 2015
New Revision: 282401
URL: https://svnweb.freebsd.org/changeset/base/282401

Log:
  Handle properly IBSS merges (works with patch from bug 199632).
  
  PR:           kern/197143
  Submitted by: Andriy Voskoboinyk <s3er...@gmail.com>

Modified:
  head/sys/dev/wpi/if_wpi.c
  head/sys/dev/wpi/if_wpivar.h

Modified: head/sys/dev/wpi/if_wpi.c
==============================================================================
--- head/sys/dev/wpi/if_wpi.c   Sun May  3 23:39:02 2015        (r282400)
+++ head/sys/dev/wpi/if_wpi.c   Sun May  3 23:39:44 2015        (r282401)
@@ -174,9 +174,13 @@ static int wpi_setregdomain(struct ieee8
                    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, 
        /* 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 *s
        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, e
 
        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
        }
 
        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;

Modified: head/sys/dev/wpi/if_wpivar.h
==============================================================================
--- head/sys/dev/wpi/if_wpivar.h        Sun May  3 23:39:02 2015        
(r282400)
+++ head/sys/dev/wpi/if_wpivar.h        Sun May  3 23:39:44 2015        
(r282401)
@@ -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;
-
-       uint32_t                        wv_gtk;
-#define WPI_VAP_KEY(kid)               (1 << kid)
-
-       int                             (*wv_newstate)(struct ieee80211vap *,
-                                           enum ieee80211_state, int);
+       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)
+
+       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;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to