On Tue, Sep 30, 2014 at 11:59:25AM +0200, Martin Pieuchot wrote:
> Hey Vadim, I'm happy to see you've put some efforts into improving
> how wireless networks are configured on OpenBSD.  I have some questions
> below.
> 
> On 26/09/14(Fri) 21:38, Vadim Zhukov wrote:
> > 
> > This is a proof-of-concept patch that implements network "profiles"
> > in kernel, using IEEE 802.11 network name and/or BSSID.
> 
> Why did you choose to put this in the kernel, did you encounter any
> technical problem, or was it easier/better that way?

Note also that there is an existing 'autoassoc' behaviour.
The net80211 stack will try to automatically associate with
an open wireless network as soon as the interface is brought up.
I think it would make sense to try to keep this behaviour for
encrypted networks for which the key has been pre-loaded into
kernel memory somehow. The primary focus of the kernel should be
on trying to get link on an interface, like it does with open wifi.

Below is a diff I once wrote which caches network keys in the kernel.
It's not perfect either because it still requires users to enter the
nwid they want to associate with if a network is encrypted. In other words,
it doesn't require users to enter a wep/wpa key more than once while the
system is accumulating uptime. But there is no automatic association
with an encrypted network found during a scan, and no integration with
userland via routing sockets (an idea which I like a lot because it
opens up the possibility for desktop integration and other nice things).

