1 /*
2  * Driver interaction with OpenBSD net80211 layer
3  * Copyright (c) 2013, Mark Kettenis
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 #include <sys/ioctl.h>
11 
12 #include <net/if.h>
13 #include <net80211/ieee80211.h>
14 #include <net80211/ieee80211_crypto.h>
15 #include <net80211/ieee80211_ioctl.h>
16 
17 #include "common.h"
18 #include "driver.h"
19 
20 struct openbsd_driver_data {
21 	char ifname[IFNAMSIZ + 1];
22 	void *ctx;
23 
24 	int sock;			/* open socket for 802.11 ioctls */
25 };
26 
27 
28 static int
29 wpa_driver_openbsd_get_ssid(void *priv, u8 *ssid)
30 {
31 	struct openbsd_driver_data *drv = priv;
32 	struct ieee80211_nwid nwid;
33 	struct ifreq ifr;
34 
35 	os_memset(&ifr, 0, sizeof(ifr));
36 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
37 	ifr.ifr_data = (void *)&nwid;
38 	if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
39 	    nwid.i_len > IEEE80211_NWID_LEN)
40 		return -1;
41 
42 	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
43 	return nwid.i_len;
44 }
45 
46 static int
47 wpa_driver_openbsd_get_bssid(void *priv, u8 *bssid)
48 {
49 	struct openbsd_driver_data *drv = priv;
50 	struct ieee80211_bssid id;
51 
52 	os_strlcpy(id.i_name, drv->ifname, sizeof(id.i_name));
53 	if (ioctl(drv->sock, SIOCG80211BSSID, &id) < 0)
54 		return -1;
55 
56 	os_memcpy(bssid, id.i_bssid, IEEE80211_ADDR_LEN);
57 	return 0;
58 }
59 
60 
61 static int
62 wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
63 {
64 	os_memset(capa, 0, sizeof(*capa));
65 	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK |
66 		      WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
67 	return 0;
68 }
69 
70 
71 static int
72 wpa_driver_openbsd_set_key(void *priv, struct wpa_driver_set_key_params *params)
73 {
74 	struct openbsd_driver_data *drv = priv;
75 	struct ieee80211_keyavail keyavail;
76 	enum key_flag key_flag = params->key_flag;
77 	const u8 *key = params->key;
78 	size_t key_len = params->key_len;
79 
80 	if (key_len > IEEE80211_PMK_LEN ||
81 	    (key_flag & KEY_FLAG_PMK_MASK) != KEY_FLAG_PMK) {
82 		return -1;
83 
84 	memset(&keyavail, 0, sizeof(keyavail));
85 	os_strlcpy(keyavail.i_name, drv->ifname, sizeof(keyavail.i_name));
86 	if (wpa_driver_openbsd_get_bssid(priv, keyavail.i_macaddr) < 0)
87 		return -1;
88 	memcpy(keyavail.i_key, key, key_len);
89 
90 	if (ioctl(drv->sock, SIOCS80211KEYAVAIL, &keyavail) < 0)
91 		return -1;
92 
93 	return 0;
94 }
95 
96 static void *
97 wpa_driver_openbsd_init(void *ctx, const char *ifname)
98 {
99 	struct openbsd_driver_data *drv;
100 
101 	drv = os_zalloc(sizeof(*drv));
102 	if (drv == NULL)
103 		return NULL;
104 
105 	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
106 	if (drv->sock < 0)
107 		goto fail;
108 
109 	drv->ctx = ctx;
110 	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
111 
112 	return drv;
113 
114 fail:
115 	os_free(drv);
116 	return NULL;
117 }
118 
119 
120 static void
121 wpa_driver_openbsd_deinit(void *priv)
122 {
123 	struct openbsd_driver_data *drv = priv;
124 
125 	close(drv->sock);
126 	os_free(drv);
127 }
128 
129 
130 const struct wpa_driver_ops wpa_driver_openbsd_ops = {
131 	.name = "openbsd",
132 	.desc = "OpenBSD 802.11 support",
133 	.get_ssid = wpa_driver_openbsd_get_ssid,
134 	.get_bssid = wpa_driver_openbsd_get_bssid,
135 	.get_capa = wpa_driver_openbsd_get_capa,
136 	.set_key = wpa_driver_openbsd_set_key,
137 	.init = wpa_driver_openbsd_init,
138 	.deinit = wpa_driver_openbsd_deinit,
139 };
140