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
20struct openbsd_driver_data {
21	char ifname[IFNAMSIZ + 1];
22	void *ctx;
23
24	int sock;			/* open socket for 802.11 ioctls */
25};
26
27
28static int
29wpa_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
46static int
47wpa_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
61static int
62wpa_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;
66	return 0;
67}
68
69
70static int
71wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
72	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
73	    size_t seq_len, const u8 *key, size_t key_len)
74{
75	struct openbsd_driver_data *drv = priv;
76	struct ieee80211_keyavail keyavail;
77
78	if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
79		return -1;
80
81	memset(&keyavail, 0, sizeof(keyavail));
82	os_strlcpy(keyavail.i_name, drv->ifname, sizeof(keyavail.i_name));
83	if (wpa_driver_openbsd_get_bssid(priv, keyavail.i_macaddr) < 0)
84		return -1;
85	memcpy(keyavail.i_key, key, key_len);
86
87	if (ioctl(drv->sock, SIOCS80211KEYAVAIL, &keyavail) < 0)
88		return -1;
89
90	return 0;
91}
92
93static void *
94wpa_driver_openbsd_init(void *ctx, const char *ifname)
95{
96	struct openbsd_driver_data *drv;
97
98	drv = os_zalloc(sizeof(*drv));
99	if (drv == NULL)
100		return NULL;
101
102	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
103	if (drv->sock < 0)
104		goto fail;
105
106	drv->ctx = ctx;
107	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
108
109	return drv;
110
111fail:
112	os_free(drv);
113	return NULL;
114}
115
116
117static void
118wpa_driver_openbsd_deinit(void *priv)
119{
120	struct openbsd_driver_data *drv = priv;
121
122	close(drv->sock);
123	os_free(drv);
124}
125
126
127const struct wpa_driver_ops wpa_driver_openbsd_ops = {
128	.name = "openbsd",
129	.desc = "OpenBSD 802.11 support",
130	.get_ssid = wpa_driver_openbsd_get_ssid,
131	.get_bssid = wpa_driver_openbsd_get_bssid,
132	.get_capa = wpa_driver_openbsd_get_capa,
133	.set_key = wpa_driver_openbsd_set_key,
134	.init = wpa_driver_openbsd_init,
135	.deinit = wpa_driver_openbsd_deinit,
136};
137