Author: avos
Date: Tue Nov 10 12:52:26 2015
New Revision: 290651
URL: https://svnweb.freebsd.org/changeset/base/290651

Log:
  urtwn(4): add IBSS mode support
  
  Tested with RTL8188EU, IBSS and STA modes.
  
  Reviewed by:  kevlo
  Approved by:  adrian (mentor)
  Differential Revision:        https://reviews.freebsd.org/D4038

Modified:
  head/sys/dev/usb/wlan/if_urtwn.c
  head/sys/dev/usb/wlan/if_urtwnvar.h

Modified: head/sys/dev/usb/wlan/if_urtwn.c
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwn.c    Tue Nov 10 12:20:22 2015        
(r290650)
+++ head/sys/dev/usb/wlan/if_urtwn.c    Tue Nov 10 12:52:26 2015        
(r290651)
@@ -228,10 +228,14 @@ static int                urtwn_setup_beacon(struct ur
 static void            urtwn_update_beacon(struct ieee80211vap *, int);
 static int             urtwn_tx_beacon(struct urtwn_softc *sc,
                            struct urtwn_vap *);
+static void            urtwn_tsf_task_adhoc(void *, int);
 static void            urtwn_tsf_sync_enable(struct urtwn_softc *,
                            struct ieee80211vap *);
 static void            urtwn_set_led(struct urtwn_softc *, int, int);
 static void            urtwn_set_mode(struct urtwn_softc *, uint8_t);
+static void            urtwn_ibss_recv_mgmt(struct ieee80211_node *,
+                           struct mbuf *, int,
+                           const struct ieee80211_rx_stats *, int, int);
 static int             urtwn_newstate(struct ieee80211vap *,
                            enum ieee80211_state, int);
 static void            urtwn_watchdog(void *);
@@ -449,6 +453,7 @@ urtwn_attach(device_t self)
        ic->ic_caps =
                  IEEE80211_C_STA               /* station mode */
                | IEEE80211_C_MONITOR           /* monitor mode */
+               | IEEE80211_C_IBSS              /* adhoc mode */
                | IEEE80211_C_HOSTAP            /* hostap mode */
                | IEEE80211_C_SHPREAMBLE        /* short preamble supported */
                | IEEE80211_C_SHSLOT            /* short slot time supported */
@@ -592,13 +597,18 @@ urtwn_vap_create(struct ieee80211com *ic
                return (NULL);
        }
 
-       if (opmode == IEEE80211_M_HOSTAP)
+       if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_IBSS)
                urtwn_init_beacon(sc, uvp);
 
        /* override state transition machine */
        uvp->newstate = vap->iv_newstate;
        vap->iv_newstate = urtwn_newstate;
        vap->iv_update_beacon = urtwn_update_beacon;
