Author: bschmidt
Date: Sat Apr 10 13:54:00 2010
New Revision: 206457
URL: http://svn.freebsd.org/changeset/base/206457

Log:
  Add WPA-None support:
  * WPA-None requires ap_scan=2:
    The major difference between ap_scan=1 (default) and 2 is, that no
    IEEE80211_IOC_SCAN* ioctls/functions are called, though, there is a
    dependency on those. For example the call to wpa_driver_bsd_scan()
    sets the interface UP, this never happens, therefore the interface
    must be marked up in wpa_driver_bsd_associate(). IEEE80211_IOC_SSID
    also is not called, which means that the SSID has not been set prior
    to the IEEE80211_MLME_ASSOC call.
  * WPA-None has no support for sequence number updates, it doesn't make
    sense to check for replay violations..
  * I had some crashes right after the switch to RUN state, issue is
    that sc->sc_lastrs was not yet defined.
  
  Approved by:  rpaulo (mentor)
  MFC after:    3 weeks

Modified:
  head/sys/dev/ath/if_ath.c
  head/sys/net80211/ieee80211_crypto_ccmp.c
  head/sys/net80211/ieee80211_crypto_tkip.c
  head/sys/net80211/ieee80211_ioctl.c
  head/usr.sbin/wpa/wpa_supplicant/driver_freebsd.c
  head/usr.sbin/wpa/wpa_supplicant/wpa_supplicant.conf.5

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c   Sat Apr 10 12:47:06 2010        (r206456)
+++ head/sys/dev/ath/if_ath.c   Sat Apr 10 13:54:00 2010        (r206457)
@@ -3654,8 +3654,14 @@ ath_recv_mgmt(struct ieee80211_node *ni,
        case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
                if (vap->iv_opmode == IEEE80211_M_IBSS &&
                    vap->iv_state == IEEE80211_S_RUN) {
-                       uint32_t rstamp = sc->sc_lastrs->rs_tstamp;
-                       u_int64_t tsf = ath_extend_tsf(rstamp,
+                       uint32_t rstamp;
+                       uint64_t tsf;
+
+                       if (sc->sc_lastrs == NULL)
+                               break;
+
+                       rstamp = sc->sc_lastrs->rs_tstamp;
+                       tsf = ath_extend_tsf(rstamp,
                                ath_hal_gettsf64(sc->sc_ah));
                        /*
                         * Handle ibss merge as needed; check the tsf on the

Modified: head/sys/net80211/ieee80211_crypto_ccmp.c
==============================================================================
--- head/sys/net80211/ieee80211_crypto_ccmp.c   Sat Apr 10 12:47:06 2010        
(r206456)
+++ head/sys/net80211/ieee80211_crypto_ccmp.c   Sat Apr 10 13:54:00 2010        
(r206457)
@@ -226,7 +226,14 @@ ccmp_decap(struct ieee80211_key *k, stru
        }
        tid = ieee80211_gettid(wh);
        pn = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
-       if (pn <= k->wk_keyrsc[tid]) {
+       /*
+        * NB: Multiple stations are using the same key in
+        * IBSS mode, there is currently no way to sync keyrsc
+        * counters without discarding too many frames.
+        */
+       if (vap->iv_opmode != IEEE80211_M_IBSS &&
+           vap->iv_opmode != IEEE80211_M_AHDEMO &&
+           pn <= k->wk_keyrsc[tid]) {
                /*
                 * Replay violation.
                 */

Modified: head/sys/net80211/ieee80211_crypto_tkip.c
==============================================================================
--- head/sys/net80211/ieee80211_crypto_tkip.c   Sat Apr 10 12:47:06 2010        
(r206456)
+++ head/sys/net80211/ieee80211_crypto_tkip.c   Sat Apr 10 13:54:00 2010        
(r206457)
@@ -281,7 +281,14 @@ tkip_decap(struct ieee80211_key *k, stru
 
        tid = ieee80211_gettid(wh);
        ctx->rx_rsc = READ_6(ivp[2], ivp[0], ivp[4], ivp[5], ivp[6], ivp[7]);
-       if (ctx->rx_rsc <= k->wk_keyrsc[tid]) {
+       /*
+        * NB: Multiple stations are using the same key in
+        * IBSS mode, there is currently no way to sync keyrsc
+        * counters without discarding too many frames.
+        */
+       if (vap->iv_opmode != IEEE80211_M_IBSS &&
+           vap->iv_opmode != IEEE80211_M_AHDEMO &&
+           ctx->rx_rsc <= k->wk_keyrsc[tid]) {
                /*
                 * Replay violation; notify upper layer.
                 */

Modified: head/sys/net80211/ieee80211_ioctl.c
==============================================================================
--- head/sys/net80211/ieee80211_ioctl.c Sat Apr 10 12:47:06 2010        
(r206456)
+++ head/sys/net80211/ieee80211_ioctl.c Sat Apr 10 13:54:00 2010        
(r206457)
@@ -70,6 +70,8 @@ __FBSDID("$FreeBSD$");
 static const uint8_t zerobssid[IEEE80211_ADDR_LEN];
 static struct ieee80211_channel *findchannel(struct ieee80211com *,
                int ieee, int mode);
+static int ieee80211_scanreq(struct ieee80211vap *,
+               struct ieee80211_scan_req *);
 
 static __noinline int
 ieee80211_ioctl_getkey(struct ieee80211vap *vap, struct ieee80211req *ireq)
@@ -1471,14 +1473,15 @@ mlmelookup(void *arg, const struct ieee8
 }
 
 static __noinline int
-setmlme_assoc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],
-       int ssid_len, const uint8_t ssid[IEEE80211_NWID_LEN])
+setmlme_assoc_sta(struct ieee80211vap *vap,
+       const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len,
+       const uint8_t ssid[IEEE80211_NWID_LEN])
 {
        struct scanlookup lookup;
 
-       /* XXX ibss/ahdemo */
-       if (vap->iv_opmode != IEEE80211_M_STA)
-               return EINVAL;
+       KASSERT(vap->iv_opmode == IEEE80211_M_STA,
+           ("expected opmode STA not %s",
+           ieee80211_opmode_name[vap->iv_opmode]));
 
        /* NB: this is racey if roaming is !manual */
        lookup.se = NULL;
@@ -1495,6 +1498,36 @@ setmlme_assoc(struct ieee80211vap *vap, 
 }
 
 static __noinline int
+setmlme_assoc_adhoc(struct ieee80211vap *vap,
+       const uint8_t mac[IEEE80211_ADDR_LEN], int ssid_len,
+       const uint8_t ssid[IEEE80211_NWID_LEN])
+{
+       struct ieee80211_scan_req sr;
+
+       KASSERT(vap->iv_opmode == IEEE80211_M_IBSS ||
+           vap->iv_opmode == IEEE80211_M_AHDEMO,
+           ("expected opmode IBSS or AHDEMO not %s",
+           ieee80211_opmode_name[vap->iv_opmode]));
+
+       if (ssid_len == 0)
+               return EINVAL;
+
+       /* NB: IEEE80211_IOC_SSID call missing for ap_scan=2. */
+       memset(vap->iv_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
+       vap->iv_des_ssid[0].len = ssid_len;
+       memcpy(vap->iv_des_ssid[0].ssid, ssid, ssid_len);
+       vap->iv_des_nssid = 1;
+
+       sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE;
+       sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
+       memcpy(sr.sr_ssid[0].ssid, ssid, ssid_len);
+       sr.sr_ssid[0].len = ssid_len;
+       sr.sr_nssid = 1;
+
+       return ieee80211_scanreq(vap, &sr);
+}
+
+static __noinline int
 ieee80211_ioctl_setmlme(struct ieee80211vap *vap, struct ieee80211req *ireq)
 {
        struct ieee80211req_mlme mlme;
@@ -1505,9 +1538,13 @@ ieee80211_ioctl_setmlme(struct ieee80211
        error = copyin(ireq->i_data, &mlme, sizeof(mlme));
        if (error)
                return error;
-       if  (mlme.im_op == IEEE80211_MLME_ASSOC)
-               return setmlme_assoc(vap, mlme.im_macaddr,
+       if  (vap->iv_opmode == IEEE80211_M_STA &&
+           mlme.im_op == IEEE80211_MLME_ASSOC)
+               return setmlme_assoc_sta(vap, mlme.im_macaddr,
                    vap->iv_des_ssid[0].len, vap->iv_des_ssid[0].ssid);
+       else if (mlme.im_op == IEEE80211_MLME_ASSOC)
+               return setmlme_assoc_adhoc(vap, mlme.im_macaddr,
+                   mlme.im_ssid_len, mlme.im_ssid);
        else
                return setmlme_common(vap, mlme.im_op,
                    mlme.im_macaddr, mlme.im_reason);
@@ -2332,8 +2369,8 @@ ieee80211_ioctl_chanswitch(struct ieee80
        return error;
 }
 
-static __noinline int
-ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
+static int
+ieee80211_scanreq(struct ieee80211vap *vap, struct ieee80211_scan_req *sr)
 {
 #define        IEEE80211_IOC_SCAN_FLAGS \
        (IEEE80211_IOC_SCAN_NOPICK | IEEE80211_IOC_SCAN_ACTIVE | \
@@ -2342,48 +2379,38 @@ ieee80211_ioctl_scanreq(struct ieee80211
         IEEE80211_IOC_SCAN_NOJOIN | IEEE80211_IOC_SCAN_FLUSH | \
         IEEE80211_IOC_SCAN_CHECK)
        struct ieee80211com *ic = vap->iv_ic;
-       struct ieee80211_scan_req sr;           /* XXX off stack? */
-       int error, i;
-
-       /* NB: parent must be running */
-       if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
-               return ENXIO;
+       int i;
 
-       if (ireq->i_len != sizeof(sr))
-               return EINVAL;
-       error = copyin(ireq->i_data, &sr, sizeof(sr));
-       if (error != 0)
-               return error;
        /* convert duration */
-       if (sr.sr_duration == IEEE80211_IOC_SCAN_FOREVER)
-               sr.sr_duration = IEEE80211_SCAN_FOREVER;
+       if (sr->sr_duration == IEEE80211_IOC_SCAN_FOREVER)
+               sr->sr_duration = IEEE80211_SCAN_FOREVER;
        else {
-               if (sr.sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN ||
-                   sr.sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX)
+               if (sr->sr_duration < IEEE80211_IOC_SCAN_DURATION_MIN ||
+                   sr->sr_duration > IEEE80211_IOC_SCAN_DURATION_MAX)
                        return EINVAL;
-               sr.sr_duration = msecs_to_ticks(sr.sr_duration);
-               if (sr.sr_duration < 1)
-                       sr.sr_duration = 1;
+               sr->sr_duration = msecs_to_ticks(sr->sr_duration);
+               if (sr->sr_duration < 1)
+                       sr->sr_duration = 1;
        }
        /* convert min/max channel dwell */
-       if (sr.sr_mindwell != 0) {
-               sr.sr_mindwell = msecs_to_ticks(sr.sr_mindwell);
-               if (sr.sr_mindwell < 1)
-                       sr.sr_mindwell = 1;
-       }
-       if (sr.sr_maxdwell != 0) {
-               sr.sr_maxdwell = msecs_to_ticks(sr.sr_maxdwell);
-               if (sr.sr_maxdwell < 1)
-                       sr.sr_maxdwell = 1;
+       if (sr->sr_mindwell != 0) {
+               sr->sr_mindwell = msecs_to_ticks(sr->sr_mindwell);
+               if (sr->sr_mindwell < 1)
+                       sr->sr_mindwell = 1;
+       }
+       if (sr->sr_maxdwell != 0) {
+               sr->sr_maxdwell = msecs_to_ticks(sr->sr_maxdwell);
+               if (sr->sr_maxdwell < 1)
+                       sr->sr_maxdwell = 1;
        }
        /* NB: silently reduce ssid count to what is supported */
-       if (sr.sr_nssid > IEEE80211_SCAN_MAX_SSID)
-               sr.sr_nssid = IEEE80211_SCAN_MAX_SSID;
-       for (i = 0; i < sr.sr_nssid; i++)
-               if (sr.sr_ssid[i].len > IEEE80211_NWID_LEN)
+       if (sr->sr_nssid > IEEE80211_SCAN_MAX_SSID)
+               sr->sr_nssid = IEEE80211_SCAN_MAX_SSID;
+       for (i = 0; i < sr->sr_nssid; i++)
+               if (sr->sr_ssid[i].len > IEEE80211_NWID_LEN)
                        return EINVAL;
        /* cleanse flags just in case, could reject if invalid flags */
-       sr.sr_flags &= IEEE80211_IOC_SCAN_FLAGS;
+       sr->sr_flags &= IEEE80211_IOC_SCAN_FLAGS;
        /*
         * Add an implicit NOPICK if the vap is not marked UP.  This
         * allows applications to scan without joining a bss (or picking
@@ -2391,13 +2418,13 @@ ieee80211_ioctl_scanreq(struct ieee80211
         * roaming mode--you just need to mark the parent device UP.
         */
        if ((vap->iv_ifp->if_flags & IFF_UP) == 0)
-               sr.sr_flags |= IEEE80211_IOC_SCAN_NOPICK;
+               sr->sr_flags |= IEEE80211_IOC_SCAN_NOPICK;
 
        IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
            "%s: flags 0x%x%s duration 0x%x mindwell %u maxdwell %u nssid %d\n",
-           __func__, sr.sr_flags,
+           __func__, sr->sr_flags,
            (vap->iv_ifp->if_flags & IFF_UP) == 0 ? " (!IFF_UP)" : "",
-           sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell, sr.sr_nssid);
+           sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell, sr->sr_nssid);
        /*
         * If we are in INIT state then the driver has never had a chance
         * to setup hardware state to do a scan; we must use the state
@@ -2412,13 +2439,13 @@ ieee80211_ioctl_scanreq(struct ieee80211
        IEEE80211_LOCK(ic);
        if (vap->iv_state == IEEE80211_S_INIT) {
                /* NB: clobbers previous settings */
-               vap->iv_scanreq_flags = sr.sr_flags;
-               vap->iv_scanreq_duration = sr.sr_duration;
-               vap->iv_scanreq_nssid = sr.sr_nssid;
-               for (i = 0; i < sr.sr_nssid; i++) {
-                       vap->iv_scanreq_ssid[i].len = sr.sr_ssid[i].len;
-                       memcpy(vap->iv_scanreq_ssid[i].ssid, sr.sr_ssid[i].ssid,
-                           sr.sr_ssid[i].len);
+               vap->iv_scanreq_flags = sr->sr_flags;
+               vap->iv_scanreq_duration = sr->sr_duration;
+               vap->iv_scanreq_nssid = sr->sr_nssid;
+               for (i = 0; i < sr->sr_nssid; i++) {
+                       vap->iv_scanreq_ssid[i].len = sr->sr_ssid[i].len;
+                       memcpy(vap->iv_scanreq_ssid[i].ssid,
+                           sr->sr_ssid[i].ssid, sr->sr_ssid[i].len);
                }
                vap->iv_flags_ext |= IEEE80211_FEXT_SCANREQ;
                IEEE80211_UNLOCK(ic);
@@ -2427,25 +2454,44 @@ ieee80211_ioctl_scanreq(struct ieee80211
                vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ;
                IEEE80211_UNLOCK(ic);
                /* XXX neeed error return codes */
-               if (sr.sr_flags & IEEE80211_IOC_SCAN_CHECK) {
-                       (void) ieee80211_check_scan(vap, sr.sr_flags,
-                           sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell,
-                           sr.sr_nssid,
+               if (sr->sr_flags & IEEE80211_IOC_SCAN_CHECK) {
+                       (void) ieee80211_check_scan(vap, sr->sr_flags,
+                           sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell,
+                           sr->sr_nssid,
                            /* NB: cheat, we assume structures are compatible */
-                           (const struct ieee80211_scan_ssid *) 
&sr.sr_ssid[0]);
+                           (const struct ieee80211_scan_ssid *) 
&sr->sr_ssid[0]);
                } else {
-                       (void) ieee80211_start_scan(vap, sr.sr_flags,
-                           sr.sr_duration, sr.sr_mindwell, sr.sr_maxdwell,
-                           sr.sr_nssid,
+                       (void) ieee80211_start_scan(vap, sr->sr_flags,
+                           sr->sr_duration, sr->sr_mindwell, sr->sr_maxdwell,
+                           sr->sr_nssid,
                            /* NB: cheat, we assume structures are compatible */
-                           (const struct ieee80211_scan_ssid *) 
&sr.sr_ssid[0]);
+                           (const struct ieee80211_scan_ssid *) 
&sr->sr_ssid[0]);
                }
        }
-       return error;
+       return 0;
 #undef IEEE80211_IOC_SCAN_FLAGS
 }
 
 static __noinline int
+ieee80211_ioctl_scanreq(struct ieee80211vap *vap, struct ieee80211req *ireq)
+{
+       struct ieee80211com *ic = vap->iv_ic;
+       struct ieee80211_scan_req sr;           /* XXX off stack? */
+       int error;
+
+       /* NB: parent must be running */
+       if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+               return ENXIO;
+
+       if (ireq->i_len != sizeof(sr))
+               return EINVAL;
+       error = copyin(ireq->i_data, &sr, sizeof(sr));
+       if (error != 0)
+               return error;
+       return ieee80211_scanreq(vap, &sr);
+}
+
+static __noinline int
 ieee80211_ioctl_setstavlan(struct ieee80211vap *vap, struct ieee80211req *ireq)
 {
        struct ieee80211_node *ni;

Modified: head/usr.sbin/wpa/wpa_supplicant/driver_freebsd.c
==============================================================================
--- head/usr.sbin/wpa/wpa_supplicant/driver_freebsd.c   Sat Apr 10 12:47:06 
2010        (r206456)
+++ head/usr.sbin/wpa/wpa_supplicant/driver_freebsd.c   Sat Apr 10 13:54:00 
2010        (r206457)
@@ -396,7 +396,7 @@ wpa_driver_bsd_associate(void *priv, str
 {
        struct wpa_driver_bsd_data *drv = priv;
        struct ieee80211req_mlme mlme;
-       int privacy;
+       int flags, privacy;
 
        wpa_printf(MSG_DEBUG,
                "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
@@ -408,6 +408,17 @@ wpa_driver_bsd_associate(void *priv, str
                , params->key_mgmt_suite
        );
 
+       /* NB: interface must be marked UP to associate */
+       if (getifflags(drv, &flags) != 0) {
+               wpa_printf(MSG_DEBUG, "%s did not mark interface UP", __func__);
+               return -1;
+       }
+       if ((flags & IFF_UP) == 0 && setifflags(drv, flags | IFF_UP) != 0) {
+               wpa_printf(MSG_DEBUG, "%s unable to mark interface UP",
+                   __func__);
+               return -1;
+       }
+
        /* XXX error handling is wrong but unclear what to do... */
        if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) 
< 0)
                return -1;

Modified: head/usr.sbin/wpa/wpa_supplicant/wpa_supplicant.conf.5
==============================================================================
--- head/usr.sbin/wpa/wpa_supplicant/wpa_supplicant.conf.5      Sat Apr 10 
12:47:06 2010        (r206456)
+++ head/usr.sbin/wpa/wpa_supplicant/wpa_supplicant.conf.5      Sat Apr 10 
13:54:00 2010        (r206457)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 8, 2007
+.Dd April 10, 2010
 .Dt WPA_SUPPLICANT.CONF 5
 .Os
 .Sh NAME
@@ -153,7 +153,27 @@ Note that IBSS (adhoc) mode can only be 
 .Va key_mgmt
 set to
 .Li NONE
-(plaintext and static WEP).
+(plaintext and static WEP), or
+.Va key_mgmt
+set to
+.Li WPA-NONE
+(fixed group key TKIP/CCMP).
+In addition,
+.Va ap_scan
+has to be set to 2 for IBSS.
+.Li WPA-NONE
+requires
+.Va proto
+set to WPA,
+.Va key_mgmt
+set to WPA-NONE,
+.Va pairwise
+set to NONE,
+.Va group
+set to either
+CCMP or TKIP (but not both), and
+.Va psk
+must also be set.
 .It Va proto
 List of acceptable protocols; one or more of:
 .Li WPA
_______________________________________________
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