14b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt/*
24b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt * Driver interaction with OpenBSD net80211 layer
34b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt * Copyright (c) 2013, Mark Kettenis
44b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt *
54b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt * This software may be distributed under the terms of the BSD license.
64b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt * See README for more details.
74b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt */
84b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
94b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#include "includes.h"
104b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#include <sys/ioctl.h>
114b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
124b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#include <net/if.h>
134b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#include <net80211/ieee80211.h>
144b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#include <net80211/ieee80211_crypto.h>
154b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#include <net80211/ieee80211_ioctl.h>
164b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
174b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#include "common.h"
184b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#include "driver.h"
194b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
204b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstruct openbsd_driver_data {
214b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	char ifname[IFNAMSIZ + 1];
224b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	void *ctx;
234b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
244b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	int sock;			/* open socket for 802.11 ioctls */
254b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt};
264b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
274b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
284b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int
294b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtwpa_driver_openbsd_get_ssid(void *priv, u8 *ssid)
304b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
314b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct openbsd_driver_data *drv = priv;
324b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct ieee80211_nwid nwid;
334b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct ifreq ifr;
344b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
354b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_memset(&ifr, 0, sizeof(ifr));
364b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
374b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	ifr.ifr_data = (void *)&nwid;
384b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 ||
394b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	    nwid.i_len > IEEE80211_NWID_LEN)
404b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		return -1;
414b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
424b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_memcpy(ssid, nwid.i_nwid, nwid.i_len);
434b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return nwid.i_len;
444b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
454b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
464b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int
474b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtwpa_driver_openbsd_get_bssid(void *priv, u8 *bssid)
484b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
494b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct openbsd_driver_data *drv = priv;
504b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct ieee80211_bssid id;
514b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
524b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_strlcpy(id.i_name, drv->ifname, sizeof(id.i_name));
534b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	if (ioctl(drv->sock, SIOCG80211BSSID, &id) < 0)
544b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		return -1;
554b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
564b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_memcpy(bssid, id.i_bssid, IEEE80211_ADDR_LEN);
574b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return 0;
584b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
594b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
604b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
614b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int
624b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtwpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
634b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
644b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_memset(capa, 0, sizeof(*capa));
654b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
664b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return 0;
674b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
684b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
694b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
704b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int
714b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtwpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
724b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
734b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	    size_t seq_len, const u8 *key, size_t key_len)
744b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
754b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct openbsd_driver_data *drv = priv;
764b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct ieee80211_keyavail keyavail;
774b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
784b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN)
794b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		return -1;
804b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
814b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	memset(&keyavail, 0, sizeof(keyavail));
824b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_strlcpy(keyavail.i_name, drv->ifname, sizeof(keyavail.i_name));
834b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	if (wpa_driver_openbsd_get_bssid(priv, keyavail.i_macaddr) < 0)
844b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		return -1;
854b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	memcpy(keyavail.i_key, key, key_len);
864b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
874b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	if (ioctl(drv->sock, SIOCS80211KEYAVAIL, &keyavail) < 0)
884b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		return -1;
894b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
904b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return 0;
914b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
924b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
934b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic void *
944b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtwpa_driver_openbsd_init(void *ctx, const char *ifname)
954b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
964b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct openbsd_driver_data *drv;
974b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
984b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	drv = os_zalloc(sizeof(*drv));
994b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	if (drv == NULL)
1004b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		return NULL;
1014b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
1024b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
1034b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	if (drv->sock < 0)
1044b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		goto fail;
1054b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
1064b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	drv->ctx = ctx;
1074b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
1084b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
1094b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return drv;
1104b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
1114b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtfail:
1124b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_free(drv);
1134b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return NULL;
1144b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
1154b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
1164b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
1174b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic void
1184b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtwpa_driver_openbsd_deinit(void *priv)
1194b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
1204b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct openbsd_driver_data *drv = priv;
1214b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
1224b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	close(drv->sock);
1234b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	os_free(drv);
1244b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
1254b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
1264b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
1274b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtconst struct wpa_driver_ops wpa_driver_openbsd_ops = {
1284b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.name = "openbsd",
1294b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.desc = "OpenBSD 802.11 support",
1304b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.get_ssid = wpa_driver_openbsd_get_ssid,
1314b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.get_bssid = wpa_driver_openbsd_get_bssid,
1324b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.get_capa = wpa_driver_openbsd_get_capa,
1334b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.set_key = wpa_driver_openbsd_set_key,
1344b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.init = wpa_driver_openbsd_init,
1354b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.deinit = wpa_driver_openbsd_deinit,
1364b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt};
137