X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fdrivers%2Fdriver_nl80211.c;h=74749e87fcba3faaf6096207933074e391de068c;hb=d2440ba01b058138052c9914bab0f3d1de7d51b1;hp=f11dd181bdf840dc87aa84769483e80738605292;hpb=625f587b0331eeb2c6de9d7a6c7bbf1ee18959ef;p=wpasupplicant diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index f11dd18..74749e8 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -41,42 +41,18 @@ #endif -#ifndef NO_WEXT_COMPAT -/* - * Fall back to WEXT association, if the kernel does not support nl80211 MLME - * commands. This is temporary backwards compatibility version that will be - * removed at some point. - */ -#define WEXT_COMPAT -#endif /* NO_WEXT_COMPAT */ - - struct wpa_driver_nl80211_data { void *ctx; - int wext_event_sock; + int link_event_sock; int ioctl_sock; char ifname[IFNAMSIZ + 1]; int ifindex; int if_removed; struct wpa_driver_capa capa; int has_capability; - int we_version_compiled; - -#ifdef WEXT_COMPAT - u8 *assoc_req_ies; - size_t assoc_req_ies_len; - u8 *assoc_resp_ies; - size_t assoc_resp_ies_len; - - /* for set_auth_alg fallback */ - int use_crypt; - int auth_alg_fallback; -#endif /* WEXT_COMPAT */ int operstate; - char mlmedev[IFNAMSIZ + 1]; - int scan_complete_events; struct nl_handle *nl_handle; @@ -86,14 +62,20 @@ struct wpa_driver_nl80211_data { u8 bssid[ETH_ALEN]; int associated; + u8 ssid[32]; + size_t ssid_len; + +#ifdef CONFIG_AP + int beacon_int; + unsigned int beacon_set:1; +#endif /* CONFIG_AP */ }; static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx); -static int wpa_driver_nl80211_set_mode(void *priv, int mode); -static int wpa_driver_nl80211_flush_pmkid(void *priv); -static int wpa_driver_nl80211_get_range(void *priv); +static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv, + int mode); static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv); @@ -267,7 +249,7 @@ static int wpa_driver_nl80211_send_oper_ifla( wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d", linkmode, operstate); - ret = send(drv->wext_event_sock, &req, req.hdr.nlmsg_len, 0); + ret = send(drv->link_event_sock, &req, req.hdr.nlmsg_len, 0); if (ret < 0) { wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: " "%s (assume operstate is not supported)", @@ -305,23 +287,6 @@ static int wpa_driver_nl80211_set_auth_param( static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid) { struct wpa_driver_nl80211_data *drv = priv; -#ifdef WEXT_COMPAT - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - - if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) { - perror("ioctl[SIOCGIWAP]"); - ret = -1; - } - os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN); - - return ret; - } -#endif /* WEXT_COMPAT */ if (!drv->associated) return -1; os_memcpy(bssid, drv->bssid, ETH_ALEN); @@ -329,418 +294,13 @@ static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid) } -static int wpa_driver_nl80211_set_bssid(void *priv, const u8 *bssid) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.ap_addr.sa_family = ARPHRD_ETHER; - if (bssid) - os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN); - else - os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN); - - if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) { - perror("ioctl[SIOCSIWAP]"); - ret = -1; - } - - return ret; -} - - static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid) { struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.essid.pointer = (caddr_t) ssid; - iwr.u.essid.length = 32; - - if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { - perror("ioctl[SIOCGIWESSID]"); - ret = -1; - } else { - ret = iwr.u.essid.length; - if (ret > 32) - ret = 32; - /* Some drivers include nul termination in the SSID, so let's - * remove it here before further processing. WE-21 changes this - * to explicitly require the length _not_ to include nul - * termination. */ - if (ret > 0 && ssid[ret - 1] == '\0' && - drv->we_version_compiled < 21) - ret--; - } - - return ret; -} - - -static int wpa_driver_nl80211_set_ssid(void *priv, const u8 *ssid, - size_t ssid_len) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - char buf[33]; - - if (ssid_len > 32) - return -1; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - /* flags: 1 = ESSID is active, 0 = not (promiscuous) */ - iwr.u.essid.flags = (ssid_len != 0); - os_memset(buf, 0, sizeof(buf)); - os_memcpy(buf, ssid, ssid_len); - iwr.u.essid.pointer = (caddr_t) buf; - if (drv->we_version_compiled < 21) { - /* For historic reasons, set SSID length to include one extra - * character, C string nul termination, even though SSID is - * really an octet string that should not be presented as a C - * string. Some Linux drivers decrement the length by one and - * can thus end up missing the last octet of the SSID if the - * length is not incremented here. WE-21 changes this to - * explicitly require the length _not_ to include nul - * termination. */ - if (ssid_len) - ssid_len++; - } - iwr.u.essid.length = ssid_len; - - if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) { - perror("ioctl[SIOCSIWESSID]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_nl80211_set_freq(void *priv, int freq) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.freq.m = freq * 100000; - iwr.u.freq.e = 1; - - if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) { - perror("ioctl[SIOCSIWFREQ]"); - ret = -1; - } - - return ret; -} - - -#ifdef WEXT_COMPAT -static void -wpa_driver_nl80211_event_wireless_custom(void *ctx, char *custom) -{ - union wpa_event_data data; - - wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'", - custom); - - os_memset(&data, 0, sizeof(data)); - /* Host AP driver */ - if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { - data.michael_mic_failure.unicast = - os_strstr(custom, " unicast ") != NULL; - /* TODO: parse parameters(?) */ - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); - } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) { - char *spos; - int bytes; - - spos = custom + 17; - - bytes = strspn(spos, "0123456789abcdefABCDEF"); - if (!bytes || (bytes & 1)) - return; - bytes /= 2; - - data.assoc_info.req_ies = os_malloc(bytes); - if (data.assoc_info.req_ies == NULL) - return; - - data.assoc_info.req_ies_len = bytes; - hexstr2bin(spos, data.assoc_info.req_ies, bytes); - - spos += bytes * 2; - - data.assoc_info.resp_ies = NULL; - data.assoc_info.resp_ies_len = 0; - - if (os_strncmp(spos, " RespIEs=", 9) == 0) { - spos += 9; - - bytes = strspn(spos, "0123456789abcdefABCDEF"); - if (!bytes || (bytes & 1)) - goto done; - bytes /= 2; - - data.assoc_info.resp_ies = os_malloc(bytes); - if (data.assoc_info.resp_ies == NULL) - goto done; - - data.assoc_info.resp_ies_len = bytes; - hexstr2bin(spos, data.assoc_info.resp_ies, bytes); - } - - wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data); - - done: - os_free(data.assoc_info.resp_ies); - os_free(data.assoc_info.req_ies); -#ifdef CONFIG_PEERKEY - } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) { - if (hwaddr_aton(custom + 17, data.stkstart.peer)) { - wpa_printf(MSG_DEBUG, "WEXT: unrecognized " - "STKSTART.request '%s'", custom + 17); - return; - } - wpa_supplicant_event(ctx, EVENT_STKSTART, &data); -#endif /* CONFIG_PEERKEY */ - } -} -#endif /* WEXT_COMPAT */ - - -static int wpa_driver_nl80211_event_wireless_michaelmicfailure( - void *ctx, const char *ev, size_t len) -{ - const struct iw_michaelmicfailure *mic; - union wpa_event_data data; - - if (len < sizeof(*mic)) - return -1; - - mic = (const struct iw_michaelmicfailure *) ev; - - wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: " - "flags=0x%x src_addr=" MACSTR, mic->flags, - MAC2STR(mic->src_addr.sa_data)); - - os_memset(&data, 0, sizeof(data)); - data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP); - wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data); - - return 0; -} - - -static int wpa_driver_nl80211_event_wireless_pmkidcand( - struct wpa_driver_nl80211_data *drv, const char *ev, size_t len) -{ - const struct iw_pmkid_cand *cand; - union wpa_event_data data; - const u8 *addr; - - if (len < sizeof(*cand)) - return -1; - - cand = (const struct iw_pmkid_cand *) ev; - addr = (const u8 *) cand->bssid.sa_data; - - wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: " - "flags=0x%x index=%d bssid=" MACSTR, cand->flags, - cand->index, MAC2STR(addr)); - - os_memset(&data, 0, sizeof(data)); - os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN); - data.pmkid_candidate.index = cand->index; - data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH; - wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data); - - return 0; -} - - -#ifdef WEXT_COMPAT -static int wpa_driver_nl80211_event_wireless_assocreqie( - struct wpa_driver_nl80211_data *drv, const char *ev, int len) -{ - if (len < 0) - return -1; - - wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev, - len); - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = os_malloc(len); - if (drv->assoc_req_ies == NULL) { - drv->assoc_req_ies_len = 0; - return -1; - } - os_memcpy(drv->assoc_req_ies, ev, len); - drv->assoc_req_ies_len = len; - - return 0; -} - - -static int wpa_driver_nl80211_event_wireless_assocrespie( - struct wpa_driver_nl80211_data *drv, const char *ev, int len) -{ - if (len < 0) - return -1; - - wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev, - len); - os_free(drv->assoc_resp_ies); - drv->assoc_resp_ies = os_malloc(len); - if (drv->assoc_resp_ies == NULL) { - drv->assoc_resp_ies_len = 0; + if (!drv->associated) return -1; - } - os_memcpy(drv->assoc_resp_ies, ev, len); - drv->assoc_resp_ies_len = len; - - return 0; -} - - -static void wpa_driver_nl80211_event_assoc_ies(struct wpa_driver_nl80211_data *drv) -{ - union wpa_event_data data; - - if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL) - return; - - os_memset(&data, 0, sizeof(data)); - if (drv->assoc_req_ies) { - data.assoc_info.req_ies = drv->assoc_req_ies; - drv->assoc_req_ies = NULL; - data.assoc_info.req_ies_len = drv->assoc_req_ies_len; - } - if (drv->assoc_resp_ies) { - data.assoc_info.resp_ies = drv->assoc_resp_ies; - drv->assoc_resp_ies = NULL; - data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len; - } - - wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data); - - os_free(data.assoc_info.req_ies); - os_free(data.assoc_info.resp_ies); -} -#endif /* WEXT_COMPAT */ - - -static void wpa_driver_nl80211_event_wireless(struct wpa_driver_nl80211_data *drv, - void *ctx, char *data, int len) -{ - struct iw_event iwe_buf, *iwe = &iwe_buf; - char *pos, *end, *custom; -#ifdef WEXT_COMPAT - char *buf; -#endif /* WEXT_COMPAT */ - - pos = data; - end = data + len; - - while (pos + IW_EV_LCP_LEN <= end) { - /* Event data may be unaligned, so make a local, aligned copy - * before processing. */ - os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN); - wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d", - iwe->cmd, iwe->len); - if (iwe->len <= IW_EV_LCP_LEN) - return; - - custom = pos + IW_EV_POINT_LEN; - if (drv->we_version_compiled > 18 && - (iwe->cmd == IWEVMICHAELMICFAILURE || - iwe->cmd == IWEVCUSTOM || - iwe->cmd == IWEVASSOCREQIE || - iwe->cmd == IWEVASSOCRESPIE || - iwe->cmd == IWEVPMKIDCAND)) { - /* WE-19 removed the pointer from struct iw_point */ - char *dpos = (char *) &iwe_buf.u.data.length; - int dlen = dpos - (char *) &iwe_buf; - os_memcpy(dpos, pos + IW_EV_LCP_LEN, - sizeof(struct iw_event) - dlen); - } else { - os_memcpy(&iwe_buf, pos, sizeof(struct iw_event)); - custom += IW_EV_POINT_OFF; - } - - switch (iwe->cmd) { -#ifdef WEXT_COMPAT - case SIOCGIWAP: - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) - break; - wpa_printf(MSG_DEBUG, "Wireless event: new AP: " - MACSTR, - MAC2STR((u8 *) iwe->u.ap_addr.sa_data)); - if (is_zero_ether_addr( - (const u8 *) iwe->u.ap_addr.sa_data) || - os_memcmp(iwe->u.ap_addr.sa_data, - "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == - 0) { - os_free(drv->assoc_req_ies); - drv->assoc_req_ies = NULL; - os_free(drv->assoc_resp_ies); - drv->assoc_resp_ies = NULL; - wpa_supplicant_event(ctx, EVENT_DISASSOC, - NULL); - - } else { - wpa_driver_nl80211_event_assoc_ies(drv); - wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); - } - break; -#endif /* WEXT_COMPAT */ - case IWEVMICHAELMICFAILURE: - wpa_driver_nl80211_event_wireless_michaelmicfailure( - ctx, custom, iwe->u.data.length); - break; -#ifdef WEXT_COMPAT - case IWEVCUSTOM: - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) - break; - if (custom + iwe->u.data.length > end) - return; - buf = os_malloc(iwe->u.data.length + 1); - if (buf == NULL) - return; - os_memcpy(buf, custom, iwe->u.data.length); - buf[iwe->u.data.length] = '\0'; - wpa_driver_nl80211_event_wireless_custom(ctx, buf); - os_free(buf); - break; - case IWEVASSOCREQIE: - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) - break; - wpa_driver_nl80211_event_wireless_assocreqie( - drv, custom, iwe->u.data.length); - break; - case IWEVASSOCRESPIE: - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) - break; - wpa_driver_nl80211_event_wireless_assocrespie( - drv, custom, iwe->u.data.length); - break; -#endif /* WEXT_COMPAT */ - case IWEVPMKIDCAND: - wpa_driver_nl80211_event_wireless_pmkidcand( - drv, custom, iwe->u.data.length); - break; - } - - pos += iwe->len; - } + os_memcpy(ssid, drv->ssid, drv->ssid_len); + return drv->ssid_len; } @@ -871,11 +431,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { - if (attr->rta_type == IFLA_WIRELESS) { - wpa_driver_nl80211_event_wireless( - drv, ctx, ((char *) attr) + rta_len, - attr->rta_len - rta_len); - } else if (attr->rta_type == IFLA_IFNAME) { + if (attr->rta_type == IFLA_IFNAME) { wpa_driver_nl80211_event_link( drv, ctx, ((char *) attr) + rta_len, @@ -920,7 +476,7 @@ static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data } -static void wpa_driver_nl80211_event_receive_wext(int sock, void *eloop_ctx, +static void wpa_driver_nl80211_event_receive_link(int sock, void *eloop_ctx, void *sock_ctx) { char buf[8192]; @@ -1035,10 +591,16 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, status = le_to_host16(mgmt->u.assoc_resp.status_code); if (status != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, "nl80211: Association failed: status " - "code %d", status); - /* TODO: notify SME so that things like SA Query and comeback - * time can be implemented */ + os_memset(&event, 0, sizeof(event)); + if (len > 24 + sizeof(mgmt->u.assoc_resp)) { + event.assoc_reject.resp_ies = + (u8 *) mgmt->u.assoc_resp.variable; + event.assoc_reject.resp_ies_len = + len - 24 - sizeof(mgmt->u.assoc_resp); + } + event.assoc_reject.status_code = status; + + wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event); return; } @@ -1049,7 +611,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, if (len > 24 + sizeof(mgmt->u.assoc_resp)) { event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable; event.assoc_info.resp_ies_len = - len - 24 - sizeof(mgmt->u.assoc_req); + len - 24 - sizeof(mgmt->u.assoc_resp); } wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event); @@ -1257,6 +819,7 @@ nla_put_failure: struct wiphy_info_data { int max_scan_ssids; + int ap_supported; }; @@ -1273,6 +836,18 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) info->max_scan_ssids = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]); + if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { + struct nlattr *nl_mode; + int i; + nla_for_each_nested(nl_mode, + tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { + if (nl_mode->nla_type == NL80211_IFTYPE_AP) { + info->ap_supported = 1; + break; + } + } + } + return NL_SKIP; } @@ -1307,7 +882,19 @@ static void wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) if (wpa_driver_nl80211_get_info(drv, &info)) return; drv->has_capability = 1; + /* 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.max_scan_ssids = info.max_scan_ssids; + if (info.ap_supported) + drv->capa.flags |= WPA_DRIVER_FLAGS_AP; } @@ -1377,15 +964,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) ret = nl_get_multicast_id(drv, "nl80211", "mlme"); if (ret >= 0) ret = nl_socket_add_membership(drv->nl_handle, ret); -#ifdef WEXT_COMPAT - if (ret < 0) { - wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " - "membership for mlme events: %d (%s)", - ret, strerror(-ret)); - /* Use WEXT for association request */ - } else - drv->capa.flags |= WPA_DRIVER_FLAGS_SME; -#else /* WEXT_COMPAT */ if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " "membership for mlme events: %d (%s)", @@ -1393,7 +971,6 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) goto err4; } drv->capa.flags |= WPA_DRIVER_FLAGS_SME; -#endif /* WEXT_COMPAT */ eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle), wpa_driver_nl80211_event_receive, drv, ctx); @@ -1419,9 +996,9 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) goto err6; } - eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_wext, drv, + eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_link, drv, ctx); - drv->wext_event_sock = s; + drv->link_event_sock = s; if (wpa_driver_nl80211_finish_drv_init(drv)) goto err7; @@ -1429,8 +1006,8 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname) return drv; err7: - eloop_unregister_read_sock(drv->wext_event_sock); - close(drv->wext_event_sock); + eloop_unregister_read_sock(drv->link_event_sock); + close(drv->link_event_sock); err6: close(drv->ioctl_sock); err5: @@ -1452,6 +1029,13 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) { int flags; + drv->ifindex = if_nametoindex(drv->ifname); + + if (wpa_driver_nl80211_set_mode(drv, 0) < 0) { + wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to " + "use managed mode"); + } + if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0) { wpa_printf(MSG_ERROR, "Could not get interface '%s' flags", drv->ifname); @@ -1465,19 +1049,6 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) } } - /* - * Make sure that the driver does not have any obsolete PMKID entries. - */ - wpa_driver_nl80211_flush_pmkid(drv); - - if (wpa_driver_nl80211_set_mode(drv, 0) < 0) { - printf("Could not configure driver to use managed mode\n"); - } - - wpa_driver_nl80211_get_range(drv); - - drv->ifindex = if_nametoindex(drv->ifname); - wpa_driver_nl80211_capa(drv); wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT); @@ -1500,26 +1071,18 @@ static void wpa_driver_nl80211_deinit(void *priv) eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx); - /* - * Clear possibly configured driver parameters in order to make it - * easier to use the driver after wpa_supplicant has been terminated. - */ - (void) wpa_driver_nl80211_set_bssid(drv, - (u8 *) "\x00\x00\x00\x00\x00\x00"); + wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, 0); wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP); - eloop_unregister_read_sock(drv->wext_event_sock); + eloop_unregister_read_sock(drv->link_event_sock); if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0) (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP); + wpa_driver_nl80211_set_mode(drv, 0); - close(drv->wext_event_sock); + close(drv->link_event_sock); close(drv->ioctl_sock); -#ifdef WEXT_COMPAT - os_free(drv->assoc_req_ies); - os_free(drv->assoc_resp_ies); -#endif /* WEXT_COMPAT */ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle)); genl_family_put(drv->nl80211); @@ -1557,14 +1120,16 @@ static int wpa_driver_nl80211_scan(void *priv, { struct wpa_driver_nl80211_data *drv = priv; int ret = 0, timeout; - struct nl_msg *msg, *ssids; + struct nl_msg *msg, *ssids, *freqs; size_t i; msg = nlmsg_alloc(); ssids = nlmsg_alloc(); - if (!msg || !ssids) { + freqs = nlmsg_alloc(); + if (!msg || !ssids || !freqs) { nlmsg_free(msg); nlmsg_free(ssids); + nlmsg_free(freqs); return -1; } @@ -1585,6 +1150,12 @@ static int wpa_driver_nl80211_scan(void *priv, params->extra_ies); } + if (params->freqs) { + for (i = 0; params->freqs[i]; i++) + NLA_PUT_U32(freqs, i + 1, params->freqs[i]); + nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs); + } + ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; if (ret) { @@ -1613,6 +1184,7 @@ static int wpa_driver_nl80211_scan(void *priv, nla_put_failure: nlmsg_free(ssids); nlmsg_free(msg); + nlmsg_free(freqs); return ret; } @@ -1734,84 +1306,6 @@ nla_put_failure: } -static int wpa_driver_nl80211_get_range(void *priv) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct iw_range *range; - struct iwreq iwr; - int minlen; - size_t buflen; - - /* - * Use larger buffer than struct iw_range in order to allow the - * structure to grow in the future. - */ - buflen = sizeof(struct iw_range) + 500; - range = os_zalloc(buflen); - if (range == NULL) - return -1; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) range; - iwr.u.data.length = buflen; - - minlen = ((char *) &range->enc_capa) - (char *) range + - sizeof(range->enc_capa); - - if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) { - perror("ioctl[SIOCGIWRANGE]"); - os_free(range); - return -1; - } else if (iwr.u.data.length >= minlen && - range->we_version_compiled >= 18) { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d " - "WE(source)=%d enc_capa=0x%x", - range->we_version_compiled, - range->we_version_source, - range->enc_capa); - drv->has_capability = 1; - drv->we_version_compiled = range->we_version_compiled; - if (range->enc_capa & IW_ENC_CAPA_WPA) { - drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA | - WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK; - } - if (range->enc_capa & IW_ENC_CAPA_WPA2) { - drv->capa.key_mgmt |= 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; - if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP; - if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) - drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP; - wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x", - drv->capa.key_mgmt, drv->capa.enc); - } else { - wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - " - "assuming WPA is not supported"); - } - - os_free(range); - return 0; -} - - -#ifdef WEXT_COMPAT -static int wpa_driver_nl80211_set_wpa(void *priv, int enabled) -{ - struct wpa_driver_nl80211_data *drv = priv; - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) - return 0; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_WPA_ENABLED, - enabled); -} -#endif /* WEXT_COMPAT */ - - static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, @@ -1853,6 +1347,11 @@ static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg, case WPA_ALG_CCMP: NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04); break; +#ifdef CONFIG_IEEE80211W + case WPA_ALG_IGTK: + NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06); + break; +#endif /* CONFIG_IEEE80211W */ default: nlmsg_free(msg); return -1; @@ -1899,63 +1398,6 @@ nla_put_failure: } -#ifdef WEXT_COMPAT -static int wpa_driver_nl80211_set_countermeasures(void *priv, - int enabled) -{ - struct wpa_driver_nl80211_data *drv = priv; - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) - return 0; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - return wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_TKIP_COUNTERMEASURES, - enabled); -} -#endif /* WEXT_COMPAT */ - - -static int wpa_driver_nl80211_set_drop_unencrypted(void *priv, - int enabled) -{ - struct wpa_driver_nl80211_data *drv = priv; - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); -#ifdef WEXT_COMPAT - drv->use_crypt = enabled; -#endif /* WEXT_COMPAT */ - return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, - enabled); -} - - -#ifdef WEXT_COMPAT -static int wpa_driver_nl80211_mlme_wext(struct wpa_driver_nl80211_data *drv, - const u8 *addr, int cmd, - int reason_code) -{ - struct iwreq iwr; - struct iw_mlme mlme; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - os_memset(&mlme, 0, sizeof(mlme)); - mlme.cmd = cmd; - mlme.reason_code = reason_code; - mlme.addr.sa_family = ARPHRD_ETHER; - os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN); - iwr.u.data.pointer = (caddr_t) &mlme; - iwr.u.data.length = sizeof(mlme); - - if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) { - perror("ioctl[SIOCSIWMLME]"); - ret = -1; - } - - return ret; -} -#endif /* WEXT_COMPAT */ - - static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, const u8 *addr, int cmd, u16 reason_code) { @@ -1992,12 +1434,6 @@ static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr, { struct wpa_driver_nl80211_data *drv = priv; wpa_printf(MSG_DEBUG, "%s", __func__); -#ifdef WEXT_COMPAT - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) - return wpa_driver_nl80211_mlme_wext(drv, addr, IW_MLME_DEAUTH, - reason_code); -#endif /* WEXT_COMPAT */ - return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE, reason_code); } @@ -2008,227 +1444,11 @@ static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr, { struct wpa_driver_nl80211_data *drv = priv; wpa_printf(MSG_DEBUG, "%s", __func__); -#ifdef WEXT_COMPAT - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) - return wpa_driver_nl80211_mlme_wext(drv, addr, - IW_MLME_DISASSOC, - reason_code); -#endif /* WEXT_COMPAT */ return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE, reason_code); } -#ifdef WEXT_COMPAT -static int wpa_driver_nl80211_set_gen_ie(void *priv, const u8 *ie, - size_t ie_len) -{ - struct wpa_driver_nl80211_data *drv = priv; - struct iwreq iwr; - int ret = 0; - - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) - return 0; - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - iwr.u.data.pointer = (caddr_t) ie; - iwr.u.data.length = ie_len; - - if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) { - perror("ioctl[SIOCSIWGENIE]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_nl80211_cipher2wext(int cipher) -{ - switch (cipher) { - case CIPHER_NONE: - return IW_AUTH_CIPHER_NONE; - case CIPHER_WEP40: - return IW_AUTH_CIPHER_WEP40; - case CIPHER_TKIP: - return IW_AUTH_CIPHER_TKIP; - case CIPHER_CCMP: - return IW_AUTH_CIPHER_CCMP; - case CIPHER_WEP104: - return IW_AUTH_CIPHER_WEP104; - default: - return 0; - } -} - - -static int wpa_driver_nl80211_keymgmt2wext(int keymgmt) -{ - switch (keymgmt) { - case KEY_MGMT_802_1X: - case KEY_MGMT_802_1X_NO_WPA: - return IW_AUTH_KEY_MGMT_802_1X; - case KEY_MGMT_PSK: - return IW_AUTH_KEY_MGMT_PSK; - default: - return 0; - } -} - - -static int -wpa_driver_nl80211_auth_alg_fallback(struct wpa_driver_nl80211_data *drv, - struct wpa_driver_associate_params *params) -{ - struct iwreq iwr; - int ret = 0; - - wpa_printf(MSG_DEBUG, "WEXT: Driver did not support " - "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE"); - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - /* Just changing mode, not actual keys */ - iwr.u.encoding.flags = 0; - iwr.u.encoding.pointer = (caddr_t) NULL; - iwr.u.encoding.length = 0; - - /* - * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two - * different things. Here they are used to indicate Open System vs. - * Shared Key authentication algorithm. However, some drivers may use - * them to select between open/restricted WEP encrypted (open = allow - * both unencrypted and encrypted frames; restricted = only allow - * encrypted frames). - */ - - if (!drv->use_crypt) { - iwr.u.encoding.flags |= IW_ENCODE_DISABLED; - } else { - if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM) - iwr.u.encoding.flags |= IW_ENCODE_OPEN; - if (params->auth_alg & AUTH_ALG_SHARED_KEY) - iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED; - } - - if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) { - perror("ioctl[SIOCSIWENCODE]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_nl80211_associate_wext( - void *priv, struct wpa_driver_associate_params *params) -{ - struct wpa_driver_nl80211_data *drv = priv; - int ret = 0; - int allow_unencrypted_eapol; - int value; - - wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); - - /* - * If the driver did not support SIOCSIWAUTH, fallback to - * SIOCSIWENCODE here. - */ - if (drv->auth_alg_fallback && - wpa_driver_nl80211_auth_alg_fallback(drv, params) < 0) - ret = -1; - - if (!params->bssid && - wpa_driver_nl80211_set_bssid(drv, NULL) < 0) - ret = -1; - - /* TODO: should consider getting wpa version and cipher/key_mgmt suites - * from configuration, not from here, where only the selected suite is - * available */ - if (wpa_driver_nl80211_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len) - < 0) - ret = -1; - if (params->wpa_ie == NULL || params->wpa_ie_len == 0) - value = IW_AUTH_WPA_VERSION_DISABLED; - else if (params->wpa_ie[0] == WLAN_EID_RSN) - value = IW_AUTH_WPA_VERSION_WPA2; - else - value = IW_AUTH_WPA_VERSION_WPA; - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_WPA_VERSION, value) < 0) - ret = -1; - value = wpa_driver_nl80211_cipher2wext(params->pairwise_suite); - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_CIPHER_PAIRWISE, value) < 0) - ret = -1; - value = wpa_driver_nl80211_cipher2wext(params->group_suite); - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_CIPHER_GROUP, value) < 0) - ret = -1; - value = wpa_driver_nl80211_keymgmt2wext(params->key_mgmt_suite); - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_KEY_MGMT, value) < 0) - ret = -1; - value = params->key_mgmt_suite != KEY_MGMT_NONE || - params->pairwise_suite != CIPHER_NONE || - params->group_suite != CIPHER_NONE || - params->wpa_ie_len; - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_PRIVACY_INVOKED, value) < 0) - ret = -1; - - /* Allow unencrypted EAPOL messages even if pairwise keys are set when - * not using WPA. IEEE 802.1X specifies that these frames are not - * encrypted, but WPA encrypts them when pairwise keys are in use. */ - if (params->key_mgmt_suite == KEY_MGMT_802_1X || - params->key_mgmt_suite == KEY_MGMT_PSK) - allow_unencrypted_eapol = 0; - else - allow_unencrypted_eapol = 1; - - if (wpa_driver_nl80211_set_auth_param(drv, - IW_AUTH_RX_UNENCRYPTED_EAPOL, - allow_unencrypted_eapol) < 0) - ret = -1; - if (params->freq && wpa_driver_nl80211_set_freq(drv, params->freq) < 0) - ret = -1; - if (wpa_driver_nl80211_set_ssid(drv, params->ssid, params->ssid_len) < 0) - ret = -1; - if (params->bssid && - wpa_driver_nl80211_set_bssid(drv, params->bssid) < 0) - ret = -1; - - return ret; -} - - -static int wpa_driver_nl80211_set_auth_alg(void *priv, int auth_alg) -{ - struct wpa_driver_nl80211_data *drv = priv; - int algs = 0, res; - - if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) - return 0; - - if (auth_alg & AUTH_ALG_OPEN_SYSTEM) - algs |= IW_AUTH_ALG_OPEN_SYSTEM; - if (auth_alg & AUTH_ALG_SHARED_KEY) - algs |= IW_AUTH_ALG_SHARED_KEY; - if (auth_alg & AUTH_ALG_LEAP) - algs |= IW_AUTH_ALG_LEAP; - if (algs == 0) { - /* at least one algorithm should be set */ - algs = IW_AUTH_ALG_OPEN_SYSTEM; - } - - res = wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG, - algs); - drv->auth_alg_fallback = res == -2; - return res; -} -#endif /* WEXT_COMPAT */ - - static int wpa_driver_nl80211_authenticate( void *priv, struct wpa_driver_auth_params *params) { @@ -2301,6 +1521,119 @@ nla_put_failure: } +#ifdef CONFIG_AP +static int wpa_driver_nl80211_set_beacon(void *priv, + const u8 *head, size_t head_len, + const u8 *tail, size_t tail_len, + int dtim_period) +{ + struct wpa_driver_nl80211_data *drv = priv; + struct nl_msg *msg; + u8 cmd = NL80211_CMD_NEW_BEACON; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)", + drv->beacon_set); + if (drv->beacon_set) + cmd = NL80211_CMD_SET_BEACON; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, cmd, 0); + NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head); + NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + if (!drv->beacon_int) + drv->beacon_int = 100; + NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, drv->beacon_int); + NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", + ret, strerror(-ret)); + } else + drv->beacon_set = 1; + return ret; + nla_put_failure: + return -ENOBUFS; +} + + +static int wpa_driver_nl80211_set_beacon_int(void *priv, int value) +{ + struct wpa_driver_nl80211_data *drv = priv; + struct nl_msg *msg; + + drv->beacon_int = value; + + if (!drv->beacon_set) + return 0; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + wpa_printf(MSG_DEBUG, "nl80211: Set beacon interval %d " + "(beacon_set=%d)", value, drv->beacon_set); + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_SET_BEACON, 0); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + nla_put_failure: + return -ENOBUFS; +} + + +static int wpa_driver_nl80211_set_freq2( + struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params) +{ + struct nl_msg *msg; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return -1; + + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, + NL80211_CMD_SET_WIPHY, 0); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret == 0) + return 0; + wpa_printf(MSG_DEBUG, "nl80211: MLME Failed to set channel (freq=%d): " + "%d (%s)", params->freq, ret, strerror(-ret)); +nla_put_failure: + return -1; +} + + +static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, + struct wpa_driver_associate_params *params) +{ + if (wpa_driver_nl80211_set_mode(drv, params->mode) || + wpa_driver_nl80211_set_freq2(drv, params)) + return -1; + + /* TODO: setup monitor interface (and add code somewhere to remove this + * when AP mode is stopped; associate with mode != 2 or drv_deinit) */ + + return 0; +} +#endif /* CONFIG_AP */ + + static int wpa_driver_nl80211_associate( void *priv, struct wpa_driver_associate_params *params) { @@ -2308,10 +1641,13 @@ static int wpa_driver_nl80211_associate( int ret = -1; struct nl_msg *msg; -#ifdef WEXT_COMPAT - if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) - return wpa_driver_nl80211_associate_wext(drv, params); -#endif /* WEXT_COMPAT */ +#ifdef CONFIG_AP + if (params->mode == 2) + return wpa_driver_nl80211_ap(drv, params); +#endif /* CONFIG_AP */ + + wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED, + params->drop_unencrypted); drv->associated = 0; @@ -2339,6 +1675,10 @@ static int wpa_driver_nl80211_associate( params->ssid, params->ssid_len); NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid); + if (params->ssid_len > sizeof(drv->ssid)) + goto nla_put_failure; + os_memcpy(drv->ssid, params->ssid, params->ssid_len); + drv->ssid_len = params->ssid_len; } wpa_hexdump(MSG_DEBUG, " * IEs", params->wpa_ie, params->wpa_ie_len); if (params->wpa_ie) @@ -2363,16 +1703,31 @@ nla_put_failure: /** - * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE - * @priv: Pointer to private wext data from wpa_driver_nl80211_init() + * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc) + * @drv: Pointer to private driver data from wpa_driver_nl80211_init() * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS * Returns: 0 on success, -1 on failure */ -static int wpa_driver_nl80211_set_mode(void *priv, int mode) +static int wpa_driver_nl80211_set_mode(struct wpa_driver_nl80211_data *drv, + int mode) { - struct wpa_driver_nl80211_data *drv = priv; int ret = -1, flags; struct nl_msg *msg; + int nlmode; + + switch (mode) { + case 0: + nlmode = NL80211_IFTYPE_STATION; + break; + case 1: + nlmode = NL80211_IFTYPE_ADHOC; + break; + case 2: + nlmode = NL80211_IFTYPE_AP; + break; + default: + return -1; + } msg = nlmsg_alloc(); if (!msg) @@ -2381,8 +1736,7 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode) genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, - mode ? NL80211_IFTYPE_ADHOC : NL80211_IFTYPE_STATION); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, nlmode); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (!ret) @@ -2391,7 +1745,8 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode) goto try_again; nla_put_failure: - wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode"); + wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode: %d (%s)", + ret, strerror(-ret)); return -1; try_again: @@ -2410,13 +1765,12 @@ try_again: genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, NL80211_CMD_SET_INTERFACE, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, - mode ? NL80211_IFTYPE_ADHOC : - NL80211_IFTYPE_STATION); + NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, nlmode); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { wpa_printf(MSG_ERROR, "Failed to set interface %s " - "mode", drv->ifname); + "mode(try_again): %d (%s)", + drv->ifname, ret, strerror(-ret)); } /* Ignore return value of get_ifflags to ensure that the device @@ -2430,58 +1784,6 @@ try_again: } -static int wpa_driver_nl80211_pmksa(struct wpa_driver_nl80211_data *drv, - u32 cmd, const u8 *bssid, const u8 *pmkid) -{ - struct iwreq iwr; - struct iw_pmksa pmksa; - int ret = 0; - - os_memset(&iwr, 0, sizeof(iwr)); - os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); - os_memset(&pmksa, 0, sizeof(pmksa)); - pmksa.cmd = cmd; - pmksa.bssid.sa_family = ARPHRD_ETHER; - if (bssid) - os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN); - if (pmkid) - os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN); - iwr.u.data.pointer = (caddr_t) &pmksa; - iwr.u.data.length = sizeof(pmksa); - - if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) { - if (errno != EOPNOTSUPP) - perror("ioctl[SIOCSIWPMKSA]"); - ret = -1; - } - - return ret; -} - - -static int wpa_driver_nl80211_add_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_nl80211_data *drv = priv; - return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid); -} - - -static int wpa_driver_nl80211_remove_pmkid(void *priv, const u8 *bssid, - const u8 *pmkid) -{ - struct wpa_driver_nl80211_data *drv = priv; - return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid); -} - - -static int wpa_driver_nl80211_flush_pmkid(void *priv) -{ - struct wpa_driver_nl80211_data *drv = priv; - return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL); -} - - static int wpa_driver_nl80211_get_capa(void *priv, struct wpa_driver_capa *capa) { @@ -2511,25 +1813,19 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_bssid = wpa_driver_nl80211_get_bssid, .get_ssid = wpa_driver_nl80211_get_ssid, .set_key = wpa_driver_nl80211_set_key, - .set_drop_unencrypted = wpa_driver_nl80211_set_drop_unencrypted, .scan2 = wpa_driver_nl80211_scan, .get_scan_results2 = wpa_driver_nl80211_get_scan_results, .deauthenticate = wpa_driver_nl80211_deauthenticate, .disassociate = wpa_driver_nl80211_disassociate, - .set_mode = wpa_driver_nl80211_set_mode, .authenticate = wpa_driver_nl80211_authenticate, .associate = wpa_driver_nl80211_associate, .init = wpa_driver_nl80211_init, .deinit = wpa_driver_nl80211_deinit, - .add_pmkid = wpa_driver_nl80211_add_pmkid, - .remove_pmkid = wpa_driver_nl80211_remove_pmkid, - .flush_pmkid = wpa_driver_nl80211_flush_pmkid, .get_capa = wpa_driver_nl80211_get_capa, .set_operstate = wpa_driver_nl80211_set_operstate, .set_country = wpa_driver_nl80211_set_country, -#ifdef WEXT_COMPAT - .set_wpa = wpa_driver_nl80211_set_wpa, - .set_countermeasures = wpa_driver_nl80211_set_countermeasures, - .set_auth_alg = wpa_driver_nl80211_set_auth_alg, -#endif /* WEXT_COMPAT */ +#ifdef CONFIG_AP + .set_beacon = wpa_driver_nl80211_set_beacon, + .set_beacon_int = wpa_driver_nl80211_set_beacon_int, +#endif /* CONFIG_AP */ };