Index: ieee80211_crypto.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_crypto.c,v
retrieving revision 1.60
diff -u -p -r1.60 ieee80211_crypto.c
--- ieee80211_crypto.c  11 Jan 2011 15:42:05 -0000      1.60
+++ ieee80211_crypto.c  21 Aug 2013 14:17:25 -0000
@@ -65,6 +65,7 @@ ieee80211_crypto_attach(struct ifnet *if
        struct ieee80211com *ic = (void *)ifp;
 
        TAILQ_INIT(&ic->ic_pmksa);
+       TAILQ_INIT(&ic->ic_pws);
        if (ic->ic_caps & IEEE80211_C_RSN) {
                ic->ic_rsnprotos = IEEE80211_PROTO_WPA | IEEE80211_PROTO_RSN;
                ic->ic_rsnakms = IEEE80211_AKM_PSK;
@@ -91,6 +92,8 @@ ieee80211_crypto_detach(struct ifnet *if
                free(pmk, M_DEVBUF);
        }
 
+       ieee80211_passwd_remove_all(ic);
+
        /* clear all group keys from memory */
        for (i = 0; i < IEEE80211_GROUP_NKID; i++) {
                struct ieee80211_key *k = &ic->ic_nw_keys[i];
@@ -648,4 +651,159 @@ ieee80211_pmksa_find(struct ieee80211com
                        break;
        }
        return pmk;
+}
+
+#define IEEE80211_PW_CACHE_SIZE 16
+
+#define IEEE80211_PW_DEBUG
+
+/*
+ * Cache a WPA PSK for the current desired ESSID.
+ * If PSK is NULL, clear the cached PSK.
+ */
+struct ieee80211_passwd *
+ieee80211_passwd_psk(struct ieee80211com *ic, u_int8_t *psk)
+{
+       struct ieee80211_passwd *pw;
+#ifdef IEEE80211_PW_DEBUG
+       char essid[IEEE80211_NWID_LEN + 1];
+#endif
+
+       if (ic->ic_npws >= IEEE80211_PW_CACHE_SIZE) {
+               /* TODO expire least recently used entry instead of return */
+               return NULL;
+       }
+
+       if (ic->ic_des_esslen == 0)
+               return NULL;
+
+#ifdef IEEE80211_PW_DEBUG
+       memcpy(essid, pw->pw_nwid, IEEE80211_NWID_LEN);
+       essid[IEEE80211_NWID_LEN] = '\0';
+#endif
+
+       pw = ieee80211_passwd_find(ic);
+       if (pw == NULL) {
+               if (psk == NULL)
+                       return NULL;
+#ifdef IEEE80211_PW_DEBUG
+               printf("%s: new wpa psk for %s\n", __func__, essid);
+#endif
+               pw = malloc(sizeof(*pw), M_DEVBUF, M_ZERO|M_NOWAIT);
+               if (pw == NULL)
+                       return NULL;
+               memcpy(pw->pw_nwid, ic->ic_des_essid, IEEE80211_NWID_LEN);
+               TAILQ_INSERT_TAIL(&ic->ic_pws, pw, pw_next);
+               ic->ic_npws++;
+       }
+#ifdef IEEE80211_PW_DEBUG
+       else
+               printf("%s: changing wpa psk for %s\n", __func__, essid);
+#endif
+
+       if (psk) {
+               memcpy(pw->pw_psk, psk, IEEE80211_PMK_LEN);
+               pw->pw_flags |= IEEE80211_PASSWD_HAVE_PSK;
+       } else if (pw->pw_flags & IEEE80211_PASSWD_HAVE_PSK) {
+               explicit_bzero(pw->pw_psk, IEEE80211_PMK_LEN);
+               pw->pw_flags &= ~IEEE80211_PASSWD_HAVE_PSK;
+       }
+
+       return pw;
+}
+
+/*
+ * Cache WEP keys for the current desired ESSID.
+ * Clear cached keys if KEYS is NULL.
+ */
+struct ieee80211_passwd *
+ieee80211_passwd_wep(struct ieee80211com *ic, struct ieee80211_key *keys,
+    int def_txkey)
+{
+       struct ieee80211_passwd *pw;
+#ifdef IEEE80211_PW_DEBUG
+       char essid[IEEE80211_NWID_LEN + 1];
+#endif
+       int i;
+
+       if (ic->ic_npws >= IEEE80211_PW_CACHE_SIZE) {
+               /* TODO expire least recently used entry instead of return */
+               return NULL;
+       }
+
+       if (ic->ic_des_esslen == 0)
+               return NULL;
+
+#ifdef IEEE80211_PW_DEBUG
+       memcpy(essid, pw->pw_nwid, IEEE80211_NWID_LEN);
+       essid[IEEE80211_NWID_LEN] = '\0';
+#endif
+
+       pw = ieee80211_passwd_find(ic);
+       if (pw == NULL) {
+               if (keys == NULL)
+                       return NULL;
+#ifdef IEEE80211_PW_DEBUG
+               printf("%s: new wep keys for %s\n", __func__, essid);
+#endif
+               pw = malloc(sizeof(*pw), M_DEVBUF, M_ZERO|M_NOWAIT);
+               if (pw == NULL)
+                       return NULL;
+               memcpy(pw->pw_nwid, ic->ic_des_essid, IEEE80211_NWID_LEN);
+               TAILQ_INSERT_TAIL(&ic->ic_pws, pw, pw_next);
+               ic->ic_npws++;
+       }
+#ifdef IEEE80211_PW_DEBUG
+       else
+               printf("%s: changing wep keys for %s\n", __func__, essid);
+#endif
+
+       if (keys) {
+               for (i = 0; i < IEEE80211_WEP_NKID; i++)
+                       memcpy(&pw->pw_nw_keys[i], &keys[i],
+                           sizeof(struct ieee80211_key));
+               pw->pw_def_txkey = def_txkey;
+               pw->pw_flags |= IEEE80211_PASSWD_HAVE_NWKEYS;
+       } else if (pw->pw_flags & IEEE80211_PASSWD_HAVE_NWKEYS) {
+               for (i = 0; i < IEEE80211_WEP_NKID; i++)
+                       explicit_bzero(&pw->pw_nw_keys[i],
+                           sizeof(struct ieee80211_key));
+               pw->pw_flags &= ~IEEE80211_PASSWD_HAVE_NWKEYS;
+       }
+
+       return pw;
+}
+
+/* Find a WEP/WPA password cache entry for desired ESSID of IC. */
+struct ieee80211_passwd *
+ieee80211_passwd_find(struct ieee80211com *ic)
+{
+       struct ieee80211_passwd *pw;
+
+       if (ic->ic_npws == 0 || ic->ic_des_esslen == 0)
+               return NULL;
+
+       TAILQ_FOREACH(pw, &ic->ic_pws, pw_next) {
+               if (memcmp(pw->pw_nwid, ic->ic_des_essid,
+                       IEEE80211_NWID_LEN) == 0)
+                       break;
+       }
+
+       return pw;
+}
+
+/* 
+ * Purge the WEP/WPA password cache.
+ */
+void
+ieee80211_passwd_remove_all(struct ieee80211com *ic)
+{
+       struct ieee80211_passwd *pw;
+
+       while ((pw = TAILQ_FIRST(&ic->ic_pws)) != NULL) {
+               TAILQ_REMOVE(&ic->ic_pws, pw, pw_next);
+               explicit_bzero(pw, sizeof(*pw));
+               free(pw, M_DEVBUF);
+               ic->ic_npws--;
+       }
 }
Index: ieee80211_crypto.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_crypto.h,v
retrieving revision 1.22
diff -u -p -r1.22 ieee80211_crypto.h
--- ieee80211_crypto.h  26 Jan 2009 19:09:41 -0000      1.22
+++ ieee80211_crypto.h  21 Aug 2013 14:13:56 -0000
@@ -178,4 +178,11 @@ struct     mbuf *ieee80211_bip_encap(struct 
 struct mbuf *ieee80211_bip_decap(struct ieee80211com *, struct mbuf *,
            struct ieee80211_key *);
 
+struct ieee80211_passwd *ieee80211_passwd_psk(struct ieee80211com *,
+            u_int8_t *);
+struct ieee80211_passwd *ieee80211_passwd_wep(struct ieee80211com *,
+            struct ieee80211_key *, int);
+struct ieee80211_passwd *ieee80211_passwd_find(struct ieee80211com *);
+void   ieee80211_passwd_remove_all(struct ieee80211com *);
+
 #endif /* _NET80211_IEEE80211_CRYPTO_H_ */
Index: ieee80211_ioctl.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_ioctl.c,v
retrieving revision 1.34
diff -u -p -r1.34 ieee80211_ioctl.c
--- ieee80211_ioctl.c   29 Sep 2010 20:00:51 -0000      1.34
+++ ieee80211_ioctl.c   21 Aug 2013 14:16:12 -0000
@@ -176,6 +176,8 @@ ieee80211_ioctl_setnwkeys(struct ieee802
        ic->ic_def_txkey = nwkey->i_defkid - 1;
        ic->ic_flags |= IEEE80211_F_WEPON;
 
+       ieee80211_passwd_wep(ic, ic->ic_nw_keys, ic->ic_def_txkey);
+
        return ENETRESET;
 }
 
@@ -330,6 +332,7 @@ ieee80211_ioctl(struct ifnet *ifp, u_lon
        int i, error = 0;
        struct ieee80211_nwid nwid;
        struct ieee80211_wpapsk *psk;
+       struct ieee80211_passwd *pw;
        struct ieee80211_wmmparams *wmm;
        struct ieee80211_keyavail *ka;
        struct ieee80211_keyrun *kr;
@@ -363,6 +366,26 @@ ieee80211_ioctl(struct ifnet *ifp, u_lon
                memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
                ic->ic_des_esslen = nwid.i_len;
                memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
+               pw = ieee80211_passwd_find(ic);
+               if (pw && (pw->pw_flags & IEEE80211_PASSWD_HAVE_PSK)) {
+                       memcpy(ic->ic_psk, pw->pw_psk, sizeof(ic->ic_psk));
+                       ic->ic_flags |= IEEE80211_F_PSK;
+               }
+               if (pw && (pw->pw_flags & IEEE80211_PASSWD_HAVE_NWKEYS)) {
+                       struct ieee80211_key *k;
+
+                       for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+                               k = &ic->ic_nw_keys[i];
+                               if (k->k_cipher != IEEE80211_CIPHER_NONE)
+                                       (*ic->ic_delete_key)(ic, NULL, k);
+                               memcpy(k, &pw->pw_nw_keys[i], sizeof(*k));
+                               error = (*ic->ic_set_key)(ic, NULL, k);
+                               if (error != 0)
+                                       return error;
+                       }
+                       ic->ic_def_txkey = pw->pw_def_txkey;
+                       ic->ic_flags |= IEEE80211_F_WEPON;
+               }
                error = ENETRESET;
                break;
        case SIOCG80211NWID:
@@ -421,6 +444,7 @@ ieee80211_ioctl(struct ifnet *ifp, u_lon
                if (psk->i_enabled) {
                        ic->ic_flags |= IEEE80211_F_PSK;
                        memcpy(ic->ic_psk, psk->i_psk, sizeof(ic->ic_psk));
+                       ieee80211_passwd_psk(ic, ic->ic_psk);
                } else {
                        ic->ic_flags &= ~IEEE80211_F_PSK;
                        memset(ic->ic_psk, 0, sizeof(ic->ic_psk));
Index: ieee80211_proto.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_proto.c,v
retrieving revision 1.46
diff -u -p -r1.46 ieee80211_proto.c
--- ieee80211_proto.c   18 Jan 2012 14:35:56 -0000      1.46
+++ ieee80211_proto.c   21 Aug 2013 10:26:58 -0000
@@ -804,6 +804,8 @@ ieee80211_newstate(struct ieee80211com *
                                RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) {
                                        if (ni->ni_associd == 0)
                                                continue;
+                                       printf("%s: sending assoc_leave to node 
%s\n",
+                                           __func__, 
ether_sprintf(ni->ni_macaddr));
                                        IEEE80211_SEND_MGMT(ic, ni,
                                            IEEE80211_FC0_SUBTYPE_DISASSOC,
                                            IEEE80211_REASON_ASSOC_LEAVE);
@@ -828,6 +830,8 @@ ieee80211_newstate(struct ieee80211com *
                        case IEEE80211_M_HOSTAP:
                                s = splnet();
                                RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) {
+                                       printf("%s: sending auth_leave to node 
%s\n",
+                                           __func__, 
ether_sprintf(ni->ni_macaddr));
                                        IEEE80211_SEND_MGMT(ic, ni,
                                            IEEE80211_FC0_SUBTYPE_DEAUTH,
                                            IEEE80211_REASON_AUTH_LEAVE);
Index: ieee80211_var.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_var.h,v
retrieving revision 1.62
diff -u -p -r1.62 ieee80211_var.h
--- ieee80211_var.h     21 Jan 2012 19:42:16 -0000      1.62
+++ ieee80211_var.h     21 Aug 2013 13:57:55 -0000
@@ -190,6 +190,21 @@ struct ieee80211_defrag {
 
 #define IEEE80211_GROUP_NKID   6
 
+/*
+ * Entry in the WEP/WPA password cache.
+ */
+struct ieee80211_passwd {
+       u_int8_t                pw_nwid[IEEE80211_NWID_LEN];
+       u_int8_t                pw_psk[IEEE80211_PMK_LEN];
+       struct ieee80211_key    pw_nw_keys[IEEE80211_WEP_NKID];
+       int                     pw_def_txkey;
+       u_int8_t                pw_flags;
+#define        IEEE80211_PASSWD_HAVE_PSK       0x01
+#define        IEEE80211_PASSWD_HAVE_NWKEYS    0x02
+
+       TAILQ_ENTRY(ieee80211_passwd) pw_next;
+};
+
 struct ieee80211com {
        struct arpcom           ic_ac;
        LIST_ENTRY(ieee80211com) ic_list;       /* chain of all ieee80211com */
@@ -321,6 +336,8 @@ struct ieee80211com {
        u_int8_t                ic_dialog_token;
 
        LIST_HEAD(, ieee80211_vap) ic_vaps;
+       TAILQ_HEAD(, ieee80211_passwd) ic_pws;
+       int                     ic_npws;
 };
 #define        ic_if           ic_ac.ac_if
 #define        ic_softc        ic_if.if_softc

Reply via email to