driver_bsd.c revision 252190
1209139Srpaulo/* 2209139Srpaulo * WPA Supplicant - driver interaction with BSD net80211 layer 3209139Srpaulo * Copyright (c) 2004, Sam Leffler <sam@errno.com> 4214501Srpaulo * Copyright (c) 2004, 2Wire, Inc 5209139Srpaulo * 6252190Srpaulo * This software may be distributed under the terms of the BSD license. 7252190Srpaulo * See README for more details. 8209139Srpaulo */ 9209139Srpaulo 10209139Srpaulo#include "includes.h" 11209139Srpaulo#include <sys/ioctl.h> 12252190Srpaulo#include <sys/sysctl.h> 13209139Srpaulo 14209139Srpaulo#include "common.h" 15209139Srpaulo#include "driver.h" 16209139Srpaulo#include "eloop.h" 17214501Srpaulo#include "common/ieee802_11_defs.h" 18252190Srpaulo#include "common/wpa_common.h" 19209139Srpaulo 20209139Srpaulo#include <net/if.h> 21214501Srpaulo#include <net/if_media.h> 22209139Srpaulo 23209139Srpaulo#ifdef __NetBSD__ 24209139Srpaulo#include <net/if_ether.h> 25209139Srpaulo#else 26209139Srpaulo#include <net/ethernet.h> 27209139Srpaulo#endif 28214501Srpaulo#include <net/route.h> 29209139Srpaulo 30214501Srpaulo#ifdef __DragonFly__ 31214501Srpaulo#include <netproto/802_11/ieee80211_ioctl.h> 32214501Srpaulo#include <netproto/802_11/ieee80211_dragonfly.h> 33214501Srpaulo#else /* __DragonFly__ */ 34214501Srpaulo#ifdef __GLIBC__ 35214501Srpaulo#include <netinet/ether.h> 36214501Srpaulo#endif /* __GLIBC__ */ 37209139Srpaulo#include <net80211/ieee80211.h> 38214501Srpaulo#include <net80211/ieee80211_ioctl.h> 39209139Srpaulo#include <net80211/ieee80211_crypto.h> 40214501Srpaulo#endif /* __DragonFly__ || __GLIBC__ */ 41214501Srpaulo#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 42214501Srpaulo#include <net80211/ieee80211_freebsd.h> 43214501Srpaulo#endif 44214501Srpaulo#if __NetBSD__ 45214501Srpaulo#include <net80211/ieee80211_netbsd.h> 46214501Srpaulo#endif 47209139Srpaulo 48214501Srpaulo#include "l2_packet/l2_packet.h" 49214501Srpaulo 50214501Srpaulostruct bsd_driver_data { 51214501Srpaulo struct hostapd_data *hapd; /* back pointer */ 52214501Srpaulo 53209139Srpaulo int sock; /* open socket for 802.11 ioctls */ 54214501Srpaulo struct l2_packet_data *sock_xmit;/* raw packet xmit socket */ 55209139Srpaulo int route; /* routing socket for events */ 56209139Srpaulo char ifname[IFNAMSIZ+1]; /* interface name */ 57209139Srpaulo unsigned int ifindex; /* interface index */ 58209139Srpaulo void *ctx; 59214501Srpaulo struct wpa_driver_capa capa; /* driver capability */ 60214501Srpaulo int is_ap; /* Access point mode */ 61214501Srpaulo int prev_roaming; /* roaming state to restore on deinit */ 62214501Srpaulo int prev_privacy; /* privacy state to restore on deinit */ 63214501Srpaulo int prev_wpa; /* wpa state to restore on deinit */ 64209139Srpaulo}; 65209139Srpaulo 66214501Srpaulo/* Generic functions for hostapd and wpa_supplicant */ 67214501Srpaulo 68209139Srpaulostatic int 69214501Srpaulobsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) 70209139Srpaulo{ 71214501Srpaulo struct bsd_driver_data *drv = priv; 72209139Srpaulo struct ieee80211req ireq; 73209139Srpaulo 74209139Srpaulo os_memset(&ireq, 0, sizeof(ireq)); 75214501Srpaulo os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name)); 76209139Srpaulo ireq.i_type = op; 77214501Srpaulo ireq.i_val = val; 78214501Srpaulo ireq.i_data = (void *) arg; 79209139Srpaulo ireq.i_len = arg_len; 80209139Srpaulo 81209139Srpaulo if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) { 82214501Srpaulo wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, " 83214501Srpaulo "arg_len=%u]: %s", op, val, arg_len, 84214501Srpaulo strerror(errno)); 85209139Srpaulo return -1; 86209139Srpaulo } 87209139Srpaulo return 0; 88209139Srpaulo} 89209139Srpaulo 90209139Srpaulostatic int 91214501Srpaulobsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg, 92214501Srpaulo int arg_len) 93209139Srpaulo{ 94214501Srpaulo struct bsd_driver_data *drv = priv; 95209139Srpaulo 96214501Srpaulo os_memset(ireq, 0, sizeof(*ireq)); 97214501Srpaulo os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name)); 98214501Srpaulo ireq->i_type = op; 99214501Srpaulo ireq->i_len = arg_len; 100214501Srpaulo ireq->i_data = arg; 101209139Srpaulo 102214501Srpaulo if (ioctl(drv->sock, SIOCG80211, ireq) < 0) { 103214501Srpaulo wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, " 104214501Srpaulo "arg_len=%u]: %s", op, arg_len, strerror(errno)); 105209139Srpaulo return -1; 106209139Srpaulo } 107214501Srpaulo return 0; 108209139Srpaulo} 109209139Srpaulo 110209139Srpaulostatic int 111214501Srpauloget80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len) 112209139Srpaulo{ 113209139Srpaulo struct ieee80211req ireq; 114209139Srpaulo 115214501Srpaulo if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0) 116209139Srpaulo return -1; 117214501Srpaulo return ireq.i_len; 118209139Srpaulo} 119209139Srpaulo 120209139Srpaulostatic int 121214501Srpauloset80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len) 122209139Srpaulo{ 123214501Srpaulo return bsd_set80211(drv, op, 0, arg, arg_len); 124214501Srpaulo} 125209139Srpaulo 126214501Srpaulostatic int 127214501Srpauloset80211param(struct bsd_driver_data *drv, int op, int arg) 128214501Srpaulo{ 129214501Srpaulo return bsd_set80211(drv, op, arg, NULL, 0); 130209139Srpaulo} 131209139Srpaulo 132209139Srpaulostatic int 133214501Srpaulobsd_get_ssid(void *priv, u8 *ssid, int len) 134209139Srpaulo{ 135214501Srpaulo struct bsd_driver_data *drv = priv; 136214501Srpaulo#ifdef SIOCG80211NWID 137214501Srpaulo struct ieee80211_nwid nwid; 138209139Srpaulo struct ifreq ifr; 139209139Srpaulo 140209139Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 141209139Srpaulo os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 142214501Srpaulo ifr.ifr_data = (void *)&nwid; 143214501Srpaulo if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || 144214501Srpaulo nwid.i_len > IEEE80211_NWID_LEN) 145214501Srpaulo return -1; 146214501Srpaulo os_memcpy(ssid, nwid.i_nwid, nwid.i_len); 147214501Srpaulo return nwid.i_len; 148214501Srpaulo#else 149214501Srpaulo return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN); 150214501Srpaulo#endif 151209139Srpaulo} 152209139Srpaulo 153209139Srpaulostatic int 154214501Srpaulobsd_set_ssid(void *priv, const u8 *ssid, int ssid_len) 155209139Srpaulo{ 156214501Srpaulo struct bsd_driver_data *drv = priv; 157214501Srpaulo#ifdef SIOCS80211NWID 158214501Srpaulo struct ieee80211_nwid nwid; 159209139Srpaulo struct ifreq ifr; 160209139Srpaulo 161214501Srpaulo os_memcpy(nwid.i_nwid, ssid, ssid_len); 162214501Srpaulo nwid.i_len = ssid_len; 163209139Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 164209139Srpaulo os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 165214501Srpaulo ifr.ifr_data = (void *)&nwid; 166214501Srpaulo return ioctl(drv->sock, SIOCS80211NWID, &ifr); 167214501Srpaulo#else 168214501Srpaulo return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len); 169214501Srpaulo#endif 170209139Srpaulo} 171209139Srpaulo 172209139Srpaulostatic int 173214501Srpaulobsd_get_if_media(void *priv) 174209139Srpaulo{ 175214501Srpaulo struct bsd_driver_data *drv = priv; 176214501Srpaulo struct ifmediareq ifmr; 177209139Srpaulo 178214501Srpaulo os_memset(&ifmr, 0, sizeof(ifmr)); 179214501Srpaulo os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); 180209139Srpaulo 181214501Srpaulo if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) { 182214501Srpaulo wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__, 183214501Srpaulo strerror(errno)); 184214501Srpaulo return -1; 185214501Srpaulo } 186209139Srpaulo 187214501Srpaulo return ifmr.ifm_current; 188209139Srpaulo} 189209139Srpaulo 190209139Srpaulostatic int 191214501Srpaulobsd_set_if_media(void *priv, int media) 192209139Srpaulo{ 193214501Srpaulo struct bsd_driver_data *drv = priv; 194214501Srpaulo struct ifreq ifr; 195209139Srpaulo 196214501Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 197214501Srpaulo os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 198214501Srpaulo ifr.ifr_media = media; 199209139Srpaulo 200214501Srpaulo if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) { 201214501Srpaulo wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__, 202214501Srpaulo strerror(errno)); 203214501Srpaulo return -1; 204214501Srpaulo } 205209139Srpaulo 206214501Srpaulo return 0; 207209139Srpaulo} 208209139Srpaulo 209209139Srpaulostatic int 210214501Srpaulobsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode) 211209139Srpaulo{ 212214501Srpaulo int media = bsd_get_if_media(priv); 213214501Srpaulo 214214501Srpaulo if (media < 0) 215214501Srpaulo return -1; 216214501Srpaulo media &= ~mask; 217214501Srpaulo media |= mode; 218214501Srpaulo if (bsd_set_if_media(priv, media) < 0) 219214501Srpaulo return -1; 220214501Srpaulo return 0; 221209139Srpaulo} 222209139Srpaulo 223209139Srpaulostatic int 224214501Srpaulobsd_del_key(void *priv, const u8 *addr, int key_idx) 225209139Srpaulo{ 226214501Srpaulo struct ieee80211req_del_key wk; 227209139Srpaulo 228214501Srpaulo os_memset(&wk, 0, sizeof(wk)); 229214501Srpaulo if (addr == NULL) { 230214501Srpaulo wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx); 231214501Srpaulo wk.idk_keyix = key_idx; 232214501Srpaulo } else { 233214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, 234214501Srpaulo MAC2STR(addr)); 235214501Srpaulo os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); 236214501Srpaulo wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */ 237214501Srpaulo } 238209139Srpaulo 239214501Srpaulo return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); 240209139Srpaulo} 241209139Srpaulo 242209139Srpaulostatic int 243214501Srpaulobsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr) 244209139Srpaulo{ 245214501Srpaulo struct ieee80211req_mlme mlme; 246209139Srpaulo 247214501Srpaulo os_memset(&mlme, 0, sizeof(mlme)); 248214501Srpaulo mlme.im_op = op; 249214501Srpaulo mlme.im_reason = reason; 250214501Srpaulo os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 251214501Srpaulo return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); 252209139Srpaulo} 253209139Srpaulo 254209139Srpaulostatic int 255214501Srpaulobsd_ctrl_iface(void *priv, int enable) 256209139Srpaulo{ 257214501Srpaulo struct bsd_driver_data *drv = priv; 258214501Srpaulo struct ifreq ifr; 259209139Srpaulo 260214501Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 261214501Srpaulo os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 262209139Srpaulo 263214501Srpaulo if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) { 264214501Srpaulo perror("ioctl[SIOCGIFFLAGS]"); 265214501Srpaulo return -1; 266209139Srpaulo } 267214501Srpaulo 268214501Srpaulo if (enable) 269214501Srpaulo ifr.ifr_flags |= IFF_UP; 270214501Srpaulo else 271214501Srpaulo ifr.ifr_flags &= ~IFF_UP; 272214501Srpaulo 273214501Srpaulo if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) { 274214501Srpaulo perror("ioctl[SIOCSIFFLAGS]"); 275214501Srpaulo return -1; 276214501Srpaulo } 277214501Srpaulo 278214501Srpaulo return 0; 279209139Srpaulo} 280209139Srpaulo 281209139Srpaulostatic int 282214501Srpaulobsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, 283214501Srpaulo const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, 284214501Srpaulo size_t seq_len, const u8 *key, size_t key_len) 285209139Srpaulo{ 286209139Srpaulo struct ieee80211req_key wk; 287209139Srpaulo 288214501Srpaulo wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " 289214501Srpaulo "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx, 290214501Srpaulo set_tx, seq_len, key_len); 291209139Srpaulo 292214501Srpaulo if (alg == WPA_ALG_NONE) { 293214501Srpaulo#ifndef HOSTAPD 294252190Srpaulo if (addr == NULL || is_broadcast_ether_addr(addr)) 295214501Srpaulo return bsd_del_key(priv, NULL, key_idx); 296214501Srpaulo else 297214501Srpaulo#endif /* HOSTAPD */ 298214501Srpaulo return bsd_del_key(priv, addr, key_idx); 299214501Srpaulo } 300214501Srpaulo 301214501Srpaulo os_memset(&wk, 0, sizeof(wk)); 302209139Srpaulo switch (alg) { 303209139Srpaulo case WPA_ALG_WEP: 304214501Srpaulo wk.ik_type = IEEE80211_CIPHER_WEP; 305209139Srpaulo break; 306209139Srpaulo case WPA_ALG_TKIP: 307214501Srpaulo wk.ik_type = IEEE80211_CIPHER_TKIP; 308209139Srpaulo break; 309209139Srpaulo case WPA_ALG_CCMP: 310214501Srpaulo wk.ik_type = IEEE80211_CIPHER_AES_CCM; 311209139Srpaulo break; 312209139Srpaulo default: 313214501Srpaulo wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg); 314209139Srpaulo return -1; 315209139Srpaulo } 316209139Srpaulo 317209139Srpaulo wk.ik_flags = IEEE80211_KEY_RECV; 318209139Srpaulo if (set_tx) 319209139Srpaulo wk.ik_flags |= IEEE80211_KEY_XMIT; 320214501Srpaulo 321214501Srpaulo if (addr == NULL) { 322214501Srpaulo os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 323209139Srpaulo wk.ik_keyix = key_idx; 324209139Srpaulo } else { 325214501Srpaulo os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 326214501Srpaulo /* 327214501Srpaulo * Deduce whether group/global or unicast key by checking 328214501Srpaulo * the address (yech). Note also that we can only mark global 329214501Srpaulo * keys default; doing this for a unicast key is an error. 330214501Srpaulo */ 331252190Srpaulo if (is_broadcast_ether_addr(addr)) { 332214501Srpaulo wk.ik_flags |= IEEE80211_KEY_GROUP; 333214501Srpaulo wk.ik_keyix = key_idx; 334214501Srpaulo } else { 335214501Srpaulo wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE : 336214501Srpaulo key_idx; 337214501Srpaulo } 338209139Srpaulo } 339209139Srpaulo if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx) 340209139Srpaulo wk.ik_flags |= IEEE80211_KEY_DEFAULT; 341209139Srpaulo wk.ik_keylen = key_len; 342252190Srpaulo if (seq) { 343252190Srpaulo#ifdef WORDS_BIGENDIAN 344252190Srpaulo /* 345252190Srpaulo * wk.ik_keyrsc is in host byte order (big endian), need to 346252190Srpaulo * swap it to match with the byte order used in WPA. 347252190Srpaulo */ 348252190Srpaulo int i; 349252190Srpaulo u8 *keyrsc = (u8 *) &wk.ik_keyrsc; 350252190Srpaulo for (i = 0; i < seq_len; i++) 351252190Srpaulo keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i]; 352252190Srpaulo#else /* WORDS_BIGENDIAN */ 353252190Srpaulo os_memcpy(&wk.ik_keyrsc, seq, seq_len); 354252190Srpaulo#endif /* WORDS_BIGENDIAN */ 355252190Srpaulo } 356209139Srpaulo os_memcpy(wk.ik_keydata, key, key_len); 357209139Srpaulo 358214501Srpaulo return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); 359209139Srpaulo} 360209139Srpaulo 361209139Srpaulostatic int 362214501Srpaulobsd_configure_wpa(void *priv, struct wpa_bss_params *params) 363209139Srpaulo{ 364214501Srpaulo#ifndef IEEE80211_IOC_APPIE 365214501Srpaulo static const char *ciphernames[] = 366214501Srpaulo { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" }; 367214501Srpaulo int v; 368209139Srpaulo 369214501Srpaulo switch (params->wpa_group) { 370214501Srpaulo case WPA_CIPHER_CCMP: 371214501Srpaulo v = IEEE80211_CIPHER_AES_CCM; 372214501Srpaulo break; 373214501Srpaulo case WPA_CIPHER_TKIP: 374214501Srpaulo v = IEEE80211_CIPHER_TKIP; 375214501Srpaulo break; 376214501Srpaulo case WPA_CIPHER_WEP104: 377214501Srpaulo v = IEEE80211_CIPHER_WEP; 378214501Srpaulo break; 379214501Srpaulo case WPA_CIPHER_WEP40: 380214501Srpaulo v = IEEE80211_CIPHER_WEP; 381214501Srpaulo break; 382214501Srpaulo case WPA_CIPHER_NONE: 383214501Srpaulo v = IEEE80211_CIPHER_NONE; 384214501Srpaulo break; 385214501Srpaulo default: 386214501Srpaulo printf("Unknown group key cipher %u\n", 387214501Srpaulo params->wpa_group); 388214501Srpaulo return -1; 389214501Srpaulo } 390214501Srpaulo wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)", 391214501Srpaulo __func__, ciphernames[v], v); 392214501Srpaulo if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) { 393214501Srpaulo printf("Unable to set group key cipher to %u (%s)\n", 394214501Srpaulo v, ciphernames[v]); 395214501Srpaulo return -1; 396214501Srpaulo } 397214501Srpaulo if (v == IEEE80211_CIPHER_WEP) { 398214501Srpaulo /* key length is done only for specific ciphers */ 399214501Srpaulo v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); 400214501Srpaulo if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) { 401214501Srpaulo printf("Unable to set group key length to %u\n", v); 402214501Srpaulo return -1; 403214501Srpaulo } 404214501Srpaulo } 405214501Srpaulo 406214501Srpaulo v = 0; 407214501Srpaulo if (params->wpa_pairwise & WPA_CIPHER_CCMP) 408214501Srpaulo v |= 1<<IEEE80211_CIPHER_AES_CCM; 409214501Srpaulo if (params->wpa_pairwise & WPA_CIPHER_TKIP) 410214501Srpaulo v |= 1<<IEEE80211_CIPHER_TKIP; 411214501Srpaulo if (params->wpa_pairwise & WPA_CIPHER_NONE) 412214501Srpaulo v |= 1<<IEEE80211_CIPHER_NONE; 413214501Srpaulo wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v); 414214501Srpaulo if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) { 415214501Srpaulo printf("Unable to set pairwise key ciphers to 0x%x\n", v); 416214501Srpaulo return -1; 417214501Srpaulo } 418214501Srpaulo 419214501Srpaulo wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x", 420214501Srpaulo __func__, params->wpa_key_mgmt); 421214501Srpaulo if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS, 422214501Srpaulo params->wpa_key_mgmt)) { 423214501Srpaulo printf("Unable to set key management algorithms to 0x%x\n", 424214501Srpaulo params->wpa_key_mgmt); 425214501Srpaulo return -1; 426214501Srpaulo } 427214501Srpaulo 428214501Srpaulo v = 0; 429214501Srpaulo if (params->rsn_preauth) 430214501Srpaulo v |= BIT(0); 431214501Srpaulo wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", 432214501Srpaulo __func__, params->rsn_preauth); 433214501Srpaulo if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) { 434214501Srpaulo printf("Unable to set RSN capabilities to 0x%x\n", v); 435214501Srpaulo return -1; 436214501Srpaulo } 437214501Srpaulo#endif /* IEEE80211_IOC_APPIE */ 438214501Srpaulo 439214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa); 440214501Srpaulo if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) { 441214501Srpaulo printf("Unable to set WPA to %u\n", params->wpa); 442214501Srpaulo return -1; 443214501Srpaulo } 444214501Srpaulo return 0; 445214501Srpaulo} 446214501Srpaulo 447214501Srpaulostatic int 448214501Srpaulobsd_set_ieee8021x(void *priv, struct wpa_bss_params *params) 449214501Srpaulo{ 450214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); 451214501Srpaulo 452214501Srpaulo if (!params->enabled) { 453214501Srpaulo /* XXX restore state */ 454214501Srpaulo return set80211param(priv, IEEE80211_IOC_AUTHMODE, 455214501Srpaulo IEEE80211_AUTH_AUTO); 456214501Srpaulo } 457214501Srpaulo if (!params->wpa && !params->ieee802_1x) { 458214501Srpaulo wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled", 459214501Srpaulo __func__); 460214501Srpaulo return -1; 461214501Srpaulo } 462214501Srpaulo if (params->wpa && bsd_configure_wpa(priv, params) != 0) { 463214501Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state", 464214501Srpaulo __func__); 465214501Srpaulo return -1; 466214501Srpaulo } 467214501Srpaulo if (set80211param(priv, IEEE80211_IOC_AUTHMODE, 468214501Srpaulo (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { 469214501Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X", 470214501Srpaulo __func__); 471214501Srpaulo return -1; 472214501Srpaulo } 473214501Srpaulo return bsd_ctrl_iface(priv, 1); 474214501Srpaulo} 475214501Srpaulo 476214501Srpaulostatic int 477214501Srpaulobsd_set_sta_authorized(void *priv, const u8 *addr, 478214501Srpaulo int total_flags, int flags_or, int flags_and) 479214501Srpaulo{ 480214501Srpaulo int authorized = -1; 481214501Srpaulo 482214501Srpaulo /* For now, only support setting Authorized flag */ 483214501Srpaulo if (flags_or & WPA_STA_AUTHORIZED) 484214501Srpaulo authorized = 1; 485214501Srpaulo if (!(flags_and & WPA_STA_AUTHORIZED)) 486214501Srpaulo authorized = 0; 487214501Srpaulo 488214501Srpaulo if (authorized < 0) 489214501Srpaulo return 0; 490214501Srpaulo 491214501Srpaulo return bsd_send_mlme_param(priv, authorized ? 492214501Srpaulo IEEE80211_MLME_AUTHORIZE : 493214501Srpaulo IEEE80211_MLME_UNAUTHORIZE, 0, addr); 494214501Srpaulo} 495214501Srpaulo 496214501Srpaulostatic void 497214501Srpaulobsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN]) 498214501Srpaulo{ 499214501Srpaulo struct ieee80211req_wpaie ie; 500214501Srpaulo int ielen = 0; 501214501Srpaulo u8 *iebuf = NULL; 502214501Srpaulo 503214501Srpaulo /* 504214501Srpaulo * Fetch and validate any negotiated WPA/RSN parameters. 505214501Srpaulo */ 506214501Srpaulo memset(&ie, 0, sizeof(ie)); 507214501Srpaulo memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); 508214501Srpaulo if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { 509214501Srpaulo printf("Failed to get WPA/RSN information element.\n"); 510214501Srpaulo goto no_ie; 511214501Srpaulo } 512214501Srpaulo iebuf = ie.wpa_ie; 513214501Srpaulo ielen = ie.wpa_ie[1]; 514214501Srpaulo if (ielen == 0) 515214501Srpaulo iebuf = NULL; 516214501Srpaulo else 517214501Srpaulo ielen += 2; 518214501Srpaulo 519214501Srpaulono_ie: 520252190Srpaulo drv_event_assoc(ctx, addr, iebuf, ielen, 0); 521214501Srpaulo} 522214501Srpaulo 523214501Srpaulostatic int 524214501Srpaulobsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, 525252190Srpaulo int encrypt, const u8 *own_addr, u32 flags) 526214501Srpaulo{ 527214501Srpaulo struct bsd_driver_data *drv = priv; 528214501Srpaulo 529214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len); 530214501Srpaulo 531214501Srpaulo return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data, 532214501Srpaulo data_len); 533214501Srpaulo} 534214501Srpaulo 535214501Srpaulostatic int 536252190Srpaulobsd_set_freq(void *priv, struct hostapd_freq_params *freq) 537214501Srpaulo{ 538214501Srpaulo struct bsd_driver_data *drv = priv; 539214501Srpaulo#ifdef SIOCS80211CHANNEL 540214501Srpaulo struct ieee80211chanreq creq; 541214501Srpaulo#endif /* SIOCS80211CHANNEL */ 542214501Srpaulo u32 mode; 543252190Srpaulo int channel = freq->channel; 544214501Srpaulo 545252190Srpaulo if (channel < 14) { 546252190Srpaulo mode = 547252190Srpaulo#ifdef CONFIG_IEEE80211N 548252190Srpaulo freq->ht_enabled ? IFM_IEEE80211_11NG : 549252190Srpaulo#endif /* CONFIG_IEEE80211N */ 550252190Srpaulo IFM_IEEE80211_11G; 551252190Srpaulo } else if (channel == 14) { 552214501Srpaulo mode = IFM_IEEE80211_11B; 553252190Srpaulo } else { 554252190Srpaulo mode = 555252190Srpaulo#ifdef CONFIG_IEEE80211N 556252190Srpaulo freq->ht_enabled ? IFM_IEEE80211_11NA : 557252190Srpaulo#endif /* CONFIG_IEEE80211N */ 558252190Srpaulo IFM_IEEE80211_11A; 559252190Srpaulo } 560214501Srpaulo if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) { 561214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set modulation mode", 562214501Srpaulo __func__); 563214501Srpaulo return -1; 564214501Srpaulo } 565214501Srpaulo 566214501Srpaulo#ifdef SIOCS80211CHANNEL 567214501Srpaulo os_memset(&creq, 0, sizeof(creq)); 568214501Srpaulo os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name)); 569252190Srpaulo creq.i_channel = (u_int16_t)channel; 570214501Srpaulo return ioctl(drv->sock, SIOCS80211CHANNEL, &creq); 571214501Srpaulo#else /* SIOCS80211CHANNEL */ 572214501Srpaulo return set80211param(priv, IEEE80211_IOC_CHANNEL, channel); 573214501Srpaulo#endif /* SIOCS80211CHANNEL */ 574214501Srpaulo} 575214501Srpaulo 576214501Srpaulostatic int 577214501Srpaulobsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) 578214501Srpaulo{ 579214501Srpaulo#ifdef IEEE80211_IOC_APPIE 580214501Srpaulo wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__, 581214501Srpaulo (unsigned long)ie_len); 582214501Srpaulo return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA, 583214501Srpaulo ie, ie_len); 584214501Srpaulo#endif /* IEEE80211_IOC_APPIE */ 585214501Srpaulo return 0; 586214501Srpaulo} 587214501Srpaulo 588252190Srpaulostatic int 589252190Srpaulortbuf_len(void) 590252190Srpaulo{ 591252190Srpaulo size_t len; 592214501Srpaulo 593252190Srpaulo int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0}; 594252190Srpaulo 595252190Srpaulo if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { 596252190Srpaulo wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__, 597252190Srpaulo strerror(errno)); 598252190Srpaulo len = 2048; 599252190Srpaulo } 600252190Srpaulo 601252190Srpaulo return len; 602252190Srpaulo} 603252190Srpaulo 604214501Srpaulo#ifdef HOSTAPD 605214501Srpaulo 606214501Srpaulo/* 607214501Srpaulo * Avoid conflicts with hostapd definitions by undefining couple of defines 608214501Srpaulo * from net80211 header files. 609214501Srpaulo */ 610214501Srpaulo#undef RSN_VERSION 611214501Srpaulo#undef WPA_VERSION 612214501Srpaulo#undef WPA_OUI_TYPE 613214501Srpaulo 614214501Srpaulostatic int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, 615214501Srpaulo int reason_code); 616214501Srpaulo 617214501Srpaulostatic const char * 618214501Srpauloether_sprintf(const u8 *addr) 619214501Srpaulo{ 620214501Srpaulo static char buf[sizeof(MACSTR)]; 621214501Srpaulo 622214501Srpaulo if (addr != NULL) 623214501Srpaulo snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); 624214501Srpaulo else 625214501Srpaulo snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); 626214501Srpaulo return buf; 627214501Srpaulo} 628214501Srpaulo 629214501Srpaulostatic int 630214501Srpaulobsd_set_privacy(void *priv, int enabled) 631214501Srpaulo{ 632209139Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 633214501Srpaulo 634214501Srpaulo return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled); 635209139Srpaulo} 636209139Srpaulo 637214501Srpaulostatic int 638214501Srpaulobsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, 639214501Srpaulo u8 *seq) 640214501Srpaulo{ 641214501Srpaulo struct ieee80211req_key wk; 642209139Srpaulo 643214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", 644214501Srpaulo __func__, ether_sprintf(addr), idx); 645214501Srpaulo 646214501Srpaulo memset(&wk, 0, sizeof(wk)); 647214501Srpaulo if (addr == NULL) 648214501Srpaulo memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 649214501Srpaulo else 650214501Srpaulo memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 651214501Srpaulo wk.ik_keyix = idx; 652214501Srpaulo 653214501Srpaulo if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { 654214501Srpaulo printf("Failed to get encryption.\n"); 655214501Srpaulo return -1; 656214501Srpaulo } 657214501Srpaulo 658214501Srpaulo#ifdef WORDS_BIGENDIAN 659214501Srpaulo { 660214501Srpaulo /* 661214501Srpaulo * wk.ik_keytsc is in host byte order (big endian), need to 662214501Srpaulo * swap it to match with the byte order used in WPA. 663214501Srpaulo */ 664214501Srpaulo int i; 665214501Srpaulo u8 tmp[WPA_KEY_RSC_LEN]; 666214501Srpaulo memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 667214501Srpaulo for (i = 0; i < WPA_KEY_RSC_LEN; i++) { 668214501Srpaulo seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; 669214501Srpaulo } 670214501Srpaulo } 671214501Srpaulo#else /* WORDS_BIGENDIAN */ 672214501Srpaulo memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 673214501Srpaulo#endif /* WORDS_BIGENDIAN */ 674214501Srpaulo return 0; 675214501Srpaulo} 676214501Srpaulo 677214501Srpaulo 678214501Srpaulostatic int 679214501Srpaulobsd_flush(void *priv) 680214501Srpaulo{ 681214501Srpaulo u8 allsta[IEEE80211_ADDR_LEN]; 682214501Srpaulo 683214501Srpaulo memset(allsta, 0xff, IEEE80211_ADDR_LEN); 684214501Srpaulo return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); 685214501Srpaulo} 686214501Srpaulo 687214501Srpaulo 688209139Srpaulostatic int 689214501Srpaulobsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, 690214501Srpaulo const u8 *addr) 691209139Srpaulo{ 692214501Srpaulo struct ieee80211req_sta_stats stats; 693209139Srpaulo 694214501Srpaulo memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); 695214501Srpaulo if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) 696214501Srpaulo > 0) { 697214501Srpaulo /* XXX? do packets counts include non-data frames? */ 698214501Srpaulo data->rx_packets = stats.is_stats.ns_rx_data; 699214501Srpaulo data->rx_bytes = stats.is_stats.ns_rx_bytes; 700214501Srpaulo data->tx_packets = stats.is_stats.ns_tx_data; 701214501Srpaulo data->tx_bytes = stats.is_stats.ns_tx_bytes; 702214501Srpaulo } 703214501Srpaulo return 0; 704214501Srpaulo} 705214501Srpaulo 706214501Srpaulostatic int 707214501Srpaulobsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code) 708214501Srpaulo{ 709214501Srpaulo return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, 710214501Srpaulo addr); 711214501Srpaulo} 712214501Srpaulo 713214501Srpaulostatic int 714214501Srpaulobsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, 715214501Srpaulo int reason_code) 716214501Srpaulo{ 717214501Srpaulo return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code, 718214501Srpaulo addr); 719214501Srpaulo} 720214501Srpaulo 721214501Srpaulostatic void 722214501Srpaulobsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) 723214501Srpaulo{ 724214501Srpaulo struct bsd_driver_data *drv = ctx; 725252190Srpaulo char *buf; 726214501Srpaulo struct if_announcemsghdr *ifan; 727214501Srpaulo struct rt_msghdr *rtm; 728214501Srpaulo struct ieee80211_michael_event *mic; 729214501Srpaulo struct ieee80211_join_event *join; 730214501Srpaulo struct ieee80211_leave_event *leave; 731252190Srpaulo int n, len; 732214501Srpaulo union wpa_event_data data; 733214501Srpaulo 734252190Srpaulo len = rtbuf_len(); 735252190Srpaulo 736252190Srpaulo buf = os_malloc(len); 737252190Srpaulo if (buf == NULL) { 738252190Srpaulo wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__); 739252190Srpaulo return; 740252190Srpaulo } 741252190Srpaulo 742252190Srpaulo n = read(sock, buf, len); 743214501Srpaulo if (n < 0) { 744214501Srpaulo if (errno != EINTR && errno != EAGAIN) 745252190Srpaulo wpa_printf(MSG_ERROR, "%s read() failed: %s\n", 746252190Srpaulo __func__, strerror(errno)); 747252190Srpaulo os_free(buf); 748214501Srpaulo return; 749214501Srpaulo } 750214501Srpaulo 751214501Srpaulo rtm = (struct rt_msghdr *) buf; 752214501Srpaulo if (rtm->rtm_version != RTM_VERSION) { 753252190Srpaulo wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", 754252190Srpaulo rtm->rtm_version); 755252190Srpaulo os_free(buf); 756214501Srpaulo return; 757214501Srpaulo } 758214501Srpaulo ifan = (struct if_announcemsghdr *) rtm; 759214501Srpaulo switch (rtm->rtm_type) { 760214501Srpaulo case RTM_IEEE80211: 761214501Srpaulo switch (ifan->ifan_what) { 762214501Srpaulo case RTM_IEEE80211_ASSOC: 763214501Srpaulo case RTM_IEEE80211_REASSOC: 764214501Srpaulo case RTM_IEEE80211_DISASSOC: 765214501Srpaulo case RTM_IEEE80211_SCAN: 766214501Srpaulo break; 767214501Srpaulo case RTM_IEEE80211_LEAVE: 768214501Srpaulo leave = (struct ieee80211_leave_event *) &ifan[1]; 769214501Srpaulo drv_event_disassoc(drv->hapd, leave->iev_addr); 770214501Srpaulo break; 771214501Srpaulo case RTM_IEEE80211_JOIN: 772214501Srpaulo#ifdef RTM_IEEE80211_REJOIN 773214501Srpaulo case RTM_IEEE80211_REJOIN: 774214501Srpaulo#endif 775214501Srpaulo join = (struct ieee80211_join_event *) &ifan[1]; 776214501Srpaulo bsd_new_sta(drv, drv->hapd, join->iev_addr); 777214501Srpaulo break; 778214501Srpaulo case RTM_IEEE80211_REPLAY: 779214501Srpaulo /* ignore */ 780214501Srpaulo break; 781214501Srpaulo case RTM_IEEE80211_MICHAEL: 782214501Srpaulo mic = (struct ieee80211_michael_event *) &ifan[1]; 783214501Srpaulo wpa_printf(MSG_DEBUG, 784214501Srpaulo "Michael MIC failure wireless event: " 785214501Srpaulo "keyix=%u src_addr=" MACSTR, mic->iev_keyix, 786214501Srpaulo MAC2STR(mic->iev_src)); 787214501Srpaulo os_memset(&data, 0, sizeof(data)); 788214501Srpaulo data.michael_mic_failure.unicast = 1; 789214501Srpaulo data.michael_mic_failure.src = mic->iev_src; 790214501Srpaulo wpa_supplicant_event(drv->hapd, 791214501Srpaulo EVENT_MICHAEL_MIC_FAILURE, &data); 792214501Srpaulo break; 793214501Srpaulo } 794214501Srpaulo break; 795214501Srpaulo } 796252190Srpaulo os_free(buf); 797214501Srpaulo} 798214501Srpaulo 799214501Srpaulostatic void 800214501Srpaulohandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) 801214501Srpaulo{ 802214501Srpaulo struct bsd_driver_data *drv = ctx; 803214501Srpaulo drv_event_eapol_rx(drv->hapd, src_addr, buf, len); 804214501Srpaulo} 805214501Srpaulo 806214501Srpaulostatic void * 807214501Srpaulobsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) 808214501Srpaulo{ 809214501Srpaulo struct bsd_driver_data *drv; 810214501Srpaulo 811214501Srpaulo drv = os_zalloc(sizeof(struct bsd_driver_data)); 812214501Srpaulo if (drv == NULL) { 813214501Srpaulo printf("Could not allocate memory for bsd driver data\n"); 814214501Srpaulo goto bad; 815214501Srpaulo } 816214501Srpaulo 817214501Srpaulo drv->hapd = hapd; 818214501Srpaulo drv->sock = socket(PF_INET, SOCK_DGRAM, 0); 819214501Srpaulo if (drv->sock < 0) { 820214501Srpaulo perror("socket[PF_INET,SOCK_DGRAM]"); 821214501Srpaulo goto bad; 822214501Srpaulo } 823214501Srpaulo os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); 824214501Srpaulo 825214501Srpaulo drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, 826214501Srpaulo handle_read, drv, 0); 827214501Srpaulo if (drv->sock_xmit == NULL) 828214501Srpaulo goto bad; 829214501Srpaulo if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) 830214501Srpaulo goto bad; 831214501Srpaulo 832214501Srpaulo /* mark down during setup */ 833214501Srpaulo if (bsd_ctrl_iface(drv, 0) < 0) 834214501Srpaulo goto bad; 835214501Srpaulo 836214501Srpaulo drv->route = socket(PF_ROUTE, SOCK_RAW, 0); 837214501Srpaulo if (drv->route < 0) { 838214501Srpaulo perror("socket(PF_ROUTE,SOCK_RAW)"); 839214501Srpaulo goto bad; 840214501Srpaulo } 841214501Srpaulo eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv, 842214501Srpaulo NULL); 843214501Srpaulo 844214501Srpaulo if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { 845214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set operation mode", 846214501Srpaulo __func__); 847214501Srpaulo goto bad; 848214501Srpaulo } 849214501Srpaulo 850214501Srpaulo return drv; 851214501Srpaulobad: 852214501Srpaulo if (drv->sock_xmit != NULL) 853214501Srpaulo l2_packet_deinit(drv->sock_xmit); 854214501Srpaulo if (drv->sock >= 0) 855214501Srpaulo close(drv->sock); 856214501Srpaulo if (drv != NULL) 857214501Srpaulo os_free(drv); 858214501Srpaulo return NULL; 859214501Srpaulo} 860214501Srpaulo 861214501Srpaulo 862214501Srpaulostatic void 863214501Srpaulobsd_deinit(void *priv) 864214501Srpaulo{ 865214501Srpaulo struct bsd_driver_data *drv = priv; 866214501Srpaulo 867214501Srpaulo if (drv->route >= 0) { 868214501Srpaulo eloop_unregister_read_sock(drv->route); 869214501Srpaulo close(drv->route); 870214501Srpaulo } 871214501Srpaulo bsd_ctrl_iface(drv, 0); 872214501Srpaulo if (drv->sock >= 0) 873214501Srpaulo close(drv->sock); 874214501Srpaulo if (drv->sock_xmit != NULL) 875214501Srpaulo l2_packet_deinit(drv->sock_xmit); 876214501Srpaulo os_free(drv); 877214501Srpaulo} 878214501Srpaulo 879214501Srpaulo#else /* HOSTAPD */ 880214501Srpaulo 881214501Srpaulostatic int 882214501Srpauloget80211param(struct bsd_driver_data *drv, int op) 883214501Srpaulo{ 884214501Srpaulo struct ieee80211req ireq; 885214501Srpaulo 886214501Srpaulo if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0) 887214501Srpaulo return -1; 888214501Srpaulo return ireq.i_val; 889214501Srpaulo} 890214501Srpaulo 891214501Srpaulostatic int 892214501Srpaulowpa_driver_bsd_get_bssid(void *priv, u8 *bssid) 893214501Srpaulo{ 894214501Srpaulo struct bsd_driver_data *drv = priv; 895214501Srpaulo#ifdef SIOCG80211BSSID 896214501Srpaulo struct ieee80211_bssid bs; 897214501Srpaulo 898214501Srpaulo os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name)); 899214501Srpaulo if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0) 900214501Srpaulo return -1; 901214501Srpaulo os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid)); 902214501Srpaulo return 0; 903214501Srpaulo#else 904214501Srpaulo return get80211var(drv, IEEE80211_IOC_BSSID, 905214501Srpaulo bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0; 906214501Srpaulo#endif 907214501Srpaulo} 908214501Srpaulo 909214501Srpaulostatic int 910214501Srpaulowpa_driver_bsd_get_ssid(void *priv, u8 *ssid) 911214501Srpaulo{ 912214501Srpaulo struct bsd_driver_data *drv = priv; 913214501Srpaulo return bsd_get_ssid(drv, ssid, 0); 914214501Srpaulo} 915214501Srpaulo 916214501Srpaulostatic int 917214501Srpaulowpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie, 918214501Srpaulo size_t wpa_ie_len) 919214501Srpaulo{ 920214501Srpaulo#ifdef IEEE80211_IOC_APPIE 921214501Srpaulo return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len); 922214501Srpaulo#else /* IEEE80211_IOC_APPIE */ 923214501Srpaulo return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len); 924214501Srpaulo#endif /* IEEE80211_IOC_APPIE */ 925214501Srpaulo} 926214501Srpaulo 927214501Srpaulostatic int 928214501Srpaulowpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy) 929214501Srpaulo{ 930214501Srpaulo int ret = 0; 931214501Srpaulo 932214501Srpaulo wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d", 933214501Srpaulo __FUNCTION__, wpa, privacy); 934214501Srpaulo 935214501Srpaulo if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0) 936214501Srpaulo ret = -1; 937214501Srpaulo if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0) 938214501Srpaulo ret = -1; 939214501Srpaulo if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0) 940214501Srpaulo ret = -1; 941214501Srpaulo 942214501Srpaulo return ret; 943214501Srpaulo} 944214501Srpaulo 945214501Srpaulostatic int 946214501Srpaulowpa_driver_bsd_set_wpa(void *priv, int enabled) 947214501Srpaulo{ 948214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); 949214501Srpaulo 950214501Srpaulo return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled); 951214501Srpaulo} 952214501Srpaulo 953214501Srpaulostatic int 954214501Srpaulowpa_driver_bsd_set_countermeasures(void *priv, int enabled) 955214501Srpaulo{ 956209139Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 957214501Srpaulo return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled); 958209139Srpaulo} 959209139Srpaulo 960214501Srpaulo 961209139Srpaulostatic int 962214501Srpaulowpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled) 963214501Srpaulo{ 964214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 965214501Srpaulo return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled); 966214501Srpaulo} 967214501Srpaulo 968214501Srpaulostatic int 969209139Srpaulowpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code) 970209139Srpaulo{ 971214501Srpaulo return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, 972214501Srpaulo addr); 973209139Srpaulo} 974209139Srpaulo 975209139Srpaulostatic int 976214501Srpaulowpa_driver_bsd_set_auth_alg(void *priv, int auth_alg) 977214501Srpaulo{ 978214501Srpaulo int authmode; 979214501Srpaulo 980214501Srpaulo if ((auth_alg & WPA_AUTH_ALG_OPEN) && 981214501Srpaulo (auth_alg & WPA_AUTH_ALG_SHARED)) 982214501Srpaulo authmode = IEEE80211_AUTH_AUTO; 983214501Srpaulo else if (auth_alg & WPA_AUTH_ALG_SHARED) 984214501Srpaulo authmode = IEEE80211_AUTH_SHARED; 985214501Srpaulo else 986214501Srpaulo authmode = IEEE80211_AUTH_OPEN; 987214501Srpaulo 988214501Srpaulo return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode); 989209139Srpaulo} 990209139Srpaulo 991214501Srpaulostatic void 992214501Srpaulohandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) 993214501Srpaulo{ 994214501Srpaulo struct bsd_driver_data *drv = ctx; 995214501Srpaulo 996214501Srpaulo drv_event_eapol_rx(drv->ctx, src_addr, buf, len); 997214501Srpaulo} 998214501Srpaulo 999209139Srpaulostatic int 1000209139Srpaulowpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) 1001209139Srpaulo{ 1002214501Srpaulo struct bsd_driver_data *drv = priv; 1003209139Srpaulo struct ieee80211req_mlme mlme; 1004214501Srpaulo u32 mode; 1005209139Srpaulo int privacy; 1006214501Srpaulo int ret = 0; 1007209139Srpaulo 1008209139Srpaulo wpa_printf(MSG_DEBUG, 1009209139Srpaulo "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u" 1010209139Srpaulo , __func__ 1011214501Srpaulo , (unsigned int) params->ssid_len, params->ssid 1012214501Srpaulo , (unsigned int) params->wpa_ie_len 1013209139Srpaulo , params->pairwise_suite 1014209139Srpaulo , params->group_suite 1015209139Srpaulo , params->key_mgmt_suite 1016209139Srpaulo ); 1017209139Srpaulo 1018214501Srpaulo switch (params->mode) { 1019214501Srpaulo case IEEE80211_MODE_INFRA: 1020214501Srpaulo mode = 0 /* STA */; 1021214501Srpaulo break; 1022214501Srpaulo case IEEE80211_MODE_IBSS: 1023214501Srpaulo mode = IFM_IEEE80211_IBSS; 1024214501Srpaulo break; 1025214501Srpaulo case IEEE80211_MODE_AP: 1026214501Srpaulo mode = IFM_IEEE80211_HOSTAP; 1027214501Srpaulo break; 1028214501Srpaulo default: 1029214501Srpaulo wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__); 1030214501Srpaulo return -1; 1031214501Srpaulo } 1032214501Srpaulo if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) { 1033214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set operation mode", 1034214501Srpaulo __func__); 1035214501Srpaulo return -1; 1036214501Srpaulo } 1037214501Srpaulo 1038214501Srpaulo if (params->mode == IEEE80211_MODE_AP) { 1039214501Srpaulo drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, 1040214501Srpaulo handle_read, drv, 0); 1041214501Srpaulo if (drv->sock_xmit == NULL) 1042214501Srpaulo return -1; 1043214501Srpaulo drv->is_ap = 1; 1044214501Srpaulo return 0; 1045214501Srpaulo } 1046214501Srpaulo 1047214501Srpaulo if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted) 1048214501Srpaulo < 0) 1049214501Srpaulo ret = -1; 1050214501Srpaulo if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0) 1051214501Srpaulo ret = -1; 1052209139Srpaulo /* XXX error handling is wrong but unclear what to do... */ 1053209139Srpaulo if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) 1054209139Srpaulo return -1; 1055209139Srpaulo 1056209139Srpaulo privacy = !(params->pairwise_suite == CIPHER_NONE && 1057209139Srpaulo params->group_suite == CIPHER_NONE && 1058209139Srpaulo params->key_mgmt_suite == KEY_MGMT_NONE && 1059209139Srpaulo params->wpa_ie_len == 0); 1060209139Srpaulo wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy); 1061209139Srpaulo 1062209139Srpaulo if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0) 1063209139Srpaulo return -1; 1064209139Srpaulo 1065209139Srpaulo if (params->wpa_ie_len && 1066209139Srpaulo set80211param(drv, IEEE80211_IOC_WPA, 1067209139Srpaulo params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0) 1068209139Srpaulo return -1; 1069209139Srpaulo 1070209139Srpaulo os_memset(&mlme, 0, sizeof(mlme)); 1071209139Srpaulo mlme.im_op = IEEE80211_MLME_ASSOC; 1072209139Srpaulo if (params->ssid != NULL) 1073209139Srpaulo os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len); 1074209139Srpaulo mlme.im_ssid_len = params->ssid_len; 1075209139Srpaulo if (params->bssid != NULL) 1076209139Srpaulo os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN); 1077209139Srpaulo if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0) 1078209139Srpaulo return -1; 1079214501Srpaulo return ret; 1080209139Srpaulo} 1081209139Srpaulo 1082209139Srpaulostatic int 1083214501Srpaulowpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) 1084209139Srpaulo{ 1085214501Srpaulo struct bsd_driver_data *drv = priv; 1086214501Srpaulo#ifdef IEEE80211_IOC_SCAN_MAX_SSID 1087214501Srpaulo struct ieee80211_scan_req sr; 1088214501Srpaulo int i; 1089214501Srpaulo#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ 1090209139Srpaulo 1091214501Srpaulo if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) { 1092214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set operation mode", 1093214501Srpaulo __func__); 1094214501Srpaulo return -1; 1095214501Srpaulo } 1096209139Srpaulo 1097214501Srpaulo if (set80211param(drv, IEEE80211_IOC_ROAMING, 1098214501Srpaulo IEEE80211_ROAMING_MANUAL) < 0) { 1099214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set " 1100214501Srpaulo "wpa_supplicant-based roaming: %s", __func__, 1101214501Srpaulo strerror(errno)); 1102214501Srpaulo return -1; 1103214501Srpaulo } 1104209139Srpaulo 1105214501Srpaulo if (wpa_driver_bsd_set_wpa(drv, 1) < 0) { 1106214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__, 1107214501Srpaulo strerror(errno)); 1108214501Srpaulo return -1; 1109214501Srpaulo } 1110209139Srpaulo 1111209139Srpaulo /* NB: interface must be marked UP to do a scan */ 1112214501Srpaulo if (bsd_ctrl_iface(drv, 1) < 0) 1113209139Srpaulo return -1; 1114209139Srpaulo 1115214501Srpaulo#ifdef IEEE80211_IOC_SCAN_MAX_SSID 1116214501Srpaulo os_memset(&sr, 0, sizeof(sr)); 1117214501Srpaulo sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE | 1118214501Srpaulo IEEE80211_IOC_SCAN_NOJOIN; 1119214501Srpaulo sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; 1120214501Srpaulo if (params->num_ssids > 0) { 1121214501Srpaulo sr.sr_nssid = params->num_ssids; 1122214501Srpaulo#if 0 1123214501Srpaulo /* Boundary check is done by upper layer */ 1124214501Srpaulo if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID) 1125214501Srpaulo sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID; 1126214501Srpaulo#endif 1127214501Srpaulo 1128214501Srpaulo /* NB: check scan cache first */ 1129214501Srpaulo sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK; 1130214501Srpaulo } 1131214501Srpaulo for (i = 0; i < sr.sr_nssid; i++) { 1132214501Srpaulo sr.sr_ssid[i].len = params->ssids[i].ssid_len; 1133214501Srpaulo os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid, 1134214501Srpaulo sr.sr_ssid[i].len); 1135214501Srpaulo } 1136214501Srpaulo 1137214501Srpaulo /* NB: net80211 delivers a scan complete event so no need to poll */ 1138214501Srpaulo return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr)); 1139214501Srpaulo#else /* IEEE80211_IOC_SCAN_MAX_SSID */ 1140209139Srpaulo /* set desired ssid before scan */ 1141214501Srpaulo if (bsd_set_ssid(drv, params->ssids[0].ssid, 1142214501Srpaulo params->ssids[0].ssid_len) < 0) 1143209139Srpaulo return -1; 1144209139Srpaulo 1145209139Srpaulo /* NB: net80211 delivers a scan complete event so no need to poll */ 1146209139Srpaulo return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0); 1147214501Srpaulo#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ 1148209139Srpaulo} 1149209139Srpaulo 1150209139Srpaulostatic void 1151209139Srpaulowpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) 1152209139Srpaulo{ 1153214501Srpaulo struct bsd_driver_data *drv = sock_ctx; 1154252190Srpaulo char *buf; 1155209139Srpaulo struct if_announcemsghdr *ifan; 1156209139Srpaulo struct if_msghdr *ifm; 1157209139Srpaulo struct rt_msghdr *rtm; 1158209139Srpaulo union wpa_event_data event; 1159209139Srpaulo struct ieee80211_michael_event *mic; 1160214501Srpaulo struct ieee80211_leave_event *leave; 1161214501Srpaulo struct ieee80211_join_event *join; 1162252190Srpaulo int n, len; 1163209139Srpaulo 1164252190Srpaulo len = rtbuf_len(); 1165252190Srpaulo 1166252190Srpaulo buf = os_malloc(len); 1167252190Srpaulo if (buf == NULL) { 1168252190Srpaulo wpa_printf(MSG_ERROR, "%s os_malloc() failed\n", __func__); 1169252190Srpaulo return; 1170252190Srpaulo } 1171252190Srpaulo 1172252190Srpaulo n = read(sock, buf, len); 1173209139Srpaulo if (n < 0) { 1174209139Srpaulo if (errno != EINTR && errno != EAGAIN) 1175252190Srpaulo wpa_printf(MSG_ERROR, "%s read() failed: %s\n", 1176252190Srpaulo __func__, strerror(errno)); 1177252190Srpaulo os_free(buf); 1178209139Srpaulo return; 1179209139Srpaulo } 1180209139Srpaulo 1181209139Srpaulo rtm = (struct rt_msghdr *) buf; 1182209139Srpaulo if (rtm->rtm_version != RTM_VERSION) { 1183252190Srpaulo wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", 1184252190Srpaulo rtm->rtm_version); 1185252190Srpaulo os_free(buf); 1186209139Srpaulo return; 1187209139Srpaulo } 1188209139Srpaulo os_memset(&event, 0, sizeof(event)); 1189209139Srpaulo switch (rtm->rtm_type) { 1190209139Srpaulo case RTM_IFANNOUNCE: 1191209139Srpaulo ifan = (struct if_announcemsghdr *) rtm; 1192209139Srpaulo if (ifan->ifan_index != drv->ifindex) 1193209139Srpaulo break; 1194214501Srpaulo os_strlcpy(event.interface_status.ifname, drv->ifname, 1195214501Srpaulo sizeof(event.interface_status.ifname)); 1196209139Srpaulo switch (ifan->ifan_what) { 1197209139Srpaulo case IFAN_DEPARTURE: 1198209139Srpaulo event.interface_status.ievent = EVENT_INTERFACE_REMOVED; 1199209139Srpaulo default: 1200252190Srpaulo os_free(buf); 1201209139Srpaulo return; 1202209139Srpaulo } 1203209139Srpaulo wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", 1204209139Srpaulo event.interface_status.ifname, 1205209139Srpaulo ifan->ifan_what == IFAN_DEPARTURE ? 1206209139Srpaulo "removed" : "added"); 1207209139Srpaulo wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); 1208209139Srpaulo break; 1209209139Srpaulo case RTM_IEEE80211: 1210209139Srpaulo ifan = (struct if_announcemsghdr *) rtm; 1211209139Srpaulo if (ifan->ifan_index != drv->ifindex) 1212209139Srpaulo break; 1213209139Srpaulo switch (ifan->ifan_what) { 1214209139Srpaulo case RTM_IEEE80211_ASSOC: 1215209139Srpaulo case RTM_IEEE80211_REASSOC: 1216214501Srpaulo if (drv->is_ap) 1217214501Srpaulo break; 1218209139Srpaulo wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); 1219209139Srpaulo break; 1220209139Srpaulo case RTM_IEEE80211_DISASSOC: 1221214501Srpaulo if (drv->is_ap) 1222214501Srpaulo break; 1223209139Srpaulo wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); 1224209139Srpaulo break; 1225209139Srpaulo case RTM_IEEE80211_SCAN: 1226214501Srpaulo if (drv->is_ap) 1227214501Srpaulo break; 1228209139Srpaulo wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); 1229209139Srpaulo break; 1230214501Srpaulo case RTM_IEEE80211_LEAVE: 1231214501Srpaulo leave = (struct ieee80211_leave_event *) &ifan[1]; 1232214501Srpaulo drv_event_disassoc(ctx, leave->iev_addr); 1233214501Srpaulo break; 1234214501Srpaulo case RTM_IEEE80211_JOIN: 1235214501Srpaulo#ifdef RTM_IEEE80211_REJOIN 1236214501Srpaulo case RTM_IEEE80211_REJOIN: 1237214501Srpaulo#endif 1238214501Srpaulo join = (struct ieee80211_join_event *) &ifan[1]; 1239214501Srpaulo bsd_new_sta(drv, ctx, join->iev_addr); 1240214501Srpaulo break; 1241209139Srpaulo case RTM_IEEE80211_REPLAY: 1242209139Srpaulo /* ignore */ 1243209139Srpaulo break; 1244209139Srpaulo case RTM_IEEE80211_MICHAEL: 1245209139Srpaulo mic = (struct ieee80211_michael_event *) &ifan[1]; 1246209139Srpaulo wpa_printf(MSG_DEBUG, 1247209139Srpaulo "Michael MIC failure wireless event: " 1248209139Srpaulo "keyix=%u src_addr=" MACSTR, mic->iev_keyix, 1249209139Srpaulo MAC2STR(mic->iev_src)); 1250209139Srpaulo 1251209139Srpaulo os_memset(&event, 0, sizeof(event)); 1252209139Srpaulo event.michael_mic_failure.unicast = 1253209139Srpaulo !IEEE80211_IS_MULTICAST(mic->iev_dst); 1254209139Srpaulo wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, 1255209139Srpaulo &event); 1256209139Srpaulo break; 1257209139Srpaulo } 1258209139Srpaulo break; 1259209139Srpaulo case RTM_IFINFO: 1260209139Srpaulo ifm = (struct if_msghdr *) rtm; 1261209139Srpaulo if (ifm->ifm_index != drv->ifindex) 1262209139Srpaulo break; 1263209139Srpaulo if ((rtm->rtm_flags & RTF_UP) == 0) { 1264214501Srpaulo os_strlcpy(event.interface_status.ifname, drv->ifname, 1265214501Srpaulo sizeof(event.interface_status.ifname)); 1266209139Srpaulo event.interface_status.ievent = EVENT_INTERFACE_REMOVED; 1267209139Srpaulo wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", 1268209139Srpaulo event.interface_status.ifname); 1269209139Srpaulo wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); 1270209139Srpaulo } 1271209139Srpaulo break; 1272209139Srpaulo } 1273252190Srpaulo os_free(buf); 1274209139Srpaulo} 1275209139Srpaulo 1276214501Srpaulostatic void 1277214501Srpaulowpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, 1278214501Srpaulo struct ieee80211req_scan_result *sr) 1279209139Srpaulo{ 1280214501Srpaulo struct wpa_scan_res *result, **tmp; 1281214501Srpaulo size_t extra_len; 1282214501Srpaulo u8 *pos; 1283209139Srpaulo 1284214501Srpaulo extra_len = 2 + sr->isr_ssid_len; 1285214501Srpaulo extra_len += 2 + sr->isr_nrates; 1286214501Srpaulo extra_len += 3; /* ERP IE */ 1287214501Srpaulo extra_len += sr->isr_ie_len; 1288209139Srpaulo 1289214501Srpaulo result = os_zalloc(sizeof(*result) + extra_len); 1290214501Srpaulo if (result == NULL) 1291214501Srpaulo return; 1292214501Srpaulo os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN); 1293214501Srpaulo result->freq = sr->isr_freq; 1294214501Srpaulo result->beacon_int = sr->isr_intval; 1295214501Srpaulo result->caps = sr->isr_capinfo; 1296214501Srpaulo result->qual = sr->isr_rssi; 1297214501Srpaulo result->noise = sr->isr_noise; 1298209139Srpaulo 1299214501Srpaulo pos = (u8 *)(result + 1); 1300209139Srpaulo 1301214501Srpaulo *pos++ = WLAN_EID_SSID; 1302214501Srpaulo *pos++ = sr->isr_ssid_len; 1303214501Srpaulo os_memcpy(pos, sr + 1, sr->isr_ssid_len); 1304214501Srpaulo pos += sr->isr_ssid_len; 1305209139Srpaulo 1306214501Srpaulo /* 1307214501Srpaulo * Deal all rates as supported rate. 1308214501Srpaulo * Because net80211 doesn't report extended supported rate or not. 1309214501Srpaulo */ 1310214501Srpaulo *pos++ = WLAN_EID_SUPP_RATES; 1311214501Srpaulo *pos++ = sr->isr_nrates; 1312214501Srpaulo os_memcpy(pos, sr->isr_rates, sr->isr_nrates); 1313214501Srpaulo pos += sr->isr_nrates; 1314214501Srpaulo 1315214501Srpaulo *pos++ = WLAN_EID_ERP_INFO; 1316214501Srpaulo *pos++ = 1; 1317214501Srpaulo *pos++ = sr->isr_erp; 1318214501Srpaulo 1319214501Srpaulo os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len); 1320214501Srpaulo pos += sr->isr_ie_len; 1321214501Srpaulo 1322214501Srpaulo result->ie_len = pos - (u8 *)(result + 1); 1323214501Srpaulo 1324252190Srpaulo tmp = os_realloc_array(res->res, res->num + 1, 1325252190Srpaulo sizeof(struct wpa_scan_res *)); 1326214501Srpaulo if (tmp == NULL) { 1327214501Srpaulo os_free(result); 1328214501Srpaulo return; 1329214501Srpaulo } 1330214501Srpaulo tmp[res->num++] = result; 1331214501Srpaulo res->res = tmp; 1332209139Srpaulo} 1333209139Srpaulo 1334214501Srpaulostruct wpa_scan_results * 1335214501Srpaulowpa_driver_bsd_get_scan_results2(void *priv) 1336209139Srpaulo{ 1337214501Srpaulo struct ieee80211req_scan_result *sr; 1338214501Srpaulo struct wpa_scan_results *res; 1339214501Srpaulo int len, rest; 1340214501Srpaulo uint8_t buf[24*1024], *pos; 1341209139Srpaulo 1342214501Srpaulo len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024); 1343214501Srpaulo if (len < 0) 1344214501Srpaulo return NULL; 1345214501Srpaulo 1346214501Srpaulo res = os_zalloc(sizeof(*res)); 1347214501Srpaulo if (res == NULL) 1348214501Srpaulo return NULL; 1349214501Srpaulo 1350214501Srpaulo pos = buf; 1351214501Srpaulo rest = len; 1352214501Srpaulo while (rest >= sizeof(struct ieee80211req_scan_result)) { 1353214501Srpaulo sr = (struct ieee80211req_scan_result *)pos; 1354214501Srpaulo wpa_driver_bsd_add_scan_entry(res, sr); 1355214501Srpaulo pos += sr->isr_len; 1356214501Srpaulo rest -= sr->isr_len; 1357209139Srpaulo } 1358209139Srpaulo 1359214501Srpaulo wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)", 1360214501Srpaulo len, (unsigned long)res->num); 1361209139Srpaulo 1362214501Srpaulo return res; 1363209139Srpaulo} 1364209139Srpaulo 1365214501Srpaulostatic int wpa_driver_bsd_capa(struct bsd_driver_data *drv) 1366209139Srpaulo{ 1367214501Srpaulo#ifdef IEEE80211_IOC_DEVCAPS 1368214501Srpaulo/* kernel definitions copied from net80211/ieee80211_var.h */ 1369214501Srpaulo#define IEEE80211_CIPHER_WEP 0 1370214501Srpaulo#define IEEE80211_CIPHER_TKIP 1 1371214501Srpaulo#define IEEE80211_CIPHER_AES_CCM 3 1372214501Srpaulo#define IEEE80211_CRYPTO_WEP (1<<IEEE80211_CIPHER_WEP) 1373214501Srpaulo#define IEEE80211_CRYPTO_TKIP (1<<IEEE80211_CIPHER_TKIP) 1374214501Srpaulo#define IEEE80211_CRYPTO_AES_CCM (1<<IEEE80211_CIPHER_AES_CCM) 1375214501Srpaulo#define IEEE80211_C_HOSTAP 0x00000400 /* CAPABILITY: HOSTAP avail */ 1376214501Srpaulo#define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */ 1377214501Srpaulo#define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */ 1378214501Srpaulo struct ieee80211_devcaps_req devcaps; 1379209139Srpaulo 1380214501Srpaulo if (get80211var(drv, IEEE80211_IOC_DEVCAPS, &devcaps, 1381214501Srpaulo sizeof(devcaps)) < 0) { 1382214501Srpaulo wpa_printf(MSG_ERROR, "failed to IEEE80211_IOC_DEVCAPS: %s", 1383214501Srpaulo strerror(errno)); 1384209139Srpaulo return -1; 1385209139Srpaulo } 1386209139Srpaulo 1387214501Srpaulo wpa_printf(MSG_DEBUG, "%s: drivercaps=0x%08x,cryptocaps=0x%08x", 1388214501Srpaulo __func__, devcaps.dc_drivercaps, devcaps.dc_cryptocaps); 1389209139Srpaulo 1390214501Srpaulo if (devcaps.dc_drivercaps & IEEE80211_C_WPA1) 1391214501Srpaulo drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | 1392214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; 1393214501Srpaulo if (devcaps.dc_drivercaps & IEEE80211_C_WPA2) 1394214501Srpaulo drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 1395214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; 1396214501Srpaulo 1397214501Srpaulo if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP) 1398214501Srpaulo drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | 1399214501Srpaulo WPA_DRIVER_CAPA_ENC_WEP104; 1400214501Srpaulo if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP) 1401214501Srpaulo drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; 1402214501Srpaulo if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM) 1403214501Srpaulo drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; 1404214501Srpaulo 1405214501Srpaulo if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP) 1406214501Srpaulo drv->capa.flags |= WPA_DRIVER_FLAGS_AP; 1407214501Srpaulo#undef IEEE80211_CIPHER_WEP 1408214501Srpaulo#undef IEEE80211_CIPHER_TKIP 1409214501Srpaulo#undef IEEE80211_CIPHER_AES_CCM 1410214501Srpaulo#undef IEEE80211_CRYPTO_WEP 1411214501Srpaulo#undef IEEE80211_CRYPTO_TKIP 1412214501Srpaulo#undef IEEE80211_CRYPTO_AES_CCM 1413214501Srpaulo#undef IEEE80211_C_HOSTAP 1414214501Srpaulo#undef IEEE80211_C_WPA1 1415214501Srpaulo#undef IEEE80211_C_WPA2 1416214501Srpaulo#else /* IEEE80211_IOC_DEVCAPS */ 1417214501Srpaulo /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ 1418214501Srpaulo drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | 1419214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | 1420214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 1421214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; 1422214501Srpaulo drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | 1423214501Srpaulo WPA_DRIVER_CAPA_ENC_WEP104 | 1424214501Srpaulo WPA_DRIVER_CAPA_ENC_TKIP | 1425214501Srpaulo WPA_DRIVER_CAPA_ENC_CCMP; 1426214501Srpaulo drv->capa.flags |= WPA_DRIVER_FLAGS_AP; 1427214501Srpaulo#endif /* IEEE80211_IOC_DEVCAPS */ 1428214501Srpaulo#ifdef IEEE80211_IOC_SCAN_MAX_SSID 1429214501Srpaulo drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID; 1430214501Srpaulo#else /* IEEE80211_IOC_SCAN_MAX_SSID */ 1431214501Srpaulo drv->capa.max_scan_ssids = 1; 1432214501Srpaulo#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ 1433214501Srpaulo drv->capa.auth = WPA_DRIVER_AUTH_OPEN | 1434214501Srpaulo WPA_DRIVER_AUTH_SHARED | 1435214501Srpaulo WPA_DRIVER_AUTH_LEAP; 1436214501Srpaulo return 0; 1437209139Srpaulo} 1438209139Srpaulo 1439209139Srpaulostatic void * 1440209139Srpaulowpa_driver_bsd_init(void *ctx, const char *ifname) 1441209139Srpaulo{ 1442209139Srpaulo#define GETPARAM(drv, param, v) \ 1443209139Srpaulo (((v) = get80211param(drv, param)) != -1) 1444214501Srpaulo struct bsd_driver_data *drv; 1445209139Srpaulo 1446209139Srpaulo drv = os_zalloc(sizeof(*drv)); 1447209139Srpaulo if (drv == NULL) 1448209139Srpaulo return NULL; 1449209139Srpaulo /* 1450209139Srpaulo * NB: We require the interface name be mappable to an index. 1451209139Srpaulo * This implies we do not support having wpa_supplicant 1452209139Srpaulo * wait for an interface to appear. This seems ok; that 1453209139Srpaulo * doesn't belong here; it's really the job of devd. 1454209139Srpaulo */ 1455209139Srpaulo drv->ifindex = if_nametoindex(ifname); 1456209139Srpaulo if (drv->ifindex == 0) { 1457209139Srpaulo wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", 1458209139Srpaulo __func__, ifname); 1459209139Srpaulo goto fail1; 1460209139Srpaulo } 1461209139Srpaulo drv->sock = socket(PF_INET, SOCK_DGRAM, 0); 1462209139Srpaulo if (drv->sock < 0) 1463209139Srpaulo goto fail1; 1464209139Srpaulo drv->route = socket(PF_ROUTE, SOCK_RAW, 0); 1465209139Srpaulo if (drv->route < 0) 1466209139Srpaulo goto fail; 1467209139Srpaulo eloop_register_read_sock(drv->route, 1468209139Srpaulo wpa_driver_bsd_event_receive, ctx, drv); 1469209139Srpaulo 1470209139Srpaulo drv->ctx = ctx; 1471209139Srpaulo os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); 1472209139Srpaulo 1473214501Srpaulo /* Down interface during setup. */ 1474214501Srpaulo if (bsd_ctrl_iface(drv, 0) < 0) 1475214501Srpaulo goto fail; 1476214501Srpaulo 1477209139Srpaulo if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { 1478209139Srpaulo wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", 1479209139Srpaulo __func__, strerror(errno)); 1480209139Srpaulo goto fail; 1481209139Srpaulo } 1482209139Srpaulo if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) { 1483209139Srpaulo wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s", 1484209139Srpaulo __func__, strerror(errno)); 1485209139Srpaulo goto fail; 1486209139Srpaulo } 1487209139Srpaulo if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) { 1488209139Srpaulo wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s", 1489209139Srpaulo __func__, strerror(errno)); 1490209139Srpaulo goto fail; 1491209139Srpaulo } 1492209139Srpaulo 1493214501Srpaulo if (wpa_driver_bsd_capa(drv)) 1494209139Srpaulo goto fail; 1495209139Srpaulo 1496209139Srpaulo return drv; 1497209139Srpaulofail: 1498209139Srpaulo close(drv->sock); 1499209139Srpaulofail1: 1500209139Srpaulo os_free(drv); 1501209139Srpaulo return NULL; 1502209139Srpaulo#undef GETPARAM 1503209139Srpaulo} 1504209139Srpaulo 1505209139Srpaulostatic void 1506209139Srpaulowpa_driver_bsd_deinit(void *priv) 1507209139Srpaulo{ 1508214501Srpaulo struct bsd_driver_data *drv = priv; 1509209139Srpaulo 1510214501Srpaulo wpa_driver_bsd_set_wpa(drv, 0); 1511209139Srpaulo eloop_unregister_read_sock(drv->route); 1512209139Srpaulo 1513209139Srpaulo /* NB: mark interface down */ 1514214501Srpaulo bsd_ctrl_iface(drv, 0); 1515209139Srpaulo 1516209139Srpaulo wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); 1517209139Srpaulo if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0) 1518209139Srpaulo wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state", 1519209139Srpaulo __func__); 1520209139Srpaulo 1521214501Srpaulo if (drv->sock_xmit != NULL) 1522214501Srpaulo l2_packet_deinit(drv->sock_xmit); 1523209139Srpaulo (void) close(drv->route); /* ioctl socket */ 1524209139Srpaulo (void) close(drv->sock); /* event socket */ 1525209139Srpaulo os_free(drv); 1526209139Srpaulo} 1527209139Srpaulo 1528214501Srpaulostatic int 1529214501Srpaulowpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) 1530214501Srpaulo{ 1531214501Srpaulo struct bsd_driver_data *drv = priv; 1532209139Srpaulo 1533214501Srpaulo os_memcpy(capa, &drv->capa, sizeof(*capa)); 1534214501Srpaulo return 0; 1535214501Srpaulo} 1536214501Srpaulo#endif /* HOSTAPD */ 1537214501Srpaulo 1538214501Srpaulo 1539209139Srpauloconst struct wpa_driver_ops wpa_driver_bsd_ops = { 1540209139Srpaulo .name = "bsd", 1541214501Srpaulo .desc = "BSD 802.11 support", 1542214501Srpaulo#ifdef HOSTAPD 1543214501Srpaulo .hapd_init = bsd_init, 1544214501Srpaulo .hapd_deinit = bsd_deinit, 1545214501Srpaulo .set_privacy = bsd_set_privacy, 1546214501Srpaulo .get_seqnum = bsd_get_seqnum, 1547214501Srpaulo .flush = bsd_flush, 1548214501Srpaulo .read_sta_data = bsd_read_sta_driver_data, 1549214501Srpaulo .sta_disassoc = bsd_sta_disassoc, 1550214501Srpaulo .sta_deauth = bsd_sta_deauth, 1551214501Srpaulo#else /* HOSTAPD */ 1552209139Srpaulo .init = wpa_driver_bsd_init, 1553209139Srpaulo .deinit = wpa_driver_bsd_deinit, 1554209139Srpaulo .get_bssid = wpa_driver_bsd_get_bssid, 1555209139Srpaulo .get_ssid = wpa_driver_bsd_get_ssid, 1556209139Srpaulo .set_countermeasures = wpa_driver_bsd_set_countermeasures, 1557214501Srpaulo .scan2 = wpa_driver_bsd_scan, 1558214501Srpaulo .get_scan_results2 = wpa_driver_bsd_get_scan_results2, 1559209139Srpaulo .deauthenticate = wpa_driver_bsd_deauthenticate, 1560209139Srpaulo .associate = wpa_driver_bsd_associate, 1561214501Srpaulo .get_capa = wpa_driver_bsd_get_capa, 1562214501Srpaulo#endif /* HOSTAPD */ 1563252190Srpaulo .set_freq = bsd_set_freq, 1564214501Srpaulo .set_key = bsd_set_key, 1565214501Srpaulo .set_ieee8021x = bsd_set_ieee8021x, 1566214501Srpaulo .hapd_set_ssid = bsd_set_ssid, 1567214501Srpaulo .hapd_get_ssid = bsd_get_ssid, 1568214501Srpaulo .hapd_send_eapol = bsd_send_eapol, 1569214501Srpaulo .sta_set_flags = bsd_set_sta_authorized, 1570214501Srpaulo .set_generic_elem = bsd_set_opt_ie, 1571209139Srpaulo}; 1572