static void bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN]) { struct ieee80211req_wpaie ie; int ielen = 0; u8 *iebuf = NULL; /* * Fetch and validate any negotiated WPA/RSN parameters. */ memset(&ie, 0, sizeof(ie)); memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { printf("Failed to get WPA/RSN information element.\n"); goto no_ie; } iebuf = ie.wpa_ie; ielen = ie.wpa_ie[1]; if (ielen == 0) iebuf = NULL; else ielen += 2; no_ie: drv_event_assoc(ctx, addr, iebuf, ielen, 0); }
struct wpa_scan_results * wpa_driver_bsd_get_scan_results2(void *priv) { struct ieee80211req_scan_result *sr; struct wpa_scan_results *res; int len, rest; uint8_t buf[24*1024], *pos; len = get80211var(priv, IEEE80211_IOC_SCAN_RESULTS, buf, 24*1024); if (len < 0) return NULL; res = os_zalloc(sizeof(*res)); if (res == NULL) return NULL; pos = buf; rest = len; while (rest >= sizeof(struct ieee80211req_scan_result)) { sr = (struct ieee80211req_scan_result *)pos; wpa_driver_bsd_add_scan_entry(res, sr); pos += sr->isr_len; rest -= sr->isr_len; } wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%lu BSSes)", len, (unsigned long)res->num); return res; }
static int bsd_get_seqnum(void *priv, u8 *addr, int idx, u8 *seq) { struct bsd_driver_data *drv = priv; hostapd *hapd = drv->hapd; struct ieee80211req_key wk; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: addr=%s idx=%d\n", __func__, ether_sprintf(addr), idx); memset(&wk, 0, sizeof(wk)); if (addr == NULL) memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); else memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); wk.ik_keyix = idx; if (get80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { printf("Failed to get encryption.\n"); return -1; } else { memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); return 0; } }
static int bsd_get_ssid(void *priv, u8 *ssid, int len) { struct bsd_driver_data *drv = priv; return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN); }
static int wpa_driver_bsd_get_bssid(void *priv, u8 *bssid) { struct wpa_driver_bsd_data *drv = priv; return get80211var(drv, IEEE80211_IOC_BSSID, bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0; }
static int bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { struct hostapd_data *hapd = drv->hapd; struct hostapd_bss_config *conf = hapd->conf; struct sta_info *sta; struct ieee80211req_wpaie ie; int new_assoc, ielen, res; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); sta = ap_sta_add(hapd, addr); if (sta == NULL) return -1; /* * Fetch and validate any negotiated WPA/RSN parameters. */ if (conf->wpa) { memset(&ie, 0, sizeof(ie)); memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { printf("Failed to get WPA/RSN information element.\n"); return -1; /* XXX not right */ } ielen = ie.wpa_ie[1]; if (ielen == 0) { printf("No WPA/RSN information element for station!\n"); return -1; /* XXX not right */ } ielen += 2; if (sta->wpa_sm == NULL) sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr); if (sta->wpa_sm == NULL) { printf("Failed to initialize WPA state machine\n"); return -1; } res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, ie.wpa_ie, ielen, NULL, 0); if (res != WPA_IE_OK) { printf("WPA/RSN information element rejected? " "(res %u)\n", res); return -1; } } /* * Now that the internal station state is setup * kick the authenticator into action. */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); return 0; }
static int bsd_get_ssid(const char *ifname, void *priv, u8 *buf, int len) { struct bsd_driver_data *drv = priv; int ssid_len = get80211var(drv, IEEE80211_IOC_SSID, buf, len); wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, ssid_len, buf); return ssid_len; }
static int bsd_get_ssid(void *priv, u8 *buf, int len) { struct bsd_driver_data *drv = priv; hostapd *hapd = drv->hapd; int ssid_len = get80211var(priv, IEEE80211_IOC_SSID, buf, len); HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: ssid=\"%.*s\"\n", __func__, ssid_len, buf); return ssid_len; }
static int wpa_driver_bsd_get_bssid(void *priv, u8 *bssid) { struct bsd_driver_data *drv = priv; #ifdef SIOCG80211BSSID struct ieee80211_bssid bs; os_strlcpy(bs.i_name, drv->ifname, sizeof(bs.i_name)); if (ioctl(drv->sock, SIOCG80211BSSID, &bs) < 0) return -1; os_memcpy(bssid, bs.i_bssid, sizeof(bs.i_bssid)); return 0; #else return get80211var(drv, IEEE80211_IOC_BSSID, bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0; #endif }
static int bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data, const u8 *addr) { struct ieee80211req_sta_stats stats; memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN); if (get80211var(priv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) > 0) { /* XXX? do packets counts include non-data frames? */ data->rx_packets = stats.is_stats.ns_rx_data; data->rx_bytes = stats.is_stats.ns_rx_bytes; data->tx_packets = stats.is_stats.ns_tx_data; data->tx_bytes = stats.is_stats.ns_tx_bytes; } return 0; }
static int bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx, u8 *seq) { struct ieee80211req_key wk; wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d", __func__, ether_sprintf(addr), idx); memset(&wk, 0, sizeof(wk)); if (addr == NULL) memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN); else memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN); wk.ik_keyix = idx; if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) { printf("Failed to get encryption.\n"); return -1; } #ifdef WORDS_BIGENDIAN #ifndef WPA_KEY_RSC_LEN #define WPA_KEY_RSC_LEN 8 #endif { /* * wk.ik_keytsc is in host byte order (big endian), need to * swap it to match with the byte order used in WPA. */ int i; u8 tmp[WPA_KEY_RSC_LEN]; memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); for (i = 0; i < WPA_KEY_RSC_LEN; i++) { seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1]; } } #else /* WORDS_BIGENDIAN */ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc)); #endif /* WORDS_BIGENDIAN */ return 0; }
static int bsd_get_ssid(void *priv, u8 *ssid, int len) { struct bsd_driver_data *drv = priv; #ifdef SIOCG80211NWID struct ieee80211_nwid nwid; struct ifreq ifr; os_memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name)); ifr.ifr_data = (void *)&nwid; if (ioctl(drv->sock, SIOCG80211NWID, &ifr) < 0 || nwid.i_len > IEEE80211_NWID_LEN) return -1; os_memcpy(ssid, nwid.i_nwid, nwid.i_len); return nwid.i_len; #else return get80211var(drv, IEEE80211_IOC_SSID, ssid, IEEE80211_NWID_LEN); #endif }
static int wpa_driver_bsd_capa(struct bsd_driver_data *drv) { #ifdef IEEE80211_IOC_DEVCAPS /* kernel definitions copied from net80211/ieee80211_var.h */ #define IEEE80211_CIPHER_WEP 0 #define IEEE80211_CIPHER_TKIP 1 #define IEEE80211_CIPHER_AES_CCM 3 #define IEEE80211_CRYPTO_WEP (1<<IEEE80211_CIPHER_WEP) #define IEEE80211_CRYPTO_TKIP (1<<IEEE80211_CIPHER_TKIP) #define IEEE80211_CRYPTO_AES_CCM (1<<IEEE80211_CIPHER_AES_CCM) #define IEEE80211_C_HOSTAP 0x00000400 /* CAPABILITY: HOSTAP avail */ #define IEEE80211_C_WPA1 0x00800000 /* CAPABILITY: WPA1 avail */ #define IEEE80211_C_WPA2 0x01000000 /* CAPABILITY: WPA2 avail */ struct ieee80211_devcaps_req devcaps; if (get80211var(drv, IEEE80211_IOC_DEVCAPS, &devcaps, sizeof(devcaps)) < 0) { wpa_printf(MSG_ERROR, "failed to IEEE80211_IOC_DEVCAPS: %s", strerror(errno)); return -1; } wpa_printf(MSG_DEBUG, "%s: drivercaps=0x%08x,cryptocaps=0x%08x", __func__, devcaps.dc_drivercaps, devcaps.dc_cryptocaps); if (devcaps.dc_drivercaps & IEEE80211_C_WPA1) drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; if (devcaps.dc_drivercaps & IEEE80211_C_WPA2) drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_WEP) drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104; if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_TKIP) drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; if (devcaps.dc_cryptocaps & IEEE80211_CRYPTO_AES_CCM) drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; if (devcaps.dc_drivercaps & IEEE80211_C_HOSTAP) drv->capa.flags |= WPA_DRIVER_FLAGS_AP; #undef IEEE80211_CIPHER_WEP #undef IEEE80211_CIPHER_TKIP #undef IEEE80211_CIPHER_AES_CCM #undef IEEE80211_CRYPTO_WEP #undef IEEE80211_CRYPTO_TKIP #undef IEEE80211_CRYPTO_AES_CCM #undef IEEE80211_C_HOSTAP #undef IEEE80211_C_WPA1 #undef IEEE80211_C_WPA2 #else /* IEEE80211_IOC_DEVCAPS */ /* For now, assume TKIP, CCMP, WPA, WPA2 are supported */ drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK; drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 | WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP; drv->capa.flags |= WPA_DRIVER_FLAGS_AP; #endif /* IEEE80211_IOC_DEVCAPS */ #ifdef IEEE80211_IOC_SCAN_MAX_SSID drv->capa.max_scan_ssids = IEEE80211_IOC_SCAN_MAX_SSID; #else /* IEEE80211_IOC_SCAN_MAX_SSID */ drv->capa.max_scan_ssids = 1; #endif /* IEEE80211_IOC_SCAN_MAX_SSID */ drv->capa.auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; return 0; }
static int bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { struct hostapd_data *hapd = drv->hapd; struct hostapd_config *conf = hapd->conf; struct sta_info *sta; struct ieee80211req_wpaie ie; int new_assoc, ielen, res; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); sta = ap_sta_add(hapd, addr); if (sta == NULL) return -1; /* * Fetch and validate any negotiated WPA/RSN parameters. */ if (conf->wpa) { memset(&ie, 0, sizeof(ie)); memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { printf("Failed to get WPA/RSN information element.\n"); return -1; /* XXX not right */ } ielen = ie.wpa_ie[1]; if (ielen == 0) { printf("No WPA/RSN information element for station!\n"); return -1; /* XXX not right */ } ielen += 2; res = wpa_validate_wpa_ie(hapd, sta, ie.wpa_ie, ielen, ie.wpa_ie[0] == WLAN_EID_RSN ? HOSTAPD_WPA_VERSION_WPA2 : HOSTAPD_WPA_VERSION_WPA); if (res != WPA_IE_OK) { printf("WPA/RSN information element rejected? " "(res %u)\n", res); return -1; } if (sta->wpa_ie != NULL) free(sta->wpa_ie); sta->wpa_ie = malloc(ielen); if (sta->wpa_ie == NULL) { printf("No memory for WPA/RSN information element!\n"); return -1; } memcpy(sta->wpa_ie, ie.wpa_ie, ielen); sta->wpa_ie_len = ielen; } else { if (sta->wpa_ie != NULL) free(sta->wpa_ie); sta->wpa_ie = NULL; sta->wpa_ie_len = 0; } /* * Now that the internal station state is setup * kick the authenticator into action. */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_ASSOC; if (conf->wpa) wpa_sm_event(hapd, sta, WPA_ASSOC); if (new_assoc) hostapd_new_assoc_sta(hapd, sta); else if (conf->wpa) wpa_sm_event(hapd, sta, WPA_REAUTH); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); return 0; }
static void * wpa_driver_bsd_init(void *ctx, const char *ifname) { struct wpa_driver_bsd_data *drv; struct ieee80211_devcaps_req devcaps; int flags; drv = malloc(sizeof(*drv)); if (drv == NULL) return NULL; memset(drv, 0, sizeof(*drv)); /* * NB: We require the interface name be mappable to an index. * This implies we do not support having wpa_supplicant * wait for an interface to appear. This seems ok; that * doesn't belong here; it's really the job of devd. */ drv->ifindex = if_nametoindex(ifname); if (drv->ifindex == 0) { wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", __func__, ifname); goto fail1; } drv->sock = socket(PF_INET, SOCK_DGRAM, 0); if (drv->sock < 0) goto fail1; drv->ctx = ctx; strncpy(drv->ifname, ifname, sizeof(drv->ifname)); /* * Mark the interface as down to ensure wpa_supplicant has exclusive * access to the net80211 state machine, do this before opening the * route socket to avoid a false event that the interface disappeared. */ if (getifflags(drv, &flags) == 0) (void) setifflags(drv, flags &~ IFF_UP); drv->route = socket(PF_ROUTE, SOCK_RAW, 0); if (drv->route < 0) goto fail; eloop_register_read_sock(drv->route, wpa_driver_bsd_event_receive, ctx, drv); if (get80211var(drv, IEEE80211_IOC_DEVCAPS, &devcaps, sizeof(devcaps)) < 0) { wpa_printf(MSG_DEBUG, "%s: failed to get device capabilities: %s", __func__, strerror(errno)); goto fail; } drv->drivercaps = devcaps.dc_drivercaps; drv->cryptocaps = devcaps.dc_cryptocaps; if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) { wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s", __func__, strerror(errno)); goto fail; } if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) { wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s", __func__, strerror(errno)); goto fail; } if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) { wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s", __func__, strerror(errno)); goto fail; } if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) { wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based " "roaming: %s", __func__, strerror(errno)); goto fail; } if (drv->drivercaps & IEEE80211_C_BGSCAN) { /* * Driver does background scanning; force the scan valid * setting to 1.5 x bg scan interval so the scan cache is * always consulted before we force a foreground scan. */ if (setscanvalid(drv) < 0) { wpa_printf(MSG_DEBUG, "%s: warning, failed to set scanvalid, scanning " "may be suboptimal: %s", __func__, strerror(errno)); } } if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) { wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s", __func__, strerror(errno)); goto fail; } return drv; fail: close(drv->sock); fail1: free(drv); return NULL; }
static int wpa_driver_bsd_get_scan_results(void *priv, struct wpa_scan_result *results, size_t max_size) { #define min(a,b) ((a)>(b)?(b):(a)) struct wpa_driver_bsd_data *drv = priv; uint8_t buf[24*1024]; const uint8_t *cp, *vp; const struct ieee80211req_scan_result *sr; struct wpa_scan_result *wsr; int len, ielen; memset(results, 0, max_size * sizeof(struct wpa_scan_result)); len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf)); if (len < 0) return -1; cp = buf; wsr = results; while (len >= sizeof(struct ieee80211req_scan_result)) { sr = (const struct ieee80211req_scan_result *) cp; memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN); wsr->ssid_len = sr->isr_ssid_len; wsr->freq = sr->isr_freq; wsr->noise = sr->isr_noise; wsr->qual = sr->isr_rssi; wsr->level = 0; /* XXX? */ wsr->caps = sr->isr_capinfo; wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates); vp = ((u_int8_t *)sr) + sr->isr_ie_off; memcpy(wsr->ssid, vp, sr->isr_ssid_len); if (sr->isr_ie_len > 0) { vp += sr->isr_ssid_len; ielen = sr->isr_ie_len; while (ielen > 0) { switch (vp[0]) { case IEEE80211_ELEMID_VENDOR: if (!iswpaoui(vp)) break; wsr->wpa_ie_len = min(2+vp[1], SSID_MAX_WPA_IE_LEN); memcpy(wsr->wpa_ie, vp, wsr->wpa_ie_len); break; case IEEE80211_ELEMID_RSN: wsr->rsn_ie_len = min(2+vp[1], SSID_MAX_WPA_IE_LEN); memcpy(wsr->rsn_ie, vp, wsr->rsn_ie_len); break; } ielen -= 2+vp[1]; vp += 2+vp[1]; } } cp += sr->isr_len, len -= sr->isr_len; wsr++; } qsort(results, wsr - results, sizeof(struct wpa_scan_result), wpa_scan_result_compar); wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)", len, wsr - results); return wsr - results; #undef min }