Hello all.
This is a proof-of-concept patch that implements network "profiles"
in kernel, using IEEE 802.11 network name and/or BSSID.
Current idea is as following:
1. Each 802.11 interface now have flag "autoassoc". If enabled,
kernel will automatically scan for known networks. Interval
between scans is hardcoded to 3 seconds for now.
If a known network is found, the interface gets automatically
reconfigured using corresponding profile, and userland will
receive notification via routing socket.
If another known network is already configured and has higher
precedence (i.e., it's placed earlier in the list), nothing
will be done (for that interface).
2. Profiles are loaded (and could be viewed) via sysctl syscall.
At the present, there is not support to display profiles,
though (lazy me).
3. There is a userland companion for this functionality - reworked
autonetd, that I'll present separately, if this patch (after
polishing, of course) will go in.
Oh, and about the sys/net/if_slvar.h and sys/net/ppdefs.h: we were
lucky enough that duplicated definition didn't bite us yet, but
now it is.
I'm posting this right before going to country for the weekend.
So, unfortunately, I'll be able to answer any questions in the Monday.
--
WBR,
Vadim Zhukov
Index: sys/net/if_slvar.h
===================================================================
RCS file: /cvs/src/sys/net/if_slvar.h,v
retrieving revision 1.15
diff -u -p -r1.15 if_slvar.h
--- sys/net/if_slvar.h 3 Jul 2013 03:15:52 -0000 1.15
+++ sys/net/if_slvar.h 26 Sep 2014 17:13:29 -0000
@@ -45,6 +45,8 @@ struct slstat {
u_int sl_opackets; /* packets sent */
};
+#ifndef _VJSTAT_DEFINED
+#define _VJSTAT_DEFINED
struct vjstat {
u_int vjs_packets; /* outbound packets */
u_int vjs_compressed; /* outbound compressed packets */
@@ -55,6 +57,7 @@ struct vjstat {
u_int vjs_errorin; /* inbound unknown type packets */
u_int vjs_tossed; /* inbound packets tossed because of error */
};
+#endif /* _VJSTAT_DEFINED */
struct sl_stats {
struct slstat sl; /* basic PPP statistics */
Index: sys/net/ppp_defs.h
===================================================================
RCS file: /cvs/src/sys/net/ppp_defs.h,v
retrieving revision 1.13
diff -u -p -r1.13 ppp_defs.h
--- sys/net/ppp_defs.h 13 Sep 2002 00:12:07 -0000 1.13
+++ sys/net/ppp_defs.h 26 Sep 2014 17:13:29 -0000
@@ -127,6 +127,8 @@ struct pppstat {
u_int ppp_oerrors; /* transmit errors */
};
+#ifndef _VJSTAT_DEFINED
+#define _VJSTAT_DEFINED
struct vjstat {
u_int vjs_packets; /* outbound packets */
u_int vjs_compressed; /* outbound compressed packets */
@@ -137,6 +139,7 @@ struct vjstat {
u_int vjs_errorin; /* inbound unknown type packets */
u_int vjs_tossed; /* inbound packets tossed because of error */
};
+#endif /* _VJSTAT_DEFINED */
struct ppp_stats {
struct pppstat p; /* basic PPP statistics */
Index: sys/net/route.h
===================================================================
RCS file: /cvs/src/sys/net/route.h,v
retrieving revision 1.95
diff -u -p -r1.95 route.h
--- sys/net/route.h 29 Jul 2014 12:18:41 -0000 1.95
+++ sys/net/route.h 26 Sep 2014 17:13:29 -0000
@@ -206,6 +206,14 @@ struct rt_msghdr {
#define RTM_MAXSIZE 2048 /* Maximum size of an accepted route msg */
+struct rt_netprofiles {
+ u_short rtnp_msglen; /* to skip over non-understood messages */
+ u_char rtnp_version; /* future binary compatibility */
+ u_char rtnp_type; /* message type */
+ u_short rtnp_hdrlen; /* sizeof(rt_msghdr) to skip over the header */
+ u_short rtnp_count; /* count of profiles we have now */
+};
+
#define RTM_ADD 0x1 /* Add Route */
#define RTM_DELETE 0x2 /* Delete Route */
#define RTM_CHANGE 0x3 /* Change Metrics or flags */
@@ -220,6 +228,7 @@ struct rt_msghdr {
#define RTM_IFINFO 0xe /* iface going up/down etc. */
#define RTM_IFANNOUNCE 0xf /* iface arrival/departure */
#define RTM_DESYNC 0x10 /* route socket buffer overflow */
+#define RTM_NETPROFILES 0x11 /* network profiles list changed */
#define RTV_MTU 0x1 /* init or lock _mtu */
#define RTV_HOPCOUNT 0x2 /* init or lock _hopcount */
@@ -366,6 +375,7 @@ int route_output(struct mbuf *, ...);
int route_usrreq(struct socket *, int, struct mbuf *,
struct mbuf *, struct mbuf *, struct proc *);
void rt_ifmsg(struct ifnet *);
+void rt_netprofiles_changed(void);
void rt_ifannouncemsg(struct ifnet *, int);
void rt_maskedcopy(struct sockaddr *,
struct sockaddr *, struct sockaddr *);
Index: sys/net/rtsock.c
===================================================================
RCS file: /cvs/src/sys/net/rtsock.c,v
retrieving revision 1.150
diff -u -p -r1.150 rtsock.c
--- sys/net/rtsock.c 29 Jul 2014 12:18:41 -0000 1.150
+++ sys/net/rtsock.c 26 Sep 2014 17:13:30 -0000
@@ -364,6 +364,7 @@ route_input(struct mbuf *m0, ...)
switch (rtm->rtm_type) {
case RTM_IFANNOUNCE:
case RTM_DESYNC:
+ case RTM_NETPROFILES:
/* no tableid */
break;
case RTM_RESOLVE:
@@ -940,6 +941,9 @@ rt_msg1(int type, struct rt_addrinfo *rt
case RTM_IFANNOUNCE:
len = sizeof(struct if_announcemsghdr);
break;
+ case RTM_NETPROFILES:
+ len = sizeof(struct rt_netprofiles);
+ break;
default:
len = sizeof(struct rt_msghdr);
break;
@@ -1111,6 +1115,32 @@ rt_ifmsg(struct ifnet *ifp)
}
/*
+ * This routine is called to generate a message from the routing
+ * socket indicating that network profiles were reloaded.
+ */
+void
+rt_netprofiles_changed()
+{
+ struct mbuf *m;
+
+printf("rt_netprofiles_changed: ");
+ if (route_cb.any_count == 0)
+{
+printf("no listeners\n");
+ return;
+}
+ m = rt_msg1(RTM_NETPROFILES, NULL);
+ if (m == 0)
+{
+printf("no allocated\n");
+ return;
+}
+ route_proto.sp_protocol = 0;
+ printf("calling route_input()\n");
+ route_input(m, &route_proto, &route_src, &route_dst);
+}
+
+/*
* This is called to generate messages from the routing socket
* indicating a network interface has had addresses associated with it.
* if we ever reverse the logic and replace messages TO the routing
@@ -1392,6 +1422,12 @@ sysctl_rtable(int *name, u_int namelen,
tableinfo.rti_domainid = rtable_l2(tableid);
error = sysctl_rdstruct(where, given, new,
&tableinfo, sizeof(tableinfo));
+ splx(s);
+ return (error);
+
+ case NET_RT_PROFILES:
+ error = net_profiles_sysctl(name+1, namelen-1,
+ where, given, new, newlen);
splx(s);
return (error);
}
Index: sys/net80211/ieee80211.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211.c,v
retrieving revision 1.41
diff -u -p -r1.41 ieee80211.c
--- sys/net80211/ieee80211.c 8 Aug 2014 15:16:39 -0000 1.41
+++ sys/net80211/ieee80211.c 26 Sep 2014 17:13:30 -0000
@@ -62,6 +62,7 @@
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_priv.h>
+#include <net80211/ieee80211_profile.h>
#ifdef IEEE80211_DEBUG
int ieee80211_debug = 0;
@@ -146,12 +147,19 @@ ieee80211_ifattach(struct ifnet *ifp)
ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */
ic->ic_dtim_period = 1; /* all TIMs are DTIMs */
+ if (ic->ic_set_nwkey == NULL)
+ ic->ic_set_nwkey = ieee80211_ioctl_set_nwkey;
+ if (ic->ic_get_nwkey == NULL)
+ ic->ic_get_nwkey = ieee80211_ioctl_get_nwkey;
+
LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list);
ieee80211_node_attach(ifp);
ieee80211_proto_attach(ifp);
if_addgroup(ifp, "wlan");
ifp->if_priority = IF_WIRELESS_DEFAULT_PRIORITY;
+
+ ieee80211_profile_scan_init();
}
void
Index: sys/net80211/ieee80211_ioctl.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_ioctl.c,v
retrieving revision 1.35
diff -u -p -r1.35 ieee80211_ioctl.c
--- sys/net80211/ieee80211_ioctl.c 10 Jul 2014 14:32:28 -0000 1.35
+++ sys/net80211/ieee80211_ioctl.c 26 Sep 2014 17:13:30 -0000
@@ -55,6 +55,10 @@
#include <net80211/ieee80211_crypto.h>
#include <net80211/ieee80211_ioctl.h>
+#ifndef SMALL_KERNEL
+#include <net80211/ieee80211_profile.h>
+#endif
+
void ieee80211_node2req(struct ieee80211com *,
const struct ieee80211_node *, struct ieee80211_nodereq *);
void ieee80211_req2node(struct ieee80211com *,
@@ -140,9 +144,9 @@ ieee80211_req2node(struct ieee80211com *
ni->ni_state = nr->nr_state;
}
-static int
-ieee80211_ioctl_setnwkeys(struct ieee80211com *ic,
- const struct ieee80211_nwkey *nwkey)
+int
+ieee80211_ioctl_set_nwkey(struct ieee80211com *ic,
+ struct ieee80211_nwkey *nwkey)
{
struct ieee80211_key *k;
int error, i;
@@ -190,8 +194,8 @@ ieee80211_ioctl_setnwkeys(struct ieee802
return ENETRESET;
}
-static int
-ieee80211_ioctl_getnwkeys(struct ieee80211com *ic,
+int
+ieee80211_ioctl_get_nwkey(struct ieee80211com *ic,
struct ieee80211_nwkey *nwkey)
{
struct ieee80211_key *k;
@@ -224,7 +228,7 @@ ieee80211_ioctl_getnwkeys(struct ieee802
return 0;
}
-static int
+int
ieee80211_ioctl_setwpaparms(struct ieee80211com *ic,
const struct ieee80211_wpaparams *wpa)
{
@@ -289,7 +293,7 @@ ieee80211_ioctl_setwpaparms(struct ieee8
return ENETRESET;
}
-static int
+int
ieee80211_ioctl_getwpaparms(struct ieee80211com *ic,
struct ieee80211_wpaparams *wpa)
{
@@ -334,6 +338,36 @@ ieee80211_ioctl_getwpaparms(struct ieee8
}
int
+ieee80211_ioctl_set_nwid(struct ieee80211com *ic,
+ const struct ieee80211_nwid *nwid) {
+ if (nwid->i_len > IEEE80211_NWID_LEN)
+ return (EINVAL);
+ 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);
+ ic->ic_cur_profile = NULL;
+ return (ENETRESET);
+}
+
+int
+ieee80211_ioctl_get_nwid(struct ieee80211com *ic,
+ struct ieee80211_nwid *nwid) {
+ memset(nwid, 0, sizeof(*nwid));
+ switch (ic->ic_state) {
+ case IEEE80211_S_INIT:
+ case IEEE80211_S_SCAN:
+ nwid->i_len = ic->ic_des_esslen;
+ memcpy(nwid->i_nwid, ic->ic_des_essid, nwid->i_len);
+ break;
+ default:
+ nwid->i_len = ic->ic_bss->ni_esslen;
+ memcpy(nwid->i_nwid, ic->ic_bss->ni_essid, nwid->i_len);
+ break;
+ }
+ return (0);
+}
+
+int
ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct ieee80211com *ic = (void *)ifp;
@@ -365,39 +399,22 @@ ieee80211_ioctl(struct ifnet *ifp, u_lon
case SIOCS80211NWID:
if ((error = suser(curproc, 0)) != 0)
break;
- if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
- break;
- if (nwid.i_len > IEEE80211_NWID_LEN) {
- error = EINVAL;
- break;
- }
- 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);
- error = ENETRESET;
+ if ((error = copyin((void*)ifr->ifr_data, &nwid, sizeof(nwid)))
!= 0)
+ return (error);
+ error = ieee80211_ioctl_set_nwid(ic, &nwid);
break;
case SIOCG80211NWID:
- memset(&nwid, 0, sizeof(nwid));
- switch (ic->ic_state) {
- case IEEE80211_S_INIT:
- case IEEE80211_S_SCAN:
- nwid.i_len = ic->ic_des_esslen;
- memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
- break;
- default:
- nwid.i_len = ic->ic_bss->ni_esslen;
- memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
- break;
- }
- error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
+ if ((error = ieee80211_ioctl_get_nwid(ic, &nwid)) != 0)
+ return (error);
+ error = copyout(&nwid, (void*)ifr->ifr_data, sizeof(nwid));
break;
case SIOCS80211NWKEY:
if ((error = suser(curproc, 0)) != 0)
break;
- error = ieee80211_ioctl_setnwkeys(ic, (void *)data);
+ error = ieee80211_ioctl_set_nwkey(ic, (void *)data);
break;
case SIOCG80211NWKEY:
- error = ieee80211_ioctl_getnwkeys(ic, (void *)data);
+ error = ieee80211_ioctl_get_nwkey(ic, (void *)data);
break;
case SIOCS80211WMMPARMS:
if ((error = suser(curproc, 0)) != 0)
Index: sys/net80211/ieee80211_ioctl.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_ioctl.h,v
retrieving revision 1.20
diff -u -p -r1.20 ieee80211_ioctl.h
--- sys/net80211/ieee80211_ioctl.h 24 Aug 2014 18:01:27 -0000 1.20
+++ sys/net80211/ieee80211_ioctl.h 26 Sep 2014 17:13:30 -0000
@@ -99,12 +99,22 @@ struct ieee80211_stats {
#define SIOCG80211STATS _IOWR('i', 242, struct ifreq)
-/* network identifier (ESSID), nwid is pointed at by ifr.ifr_data */
struct ieee80211_nwid {
u_int8_t i_len;
u_int8_t i_nwid[IEEE80211_NWID_LEN];
};
+/* network identifier (ESSID) */
+struct ieee80211_nwid_ioc {
+ char ioc_name[IFNAMSIZ];
+ struct ieee80211_nwid ioc_nwid;
+};
+
+#define SIOCS80211NWID2 _IOWR('i', 218, struct
ieee80211_nwid_ioc)
+#define SIOCG80211NWID2 _IOWR('i', 219, struct
ieee80211_nwid_ioc)
+
+/* old version for compatibility, nwid is pointed at by ifr.ifr_data */
+
#define SIOCS80211NWID _IOWR('i', 230, struct ifreq)
#define SIOCG80211NWID _IOWR('i', 231, struct ifreq)
@@ -354,8 +364,9 @@ struct ieee80211_nodereq_all {
#define IEEE80211_F_HIDENWID 0x10000000 /* CONF: hidden ssid mode */
#define IEEE80211_F_NOBRIDGE 0x20000000 /* CONF: no internal bridging */
#define IEEE80211_F_HOSTAPMASK 0x30000000
+#define IEEE80211_F_AUTO_ASSOC 0x40000000 /* CONF: autoassociate */
#define IEEE80211_F_USERSHIFT 28
-#define IEEE80211_F_USERBITS "\20\01HIDENWID\02NOBRIDGE"
+#define IEEE80211_F_USERBITS "\20\01HIDENWID\02NOBRIDGE\03AUTOASSOC"
struct ieee80211_flags {
const char *f_name;
@@ -363,11 +374,23 @@ struct ieee80211_flags {
};
#define IEEE80211_FLAGS {
\
- { "hidenwid", IEEE80211_F_HIDENWID >> IEEE80211_F_USERSHIFT }, \
- { "nobridge", IEEE80211_F_NOBRIDGE >> IEEE80211_F_USERSHIFT } \
+ { "hidenwid", IEEE80211_F_HIDENWID >> IEEE80211_F_USERSHIFT }, \
+ { "nobridge", IEEE80211_F_NOBRIDGE >> IEEE80211_F_USERSHIFT }, \
+ { "autoassoc", IEEE80211_F_AUTO_ASSOC >> IEEE80211_F_USERSHIFT }\
}
#define SIOCG80211FLAGS _IOWR('i', 216, struct ifreq)
#define SIOCS80211FLAGS _IOW('i', 217, struct ifreq)
+
+#if 0
+struct ieee80211_profile_all {
+ size_t npa_count; /* count of structs in
buffer */
+ size_t npa_size; /* size of struct */
+ struct ieee80211_profile *npa_profiles; /* allocated buffer */
+};
+
+#define SIOCG80211PROFILES _IOWR('i', 208, struct ieee80211_profile_all)
+#define SIOCS80211PROFILES _IOW('i', 209, struct ieee80211_profile_all)
+#endif
#endif /* _NET80211_IEEE80211_IOCTL_H_ */
Index: sys/net80211/ieee80211_profile.c
===================================================================
RCS file: sys/net80211/ieee80211_profile.c
diff -N sys/net80211/ieee80211_profile.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/net80211/ieee80211_profile.c 26 Sep 2014 17:13:30 -0000
@@ -0,0 +1,546 @@
+/* $OpenBSD$ */
+
+/*
+ * Copyright (c) 2014 Vadim Zhukov <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/ioccom.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/rwlock.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/task.h>
+#include <sys/timeout.h>
+#include <sys/tree.h>
+
+#include <lib/libkern/libkern.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net/route.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+#include <net80211/ieee80211_priv.h>
+#include <net80211/ieee80211_profile.h>
+#include <net80211/ieee80211_var.h>
+
+
+static void ieee80211_profile_scan_start(void *);
+static void ieee80211_profile_scan(void *, void *);
+static void ieee80211_profile_setup(struct ieee80211_profile *,
+ struct ieee80211com *);
+static int ieee80211_profile_load(struct ieee80211_profile *);
+static struct ieee80211_profile *ieee80211_profile_match(struct
ieee80211com *);
+static void ieee80211_profile_free(struct ieee80211_profile *);
+
+static struct timeout scan_timeout;
+static struct task scan_task = TASK_INITIALIZER(ieee80211_profile_scan, NULL,
NULL);
+static struct ieee80211_profile *profiles = NULL;
+static int profiles_count = -1;
+static struct rwlock profiles_lock = RWLOCK_INITIALIZER("80211profiles");
+
+void
+ieee80211_profile_scan_init(void) {
+ if (profiles_count != -1)
+ return;
+ task_set(&scan_task, ieee80211_profile_scan, NULL, NULL);
+ timeout_set(&scan_timeout, ieee80211_profile_scan_start, NULL);
+ profiles_count = 0;
+ timeout_add_sec(&scan_timeout, 3);
+}
+
+void
+ieee80211_profile_scan_start(void *ignored) {
+ task_add(systqmp, &scan_task);
+}
+
+void
+ieee80211_profile_scan(void *ignored1, void *ignored2) {
+ struct ieee80211com *ic;
+ struct ieee80211_profile *np;
+ int s;
+ const int f = IEEE80211_F_AUTO_ASSOC <<
IEEE80211_F_USERSHIFT;
+
+ ieee80211_profile_scan_init();
+ rw_enter_read(&profiles_lock);
+ if (profiles == NULL || LIST_FIRST(&ieee80211com_head) == NULL)
+ goto unlock;
+ s = splnet(); /* XXX needed? */
+ LIST_FOREACH(ic, &ieee80211com_head, ic_list) {
+ DPRINTF(("\tic_flags=%x\n", ic->ic_flags));
+ if ((ic->ic_flags & f) != f)
+ continue;
+
+ /* XXX should skip interfaces in hostAP mode */
+
+ DPRINTF(("\tic_flags OK, if_flags=%x\n", ic->ic_if.if_flags));
+ if ((ic->ic_if.if_flags & IFF_UP) != IFF_UP)
+ continue;
+ DPRINTF(("\tif_flags OK, searching for profile\n"));
+ if ((np = ieee80211_profile_match(ic)) == NULL)
+ continue;
+ DPRINTF(("\tprofile found, comparing..."));
+ if (np == ic->ic_cur_profile) {
+ DPRINTF((" same, skipping interface\n"));
+ continue;
+ }
+ DPRINTF((" different, setting up...\n"));
+ ieee80211_profile_setup(np, ic);
+ }
+
+ splx(s);
+unlock:
+ rw_exit_read(&profiles_lock);
+ /* XXX make timeout tweakable via sysctl()? */
+ timeout_add_sec(&scan_timeout, 3);
+}
+
+void
+ieee80211_profile_setup(struct ieee80211_profile *np, struct ieee80211com *ic)
{
+ struct ieee80211_nwid nwid, oldnwid;
+ struct ieee80211_nwkey wep, oldwep;
+ struct ieee80211_wpapsk psk, oldpsk;
+ struct ieee80211_wpaparams wpa, oldwpa;
+ int error, i, reset = 0;
+ int wepchanged = 0, wpachanged = 0;
+
+ DPRINTF(("setting up profile %s\n", np->np_nwid));
+
+ switch (np->np_auth) {
+ case IEEE80211_P_AUTH_OPEN:
+ if ((ic->ic_caps & IEEE80211_C_WEP) &&
+ (ic->ic_flags & IEEE80211_F_WEPON)) {
+ wepchanged = 1;
+ memcpy(&wep, &oldwep, sizeof(wep));
+ wep.i_wepon = 0;
+ }
+ if ((ic->ic_caps & IEEE80211_C_RSN) &&
+ (ic->ic_flags & IEEE80211_F_RSNON)) {
+ wpachanged = 1;
+ memcpy(&wpa, &oldwpa, sizeof(wpa));
+ wpa.i_enabled = 0;
+ }
+ break;
+
+ case IEEE80211_P_AUTH_WEP:
+ wepchanged = 1;
+ memset(&wep, 0, sizeof(wep));
+ (void) strlcpy(wep.i_name, ic->ic_if.if_xname,
sizeof(wep.i_name));
+ wep.i_wepon = 1;
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ wep.i_key[i].i_keylen = np->np_wep_keylengths[i];
+ wep.i_key[i].i_keydat = np->np_wep_keys[i];
+ }
+ wep.i_defkid = np->np_wep_defkid;
+ if ((ic->ic_caps & IEEE80211_C_RSN) &&
+ (ic->ic_flags & IEEE80211_F_RSNON)) {
+ wpachanged = 1;
+ memcpy(&wpa, &oldwpa, sizeof(wpa));
+ wpa.i_enabled = 0;
+ }
+ break;
+
+ case IEEE80211_P_AUTH_WPA:
+ if ((ic->ic_caps & IEEE80211_C_WEP) &&
+ (ic->ic_flags & IEEE80211_F_WEPON)) {
+ wepchanged = 1;
+ memcpy(&wep, &oldwep, sizeof(wep));
+ wep.i_wepon = 0;
+ }
+ wpachanged = 1;
+ memset(&wpa, 0, sizeof(wpa));
+ (void) strlcpy(wpa.i_name, ic->ic_if.if_xname,
sizeof(wpa.i_name));
+ wpa.i_enabled = 1;
+ wpa.i_protos = np->np_wpa_protos;
+ wpa.i_akms = np->np_wpa_akms;
+ wpa.i_ciphers = np->np_wpa_ciphers;
+ /* XXX any point copying the one below? */
+ wpa.i_groupcipher = np->np_wpa_groupcipher;
+ memset(&psk, 0, sizeof(psk));
+ (void) strlcpy(psk.i_name, ic->ic_if.if_xname,
sizeof(psk.i_name));
+ if (wpa.i_akms &
(IEEE80211_WPA_AKM_PSK|IEEE80211_WPA_AKM_SHA256_PSK)) {
+ psk.i_enabled = 1;
+ memcpy(psk.i_psk, np->np_wpa_psk, sizeof(psk.i_psk));
+ }
+ break;
+ }
+
+ error = ieee80211_ioctl_get_nwid(ic, &oldnwid);
+ if (error) {
+ DPRINTF(("nwid get failed: %d\n", error));
+ return;
+ }
+
+ if (wepchanged) {
+ error = ic->ic_get_nwkey(ic, &oldwep);
+ if (error) {
+ DPRINTF(("nwkey get failed: %d\n", error));
+ return;
+ }
+ }
+
+ if (wpachanged) {
+ error = ieee80211_ioctl_getwpaparms(ic, &oldwpa);
+ if (error) {
+ DPRINTF(("wpa params get failed: %d\n", error));
+ return;
+ }
+ if (ic->ic_flags & IEEE80211_F_PSK) {
+ oldpsk.i_enabled = 1;
+ memcpy(&oldpsk.i_psk, ic->ic_psk, sizeof(oldpsk.i_psk));
+ } else
+ oldpsk.i_enabled = 0;
+ }
+
+ memset(&nwid, 0, sizeof(nwid));
+ nwid.i_len = np->np_nwid_len;
+ memcpy(nwid.i_nwid, np->np_nwid, np->np_nwid_len);
+ error = ieee80211_ioctl_set_nwid(ic, &nwid);
+ if (error == ENETRESET)
+ reset = 1;
+ else if (error) {
+ DPRINTF(("ieee80211_ioctl_set_nwid() failed: %d\n", error));
+ goto nwidfailed;
+ }
+
+ /* XXX SIOC[GS]80211NWKEY are overridden by an(4) and wi(4) */
+ if (wepchanged) {
+ error = ic->ic_set_nwkey(ic, &wep);
+ if (error == ENETRESET)
+ reset = 1;
+ else if (error) {
+ DPRINTF(("ic_set_nwkey failed: %d\n", error));
+ goto wepfailed;
+ }
+ }
+
+ if (wpachanged) {
+ if (psk.i_enabled) {
+ ic->ic_flags |= IEEE80211_F_PSK;
+ memcpy(ic->ic_psk, psk.i_psk, sizeof(psk.i_psk));
+ } else
+ ic->ic_flags &= ~IEEE80211_F_PSK;
+ error = ieee80211_ioctl_setwpaparms(ic, &wpa);
+ if (error == ENETRESET)
+ reset = 1;
+ else if (error) {
+ DPRINTF(("ieee80211_ioctl_setwpaparms() failed: %d\n",
error));
+ goto wpafailed;
+ }
+ }
+ ic->ic_cur_profile = np;
+
+ /*
+ * We may want to have a separate message, but
+ * in that case we'll have to make routing socket
+ * code aware of profile structures themselves,
+ * which in turn would violate namespace distinction
+ * in a very, very dirty way.
+ */
+ rt_ifmsg(&ic->ic_if);
+
+ return;
+
+wpafailed:
+ if (wpachanged) {
+ if (oldpsk.i_enabled) {
+ ic->ic_flags |= IEEE80211_F_PSK;
+ memcpy(ic->ic_psk, oldpsk.i_psk, sizeof(oldpsk.i_psk));
+ } else
+ ic->ic_flags &= ~IEEE80211_F_PSK;
+ ieee80211_ioctl_setwpaparms(ic, &oldwpa);
+ }
+
+wepfailed:
+ if (wepchanged)
+ ic->ic_set_nwkey(ic, &oldwep);
+
+nwidfailed:
+ ieee80211_ioctl_set_nwid(ic, &oldnwid);
+}
+
+struct ieee80211_profile*
+ieee80211_profile_match(struct ieee80211com *ic) {
+ struct ieee80211_node *ni, *selbs = NULL;
+ struct ieee80211_profile *np, *best = NULL;
+ int i, j, besti = IEEE80211_P_MAX, privacy;
+
+ /*
+ * Iteration of tree is much slower than iteration of the array,
+ * so save/return best (i.e., smallest) matching index.
+ */
+ RB_FOREACH(ni, ieee80211_tree, &ic->ic_tree) {
+ for (i = 0; i < profiles_count && i <= besti; i++) {
+ /*
+ * Test for best profile, too, because we want to
+ * choose the base station with most strength.
+ */
+ np = &profiles[i];
+ if (np->np_match & IEEE80211_P_MATCH_NWID) {
+ if (ni->ni_esslen != np->np_nwid_len)
+ continue;
+ if (memcmp(ni->ni_essid, np->np_nwid,
np->np_nwid_len))
+ continue;
+ }
+ if (np->np_match & IEEE80211_P_MATCH_BSSID) {
+ for (j = 0; j < np->np_bssid_count; j++)
+ if (!memcmp(&np->np_bssids[j *
IEEE80211_ADDR_LEN], ni->ni_bssid, IEEE80211_ADDR_LEN))
+ goto bssid_matched;
+ continue;
+ }
+bssid_m+#define np_wpa_ciphers np_wpa.ciphers
+#define np_wpa_groupcipher np_wpa.groupcipher
+#define np_wpa_psk np_wpa.psk
+ };
+};
+
+/* maximum number of profiles supported */
+#define IEEE80211_P_MAX 256
+
+void ieee80211_profile_scan_init(void);
+
+#endif /* !SMALL_KERNEL */
Index: sys/net80211/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
--- sys/net80211/ieee80211_var.h 21 Jan 2012 19:42:16 -0000 1.62
+++ sys/net80211/ieee80211_var.h 26 Sep 2014 17:13:31 -0000
@@ -221,6 +221,10 @@ struct ieee80211com {
struct ieee80211_node *, u_int8_t);
void (*ic_ampdu_rx_stop)(struct ieee80211com *,
struct ieee80211_node *, u_int8_t);
+ int (*ic_set_nwkey)(struct ieee80211com *,
+ struct ieee80211_nwkey *);
+ int (*ic_get_nwkey)(struct ieee80211com *,
+ struct ieee80211_nwkey *);
u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX];
struct ieee80211_channel ic_channels[IEEE80211_CHAN_MAX+1];
@@ -304,6 +308,9 @@ struct ieee80211com {
enum ieee80211_cipher ic_rsngroupcipher;
enum ieee80211_cipher ic_rsngroupmgmtcipher;
+ struct timeout ic_pscan_timeout;
+ struct ieee80211_profile *ic_cur_profile;
+
struct ieee80211_defrag ic_defrag[IEEE80211_DEFRAG_SIZE];
int ic_defrag_cur;
@@ -400,6 +407,18 @@ int ieee80211_setmode(struct ieee80211co
enum ieee80211_phymode ieee80211_next_mode(struct ifnet *);
enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *,
const struct ieee80211_channel *);
+int ieee80211_ioctl_set_nwid(struct ieee80211com *,
+ const struct ieee80211_nwid *);
+int ieee80211_ioctl_get_nwid(struct ieee80211com *,
+ struct ieee80211_nwid *);
+int ieee80211_ioctl_set_nwkey(struct ieee80211com *,
+ struct ieee80211_nwkey *);
+int ieee80211_ioctl_get_nwkey(struct ieee80211com *,
+ struct ieee80211_nwkey *);
+int ieee80211_ioctl_setwpaparms(struct ieee80211com *,
+ const struct ieee80211_wpaparams *);
+int ieee80211_ioctl_getwpaparms(struct ieee80211com *,
+ struct ieee80211_wpaparams *);
extern int ieee80211_cache_size;
Index: sys/sys/socket.h
===================================================================
RCS file: /cvs/src/sys/sys/socket.h,v
retrieving revision 1.83
diff -u -p -r1.83 socket.h
--- sys/sys/socket.h 2 Apr 2013 03:38:24 -0000 1.83
+++ sys/sys/socket.h 26 Sep 2014 17:22:15 -0000
@@ -346,7 +346,8 @@ struct sockpeercred {
#define NET_RT_IFLIST 3 /* survey interface list */
#define NET_RT_STATS 4 /* routing table statistics */
#define NET_RT_TABLE 5
-#define NET_RT_MAXID 6
+#define NET_RT_PROFILES 6
+#define NET_RT_MAXID 7
#define CTL_NET_RT_NAMES { \
{ 0, 0 }, \
@@ -355,6 +356,7 @@ struct sockpeercred {
{ "iflist", CTLTYPE_STRUCT }, \
{ "stats", CTLTYPE_STRUCT }, \
{ "table", CTLTYPE_STRUCT }, \
+ { "profiles", CTLTYPE_NODE }, \
}
/*
Index: sys/sys/sysctl.h
===================================================================
RCS file: /cvs/src/sys/sys/sysctl.h,v
retrieving revision 1.148
diff -u -p -r1.148 sysctl.h
--- sys/sys/sysctl.h 13 Jul 2014 16:41:22 -0000 1.148
+++ sys/sys/sysctl.h 26 Sep 2014 17:20:16 -0000
@@ -926,6 +926,7 @@ extern void (*cpu_setperf)(int);
int bpf_sysctl(int *, u_int, void *, size_t *, void *, size_t);
int pflow_sysctl(int *, u_int, void *, size_t *, void *, size_t);
int pipex_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int net_profiles_sysctl(int *, u_int, void *, size_t *, void *, size_t);
#else /* !_KERNEL */
Index: sys/kern/uipc_domain.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_domain.c,v
retrieving revision 1.37
diff -u -p -r1.37 uipc_domain.c
--- sys/kern/uipc_domain.c 11 Jul 2014 21:54:38 -0000 1.37
+++ sys/kern/uipc_domain.c 26 Sep 2014 17:20:16 -0000
@@ -184,6 +184,9 @@ net_sysctl(int *name, u_int namelen, voi
if (family == 0)
return (0);
+ if (family == PF_ROUTE && name[1] == NET_RT_PROFILES)
+ return (net_profiles_sysctl(name + 2, namelen - 2, oldp,
+ oldlenp, newp, newlen));
#if NBPFILTER > 0
if (family == PF_BPF)
return (bpf_sysctl(name + 1, namelen - 1, oldp, oldlenp,
Index: sbin/sysctl/sysctl.c
===================================================================
RCS file: /cvs/src/sbin/sysctl/sysctl.c,v
retrieving revision 1.202
diff -u -p -r1.202 sysctl.c
--- sbin/sysctl/sysctl.c 7 May 2014 01:49:36 -0000 1.202
+++ sbin/sysctl/sysctl.c 26 Sep 2014 17:13:31 -0000
@@ -605,6 +605,12 @@ parse(char *string, int flags)
return;
break;
}
+ if (mib[1] == PF_ROUTE && mib[2] == NET_RT_PROFILES) {
+ len = sysctl_net_profiles(string, &bufp, mib, flags,
&type);
+ if (len < 0)
+ return;
+ break;
+ }
if (flags == 0)
return;
warnx("use netstat to view %s information", string);
Index: sys/dev/ic/an.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/an.c,v
retrieving revision 1.61
diff -u -p -r1.61 an.c
--- sys/dev/ic/an.c 22 Jul 2014 13:12:11 -0000 1.61
+++ sys/dev/ic/an.c 26 Sep 2014 17:17:27 -0000
@@ -129,9 +129,9 @@ int an_ioctl(struct ifnet *, u_long, cad
int an_media_change(struct ifnet *);
void an_media_status(struct ifnet *, struct ifmediareq *);
-int an_set_nwkey(struct an_softc *, struct ieee80211_nwkey *);
+int an_set_nwkey(struct ieee80211com *, struct ieee80211_nwkey *);
int an_set_nwkey_wep(struct an_softc *, struct ieee80211_nwkey *);
-int an_get_nwkey(struct an_softc *, struct ieee80211_nwkey *);
+int an_get_nwkey(struct ieee80211com *, struct ieee80211_nwkey *);
int an_write_wepkey(struct an_softc *, int, struct an_wepkey *,
int);
@@ -273,6 +273,8 @@ an_attach(struct an_softc *sc)
ifp->if_watchdog = an_watchdog;
IFQ_SET_READY(&ifp->if_snd);
+ ic->ic_set_nwkey = an_set_nwkey;
+ ic->ic_get_nwkey = an_get_nwkey;
ic->ic_phytype = IEEE80211_T_DS;
ic->ic_opmode = IEEE80211_M_STA;
ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_PMGT | IEEE80211_C_MONITOR;
@@ -921,12 +923,6 @@ an_ioctl(struct ifnet *ifp, u_long comma
/* The Aironet has no multicast filter. */
error = 0;
break;
- case SIOCS80211NWKEY:
- error = an_set_nwkey(sc, (struct ieee80211_nwkey *)data);
- break;
- case SIOCG80211NWKEY:
- error = an_get_nwkey(sc, (struct ieee80211_nwkey *)data);
- break;
default:
error = ieee80211_ioctl(ifp, command, data);
break;
@@ -1391,10 +1387,10 @@ an_media_status(struct ifnet *ifp, struc
}
int
-an_set_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
+an_set_nwkey(struct ieee80211com *ic, struct ieee80211_nwkey *nwkey)
{
int error;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct an_softc *sc = ic->ic_softc;
u_int16_t prevauth;
error = 0;
@@ -1532,8 +1528,9 @@ an_set_nwkey_wep(struct an_softc *sc, st
}
int
-an_get_nwkey(struct an_softc *sc, struct ieee80211_nwkey *nwkey)
+an_get_nwkey(struct ieee80211com *ic, struct ieee80211_nwkey *nwkey)
{
+ struct an_softc *sc = ic->ic_softc;
int i, error;
error = 0;
Index: sys/dev/ic/if_wi.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/if_wi.c,v
retrieving revision 1.156
diff -u -p -r1.156 if_wi.c
--- sys/dev/ic/if_wi.c 22 Jul 2014 13:12:12 -0000 1.156
+++ sys/dev/ic/if_wi.c 26 Sep 2014 17:17:27 -0000
@@ -152,8 +152,8 @@ STATIC int wi_media_change(struct ifnet
STATIC void wi_media_status(struct ifnet *, struct ifmediareq *);
STATIC int wi_set_ssid(struct ieee80211_nwid *, u_int8_t *, int);
-STATIC int wi_set_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
-STATIC int wi_get_nwkey(struct wi_softc *, struct ieee80211_nwkey *);
+STATIC int wi_set_nwkey(struct ieee80211com *, struct ieee80211_nwkey *);
+STATIC int wi_get_nwkey(struct ieee80211com *, struct ieee80211_nwkey *);
STATIC int wi_sync_media(struct wi_softc *, int, int);
STATIC int wi_set_pm(struct wi_softc *, struct ieee80211_power *);
STATIC int wi_get_pm(struct wi_softc *, struct ieee80211_power *);
@@ -210,6 +210,9 @@ wi_attach(struct wi_softc *sc, struct wi
ic = &sc->sc_ic;
ifp = &ic->ic_if;
+ ic->ic_set_nwkey = wi_set_nwkey;
+ ic->ic_get_nwkey = wi_get_nwkey;
+
sc->sc_funcs = funcs;
sc->wi_cmd_count = 500;
@@ -1801,10 +1804,10 @@ wi_ioctl(struct ifnet *ifp, u_long comma
case SIOCS80211NWKEY:
if ((error = suser(curproc, 0)) != 0)
break;
- error = wi_set_nwkey(sc, (struct ieee80211_nwkey *)data);
+ error = wi_set_nwkey(&sc->sc_ic, (struct ieee80211_nwkey
*)data);
break;
case SIOCG80211NWKEY:
- error = wi_get_nwkey(sc, (struct ieee80211_nwkey *)data);
+ error = wi_get_nwkey(&sc->sc_ic, (struct ieee80211_nwkey
*)data);
break;
case SIOCS80211POWER:
if ((error = suser(curproc, 0)) != 0)
@@ -2871,11 +2874,12 @@ wi_media_status(struct ifnet *ifp, struc
}
STATIC int
-wi_set_nwkey(struct wi_softc *sc, struct ieee80211_nwkey *nwkey)
+wi_set_nwkey(struct ieee80211com *ic, struct ieee80211_nwkey *nwkey)
{
int i, len, error;
struct wi_req wreq;
struct wi_ltv_keys *wk = (struct wi_ltv_keys *)&wreq;
+ struct wi_softc *sc = ic->ic_softc;
if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
return ENODEV;
@@ -2932,9 +2936,10 @@ wi_set_nwkey(struct wi_softc *sc, struct
}
STATIC int
-wi_get_nwkey(struct wi_softc *sc, struct ieee80211_nwkey *nwkey)
+wi_get_nwkey(struct ieee80211com *ic, struct ieee80211_nwkey *nwkey)
{
int i, len, error;
+ struct wi_softc *sc = ic->ic_softc;
struct wi_ltv_keys *wk = &sc->wi_keys;
if (!(sc->wi_flags & WI_FLAGS_HAS_WEP))
Index: share/man/man4/route.4
===================================================================
RCS file: /cvs/src/share/man/man4/route.4,v
retrieving revision 1.37
diff -u -p -r1.37 route.4
--- share/man/man4/route.4 8 May 2014 09:30:48 -0000 1.37
+++ share/man/man4/route.4 26 Sep 2014 17:13:29 -0000
@@ -237,6 +237,7 @@ Messages include:
#define RTM_IFINFO 0xe /* iface going up/down etc. */
#define RTM_IFANNOUNCE 0xf /* iface arrival/departure */
#define RTM_DESYNC 0x10 /* route socket buffer overflow */
+#define RTM_NETPROFILES 0x11 /* network profiles list changed */
.Ed
.Pp
A message header consists of one of the following:
@@ -297,6 +298,14 @@ struct if_announcemsghdr {
u_short ifan_index; /* index for associated ifp */
u_short ifan_what; /* what type of announcement */
char ifan_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+};
+
+struct rt_netprofiles {
+ u_short rtnp_msglen; /* to skip over non-understood messages */
+ u_char rtnp_version; /* future binary compatibility */
+ u_char rtnp_type; /* message type */
+ u_short rtnp_hdrlen; /* sizeof(rt_msghdr) to skip over the header */
+ u_short rtnp_count; /* count of profiles we have now */
};
.Ed
.Pp