+       if (opmode == IEEE80211_M_IBSS) {
+               uvp->recv_mgmt = vap->iv_recv_mgmt;
+               vap->iv_recv_mgmt = urtwn_ibss_recv_mgmt;
+               TASK_INIT(&uvp->tsf_task_adhoc, 0, urtwn_tsf_task_adhoc, vap);
+       }
 
        /* complete setup */
        ieee80211_vap_attach(vap, ieee80211_media_change,
@@ -610,13 +620,13 @@ urtwn_vap_create(struct ieee80211com *ic
 static void
 urtwn_vap_delete(struct ieee80211vap *vap)
 {
+       struct ieee80211com *ic = vap->iv_ic;
        struct urtwn_vap *uvp = URTWN_VAP(vap);
-       enum ieee80211_opmode opmode = vap->iv_opmode;
 
-       if (opmode == IEEE80211_M_HOSTAP) {
-               if (uvp->bcn_mbuf != NULL)
-                       m_freem(uvp->bcn_mbuf);
-       }
+       if (uvp->bcn_mbuf != NULL)
+               m_freem(uvp->bcn_mbuf);
+       if (vap->iv_opmode == IEEE80211_M_IBSS)
+               ieee80211_draintask(ic, &uvp->tsf_task_adhoc);
        ieee80211_vap_detach(vap);
        free(uvp, M_80211_VAP);
 }
@@ -1611,8 +1621,50 @@ urtwn_tx_beacon(struct urtwn_softc *sc, 
 }
 
 static void
+urtwn_tsf_task_adhoc(void *arg, int pending)
+{
+       struct ieee80211vap *vap = arg;
+       struct urtwn_softc *sc = vap->iv_ic->ic_softc;
+       struct ieee80211_node *ni;
+       uint32_t reg;
+
+       URTWN_LOCK(sc);
+       ni = ieee80211_ref_node(vap->iv_bss);
+       reg = urtwn_read_1(sc, R92C_BCN_CTRL);
+
+       /* Accept beacons with the same BSSID. */
+       urtwn_set_rx_bssid_all(sc, 0);
+
+       /* Enable synchronization. */
+       reg &= ~R92C_BCN_CTRL_DIS_TSF_UDT0;
+       urtwn_write_1(sc, R92C_BCN_CTRL, reg);
+
+       /* Synchronize. */
+       usb_pause_mtx(&sc->sc_mtx, hz * ni->ni_intval * 5 / 1000);
+
+       /* Disable synchronization. */
+       reg |= R92C_BCN_CTRL_DIS_TSF_UDT0;
+       urtwn_write_1(sc, R92C_BCN_CTRL, reg);
+
+       /* Remove beacon filter. */
+       urtwn_set_rx_bssid_all(sc, 1);
+
+       /* Enable beaconing. */
+       urtwn_write_1(sc, R92C_MBID_NUM,
+           urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0);
+       reg |= R92C_BCN_CTRL_EN_BCN;
+
+       urtwn_write_1(sc, R92C_BCN_CTRL, reg);
+       ieee80211_free_node(ni);
+       URTWN_UNLOCK(sc);
+}
+
+static void
 urtwn_tsf_sync_enable(struct urtwn_softc *sc, struct ieee80211vap *vap)
 {
+       struct ieee80211com *ic = &sc->sc_ic;
+       struct urtwn_vap *uvp = URTWN_VAP(vap);
+
        /* Reset TSF. */
        urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0);
 
@@ -1623,6 +1675,9 @@ urtwn_tsf_sync_enable(struct urtwn_softc
                    urtwn_read_1(sc, R92C_BCN_CTRL) &
                    ~R92C_BCN_CTRL_DIS_TSF_UDT0);
                break;
+       case IEEE80211_M_IBSS:
+               ieee80211_runtask(ic, &uvp->tsf_task_adhoc);
+               break;
        case IEEE80211_M_HOSTAP:
                /* Enable beaconing. */
                urtwn_write_1(sc, R92C_MBID_NUM,
@@ -1674,6 +1729,37 @@ urtwn_set_mode(struct urtwn_softc *sc, u
        urtwn_write_1(sc, R92C_MSR, reg);
 }
 
+static void
+urtwn_ibss_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype,
+    const struct ieee80211_rx_stats *rxs,
+    int rssi, int nf)
+{
+       struct ieee80211vap *vap = ni->ni_vap;
+       struct urtwn_softc *sc = vap->iv_ic->ic_softc;
+       struct urtwn_vap *uvp = URTWN_VAP(vap);
+       uint64_t ni_tstamp, curr_tstamp;
+
+       uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf);
+
+       if (vap->iv_state == IEEE80211_S_RUN &&
+           (subtype == IEEE80211_FC0_SUBTYPE_BEACON ||
+           subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) {
+               ni_tstamp = le64toh(ni->ni_tstamp.tsf);
+#ifdef D3831
+               URTWN_LOCK(sc);
+               urtwn_get_tsf(sc, &curr_tstamp);
+               URTWN_UNLOCK(sc);
+               curr_tstamp = le64toh(curr_tstamp);
+
+               if (ni_tstamp >= curr_tstamp)
+                       (void) ieee80211_ibss_merge(ni);
+#else
+               (void) sc;
+               (void) curr_tstamp;
+#endif
+       }
+}
+
 static int
 urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
@@ -1757,6 +1843,9 @@ urtwn_newstate(struct ieee80211vap *vap,
                case IEEE80211_M_STA:
                        mode = R92C_MSR_INFRA;
                        break;
+               case IEEE80211_M_IBSS:
+                       mode = R92C_MSR_ADHOC;
+                       break;
                case IEEE80211_M_HOSTAP:
                        mode = R92C_MSR_AP;
                        break;
@@ -1794,13 +1883,14 @@ urtwn_newstate(struct ieee80211vap *vap,
 
                        if (vap->iv_opmode != IEEE80211_M_HOSTAP)
                                reg |= R92C_RCR_CBSSID_DATA;
-
-                       reg |= R92C_RCR_CBSSID_BCN;
+                       if (vap->iv_opmode != IEEE80211_M_IBSS)
+                               reg |= R92C_RCR_CBSSID_BCN;
 
                        urtwn_write_4(sc, R92C_RCR, reg);
                }
 
-               if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+               if (vap->iv_opmode == IEEE80211_M_HOSTAP ||
+                   vap->iv_opmode == IEEE80211_M_IBSS) {
                        error = urtwn_setup_beacon(sc, ni);
                        if (error != 0) {
                                device_printf(sc->sc_dev,
@@ -3007,6 +3097,7 @@ urtwn_rxfilter_init(struct urtwn_softc *
                    R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_BEACON));
                break;
        case IEEE80211_M_MONITOR:
+       case IEEE80211_M_IBSS:
                break;
        default:
                device_printf(sc->sc_dev, "%s: undefined opmode %d\n",
@@ -3335,7 +3426,9 @@ urtwn_scan_start(struct ieee80211com *ic
 
        URTWN_LOCK(sc);
        /* Receive beacons / probe responses from any BSSID. */
-       urtwn_set_rx_bssid_all(sc, 1);
+       if (ic->ic_opmode != IEEE80211_M_IBSS)
+               urtwn_set_rx_bssid_all(sc, 1);
+
        /* Set gain for scanning. */
        urtwn_set_gain(sc, 0x20);
        URTWN_UNLOCK(sc);
@@ -3348,8 +3441,9 @@ urtwn_scan_end(struct ieee80211com *ic)
 
        URTWN_LOCK(sc);
        /* Restore limitations. */
-       if (ic->ic_promisc == 0)
+       if (ic->ic_promisc == 0 && ic->ic_opmode != IEEE80211_M_IBSS)
                urtwn_set_rx_bssid_all(sc, 0);
+
        /* Set gain under link. */
        urtwn_set_gain(sc, 0x32);
        URTWN_UNLOCK(sc);
@@ -3393,6 +3487,9 @@ urtwn_set_promisc(struct urtwn_softc *sc
                case IEEE80211_M_HOSTAP:
                        mask2 |= R92C_RCR_CBSSID_BCN;
                        break;
+               case IEEE80211_M_IBSS:
+                       mask2 |= R92C_RCR_CBSSID_DATA;
+                       break;
                default:
                        device_printf(sc->sc_dev, "%s: undefined opmode %d\n",
                            __func__, vap->iv_opmode);

Modified: head/sys/dev/usb/wlan/if_urtwnvar.h
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwnvar.h Tue Nov 10 12:20:22 2015        
(r290650)
+++ head/sys/dev/usb/wlan/if_urtwnvar.h Tue Nov 10 12:52:26 2015        
(r290651)
@@ -87,13 +87,18 @@ struct urtwn_fw_info {
 };
 
 struct urtwn_vap {
-       struct ieee80211vap             vap;
+       struct ieee80211vap     vap;
 
-       struct r92c_tx_desc             bcn_desc;
-       struct mbuf                     *bcn_mbuf;
-
-       int                             (*newstate)(struct ieee80211vap *,
-                                           enum ieee80211_state, int);
+       struct r92c_tx_desc     bcn_desc;
+       struct mbuf             *bcn_mbuf;
+       struct task             tsf_task_adhoc;
+
+       int                     (*newstate)(struct ieee80211vap *,
+                                   enum ieee80211_state, int);
+       void                    (*recv_mgmt)(struct ieee80211_node *,
+                                   struct mbuf *, int,
+                                   const struct ieee80211_rx_stats *,
+                                   int, int);
 };
 #define        URTWN_VAP(vap)  ((struct urtwn_vap *)(vap))
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to