driver_bsd.c revision 281806
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 */ 64252726Srpaulo enum ieee80211_opmode opmode; /* operation mode */ 65281806Srpaulo char *event_buf; 66281806Srpaulo size_t event_buf_len; 67209139Srpaulo}; 68209139Srpaulo 69214501Srpaulo/* Generic functions for hostapd and wpa_supplicant */ 70209139Srpaulostatic int 71214501Srpaulobsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) 72209139Srpaulo{ 73214501Srpaulo struct bsd_driver_data *drv = priv; 74209139Srpaulo struct ieee80211req ireq; 75209139Srpaulo 76209139Srpaulo os_memset(&ireq, 0, sizeof(ireq)); 77214501Srpaulo os_strlcpy(ireq.i_name, drv->ifname, sizeof(ireq.i_name)); 78209139Srpaulo ireq.i_type = op; 79214501Srpaulo ireq.i_val = val; 80214501Srpaulo ireq.i_data = (void *) arg; 81209139Srpaulo ireq.i_len = arg_len; 82209139Srpaulo 83209139Srpaulo if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) { 84214501Srpaulo wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, val=%u, " 85214501Srpaulo "arg_len=%u]: %s", op, val, arg_len, 86214501Srpaulo strerror(errno)); 87209139Srpaulo return -1; 88209139Srpaulo } 89209139Srpaulo return 0; 90209139Srpaulo} 91209139Srpaulo 92209139Srpaulostatic int 93214501Srpaulobsd_get80211(void *priv, struct ieee80211req *ireq, int op, void *arg, 94214501Srpaulo int arg_len) 95209139Srpaulo{ 96214501Srpaulo struct bsd_driver_data *drv = priv; 97209139Srpaulo 98214501Srpaulo os_memset(ireq, 0, sizeof(*ireq)); 99214501Srpaulo os_strlcpy(ireq->i_name, drv->ifname, sizeof(ireq->i_name)); 100214501Srpaulo ireq->i_type = op; 101214501Srpaulo ireq->i_len = arg_len; 102214501Srpaulo ireq->i_data = arg; 103209139Srpaulo 104214501Srpaulo if (ioctl(drv->sock, SIOCG80211, ireq) < 0) { 105214501Srpaulo wpa_printf(MSG_ERROR, "ioctl[SIOCS80211, op=%u, " 106214501Srpaulo "arg_len=%u]: %s", op, arg_len, strerror(errno)); 107209139Srpaulo return -1; 108209139Srpaulo } 109214501Srpaulo return 0; 110209139Srpaulo} 111209139Srpaulo 112209139Srpaulostatic int 113214501Srpauloget80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len) 114209139Srpaulo{ 115209139Srpaulo struct ieee80211req ireq; 116209139Srpaulo 117214501Srpaulo if (bsd_get80211(drv, &ireq, op, arg, arg_len) < 0) 118209139Srpaulo return -1; 119214501Srpaulo return ireq.i_len; 120209139Srpaulo} 121209139Srpaulo 122209139Srpaulostatic int 123214501Srpauloset80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len) 124209139Srpaulo{ 125214501Srpaulo return bsd_set80211(drv, op, 0, arg, arg_len); 126214501Srpaulo} 127209139Srpaulo 128214501Srpaulostatic int 129214501Srpauloset80211param(struct bsd_driver_data *drv, int op, int arg) 130214501Srpaulo{ 131214501Srpaulo return bsd_set80211(drv, op, arg, NULL, 0); 132209139Srpaulo} 133209139Srpaulo 134209139Srpaulostatic int 135214501Srpaulobsd_get_ssid(void *priv, u8 *ssid, int len) 136209139Srpaulo{ 137214501Srpaulo struct bsd_driver_data *drv = priv; 138214501Srpaulo#ifdef SIOCG80211NWID 139214501Srpaulo struct ieee80211_nwid nwid; 140209139Srpaulo struct ifreq ifr; 141209139Srpaulo 142209139Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 143209139Srpaulo os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 144214501Srpaulo ifr.ifr_data = (void *)&nwid; 145214501Srpaulo if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || 146214501Srpaulo nwid.i_len > IEEE80211_NWID_LEN) 147214501Srpaulo return -1; 148214501Srpaulo os_memcpy(ssid, nwid.i_nwid, nwid.i_len); 149214501Srpaulo return nwid.i_len; 150214501Srpaulo#else 151214501Srpaulo return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN); 152214501Srpaulo#endif 153209139Srpaulo} 154209139Srpaulo 155209139Srpaulostatic int 156214501Srpaulobsd_set_ssid(void *priv, const u8 *ssid, int ssid_len) 157209139Srpaulo{ 158214501Srpaulo struct bsd_driver_data *drv = priv; 159214501Srpaulo#ifdef SIOCS80211NWID 160214501Srpaulo struct ieee80211_nwid nwid; 161209139Srpaulo struct ifreq ifr; 162209139Srpaulo 163214501Srpaulo os_memcpy(nwid.i_nwid, ssid, ssid_len); 164214501Srpaulo nwid.i_len = ssid_len; 165209139Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 166209139Srpaulo os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 167214501Srpaulo ifr.ifr_data = (void *)&nwid; 168214501Srpaulo return ioctl(drv->sock, SIOCS80211NWID, &ifr); 169214501Srpaulo#else 170214501Srpaulo return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len); 171214501Srpaulo#endif 172209139Srpaulo} 173209139Srpaulo 174209139Srpaulostatic int 175214501Srpaulobsd_get_if_media(void *priv) 176209139Srpaulo{ 177214501Srpaulo struct bsd_driver_data *drv = priv; 178214501Srpaulo struct ifmediareq ifmr; 179209139Srpaulo 180214501Srpaulo os_memset(&ifmr, 0, sizeof(ifmr)); 181214501Srpaulo os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); 182209139Srpaulo 183214501Srpaulo if (ioctl(drv->sock, SIOCGIFMEDIA, &ifmr) < 0) { 184214501Srpaulo wpa_printf(MSG_ERROR, "%s: SIOCGIFMEDIA %s", __func__, 185214501Srpaulo strerror(errno)); 186214501Srpaulo return -1; 187214501Srpaulo } 188209139Srpaulo 189214501Srpaulo return ifmr.ifm_current; 190209139Srpaulo} 191209139Srpaulo 192209139Srpaulostatic int 193214501Srpaulobsd_set_if_media(void *priv, int media) 194209139Srpaulo{ 195214501Srpaulo struct bsd_driver_data *drv = priv; 196214501Srpaulo struct ifreq ifr; 197209139Srpaulo 198214501Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 199214501Srpaulo os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 200214501Srpaulo ifr.ifr_media = media; 201209139Srpaulo 202214501Srpaulo if (ioctl(drv->sock, SIOCSIFMEDIA, &ifr) < 0) { 203214501Srpaulo wpa_printf(MSG_ERROR, "%s: SIOCSIFMEDIA %s", __func__, 204214501Srpaulo strerror(errno)); 205214501Srpaulo return -1; 206214501Srpaulo } 207209139Srpaulo 208214501Srpaulo return 0; 209209139Srpaulo} 210209139Srpaulo 211209139Srpaulostatic int 212214501Srpaulobsd_set_mediaopt(void *priv, uint32_t mask, uint32_t mode) 213209139Srpaulo{ 214214501Srpaulo int media = bsd_get_if_media(priv); 215214501Srpaulo 216214501Srpaulo if (media < 0) 217214501Srpaulo return -1; 218214501Srpaulo media &= ~mask; 219214501Srpaulo media |= mode; 220214501Srpaulo if (bsd_set_if_media(priv, media) < 0) 221214501Srpaulo return -1; 222214501Srpaulo return 0; 223209139Srpaulo} 224209139Srpaulo 225209139Srpaulostatic int 226214501Srpaulobsd_del_key(void *priv, const u8 *addr, int key_idx) 227209139Srpaulo{ 228214501Srpaulo struct ieee80211req_del_key wk; 229209139Srpaulo 230214501Srpaulo os_memset(&wk, 0, sizeof(wk)); 231214501Srpaulo if (addr == NULL) { 232214501Srpaulo wpa_printf(MSG_DEBUG, "%s: key_idx=%d", __func__, key_idx); 233214501Srpaulo wk.idk_keyix = key_idx; 234214501Srpaulo } else { 235214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, 236214501Srpaulo MAC2STR(addr)); 237214501Srpaulo os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN); 238214501Srpaulo wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */ 239214501Srpaulo } 240209139Srpaulo 241214501Srpaulo return set80211var(priv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk)); 242209139Srpaulo} 243209139Srpaulo 244209139Srpaulostatic int 245214501Srpaulobsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr) 246209139Srpaulo{ 247214501Srpaulo struct ieee80211req_mlme mlme; 248209139Srpaulo 249214501Srpaulo os_memset(&mlme, 0, sizeof(mlme)); 250214501Srpaulo mlme.im_op = op; 251214501Srpaulo mlme.im_reason = reason; 252214501Srpaulo os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN); 253214501Srpaulo return set80211var(priv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)); 254209139Srpaulo} 255209139Srpaulo 256209139Srpaulostatic int 257214501Srpaulobsd_ctrl_iface(void *priv, int enable) 258209139Srpaulo{ 259214501Srpaulo struct bsd_driver_data *drv = priv; 260214501Srpaulo struct ifreq ifr; 261209139Srpaulo 262214501Srpaulo os_memset(&ifr, 0, sizeof(ifr)); 263214501Srpaulo os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); 264209139Srpaulo 265214501Srpaulo if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) { 266281806Srpaulo wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s", 267281806Srpaulo strerror(errno)); 268214501Srpaulo return -1; 269209139Srpaulo } 270214501Srpaulo 271252726Srpaulo if (enable) { 272252726Srpaulo if (ifr.ifr_flags & IFF_UP) 273252726Srpaulo return 0; 274214501Srpaulo ifr.ifr_flags |= IFF_UP; 275252726Srpaulo } else { 276252726Srpaulo if (!(ifr.ifr_flags & IFF_UP)) 277252726Srpaulo return 0; 278214501Srpaulo ifr.ifr_flags &= ~IFF_UP; 279252726Srpaulo } 280214501Srpaulo 281214501Srpaulo if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) { 282281806Srpaulo wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s", 283281806Srpaulo strerror(errno)); 284214501Srpaulo return -1; 285214501Srpaulo } 286214501Srpaulo 287214501Srpaulo return 0; 288209139Srpaulo} 289209139Srpaulo 290209139Srpaulostatic int 291214501Srpaulobsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, 292214501Srpaulo const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, 293214501Srpaulo size_t seq_len, const u8 *key, size_t key_len) 294209139Srpaulo{ 295209139Srpaulo struct ieee80211req_key wk; 296281806Srpaulo#ifdef IEEE80211_KEY_NOREPLAY 297252726Srpaulo struct bsd_driver_data *drv = priv; 298281806Srpaulo#endif /* IEEE80211_KEY_NOREPLAY */ 299209139Srpaulo 300214501Srpaulo wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " 301214501Srpaulo "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx, 302214501Srpaulo set_tx, seq_len, key_len); 303209139Srpaulo 304214501Srpaulo if (alg == WPA_ALG_NONE) { 305214501Srpaulo#ifndef HOSTAPD 306252190Srpaulo if (addr == NULL || is_broadcast_ether_addr(addr)) 307214501Srpaulo return bsd_del_key(priv, NULL, key_idx); 308214501Srpaulo else 309214501Srpaulo#endif /* HOSTAPD */ 310214501Srpaulo return bsd_del_key(priv, addr, key_idx); 311214501Srpaulo } 312214501Srpaulo 313214501Srpaulo os_memset(&wk, 0, sizeof(wk)); 314209139Srpaulo switch (alg) { 315209139Srpaulo case WPA_ALG_WEP: 316214501Srpaulo wk.ik_type = IEEE80211_CIPHER_WEP; 317209139Srpaulo break; 318209139Srpaulo case WPA_ALG_TKIP: 319214501Srpaulo wk.ik_type = IEEE80211_CIPHER_TKIP; 320209139Srpaulo break; 321209139Srpaulo case WPA_ALG_CCMP: 322214501Srpaulo wk.ik_type = IEEE80211_CIPHER_AES_CCM; 323209139Srpaulo break; 324209139Srpaulo default: 325214501Srpaulo wpa_printf(MSG_ERROR, "%s: unknown alg=%d", __func__, alg); 326209139Srpaulo return -1; 327209139Srpaulo } 328209139Srpaulo 329209139Srpaulo wk.ik_flags = IEEE80211_KEY_RECV; 330209139Srpaulo if (set_tx) 331209139Srpaulo wk.ik_flags |= IEEE80211_KEY_XMIT; 332214501Srpaulo 333214501Srpaulo if (addr == NULL) { 334214501Srpaulo os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 335209139Srpaulo wk.ik_keyix = key_idx; 336209139Srpaulo } else { 337214501Srpaulo os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 338214501Srpaulo /* 339214501Srpaulo * Deduce whether group/global or unicast key by checking 340214501Srpaulo * the address (yech). Note also that we can only mark global 341214501Srpaulo * keys default; doing this for a unicast key is an error. 342214501Srpaulo */ 343252190Srpaulo if (is_broadcast_ether_addr(addr)) { 344214501Srpaulo wk.ik_flags |= IEEE80211_KEY_GROUP; 345214501Srpaulo wk.ik_keyix = key_idx; 346214501Srpaulo } else { 347214501Srpaulo wk.ik_keyix = key_idx == 0 ? IEEE80211_KEYIX_NONE : 348214501Srpaulo key_idx; 349214501Srpaulo } 350209139Srpaulo } 351209139Srpaulo if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx) 352209139Srpaulo wk.ik_flags |= IEEE80211_KEY_DEFAULT; 353252726Srpaulo#ifndef HOSTAPD 354281806Srpaulo#ifdef IEEE80211_KEY_NOREPLAY 355252726Srpaulo /* 356252726Srpaulo * Ignore replay failures in IBSS and AHDEMO mode. 357252726Srpaulo */ 358252726Srpaulo if (drv->opmode == IEEE80211_M_IBSS || 359252726Srpaulo drv->opmode == IEEE80211_M_AHDEMO) 360252726Srpaulo wk.ik_flags |= IEEE80211_KEY_NOREPLAY; 361281806Srpaulo#endif /* IEEE80211_KEY_NOREPLAY */ 362281806Srpaulo#endif /* HOSTAPD */ 363209139Srpaulo wk.ik_keylen = key_len; 364252190Srpaulo if (seq) { 365252190Srpaulo#ifdef WORDS_BIGENDIAN 366252190Srpaulo /* 367252190Srpaulo * wk.ik_keyrsc is in host byte order (big endian), need to 368252190Srpaulo * swap it to match with the byte order used in WPA. 369252190Srpaulo */ 370252190Srpaulo int i; 371252190Srpaulo u8 *keyrsc = (u8 *) &wk.ik_keyrsc; 372252190Srpaulo for (i = 0; i < seq_len; i++) 373252190Srpaulo keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i]; 374252190Srpaulo#else /* WORDS_BIGENDIAN */ 375252190Srpaulo os_memcpy(&wk.ik_keyrsc, seq, seq_len); 376252190Srpaulo#endif /* WORDS_BIGENDIAN */ 377252190Srpaulo } 378209139Srpaulo os_memcpy(wk.ik_keydata, key, key_len); 379209139Srpaulo 380214501Srpaulo return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)); 381209139Srpaulo} 382209139Srpaulo 383209139Srpaulostatic int 384214501Srpaulobsd_configure_wpa(void *priv, struct wpa_bss_params *params) 385209139Srpaulo{ 386214501Srpaulo#ifndef IEEE80211_IOC_APPIE 387214501Srpaulo static const char *ciphernames[] = 388214501Srpaulo { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" }; 389214501Srpaulo int v; 390209139Srpaulo 391214501Srpaulo switch (params->wpa_group) { 392214501Srpaulo case WPA_CIPHER_CCMP: 393214501Srpaulo v = IEEE80211_CIPHER_AES_CCM; 394214501Srpaulo break; 395214501Srpaulo case WPA_CIPHER_TKIP: 396214501Srpaulo v = IEEE80211_CIPHER_TKIP; 397214501Srpaulo break; 398214501Srpaulo case WPA_CIPHER_WEP104: 399214501Srpaulo v = IEEE80211_CIPHER_WEP; 400214501Srpaulo break; 401214501Srpaulo case WPA_CIPHER_WEP40: 402214501Srpaulo v = IEEE80211_CIPHER_WEP; 403214501Srpaulo break; 404214501Srpaulo case WPA_CIPHER_NONE: 405214501Srpaulo v = IEEE80211_CIPHER_NONE; 406214501Srpaulo break; 407214501Srpaulo default: 408281806Srpaulo wpa_printf(MSG_INFO, "Unknown group key cipher %u", 409281806Srpaulo params->wpa_group); 410214501Srpaulo return -1; 411214501Srpaulo } 412214501Srpaulo wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)", 413214501Srpaulo __func__, ciphernames[v], v); 414214501Srpaulo if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) { 415281806Srpaulo wpa_printf(MSG_INFO, 416281806Srpaulo "Unable to set group key cipher to %u (%s)", 417281806Srpaulo v, ciphernames[v]); 418214501Srpaulo return -1; 419214501Srpaulo } 420214501Srpaulo if (v == IEEE80211_CIPHER_WEP) { 421214501Srpaulo /* key length is done only for specific ciphers */ 422214501Srpaulo v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5); 423214501Srpaulo if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) { 424281806Srpaulo wpa_printf(MSG_INFO, 425281806Srpaulo "Unable to set group key length to %u", v); 426214501Srpaulo return -1; 427214501Srpaulo } 428214501Srpaulo } 429214501Srpaulo 430214501Srpaulo v = 0; 431214501Srpaulo if (params->wpa_pairwise & WPA_CIPHER_CCMP) 432214501Srpaulo v |= 1<<IEEE80211_CIPHER_AES_CCM; 433214501Srpaulo if (params->wpa_pairwise & WPA_CIPHER_TKIP) 434214501Srpaulo v |= 1<<IEEE80211_CIPHER_TKIP; 435214501Srpaulo if (params->wpa_pairwise & WPA_CIPHER_NONE) 436214501Srpaulo v |= 1<<IEEE80211_CIPHER_NONE; 437214501Srpaulo wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v); 438214501Srpaulo if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) { 439281806Srpaulo wpa_printf(MSG_INFO, 440281806Srpaulo "Unable to set pairwise key ciphers to 0x%x", v); 441214501Srpaulo return -1; 442214501Srpaulo } 443214501Srpaulo 444214501Srpaulo wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x", 445214501Srpaulo __func__, params->wpa_key_mgmt); 446214501Srpaulo if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS, 447214501Srpaulo params->wpa_key_mgmt)) { 448281806Srpaulo wpa_printf(MSG_INFO, 449281806Srpaulo "Unable to set key management algorithms to 0x%x", 450281806Srpaulo params->wpa_key_mgmt); 451214501Srpaulo return -1; 452214501Srpaulo } 453214501Srpaulo 454214501Srpaulo v = 0; 455214501Srpaulo if (params->rsn_preauth) 456214501Srpaulo v |= BIT(0); 457214501Srpaulo wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", 458214501Srpaulo __func__, params->rsn_preauth); 459214501Srpaulo if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) { 460281806Srpaulo wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x", 461281806Srpaulo v); 462214501Srpaulo return -1; 463214501Srpaulo } 464214501Srpaulo#endif /* IEEE80211_IOC_APPIE */ 465214501Srpaulo 466214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa); 467214501Srpaulo if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) { 468281806Srpaulo wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa); 469214501Srpaulo return -1; 470214501Srpaulo } 471214501Srpaulo return 0; 472214501Srpaulo} 473214501Srpaulo 474214501Srpaulostatic int 475214501Srpaulobsd_set_ieee8021x(void *priv, struct wpa_bss_params *params) 476214501Srpaulo{ 477214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled); 478214501Srpaulo 479214501Srpaulo if (!params->enabled) { 480214501Srpaulo /* XXX restore state */ 481214501Srpaulo return set80211param(priv, IEEE80211_IOC_AUTHMODE, 482214501Srpaulo IEEE80211_AUTH_AUTO); 483214501Srpaulo } 484214501Srpaulo if (!params->wpa && !params->ieee802_1x) { 485214501Srpaulo wpa_printf(MSG_ERROR, "%s: No 802.1X or WPA enabled", 486214501Srpaulo __func__); 487214501Srpaulo return -1; 488214501Srpaulo } 489214501Srpaulo if (params->wpa && bsd_configure_wpa(priv, params) != 0) { 490214501Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to configure WPA state", 491214501Srpaulo __func__); 492214501Srpaulo return -1; 493214501Srpaulo } 494214501Srpaulo if (set80211param(priv, IEEE80211_IOC_AUTHMODE, 495214501Srpaulo (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) { 496214501Srpaulo wpa_printf(MSG_ERROR, "%s: Failed to enable WPA/802.1X", 497214501Srpaulo __func__); 498214501Srpaulo return -1; 499214501Srpaulo } 500214501Srpaulo return bsd_ctrl_iface(priv, 1); 501214501Srpaulo} 502214501Srpaulo 503214501Srpaulostatic void 504214501Srpaulobsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN]) 505214501Srpaulo{ 506214501Srpaulo struct ieee80211req_wpaie ie; 507214501Srpaulo int ielen = 0; 508214501Srpaulo u8 *iebuf = NULL; 509214501Srpaulo 510214501Srpaulo /* 511214501Srpaulo * Fetch and validate any negotiated WPA/RSN parameters. 512214501Srpaulo */ 513214501Srpaulo memset(&ie, 0, sizeof(ie)); 514214501Srpaulo memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); 515214501Srpaulo if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { 516281806Srpaulo wpa_printf(MSG_INFO, 517281806Srpaulo "Failed to get WPA/RSN information element"); 518214501Srpaulo goto no_ie; 519214501Srpaulo } 520214501Srpaulo iebuf = ie.wpa_ie; 521214501Srpaulo ielen = ie.wpa_ie[1]; 522214501Srpaulo if (ielen == 0) 523214501Srpaulo iebuf = NULL; 524214501Srpaulo else 525214501Srpaulo ielen += 2; 526214501Srpaulo 527214501Srpaulono_ie: 528252190Srpaulo drv_event_assoc(ctx, addr, iebuf, ielen, 0); 529214501Srpaulo} 530214501Srpaulo 531214501Srpaulostatic int 532214501Srpaulobsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len, 533252190Srpaulo int encrypt, const u8 *own_addr, u32 flags) 534214501Srpaulo{ 535214501Srpaulo struct bsd_driver_data *drv = priv; 536214501Srpaulo 537214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", data, data_len); 538214501Srpaulo 539214501Srpaulo return l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, data, 540214501Srpaulo data_len); 541214501Srpaulo} 542214501Srpaulo 543214501Srpaulostatic int 544252190Srpaulobsd_set_freq(void *priv, struct hostapd_freq_params *freq) 545214501Srpaulo{ 546214501Srpaulo struct bsd_driver_data *drv = priv; 547214501Srpaulo#ifdef SIOCS80211CHANNEL 548214501Srpaulo struct ieee80211chanreq creq; 549214501Srpaulo#endif /* SIOCS80211CHANNEL */ 550214501Srpaulo u32 mode; 551252190Srpaulo int channel = freq->channel; 552214501Srpaulo 553252190Srpaulo if (channel < 14) { 554252190Srpaulo mode = 555252190Srpaulo#ifdef CONFIG_IEEE80211N 556252190Srpaulo freq->ht_enabled ? IFM_IEEE80211_11NG : 557252190Srpaulo#endif /* CONFIG_IEEE80211N */ 558252190Srpaulo IFM_IEEE80211_11G; 559252190Srpaulo } else if (channel == 14) { 560214501Srpaulo mode = IFM_IEEE80211_11B; 561252190Srpaulo } else { 562252190Srpaulo mode = 563252190Srpaulo#ifdef CONFIG_IEEE80211N 564252190Srpaulo freq->ht_enabled ? IFM_IEEE80211_11NA : 565252190Srpaulo#endif /* CONFIG_IEEE80211N */ 566252190Srpaulo IFM_IEEE80211_11A; 567252190Srpaulo } 568214501Srpaulo if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) { 569214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set modulation mode", 570214501Srpaulo __func__); 571214501Srpaulo return -1; 572214501Srpaulo } 573214501Srpaulo 574214501Srpaulo#ifdef SIOCS80211CHANNEL 575214501Srpaulo os_memset(&creq, 0, sizeof(creq)); 576214501Srpaulo os_strlcpy(creq.i_name, drv->ifname, sizeof(creq.i_name)); 577252190Srpaulo creq.i_channel = (u_int16_t)channel; 578214501Srpaulo return ioctl(drv->sock, SIOCS80211CHANNEL, &creq); 579214501Srpaulo#else /* SIOCS80211CHANNEL */ 580214501Srpaulo return set80211param(priv, IEEE80211_IOC_CHANNEL, channel); 581214501Srpaulo#endif /* SIOCS80211CHANNEL */ 582214501Srpaulo} 583214501Srpaulo 584214501Srpaulostatic int 585214501Srpaulobsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) 586214501Srpaulo{ 587214501Srpaulo#ifdef IEEE80211_IOC_APPIE 588214501Srpaulo wpa_printf(MSG_DEBUG, "%s: set WPA+RSN ie (len %lu)", __func__, 589214501Srpaulo (unsigned long)ie_len); 590214501Srpaulo return bsd_set80211(priv, IEEE80211_IOC_APPIE, IEEE80211_APPIE_WPA, 591214501Srpaulo ie, ie_len); 592214501Srpaulo#endif /* IEEE80211_IOC_APPIE */ 593214501Srpaulo return 0; 594214501Srpaulo} 595214501Srpaulo 596281806Srpaulostatic size_t 597252190Srpaulortbuf_len(void) 598252190Srpaulo{ 599252190Srpaulo size_t len; 600214501Srpaulo 601252190Srpaulo int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0}; 602252190Srpaulo 603252190Srpaulo if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { 604281806Srpaulo wpa_printf(MSG_WARNING, "%s failed: %s", __func__, 605252190Srpaulo strerror(errno)); 606252190Srpaulo len = 2048; 607252190Srpaulo } 608252190Srpaulo 609252190Srpaulo return len; 610252190Srpaulo} 611252190Srpaulo 612214501Srpaulo#ifdef HOSTAPD 613214501Srpaulo 614214501Srpaulo/* 615214501Srpaulo * Avoid conflicts with hostapd definitions by undefining couple of defines 616214501Srpaulo * from net80211 header files. 617214501Srpaulo */ 618214501Srpaulo#undef RSN_VERSION 619214501Srpaulo#undef WPA_VERSION 620214501Srpaulo#undef WPA_OUI_TYPE 621214501Srpaulo 622214501Srpaulostatic int bsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, 623214501Srpaulo int reason_code); 624214501Srpaulo 625214501Srpaulostatic const char * 626214501Srpauloether_sprintf(const u8 *addr) 627214501Srpaulo{ 628214501Srpaulo static char buf[sizeof(MACSTR)]; 629214501Srpaulo 630214501Srpaulo if (addr != NULL) 631214501Srpaulo snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr)); 632214501Srpaulo else 633214501Srpaulo snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0); 634214501Srpaulo return buf; 635214501Srpaulo} 636214501Srpaulo 637214501Srpaulostatic int 638214501Srpaulobsd_set_privacy(void *priv, int enabled) 639214501Srpaulo{ 640209139Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 641214501Srpaulo 642214501Srpaulo return set80211param(priv, IEEE80211_IOC_PRIVACY, enabled); 643209139Srpaulo} 644209139Srpaulo 645214501Srpaulostatic int 646214501Srpaulobsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, 647214501Srpaulo u8 *seq) 648214501Srpaulo{ 649214501Srpaulo struct ieee80211req_key wk; 650209139Srpaulo 651214501Srpaulo wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", 652214501Srpaulo __func__, ether_sprintf(addr), idx); 653214501Srpaulo 654214501Srpaulo memset(&wk, 0, sizeof(wk)); 655214501Srpaulo if (addr == NULL) 656214501Srpaulo memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); 657214501Srpaulo else 658214501Srpaulo memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); 659214501Srpaulo wk.ik_keyix = idx; 660214501Srpaulo 661214501Srpaulo if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { 662281806Srpaulo wpa_printf(MSG_INFO, "Failed to get encryption"); 663214501Srpaulo return -1; 664214501Srpaulo } 665214501Srpaulo 666214501Srpaulo#ifdef WORDS_BIGENDIAN 667214501Srpaulo { 668214501Srpaulo /* 669214501Srpaulo * wk.ik_keytsc is in host byte order (big endian), need to 670214501Srpaulo * swap it to match with the byte order used in WPA. 671214501Srpaulo */ 672214501Srpaulo int i; 673214501Srpaulo u8 tmp[WPA_KEY_RSC_LEN]; 674214501Srpaulo memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 675214501Srpaulo for (i = 0; i < WPA_KEY_RSC_LEN; i++) { 676214501Srpaulo seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; 677214501Srpaulo } 678214501Srpaulo } 679214501Srpaulo#else /* WORDS_BIGENDIAN */ 680214501Srpaulo memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); 681214501Srpaulo#endif /* WORDS_BIGENDIAN */ 682214501Srpaulo return 0; 683214501Srpaulo} 684214501Srpaulo 685214501Srpaulo 686281806Srpaulostatic int 687214501Srpaulobsd_flush(void *priv) 688214501Srpaulo{ 689214501Srpaulo u8 allsta[IEEE80211_ADDR_LEN]; 690214501Srpaulo 691214501Srpaulo memset(allsta, 0xff, IEEE80211_ADDR_LEN); 692214501Srpaulo return bsd_sta_deauth(priv, NULL, allsta, IEEE80211_REASON_AUTH_LEAVE); 693214501Srpaulo} 694214501Srpaulo 695214501Srpaulo 696209139Srpaulostatic int 697214501Srpaulobsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, 698214501Srpaulo const u8 *addr) 699209139Srpaulo{ 700214501Srpaulo struct ieee80211req_sta_stats stats; 701209139Srpaulo 702214501Srpaulo memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); 703214501Srpaulo if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) 704214501Srpaulo > 0) { 705214501Srpaulo /* XXX? do packets counts include non-data frames? */ 706214501Srpaulo data->rx_packets = stats.is_stats.ns_rx_data; 707214501Srpaulo data->rx_bytes = stats.is_stats.ns_rx_bytes; 708214501Srpaulo data->tx_packets = stats.is_stats.ns_tx_data; 709214501Srpaulo data->tx_bytes = stats.is_stats.ns_tx_bytes; 710214501Srpaulo } 711214501Srpaulo return 0; 712214501Srpaulo} 713214501Srpaulo 714214501Srpaulostatic int 715214501Srpaulobsd_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, int reason_code) 716214501Srpaulo{ 717214501Srpaulo return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, 718214501Srpaulo addr); 719214501Srpaulo} 720214501Srpaulo 721214501Srpaulostatic int 722214501Srpaulobsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, 723214501Srpaulo int reason_code) 724214501Srpaulo{ 725214501Srpaulo return bsd_send_mlme_param(priv, IEEE80211_MLME_DISASSOC, reason_code, 726214501Srpaulo addr); 727214501Srpaulo} 728214501Srpaulo 729214501Srpaulostatic void 730214501Srpaulobsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) 731214501Srpaulo{ 732214501Srpaulo struct bsd_driver_data *drv = ctx; 733214501Srpaulo struct if_announcemsghdr *ifan; 734214501Srpaulo struct rt_msghdr *rtm; 735214501Srpaulo struct ieee80211_michael_event *mic; 736214501Srpaulo struct ieee80211_join_event *join; 737214501Srpaulo struct ieee80211_leave_event *leave; 738281806Srpaulo int n; 739214501Srpaulo union wpa_event_data data; 740214501Srpaulo 741281806Srpaulo n = read(sock, drv->event_buf, drv->event_buf_len); 742214501Srpaulo if (n < 0) { 743214501Srpaulo if (errno != EINTR && errno != EAGAIN) 744281806Srpaulo wpa_printf(MSG_ERROR, "%s read() failed: %s", 745252190Srpaulo __func__, strerror(errno)); 746214501Srpaulo return; 747214501Srpaulo } 748214501Srpaulo 749281806Srpaulo rtm = (struct rt_msghdr *) drv->event_buf; 750214501Srpaulo if (rtm->rtm_version != RTM_VERSION) { 751252190Srpaulo wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", 752252190Srpaulo rtm->rtm_version); 753214501Srpaulo return; 754214501Srpaulo } 755214501Srpaulo ifan = (struct if_announcemsghdr *) rtm; 756214501Srpaulo switch (rtm->rtm_type) { 757214501Srpaulo case RTM_IEEE80211: 758214501Srpaulo switch (ifan->ifan_what) { 759214501Srpaulo case RTM_IEEE80211_ASSOC: 760214501Srpaulo case RTM_IEEE80211_REASSOC: 761214501Srpaulo case RTM_IEEE80211_DISASSOC: 762214501Srpaulo case RTM_IEEE80211_SCAN: 763214501Srpaulo break; 764214501Srpaulo case RTM_IEEE80211_LEAVE: 765214501Srpaulo leave = (struct ieee80211_leave_event *) &ifan[1]; 766214501Srpaulo drv_event_disassoc(drv->hapd, leave->iev_addr); 767214501Srpaulo break; 768214501Srpaulo case RTM_IEEE80211_JOIN: 769214501Srpaulo#ifdef RTM_IEEE80211_REJOIN 770214501Srpaulo case RTM_IEEE80211_REJOIN: 771214501Srpaulo#endif 772214501Srpaulo join = (struct ieee80211_join_event *) &ifan[1]; 773214501Srpaulo bsd_new_sta(drv, drv->hapd, join->iev_addr); 774214501Srpaulo break; 775214501Srpaulo case RTM_IEEE80211_REPLAY: 776214501Srpaulo /* ignore */ 777214501Srpaulo break; 778214501Srpaulo case RTM_IEEE80211_MICHAEL: 779214501Srpaulo mic = (struct ieee80211_michael_event *) &ifan[1]; 780214501Srpaulo wpa_printf(MSG_DEBUG, 781214501Srpaulo "Michael MIC failure wireless event: " 782214501Srpaulo "keyix=%u src_addr=" MACSTR, mic->iev_keyix, 783214501Srpaulo MAC2STR(mic->iev_src)); 784214501Srpaulo os_memset(&data, 0, sizeof(data)); 785214501Srpaulo data.michael_mic_failure.unicast = 1; 786214501Srpaulo data.michael_mic_failure.src = mic->iev_src; 787214501Srpaulo wpa_supplicant_event(drv->hapd, 788214501Srpaulo EVENT_MICHAEL_MIC_FAILURE, &data); 789214501Srpaulo break; 790214501Srpaulo } 791214501Srpaulo break; 792214501Srpaulo } 793214501Srpaulo} 794214501Srpaulo 795214501Srpaulostatic void 796214501Srpaulohandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) 797214501Srpaulo{ 798214501Srpaulo struct bsd_driver_data *drv = ctx; 799214501Srpaulo drv_event_eapol_rx(drv->hapd, src_addr, buf, len); 800214501Srpaulo} 801214501Srpaulo 802214501Srpaulostatic void * 803214501Srpaulobsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) 804214501Srpaulo{ 805214501Srpaulo struct bsd_driver_data *drv; 806214501Srpaulo 807214501Srpaulo drv = os_zalloc(sizeof(struct bsd_driver_data)); 808214501Srpaulo if (drv == NULL) { 809281806Srpaulo wpa_printf(MSG_ERROR, "Could not allocate memory for bsd driver data"); 810281806Srpaulo return NULL; 811281806Srpaulo } 812281806Srpaulo 813281806Srpaulo drv->event_buf_len = rtbuf_len(); 814281806Srpaulo 815281806Srpaulo drv->event_buf = os_malloc(drv->event_buf_len); 816281806Srpaulo if (drv->event_buf == NULL) { 817281806Srpaulo wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); 818214501Srpaulo goto bad; 819214501Srpaulo } 820214501Srpaulo 821214501Srpaulo drv->hapd = hapd; 822214501Srpaulo drv->sock = socket(PF_INET, SOCK_DGRAM, 0); 823214501Srpaulo if (drv->sock < 0) { 824281806Srpaulo wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s", 825281806Srpaulo strerror(errno)); 826214501Srpaulo goto bad; 827214501Srpaulo } 828214501Srpaulo os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); 829214501Srpaulo 830214501Srpaulo drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, 831214501Srpaulo handle_read, drv, 0); 832214501Srpaulo if (drv->sock_xmit == NULL) 833214501Srpaulo goto bad; 834214501Srpaulo if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) 835214501Srpaulo goto bad; 836214501Srpaulo 837214501Srpaulo /* mark down during setup */ 838214501Srpaulo if (bsd_ctrl_iface(drv, 0) < 0) 839214501Srpaulo goto bad; 840214501Srpaulo 841214501Srpaulo drv->route = socket(PF_ROUTE, SOCK_RAW, 0); 842214501Srpaulo if (drv->route < 0) { 843281806Srpaulo wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s", 844281806Srpaulo strerror(errno)); 845214501Srpaulo goto bad; 846214501Srpaulo } 847214501Srpaulo eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv, 848214501Srpaulo NULL); 849214501Srpaulo 850214501Srpaulo if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { 851214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set operation mode", 852214501Srpaulo __func__); 853214501Srpaulo goto bad; 854214501Srpaulo } 855214501Srpaulo 856214501Srpaulo return drv; 857214501Srpaulobad: 858214501Srpaulo if (drv->sock_xmit != NULL) 859214501Srpaulo l2_packet_deinit(drv->sock_xmit); 860214501Srpaulo if (drv->sock >= 0) 861214501Srpaulo close(drv->sock); 862281806Srpaulo os_free(drv->event_buf); 863214501Srpaulo if (drv != NULL) 864214501Srpaulo os_free(drv); 865214501Srpaulo return NULL; 866214501Srpaulo} 867214501Srpaulo 868214501Srpaulo 869214501Srpaulostatic void 870214501Srpaulobsd_deinit(void *priv) 871214501Srpaulo{ 872214501Srpaulo struct bsd_driver_data *drv = priv; 873214501Srpaulo 874214501Srpaulo if (drv->route >= 0) { 875214501Srpaulo eloop_unregister_read_sock(drv->route); 876214501Srpaulo close(drv->route); 877214501Srpaulo } 878214501Srpaulo bsd_ctrl_iface(drv, 0); 879214501Srpaulo if (drv->sock >= 0) 880214501Srpaulo close(drv->sock); 881214501Srpaulo if (drv->sock_xmit != NULL) 882214501Srpaulo l2_packet_deinit(drv->sock_xmit); 883281806Srpaulo os_free(drv->event_buf); 884214501Srpaulo os_free(drv); 885214501Srpaulo} 886214501Srpaulo 887281806Srpaulo 888281806Srpaulostatic int 889281806Srpaulobsd_commit(void *priv) 890281806Srpaulo{ 891281806Srpaulo return bsd_ctrl_iface(priv, 1); 892281806Srpaulo} 893281806Srpaulo 894281806Srpaulo 895281806Srpaulostatic int 896281806Srpaulobsd_set_sta_authorized(void *priv, const u8 *addr, 897281806Srpaulo int total_flags, int flags_or, int flags_and) 898281806Srpaulo{ 899281806Srpaulo int authorized = -1; 900281806Srpaulo 901281806Srpaulo /* For now, only support setting Authorized flag */ 902281806Srpaulo if (flags_or & WPA_STA_AUTHORIZED) 903281806Srpaulo authorized = 1; 904281806Srpaulo if (!(flags_and & WPA_STA_AUTHORIZED)) 905281806Srpaulo authorized = 0; 906281806Srpaulo 907281806Srpaulo if (authorized < 0) 908281806Srpaulo return 0; 909281806Srpaulo 910281806Srpaulo return bsd_send_mlme_param(priv, authorized ? 911281806Srpaulo IEEE80211_MLME_AUTHORIZE : 912281806Srpaulo IEEE80211_MLME_UNAUTHORIZE, 0, addr); 913281806Srpaulo} 914214501Srpaulo#else /* HOSTAPD */ 915214501Srpaulo 916214501Srpaulostatic int 917214501Srpauloget80211param(struct bsd_driver_data *drv, int op) 918214501Srpaulo{ 919214501Srpaulo struct ieee80211req ireq; 920214501Srpaulo 921214501Srpaulo if (bsd_get80211(drv, &ireq, op, NULL, 0) < 0) 922214501Srpaulo return -1; 923214501Srpaulo return ireq.i_val; 924214501Srpaulo} 925214501Srpaulo 926214501Srpaulostatic int 927214501Srpaulowpa_driver_bsd_get_bssid(void *priv, u8 *bssid) 928214501Srpaulo{ 929214501Srpaulo struct bsd_driver_data *drv = priv; 930214501Srpaulo#ifdef SIOCG80211BSSID 931214501Srpaulo struct ieee80211_bssid bs; 932214501Srpaulo 933214501Srpaulo os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name)); 934214501Srpaulo if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0) 935214501Srpaulo return -1; 936214501Srpaulo os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid)); 937214501Srpaulo return 0; 938214501Srpaulo#else 939214501Srpaulo return get80211var(drv, IEEE80211_IOC_BSSID, 940214501Srpaulo bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0; 941214501Srpaulo#endif 942214501Srpaulo} 943214501Srpaulo 944214501Srpaulostatic int 945214501Srpaulowpa_driver_bsd_get_ssid(void *priv, u8 *ssid) 946214501Srpaulo{ 947214501Srpaulo struct bsd_driver_data *drv = priv; 948214501Srpaulo return bsd_get_ssid(drv, ssid, 0); 949214501Srpaulo} 950214501Srpaulo 951214501Srpaulostatic int 952214501Srpaulowpa_driver_bsd_set_wpa_ie(struct bsd_driver_data *drv, const u8 *wpa_ie, 953214501Srpaulo size_t wpa_ie_len) 954214501Srpaulo{ 955214501Srpaulo#ifdef IEEE80211_IOC_APPIE 956214501Srpaulo return bsd_set_opt_ie(drv, wpa_ie, wpa_ie_len); 957214501Srpaulo#else /* IEEE80211_IOC_APPIE */ 958214501Srpaulo return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len); 959214501Srpaulo#endif /* IEEE80211_IOC_APPIE */ 960214501Srpaulo} 961214501Srpaulo 962214501Srpaulostatic int 963214501Srpaulowpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy) 964214501Srpaulo{ 965214501Srpaulo int ret = 0; 966214501Srpaulo 967214501Srpaulo wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d", 968214501Srpaulo __FUNCTION__, wpa, privacy); 969214501Srpaulo 970214501Srpaulo if (!wpa && wpa_driver_bsd_set_wpa_ie(priv, NULL, 0) < 0) 971214501Srpaulo ret = -1; 972214501Srpaulo if (set80211param(priv, IEEE80211_IOC_PRIVACY, privacy) < 0) 973214501Srpaulo ret = -1; 974214501Srpaulo if (set80211param(priv, IEEE80211_IOC_WPA, wpa) < 0) 975214501Srpaulo ret = -1; 976214501Srpaulo 977214501Srpaulo return ret; 978214501Srpaulo} 979214501Srpaulo 980214501Srpaulostatic int 981214501Srpaulowpa_driver_bsd_set_wpa(void *priv, int enabled) 982214501Srpaulo{ 983214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); 984214501Srpaulo 985214501Srpaulo return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled); 986214501Srpaulo} 987214501Srpaulo 988214501Srpaulostatic int 989214501Srpaulowpa_driver_bsd_set_countermeasures(void *priv, int enabled) 990214501Srpaulo{ 991209139Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 992214501Srpaulo return set80211param(priv, IEEE80211_IOC_COUNTERMEASURES, enabled); 993209139Srpaulo} 994209139Srpaulo 995214501Srpaulo 996209139Srpaulostatic int 997214501Srpaulowpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled) 998214501Srpaulo{ 999214501Srpaulo wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); 1000214501Srpaulo return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled); 1001214501Srpaulo} 1002214501Srpaulo 1003214501Srpaulostatic int 1004209139Srpaulowpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code) 1005209139Srpaulo{ 1006214501Srpaulo return bsd_send_mlme_param(priv, IEEE80211_MLME_DEAUTH, reason_code, 1007214501Srpaulo addr); 1008209139Srpaulo} 1009209139Srpaulo 1010209139Srpaulostatic int 1011214501Srpaulowpa_driver_bsd_set_auth_alg(void *priv, int auth_alg) 1012214501Srpaulo{ 1013214501Srpaulo int authmode; 1014214501Srpaulo 1015214501Srpaulo if ((auth_alg & WPA_AUTH_ALG_OPEN) && 1016214501Srpaulo (auth_alg & WPA_AUTH_ALG_SHARED)) 1017214501Srpaulo authmode = IEEE80211_AUTH_AUTO; 1018214501Srpaulo else if (auth_alg & WPA_AUTH_ALG_SHARED) 1019214501Srpaulo authmode = IEEE80211_AUTH_SHARED; 1020214501Srpaulo else 1021214501Srpaulo authmode = IEEE80211_AUTH_OPEN; 1022214501Srpaulo 1023214501Srpaulo return set80211param(priv, IEEE80211_IOC_AUTHMODE, authmode); 1024209139Srpaulo} 1025209139Srpaulo 1026214501Srpaulostatic void 1027214501Srpaulohandle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) 1028214501Srpaulo{ 1029214501Srpaulo struct bsd_driver_data *drv = ctx; 1030214501Srpaulo 1031214501Srpaulo drv_event_eapol_rx(drv->ctx, src_addr, buf, len); 1032214501Srpaulo} 1033214501Srpaulo 1034209139Srpaulostatic int 1035209139Srpaulowpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params) 1036209139Srpaulo{ 1037214501Srpaulo struct bsd_driver_data *drv = priv; 1038209139Srpaulo struct ieee80211req_mlme mlme; 1039214501Srpaulo u32 mode; 1040209139Srpaulo int privacy; 1041214501Srpaulo int ret = 0; 1042209139Srpaulo 1043209139Srpaulo wpa_printf(MSG_DEBUG, 1044209139Srpaulo "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u" 1045209139Srpaulo , __func__ 1046214501Srpaulo , (unsigned int) params->ssid_len, params->ssid 1047214501Srpaulo , (unsigned int) params->wpa_ie_len 1048209139Srpaulo , params->pairwise_suite 1049209139Srpaulo , params->group_suite 1050209139Srpaulo , params->key_mgmt_suite 1051209139Srpaulo ); 1052209139Srpaulo 1053214501Srpaulo switch (params->mode) { 1054214501Srpaulo case IEEE80211_MODE_INFRA: 1055214501Srpaulo mode = 0 /* STA */; 1056214501Srpaulo break; 1057214501Srpaulo case IEEE80211_MODE_IBSS: 1058214501Srpaulo mode = IFM_IEEE80211_IBSS; 1059214501Srpaulo break; 1060214501Srpaulo case IEEE80211_MODE_AP: 1061214501Srpaulo mode = IFM_IEEE80211_HOSTAP; 1062214501Srpaulo break; 1063214501Srpaulo default: 1064214501Srpaulo wpa_printf(MSG_ERROR, "%s: unknown operation mode", __func__); 1065214501Srpaulo return -1; 1066214501Srpaulo } 1067214501Srpaulo if (bsd_set_mediaopt(drv, IFM_OMASK, mode) < 0) { 1068214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set operation mode", 1069214501Srpaulo __func__); 1070214501Srpaulo return -1; 1071214501Srpaulo } 1072214501Srpaulo 1073214501Srpaulo if (params->mode == IEEE80211_MODE_AP) { 1074214501Srpaulo drv->sock_xmit = l2_packet_init(drv->ifname, NULL, ETH_P_EAPOL, 1075214501Srpaulo handle_read, drv, 0); 1076214501Srpaulo if (drv->sock_xmit == NULL) 1077214501Srpaulo return -1; 1078214501Srpaulo drv->is_ap = 1; 1079214501Srpaulo return 0; 1080214501Srpaulo } 1081214501Srpaulo 1082214501Srpaulo if (wpa_driver_bsd_set_drop_unencrypted(drv, params->drop_unencrypted) 1083214501Srpaulo < 0) 1084214501Srpaulo ret = -1; 1085214501Srpaulo if (wpa_driver_bsd_set_auth_alg(drv, params->auth_alg) < 0) 1086214501Srpaulo ret = -1; 1087209139Srpaulo /* XXX error handling is wrong but unclear what to do... */ 1088209139Srpaulo if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0) 1089209139Srpaulo return -1; 1090209139Srpaulo 1091281806Srpaulo privacy = !(params->pairwise_suite == WPA_CIPHER_NONE && 1092281806Srpaulo params->group_suite == WPA_CIPHER_NONE && 1093281806Srpaulo params->key_mgmt_suite == WPA_KEY_MGMT_NONE && 1094209139Srpaulo params->wpa_ie_len == 0); 1095209139Srpaulo wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy); 1096209139Srpaulo 1097209139Srpaulo if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0) 1098209139Srpaulo return -1; 1099209139Srpaulo 1100209139Srpaulo if (params->wpa_ie_len && 1101209139Srpaulo set80211param(drv, IEEE80211_IOC_WPA, 1102209139Srpaulo params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0) 1103209139Srpaulo return -1; 1104209139Srpaulo 1105209139Srpaulo os_memset(&mlme, 0, sizeof(mlme)); 1106209139Srpaulo mlme.im_op = IEEE80211_MLME_ASSOC; 1107209139Srpaulo if (params->ssid != NULL) 1108209139Srpaulo os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len); 1109209139Srpaulo mlme.im_ssid_len = params->ssid_len; 1110209139Srpaulo if (params->bssid != NULL) 1111209139Srpaulo os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN); 1112209139Srpaulo if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0) 1113209139Srpaulo return -1; 1114214501Srpaulo return ret; 1115209139Srpaulo} 1116209139Srpaulo 1117209139Srpaulostatic int 1118214501Srpaulowpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) 1119209139Srpaulo{ 1120214501Srpaulo struct bsd_driver_data *drv = priv; 1121214501Srpaulo#ifdef IEEE80211_IOC_SCAN_MAX_SSID 1122214501Srpaulo struct ieee80211_scan_req sr; 1123214501Srpaulo int i; 1124214501Srpaulo#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ 1125209139Srpaulo 1126214501Srpaulo if (bsd_set_mediaopt(drv, IFM_OMASK, 0 /* STA */) < 0) { 1127214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set operation mode", 1128214501Srpaulo __func__); 1129214501Srpaulo return -1; 1130214501Srpaulo } 1131209139Srpaulo 1132214501Srpaulo if (set80211param(drv, IEEE80211_IOC_ROAMING, 1133214501Srpaulo IEEE80211_ROAMING_MANUAL) < 0) { 1134214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set " 1135214501Srpaulo "wpa_supplicant-based roaming: %s", __func__, 1136214501Srpaulo strerror(errno)); 1137214501Srpaulo return -1; 1138214501Srpaulo } 1139209139Srpaulo 1140214501Srpaulo if (wpa_driver_bsd_set_wpa(drv, 1) < 0) { 1141214501Srpaulo wpa_printf(MSG_ERROR, "%s: failed to set wpa: %s", __func__, 1142214501Srpaulo strerror(errno)); 1143214501Srpaulo return -1; 1144214501Srpaulo } 1145209139Srpaulo 1146209139Srpaulo /* NB: interface must be marked UP to do a scan */ 1147214501Srpaulo if (bsd_ctrl_iface(drv, 1) < 0) 1148209139Srpaulo return -1; 1149209139Srpaulo 1150214501Srpaulo#ifdef IEEE80211_IOC_SCAN_MAX_SSID 1151214501Srpaulo os_memset(&sr, 0, sizeof(sr)); 1152214501Srpaulo sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE | IEEE80211_IOC_SCAN_ONCE | 1153214501Srpaulo IEEE80211_IOC_SCAN_NOJOIN; 1154214501Srpaulo sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER; 1155214501Srpaulo if (params->num_ssids > 0) { 1156214501Srpaulo sr.sr_nssid = params->num_ssids; 1157214501Srpaulo#if 0 1158214501Srpaulo /* Boundary check is done by upper layer */ 1159214501Srpaulo if (sr.sr_nssid > IEEE80211_IOC_SCAN_MAX_SSID) 1160214501Srpaulo sr.sr_nssid = IEEE80211_IOC_SCAN_MAX_SSID; 1161214501Srpaulo#endif 1162214501Srpaulo 1163214501Srpaulo /* NB: check scan cache first */ 1164214501Srpaulo sr.sr_flags |= IEEE80211_IOC_SCAN_CHECK; 1165214501Srpaulo } 1166214501Srpaulo for (i = 0; i < sr.sr_nssid; i++) { 1167214501Srpaulo sr.sr_ssid[i].len = params->ssids[i].ssid_len; 1168214501Srpaulo os_memcpy(sr.sr_ssid[i].ssid, params->ssids[i].ssid, 1169214501Srpaulo sr.sr_ssid[i].len); 1170214501Srpaulo } 1171214501Srpaulo 1172214501Srpaulo /* NB: net80211 delivers a scan complete event so no need to poll */ 1173214501Srpaulo return set80211var(drv, IEEE80211_IOC_SCAN_REQ, &sr, sizeof(sr)); 1174214501Srpaulo#else /* IEEE80211_IOC_SCAN_MAX_SSID */ 1175209139Srpaulo /* set desired ssid before scan */ 1176214501Srpaulo if (bsd_set_ssid(drv, params->ssids[0].ssid, 1177214501Srpaulo params->ssids[0].ssid_len) < 0) 1178209139Srpaulo return -1; 1179209139Srpaulo 1180209139Srpaulo /* NB: net80211 delivers a scan complete event so no need to poll */ 1181209139Srpaulo return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0); 1182214501Srpaulo#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ 1183209139Srpaulo} 1184209139Srpaulo 1185209139Srpaulostatic void 1186209139Srpaulowpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) 1187209139Srpaulo{ 1188214501Srpaulo struct bsd_driver_data *drv = sock_ctx; 1189209139Srpaulo struct if_announcemsghdr *ifan; 1190209139Srpaulo struct if_msghdr *ifm; 1191209139Srpaulo struct rt_msghdr *rtm; 1192209139Srpaulo union wpa_event_data event; 1193209139Srpaulo struct ieee80211_michael_event *mic; 1194214501Srpaulo struct ieee80211_leave_event *leave; 1195214501Srpaulo struct ieee80211_join_event *join; 1196281806Srpaulo int n; 1197209139Srpaulo 1198281806Srpaulo n = read(sock, drv->event_buf, drv->event_buf_len); 1199209139Srpaulo if (n < 0) { 1200209139Srpaulo if (errno != EINTR && errno != EAGAIN) 1201281806Srpaulo wpa_printf(MSG_ERROR, "%s read() failed: %s", 1202252190Srpaulo __func__, strerror(errno)); 1203209139Srpaulo return; 1204209139Srpaulo } 1205209139Srpaulo 1206281806Srpaulo rtm = (struct rt_msghdr *) drv->event_buf; 1207209139Srpaulo if (rtm->rtm_version != RTM_VERSION) { 1208252190Srpaulo wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", 1209252190Srpaulo rtm->rtm_version); 1210209139Srpaulo return; 1211209139Srpaulo } 1212209139Srpaulo os_memset(&event, 0, sizeof(event)); 1213209139Srpaulo switch (rtm->rtm_type) { 1214209139Srpaulo case RTM_IFANNOUNCE: 1215209139Srpaulo ifan = (struct if_announcemsghdr *) rtm; 1216209139Srpaulo if (ifan->ifan_index != drv->ifindex) 1217209139Srpaulo break; 1218214501Srpaulo os_strlcpy(event.interface_status.ifname, drv->ifname, 1219214501Srpaulo sizeof(event.interface_status.ifname)); 1220209139Srpaulo switch (ifan->ifan_what) { 1221209139Srpaulo case IFAN_DEPARTURE: 1222209139Srpaulo event.interface_status.ievent = EVENT_INTERFACE_REMOVED; 1223209139Srpaulo default: 1224209139Srpaulo return; 1225209139Srpaulo } 1226209139Srpaulo wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", 1227209139Srpaulo event.interface_status.ifname, 1228209139Srpaulo ifan->ifan_what == IFAN_DEPARTURE ? 1229209139Srpaulo "removed" : "added"); 1230209139Srpaulo wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); 1231209139Srpaulo break; 1232209139Srpaulo case RTM_IEEE80211: 1233209139Srpaulo ifan = (struct if_announcemsghdr *) rtm; 1234209139Srpaulo if (ifan->ifan_index != drv->ifindex) 1235209139Srpaulo break; 1236209139Srpaulo switch (ifan->ifan_what) { 1237209139Srpaulo case RTM_IEEE80211_ASSOC: 1238209139Srpaulo case RTM_IEEE80211_REASSOC: 1239214501Srpaulo if (drv->is_ap) 1240214501Srpaulo break; 1241209139Srpaulo wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); 1242209139Srpaulo break; 1243209139Srpaulo case RTM_IEEE80211_DISASSOC: 1244214501Srpaulo if (drv->is_ap) 1245214501Srpaulo break; 1246209139Srpaulo wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); 1247209139Srpaulo break; 1248209139Srpaulo case RTM_IEEE80211_SCAN: 1249214501Srpaulo if (drv->is_ap) 1250214501Srpaulo break; 1251209139Srpaulo wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL); 1252209139Srpaulo break; 1253214501Srpaulo case RTM_IEEE80211_LEAVE: 1254214501Srpaulo leave = (struct ieee80211_leave_event *) &ifan[1]; 1255214501Srpaulo drv_event_disassoc(ctx, leave->iev_addr); 1256214501Srpaulo break; 1257214501Srpaulo case RTM_IEEE80211_JOIN: 1258214501Srpaulo#ifdef RTM_IEEE80211_REJOIN 1259214501Srpaulo case RTM_IEEE80211_REJOIN: 1260214501Srpaulo#endif 1261214501Srpaulo join = (struct ieee80211_join_event *) &ifan[1]; 1262214501Srpaulo bsd_new_sta(drv, ctx, join->iev_addr); 1263214501Srpaulo break; 1264209139Srpaulo case RTM_IEEE80211_REPLAY: 1265209139Srpaulo /* ignore */ 1266209139Srpaulo break; 1267209139Srpaulo case RTM_IEEE80211_MICHAEL: 1268209139Srpaulo mic = (struct ieee80211_michael_event *) &ifan[1]; 1269209139Srpaulo wpa_printf(MSG_DEBUG, 1270209139Srpaulo "Michael MIC failure wireless event: " 1271209139Srpaulo "keyix=%u src_addr=" MACSTR, mic->iev_keyix, 1272209139Srpaulo MAC2STR(mic->iev_src)); 1273209139Srpaulo 1274209139Srpaulo os_memset(&event, 0, sizeof(event)); 1275209139Srpaulo event.michael_mic_failure.unicast = 1276209139Srpaulo !IEEE80211_IS_MULTICAST(mic->iev_dst); 1277209139Srpaulo wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, 1278209139Srpaulo &event); 1279209139Srpaulo break; 1280209139Srpaulo } 1281209139Srpaulo break; 1282209139Srpaulo case RTM_IFINFO: 1283209139Srpaulo ifm = (struct if_msghdr *) rtm; 1284209139Srpaulo if (ifm->ifm_index != drv->ifindex) 1285209139Srpaulo break; 1286209139Srpaulo if ((rtm->rtm_flags & RTF_UP) == 0) { 1287214501Srpaulo os_strlcpy(event.interface_status.ifname, drv->ifname, 1288214501Srpaulo sizeof(event.interface_status.ifname)); 1289209139Srpaulo event.interface_status.ievent = EVENT_INTERFACE_REMOVED; 1290209139Srpaulo wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", 1291209139Srpaulo event.interface_status.ifname); 1292209139Srpaulo wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event); 1293209139Srpaulo } 1294209139Srpaulo break; 1295209139Srpaulo } 1296209139Srpaulo} 1297209139Srpaulo 1298214501Srpaulostatic void 1299214501Srpaulowpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, 1300214501Srpaulo struct ieee80211req_scan_result *sr) 1301209139Srpaulo{ 1302214501Srpaulo struct wpa_scan_res *result, **tmp; 1303214501Srpaulo size_t extra_len; 1304214501Srpaulo u8 *pos; 1305209139Srpaulo 1306214501Srpaulo extra_len = 2 + sr->isr_ssid_len; 1307214501Srpaulo extra_len += 2 + sr->isr_nrates; 1308214501Srpaulo extra_len += 3; /* ERP IE */ 1309214501Srpaulo extra_len += sr->isr_ie_len; 1310209139Srpaulo 1311214501Srpaulo result = os_zalloc(sizeof(*result) + extra_len); 1312214501Srpaulo if (result == NULL) 1313214501Srpaulo return; 1314214501Srpaulo os_memcpy(result->bssid, sr->isr_bssid, ETH_ALEN); 1315214501Srpaulo result->freq = sr->isr_freq; 1316214501Srpaulo result->beacon_int = sr->isr_intval; 1317214501Srpaulo result->caps = sr->isr_capinfo; 1318214501Srpaulo result->qual = sr->isr_rssi; 1319214501Srpaulo result->noise = sr->isr_noise; 1320252726Srpaulo /* 1321252726Srpaulo * the rssi value reported by the kernel is in 0.5dB steps relative to 1322252726Srpaulo * the reported noise floor. see ieee80211_node.h for details. 1323252726Srpaulo */ 1324252726Srpaulo result->level = sr->isr_rssi / 2 + sr->isr_noise; 1325209139Srpaulo 1326214501Srpaulo pos = (u8 *)(result + 1); 1327209139Srpaulo 1328214501Srpaulo *pos++ = WLAN_EID_SSID; 1329214501Srpaulo *pos++ = sr->isr_ssid_len; 1330214501Srpaulo os_memcpy(pos, sr + 1, sr->isr_ssid_len); 1331214501Srpaulo pos += sr->isr_ssid_len; 1332209139Srpaulo 1333214501Srpaulo /* 1334214501Srpaulo * Deal all rates as supported rate. 1335214501Srpaulo * Because net80211 doesn't report extended supported rate or not. 1336214501Srpaulo */ 1337214501Srpaulo *pos++ = WLAN_EID_SUPP_RATES; 1338214501Srpaulo *pos++ = sr->isr_nrates; 1339214501Srpaulo os_memcpy(pos, sr->isr_rates, sr->isr_nrates); 1340214501Srpaulo pos += sr->isr_nrates; 1341214501Srpaulo 1342214501Srpaulo *pos++ = WLAN_EID_ERP_INFO; 1343214501Srpaulo *pos++ = 1; 1344214501Srpaulo *pos++ = sr->isr_erp; 1345214501Srpaulo 1346281806Srpaulo#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 1347281806Srpaulo os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len + sr->isr_meshid_len, 1348281806Srpaulo sr->isr_ie_len); 1349281806Srpaulo#else 1350214501Srpaulo os_memcpy(pos, (u8 *)(sr + 1) + sr->isr_ssid_len, sr->isr_ie_len); 1351281806Srpaulo#endif 1352214501Srpaulo pos += sr->isr_ie_len; 1353214501Srpaulo 1354214501Srpaulo result->ie_len = pos - (u8 *)(result + 1); 1355214501Srpaulo 1356252190Srpaulo tmp = os_realloc_array(res->res, res->num + 1, 1357252190Srpaulo sizeof(struct wpa_scan_res *)); 1358214501Srpaulo if (tmp == NULL) { 1359214501Srpaulo os_free(result); 1360214501Srpaulo return; 1361214501Srpaulo } 1362214501Srpaulo tmp[res->num++] = result; 1363214501Srpaulo res->res = tmp; 1364209139Srpaulo} 1365209139Srpaulo 1366214501Srpaulostruct wpa_scan_results * 1367214501Srpaulowpa_driver_bsd_get_scan_results2(void *priv) 1368209139Srpaulo{ 1369214501Srpaulo struct ieee80211req_scan_result *sr; 1370214501Srpaulo struct wpa_scan_results *res; 1371214501Srpaulo int len, rest; 1372214501Srpaulo uint8_t buf[24*1024], *pos; 1373209139Srpaulo 1374214501Srpaulo len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024); 1375214501Srpaulo if (len < 0) 1376214501Srpaulo return NULL; 1377214501Srpaulo 1378214501Srpaulo res = os_zalloc(sizeof(*res)); 1379214501Srpaulo if (res == NULL) 1380214501Srpaulo return NULL; 1381214501Srpaulo 1382214501Srpaulo pos = buf; 1383214501Srpaulo rest = len; 1384214501Srpaulo while (rest >= sizeof(struct ieee80211req_scan_result)) { 1385214501Srpaulo sr = (struct ieee80211req_scan_result *)pos; 1386214501Srpaulo wpa_driver_bsd_add_scan_entry(res, sr); 1387214501Srpaulo pos += sr->isr_len; 1388214501Srpaulo rest -= sr->isr_len; 1389209139Srpaulo } 1390209139Srpaulo 1391214501Srpaulo wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)", 1392214501Srpaulo len, (unsigned long)res->num); 1393209139Srpaulo 1394214501Srpaulo return res; 1395209139Srpaulo} 1396209139Srpaulo 1397214501Srpaulostatic int wpa_driver_bsd_capa(struct bsd_driver_data *drv) 1398209139Srpaulo{ 1399214501Srpaulo#ifdef IEEE80211_IOC_DEVCAPS 1400214501Srpaulo/* kernel definitions copied from net80211/ieee80211_var.h */ 1401214501Srpaulo#define IEEE80211_CIPHER_WEP 0 1402214501Srpaulo#define IEEE80211_CIPHER_TKIP 1 1403214501Srpaulo#define IEEE80211_CIPHER_AES_CCM 3 1404214501Srpaulo#define IEEE80211_CRYPTO_WEP (1<<IEEE80211_CIPHER_WEP) 1405214501Srpaulo#define IEEE80211_CRYPTO_TKIP (1<<IEEE80211_CIPHER_TKIP) 1406214501Srpaulo#define IEEE80211_CRYPTO_AES_CCM (1<<IEEE80211_CIPHER_AES_CCM) 1407214501Srpaulo#define IEEE80211_C_HOSTAP 0x00000400 /* CAPABILITY: HOSTAP avail */ 1408214501Srpaulo#define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */ 1409214501Srpaulo#define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */ 1410214501Srpaulo struct ieee80211_devcaps_req devcaps; 1411209139Srpaulo 1412214501Srpaulo if (get80211var(drv, IEEE80211_IOC_DEVCAPS, &devcaps, 1413214501Srpaulo sizeof(devcaps)) < 0) { 1414214501Srpaulo wpa_printf(MSG_ERROR, "failed to IEEE80211_IOC_DEVCAPS: %s", 1415214501Srpaulo strerror(errno)); 1416209139Srpaulo return -1; 1417209139Srpaulo } 1418209139Srpaulo 1419214501Srpaulo wpa_printf(MSG_DEBUG, "%s: drivercaps=0x%08x,cryptocaps=0x%08x", 1420214501Srpaulo __func__, devcaps.dc_drivercaps, devcaps.dc_cryptocaps); 1421209139Srpaulo 1422214501Srpaulo if (devcaps.dc_drivercaps & IEEE80211_C_WPA1) 1423214501Srpaulo drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | 1424214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; 1425214501Srpaulo if (devcaps.dc_drivercaps & IEEE80211_C_WPA2) 1426214501Srpaulo drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 1427214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; 1428214501Srpaulo 1429263925Srpaulo#ifdef __FreeBSD__ 1430263925Srpaulo drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | 1431263925Srpaulo WPA_DRIVER_CAPA_ENC_WEP104 | 1432263925Srpaulo WPA_DRIVER_CAPA_ENC_TKIP | 1433263925Srpaulo WPA_DRIVER_CAPA_ENC_CCMP; 1434263925Srpaulo#else 1435263925Srpaulo /* 1436263925Srpaulo * XXX 1437263925Srpaulo * FreeBSD exports hardware cryptocaps. These have no meaning for wpa 1438263925Srpaulo * since net80211 performs software crypto. 1439263925Srpaulo */ 1440214501Srpaulo if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP) 1441214501Srpaulo drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | 1442214501Srpaulo WPA_DRIVER_CAPA_ENC_WEP104; 1443214501Srpaulo if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP) 1444214501Srpaulo drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; 1445214501Srpaulo if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM) 1446214501Srpaulo drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; 1447263925Srpaulo#endif 1448214501Srpaulo 1449214501Srpaulo if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP) 1450214501Srpaulo drv->capa.flags |= WPA_DRIVER_FLAGS_AP; 1451214501Srpaulo#undef IEEE80211_CIPHER_WEP 1452214501Srpaulo#undef IEEE80211_CIPHER_TKIP 1453214501Srpaulo#undef IEEE80211_CIPHER_AES_CCM 1454214501Srpaulo#undef IEEE80211_CRYPTO_WEP 1455214501Srpaulo#undef IEEE80211_CRYPTO_TKIP 1456214501Srpaulo#undef IEEE80211_CRYPTO_AES_CCM 1457214501Srpaulo#undef IEEE80211_C_HOSTAP 1458214501Srpaulo#undef IEEE80211_C_WPA1 1459214501Srpaulo#undef IEEE80211_C_WPA2 1460214501Srpaulo#else /* IEEE80211_IOC_DEVCAPS */ 1461214501Srpaulo /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ 1462214501Srpaulo drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | 1463214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | 1464214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | 1465214501Srpaulo WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; 1466214501Srpaulo drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | 1467214501Srpaulo WPA_DRIVER_CAPA_ENC_WEP104 | 1468214501Srpaulo WPA_DRIVER_CAPA_ENC_TKIP | 1469214501Srpaulo WPA_DRIVER_CAPA_ENC_CCMP; 1470214501Srpaulo drv->capa.flags |= WPA_DRIVER_FLAGS_AP; 1471214501Srpaulo#endif /* IEEE80211_IOC_DEVCAPS */ 1472214501Srpaulo#ifdef IEEE80211_IOC_SCAN_MAX_SSID 1473214501Srpaulo drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID; 1474214501Srpaulo#else /* IEEE80211_IOC_SCAN_MAX_SSID */ 1475214501Srpaulo drv->capa.max_scan_ssids = 1; 1476214501Srpaulo#endif /* IEEE80211_IOC_SCAN_MAX_SSID */ 1477214501Srpaulo drv->capa.auth = WPA_DRIVER_AUTH_OPEN | 1478214501Srpaulo WPA_DRIVER_AUTH_SHARED | 1479214501Srpaulo WPA_DRIVER_AUTH_LEAP; 1480214501Srpaulo return 0; 1481209139Srpaulo} 1482209139Srpaulo 1483281806Srpaulostatic enum ieee80211_opmode 1484281806Srpauloget80211opmode(struct bsd_driver_data *drv) 1485281806Srpaulo{ 1486281806Srpaulo struct ifmediareq ifmr; 1487281806Srpaulo 1488281806Srpaulo (void) memset(&ifmr, 0, sizeof(ifmr)); 1489281806Srpaulo (void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name)); 1490281806Srpaulo 1491281806Srpaulo if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) { 1492281806Srpaulo if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) { 1493281806Srpaulo if (ifmr.ifm_current & IFM_FLAG0) 1494281806Srpaulo return IEEE80211_M_AHDEMO; 1495281806Srpaulo else 1496281806Srpaulo return IEEE80211_M_IBSS; 1497281806Srpaulo } 1498281806Srpaulo if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP) 1499281806Srpaulo return IEEE80211_M_HOSTAP; 1500281806Srpaulo if (ifmr.ifm_current & IFM_IEEE80211_MONITOR) 1501281806Srpaulo return IEEE80211_M_MONITOR; 1502281806Srpaulo#ifdef IEEE80211_M_MBSS 1503281806Srpaulo if (ifmr.ifm_current & IFM_IEEE80211_MBSS) 1504281806Srpaulo return IEEE80211_M_MBSS; 1505281806Srpaulo#endif /* IEEE80211_M_MBSS */ 1506281806Srpaulo } 1507281806Srpaulo return IEEE80211_M_STA; 1508281806Srpaulo} 1509281806Srpaulo 1510209139Srpaulostatic void * 1511209139Srpaulowpa_driver_bsd_init(void *ctx, const char *ifname) 1512209139Srpaulo{ 1513209139Srpaulo#define GETPARAM(drv, param, v) \ 1514209139Srpaulo (((v) = get80211param(drv, param)) != -1) 1515214501Srpaulo struct bsd_driver_data *drv; 1516209139Srpaulo 1517209139Srpaulo drv = os_zalloc(sizeof(*drv)); 1518209139Srpaulo if (drv == NULL) 1519209139Srpaulo return NULL; 1520281806Srpaulo 1521281806Srpaulo drv->event_buf_len = rtbuf_len(); 1522281806Srpaulo 1523281806Srpaulo drv->event_buf = os_malloc(drv->event_buf_len); 1524281806Srpaulo if (drv->event_buf == NULL) { 1525281806Srpaulo wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); 1526281806Srpaulo goto fail1; 1527281806Srpaulo } 1528281806Srpaulo 1529209139Srpaulo /* 1530209139Srpaulo * NB: We require the interface name be mappable to an index. 1531209139Srpaulo * This implies we do not support having wpa_supplicant 1532209139Srpaulo * wait for an interface to appear. This seems ok; that 1533209139Srpaulo * doesn't belong here; it's really the job of devd. 1534209139Srpaulo */ 1535209139Srpaulo drv->ifindex = if_nametoindex(ifname); 1536209139Srpaulo if (drv->ifindex == 0) { 1537209139Srpaulo wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", 1538209139Srpaulo __func__, ifname); 1539209139Srpaulo goto fail1; 1540209139Srpaulo } 1541209139Srpaulo drv->sock = socket(PF_INET, SOCK_DGRAM, 0); 1542209139Srpaulo if (drv->sock < 0) 1543209139Srpaulo goto fail1; 1544252726Srpaulo 1545252726Srpaulo os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); 1546252726Srpaulo /* Down interface during setup. */ 1547252726Srpaulo if (bsd_ctrl_iface(drv, 0) < 0) 1548252726Srpaulo goto fail; 1549252726Srpaulo 1550209139Srpaulo drv->route = socket(PF_ROUTE, SOCK_RAW, 0); 1551209139Srpaulo if (drv->route < 0) 1552209139Srpaulo goto fail; 1553209139Srpaulo eloop_register_read_sock(drv->route, 1554209139Srpaulo wpa_driver_bsd_event_receive, ctx, drv); 1555209139Srpaulo 1556209139Srpaulo drv->ctx = ctx; 1557209139Srpaulo 1558209139Srpaulo if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { 1559209139Srpaulo wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", 1560209139Srpaulo __func__, strerror(errno)); 1561209139Srpaulo goto fail; 1562209139Srpaulo } 1563209139Srpaulo if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) { 1564209139Srpaulo wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s", 1565209139Srpaulo __func__, strerror(errno)); 1566209139Srpaulo goto fail; 1567209139Srpaulo } 1568209139Srpaulo if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) { 1569209139Srpaulo wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s", 1570209139Srpaulo __func__, strerror(errno)); 1571209139Srpaulo goto fail; 1572209139Srpaulo } 1573209139Srpaulo 1574214501Srpaulo if (wpa_driver_bsd_capa(drv)) 1575209139Srpaulo goto fail; 1576209139Srpaulo 1577252726Srpaulo drv->opmode = get80211opmode(drv); 1578252726Srpaulo 1579209139Srpaulo return drv; 1580209139Srpaulofail: 1581209139Srpaulo close(drv->sock); 1582209139Srpaulofail1: 1583281806Srpaulo os_free(drv->event_buf); 1584209139Srpaulo os_free(drv); 1585209139Srpaulo return NULL; 1586209139Srpaulo#undef GETPARAM 1587209139Srpaulo} 1588209139Srpaulo 1589209139Srpaulostatic void 1590209139Srpaulowpa_driver_bsd_deinit(void *priv) 1591209139Srpaulo{ 1592214501Srpaulo struct bsd_driver_data *drv = priv; 1593209139Srpaulo 1594214501Srpaulo wpa_driver_bsd_set_wpa(drv, 0); 1595209139Srpaulo eloop_unregister_read_sock(drv->route); 1596209139Srpaulo 1597209139Srpaulo /* NB: mark interface down */ 1598214501Srpaulo bsd_ctrl_iface(drv, 0); 1599209139Srpaulo 1600209139Srpaulo wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); 1601209139Srpaulo if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0) 1602209139Srpaulo wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state", 1603209139Srpaulo __func__); 1604209139Srpaulo 1605214501Srpaulo if (drv->sock_xmit != NULL) 1606214501Srpaulo l2_packet_deinit(drv->sock_xmit); 1607209139Srpaulo (void) close(drv->route); /* ioctl socket */ 1608209139Srpaulo (void) close(drv->sock); /* event socket */ 1609281806Srpaulo os_free(drv->event_buf); 1610209139Srpaulo os_free(drv); 1611209139Srpaulo} 1612209139Srpaulo 1613214501Srpaulostatic int 1614214501Srpaulowpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa) 1615214501Srpaulo{ 1616214501Srpaulo struct bsd_driver_data *drv = priv; 1617209139Srpaulo 1618214501Srpaulo os_memcpy(capa, &drv->capa, sizeof(*capa)); 1619214501Srpaulo return 0; 1620214501Srpaulo} 1621214501Srpaulo#endif /* HOSTAPD */ 1622214501Srpaulo 1623214501Srpaulo 1624209139Srpauloconst struct wpa_driver_ops wpa_driver_bsd_ops = { 1625209139Srpaulo .name = "bsd", 1626214501Srpaulo .desc = "BSD 802.11 support", 1627214501Srpaulo#ifdef HOSTAPD 1628214501Srpaulo .hapd_init = bsd_init, 1629214501Srpaulo .hapd_deinit = bsd_deinit, 1630214501Srpaulo .set_privacy = bsd_set_privacy, 1631214501Srpaulo .get_seqnum = bsd_get_seqnum, 1632214501Srpaulo .flush = bsd_flush, 1633214501Srpaulo .read_sta_data = bsd_read_sta_driver_data, 1634214501Srpaulo .sta_disassoc = bsd_sta_disassoc, 1635214501Srpaulo .sta_deauth = bsd_sta_deauth, 1636252726Srpaulo .sta_set_flags = bsd_set_sta_authorized, 1637252726Srpaulo .commit = bsd_commit, 1638214501Srpaulo#else /* HOSTAPD */ 1639209139Srpaulo .init = wpa_driver_bsd_init, 1640209139Srpaulo .deinit = wpa_driver_bsd_deinit, 1641209139Srpaulo .get_bssid = wpa_driver_bsd_get_bssid, 1642209139Srpaulo .get_ssid = wpa_driver_bsd_get_ssid, 1643209139Srpaulo .set_countermeasures = wpa_driver_bsd_set_countermeasures, 1644214501Srpaulo .scan2 = wpa_driver_bsd_scan, 1645214501Srpaulo .get_scan_results2 = wpa_driver_bsd_get_scan_results2, 1646209139Srpaulo .deauthenticate = wpa_driver_bsd_deauthenticate, 1647209139Srpaulo .associate = wpa_driver_bsd_associate, 1648214501Srpaulo .get_capa = wpa_driver_bsd_get_capa, 1649214501Srpaulo#endif /* HOSTAPD */ 1650252190Srpaulo .set_freq = bsd_set_freq, 1651214501Srpaulo .set_key = bsd_set_key, 1652214501Srpaulo .set_ieee8021x = bsd_set_ieee8021x, 1653214501Srpaulo .hapd_set_ssid = bsd_set_ssid, 1654214501Srpaulo .hapd_get_ssid = bsd_get_ssid, 1655214501Srpaulo .hapd_send_eapol = bsd_send_eapol, 1656214501Srpaulo .set_generic_elem = bsd_set_opt_ie, 1657209139Srpaulo}; 1658