13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * Driver interaction with OpenBSD net80211 layer
33ff40c12SJohn Marino  * Copyright (c) 2013, Mark Kettenis
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino #include <sys/ioctl.h>
113ff40c12SJohn Marino 
123ff40c12SJohn Marino #include <net/if.h>
133ff40c12SJohn Marino #include <net80211/ieee80211.h>
143ff40c12SJohn Marino #include <net80211/ieee80211_crypto.h>
153ff40c12SJohn Marino #include <net80211/ieee80211_ioctl.h>
163ff40c12SJohn Marino 
173ff40c12SJohn Marino #include "common.h"
183ff40c12SJohn Marino #include "driver.h"
193ff40c12SJohn Marino 
203ff40c12SJohn Marino struct openbsd_driver_data {
213ff40c12SJohn Marino 	char ifname[IFNAMSIZ + 1];
223ff40c12SJohn Marino 	void *ctx;
233ff40c12SJohn Marino 
243ff40c12SJohn Marino 	int sock;			/* open socket for 802.11 ioctls */
253ff40c12SJohn Marino };
263ff40c12SJohn Marino 
273ff40c12SJohn Marino 
283ff40c12SJohn Marino static int
wpa_driver_openbsd_get_ssid(void * priv,u8 * ssid)293ff40c12SJohn Marino wpa_driver_openbsd_get_ssid(void *priv, u8 *ssid)
303ff40c12SJohn Marino {
313ff40c12SJohn Marino 	struct openbsd_driver_data *drv = priv;
323ff40c12SJohn Marino 	struct ieee80211_nwid nwid;
333ff40c12SJohn Marino 	struct ifreq ifr;
343ff40c12SJohn Marino 
353ff40c12SJohn Marino 	os_memset(&ifr, 0, sizeof(ifr));
363ff40c12SJohn Marino 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
373ff40c12SJohn Marino 	ifr.ifr_data = (void *)&nwid;
383ff40c12SJohn Marino 	if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
393ff40c12SJohn Marino 	    nwid.i_len > IEEE80211_NWID_LEN)
403ff40c12SJohn Marino 		return -1;
413ff40c12SJohn Marino 
423ff40c12SJohn Marino 	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
433ff40c12SJohn Marino 	return nwid.i_len;
443ff40c12SJohn Marino }
453ff40c12SJohn Marino 
463ff40c12SJohn Marino static int
wpa_driver_openbsd_get_bssid(void * priv,u8 * bssid)473ff40c12SJohn Marino wpa_driver_openbsd_get_bssid(void *priv, u8 *bssid)
483ff40c12SJohn Marino {
493ff40c12SJohn Marino 	struct openbsd_driver_data *drv = priv;
503ff40c12SJohn Marino 	struct ieee80211_bssid id;
513ff40c12SJohn Marino 
523ff40c12SJohn Marino 	os_strlcpy(id.i_name, drv->ifname, sizeof(id.i_name));
533ff40c12SJohn Marino 	if (ioctl(drv->sock, SIOCG80211BSSID, &id) < 0)
543ff40c12SJohn Marino 		return -1;
553ff40c12SJohn Marino 
563ff40c12SJohn Marino 	os_memcpy(bssid, id.i_bssid, IEEE80211_ADDR_LEN);
573ff40c12SJohn Marino 	return 0;
583ff40c12SJohn Marino }
593ff40c12SJohn Marino 
603ff40c12SJohn Marino 
613ff40c12SJohn Marino static int
wpa_driver_openbsd_get_capa(void * priv,struct wpa_driver_capa * capa)623ff40c12SJohn Marino wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
633ff40c12SJohn Marino {
643ff40c12SJohn Marino 	os_memset(capa, 0, sizeof(*capa));
65*a1157835SDaniel Fojt 	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK |
66*a1157835SDaniel Fojt 		      WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X;
673ff40c12SJohn Marino 	return 0;
683ff40c12SJohn Marino }
693ff40c12SJohn Marino 
703ff40c12SJohn Marino 
713ff40c12SJohn Marino static int
wpa_driver_openbsd_set_key(const char * ifname,void * priv,enum wpa_alg alg,const unsigned char * addr,int key_idx,int set_tx,const u8 * seq,size_t seq_len,const u8 * key,size_t key_len)723ff40c12SJohn Marino wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
733ff40c12SJohn Marino 	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
743ff40c12SJohn Marino 	    size_t seq_len, const u8 *key, size_t key_len)
753ff40c12SJohn Marino {
763ff40c12SJohn Marino 	struct openbsd_driver_data *drv = priv;
773ff40c12SJohn Marino 	struct ieee80211_keyavail keyavail;
783ff40c12SJohn Marino 
793ff40c12SJohn Marino 	if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
803ff40c12SJohn Marino 		return -1;
813ff40c12SJohn Marino 
823ff40c12SJohn Marino 	memset(&keyavail, 0, sizeof(keyavail));
833ff40c12SJohn Marino 	os_strlcpy(keyavail.i_name, drv->ifname, sizeof(keyavail.i_name));
843ff40c12SJohn Marino 	if (wpa_driver_openbsd_get_bssid(priv, keyavail.i_macaddr) < 0)
853ff40c12SJohn Marino 		return -1;
863ff40c12SJohn Marino 	memcpy(keyavail.i_key, key, key_len);
873ff40c12SJohn Marino 
883ff40c12SJohn Marino 	if (ioctl(drv->sock, SIOCS80211KEYAVAIL, &keyavail) < 0)
893ff40c12SJohn Marino 		return -1;
903ff40c12SJohn Marino 
913ff40c12SJohn Marino 	return 0;
923ff40c12SJohn Marino }
933ff40c12SJohn Marino 
943ff40c12SJohn Marino static void *
wpa_driver_openbsd_init(void * ctx,const char * ifname)953ff40c12SJohn Marino wpa_driver_openbsd_init(void *ctx, const char *ifname)
963ff40c12SJohn Marino {
973ff40c12SJohn Marino 	struct openbsd_driver_data *drv;
983ff40c12SJohn Marino 
993ff40c12SJohn Marino 	drv = os_zalloc(sizeof(*drv));
1003ff40c12SJohn Marino 	if (drv == NULL)
1013ff40c12SJohn Marino 		return NULL;
1023ff40c12SJohn Marino 
1033ff40c12SJohn Marino 	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
1043ff40c12SJohn Marino 	if (drv->sock < 0)
1053ff40c12SJohn Marino 		goto fail;
1063ff40c12SJohn Marino 
1073ff40c12SJohn Marino 	drv->ctx = ctx;
1083ff40c12SJohn Marino 	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
1093ff40c12SJohn Marino 
1103ff40c12SJohn Marino 	return drv;
1113ff40c12SJohn Marino 
1123ff40c12SJohn Marino fail:
1133ff40c12SJohn Marino 	os_free(drv);
1143ff40c12SJohn Marino 	return NULL;
1153ff40c12SJohn Marino }
1163ff40c12SJohn Marino 
1173ff40c12SJohn Marino 
1183ff40c12SJohn Marino static void
wpa_driver_openbsd_deinit(void * priv)1193ff40c12SJohn Marino wpa_driver_openbsd_deinit(void *priv)
1203ff40c12SJohn Marino {
1213ff40c12SJohn Marino 	struct openbsd_driver_data *drv = priv;
1223ff40c12SJohn Marino 
1233ff40c12SJohn Marino 	close(drv->sock);
1243ff40c12SJohn Marino 	os_free(drv);
1253ff40c12SJohn Marino }
1263ff40c12SJohn Marino 
1273ff40c12SJohn Marino 
1283ff40c12SJohn Marino const struct wpa_driver_ops wpa_driver_openbsd_ops = {
1293ff40c12SJohn Marino 	.name = "openbsd",
1303ff40c12SJohn Marino 	.desc = "OpenBSD 802.11 support",
1313ff40c12SJohn Marino 	.get_ssid = wpa_driver_openbsd_get_ssid,
1323ff40c12SJohn Marino 	.get_bssid = wpa_driver_openbsd_get_bssid,
1333ff40c12SJohn Marino 	.get_capa = wpa_driver_openbsd_get_capa,
1343ff40c12SJohn Marino 	.set_key = wpa_driver_openbsd_set_key,
1353ff40c12SJohn Marino 	.init = wpa_driver_openbsd_init,
1363ff40c12SJohn Marino 	.deinit = wpa_driver_openbsd_deinit,
1373ff40c12SJohn Marino };
138