diff options
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/driver.h | 100 | ||||
| -rw-r--r-- | src/drivers/driver_atheros.c | 85 | ||||
| -rw-r--r-- | src/drivers/driver_bsd.c | 6 | ||||
| -rw-r--r-- | src/drivers/driver_hostap.c | 43 | ||||
| -rw-r--r-- | src/drivers/driver_hostap.h | 2 | ||||
| -rw-r--r-- | src/drivers/driver_ndis.c | 8 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 455 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.h | 9 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211_android.c | 34 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211_capa.c | 90 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211_event.c | 63 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211_scan.c | 10 | ||||
| -rw-r--r-- | src/drivers/driver_privsep.c | 94 | ||||
| -rw-r--r-- | src/drivers/driver_wext.c | 133 | ||||
| -rw-r--r-- | src/drivers/drivers.c | 2 | ||||
| -rw-r--r-- | src/drivers/drivers.mak | 4 | ||||
| -rw-r--r-- | src/drivers/linux_ioctl.c | 23 | ||||
| -rw-r--r-- | src/drivers/linux_ioctl.h | 1 | ||||
| -rw-r--r-- | src/drivers/nl80211_copy.h | 236 |
19 files changed, 1112 insertions, 286 deletions
diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 03bd1a79a14c0..3cdab5a7a87d6 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -20,6 +20,7 @@ #define WPA_SUPPLICANT_DRIVER_VERSION 4 #include "common/defs.h" +#include "common/ieee802_11_defs.h" #include "utils/list.h" #define HOSTAPD_CHAN_DISABLED 0x00000001 @@ -341,7 +342,7 @@ struct wpa_driver_scan_params { * is not needed anymore. */ struct wpa_driver_scan_filter { - u8 ssid[32]; + u8 ssid[SSID_MAX_LEN]; size_t ssid_len; } *filter_ssids; @@ -1211,6 +1212,8 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_HT_IBSS 0x0000001000000000ULL /** Driver supports IBSS with VHT datarates */ #define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL +/** Driver supports automatic band selection */ +#define WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY 0x0000004000000000ULL u64 flags; #define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001 @@ -1294,6 +1297,13 @@ struct wpa_driver_capa { */ #define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008 u32 rrm_flags; + + /* Driver concurrency capabilities */ + unsigned int conc_capab; + /* Maximum number of concurrent channels on 2.4 GHz */ + unsigned int max_conc_chan_2_4; + /* Maximum number of concurrent channels on 5 GHz */ + unsigned int max_conc_chan_5_0; }; @@ -1394,6 +1404,16 @@ enum wpa_driver_if_type { * WPA_IF_MESH - Mesh interface */ WPA_IF_MESH, + + /* + * WPA_IF_TDLS - TDLS offchannel interface (used for pref freq only) + */ + WPA_IF_TDLS, + + /* + * WPA_IF_IBSS - IBSS interface (used for pref freq only) + */ + WPA_IF_IBSS, }; struct wpa_init_params { @@ -1477,6 +1497,7 @@ struct wpa_signal_info { int above_threshold; int current_signal; int avg_signal; + int avg_beacon_signal; int current_noise; int current_txrate; enum chan_width chanwidth; @@ -1576,6 +1597,7 @@ enum drv_br_port_attr { enum drv_br_net_param { DRV_BR_NET_PARAM_GARP_ACCEPT, + DRV_BR_MULTICAST_SNOOPING, }; struct drv_acs_params { @@ -1587,6 +1609,17 @@ struct drv_acs_params { /* Indicates whether HT40 is enabled */ int ht40_enabled; + + /* Indicates whether VHT is enabled */ + int vht_enabled; + + /* Configured ACS channel width */ + u16 ch_width; + + /* ACS channel list info */ + unsigned int ch_list_len; + const u8 *ch_list; + const int *freq_list; }; @@ -1925,10 +1958,12 @@ struct wpa_driver_ops { * @data: IEEE 802.11 management frame with IEEE 802.11 header * @data_len: Size of the management frame * @noack: Do not wait for this frame to be acked (disable retries) + * @freq: Frequency (in MHz) to send the frame on, or 0 to let the + * driver decide * Returns: 0 on success, -1 on failure */ int (*send_mlme)(void *priv, const u8 *data, size_t data_len, - int noack); + int noack, unsigned int freq); /** * update_ft_ies - Update FT (IEEE 802.11r) IEs @@ -2332,7 +2367,8 @@ struct wpa_driver_ops { * Returns: 0 on success, -1 on failure */ int (*sta_set_flags)(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and); + unsigned int total_flags, unsigned int flags_or, + unsigned int flags_and); /** * set_tx_queue_params - Set TX queue parameters @@ -2656,18 +2692,6 @@ struct wpa_driver_ops { int encrypt); /** - * shared_freq - Get operating frequency of shared interface(s) - * @priv: Private driver interface data - * Returns: Operating frequency in MHz, 0 if no shared operation in - * use, or -1 on failure - * - * This command can be used to request the current operating frequency - * of any virtual interface that shares the same radio to provide - * information for channel selection for other virtual interfaces. - */ - int (*shared_freq)(void *priv); - - /** * get_noa - Get current Notice of Absence attribute payload * @priv: Private driver interface data * @buf: Buffer for returning NoA @@ -3381,6 +3405,40 @@ struct wpa_driver_ops { * indicates support for such offloading (WPA_DRIVER_FLAGS_ACS_OFFLOAD). */ int (*do_acs)(void *priv, struct drv_acs_params *params); + + /** + * set_band - Notify driver of band selection + * @priv: Private driver interface data + * @band: The selected band(s) + * Returns 0 on success, -1 on failure + */ + int (*set_band)(void *priv, enum set_band band); + + /** + * get_pref_freq_list - Get preferred frequency list for an interface + * @priv: Private driver interface data + * @if_type: Interface type + * @num: Number of channels + * @freq_list: Preferred channel frequency list encoded in MHz values + * Returns 0 on success, -1 on failure + * + * This command can be used to query the preferred frequency list from + * the driver specific to a particular interface type. + */ + int (*get_pref_freq_list)(void *priv, enum wpa_driver_if_type if_type, + unsigned int *num, unsigned int *freq_list); + + /** + * set_prob_oper_freq - Indicate probable P2P operating channel + * @priv: Private driver interface data + * @freq: Channel frequency in MHz + * Returns 0 on success, -1 on failure + * + * This command can be used to inform the driver of the operating + * frequency that an ongoing P2P group formation is likely to come up + * on. Local device is assuming P2P Client role. + */ + int (*set_prob_oper_freq)(void *priv, unsigned int freq); }; @@ -4557,10 +4615,20 @@ union wpa_event_data { * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED * @pri_channel: Selected primary channel * @sec_channel: Selected secondary channel + * @vht_seg0_center_ch: VHT mode Segment0 center channel + * @vht_seg1_center_ch: VHT mode Segment1 center channel + * @ch_width: Selected Channel width by driver. Driver may choose to + * change hostapd configured ACS channel width due driver internal + * channel restrictions. + * hw_mode: Selected band (used with hw_mode=any) */ struct acs_selected_channels { u8 pri_channel; u8 sec_channel; + u8 vht_seg0_center_ch; + u8 vht_seg1_center_ch; + u16 ch_width; + enum hostapd_hw_mode hw_mode; } acs_selected_channels; }; @@ -4631,6 +4699,6 @@ wpa_get_wowlan_triggers(const char *wowlan_triggers, const struct wpa_driver_capa *capa); /* NULL terminated array of linked in driver wrappers */ -extern struct wpa_driver_ops *wpa_drivers[]; +extern const struct wpa_driver_ops *const wpa_drivers[]; #endif /* DRIVER_H */ diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index f46442163d939..ef140934973af 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -55,6 +55,10 @@ #include "netlink.h" #include "linux_ioctl.h" +#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS) +#define ATHEROS_USE_RAW_RECEIVE +#endif + struct atheros_driver_data { struct hostapd_data *hapd; /* back pointer */ @@ -430,7 +434,8 @@ atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized) static int atheros_sta_set_flags(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) + unsigned int total_flags, unsigned int flags_or, + unsigned int flags_and) { /* For now, only support setting Authorized flag */ if (flags_or & WPA_STA_AUTHORIZED) @@ -823,7 +828,7 @@ static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set, return 0; } -#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM) || defined(CONFIG_HS20) +#ifdef ATHEROS_USE_RAW_RECEIVE static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { @@ -911,7 +916,7 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf, break; } } -#endif +#endif /* ATHEROS_USE_RAW_RECEIVE */ static int atheros_receive_pkt(struct atheros_driver_data *drv) { @@ -923,11 +928,11 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv) #ifdef CONFIG_WPS filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ; #endif /* CONFIG_WPS */ -#ifdef CONFIG_IEEE80211R +#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ | IEEE80211_FILTER_TYPE_AUTH | IEEE80211_FILTER_TYPE_ACTION); -#endif +#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ #ifdef CONFIG_WNM filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION; #endif /* CONFIG_WNM */ @@ -1026,7 +1031,7 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon, #define atheros_set_ap_wps_ie NULL #endif /* CONFIG_WPS */ -#ifdef CONFIG_IEEE80211R +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) static int atheros_sta_auth(void *priv, const u8 *own_addr, const u8 *addr, u16 seq, u16 status_code, const u8 *ie, size_t len) @@ -1102,7 +1107,7 @@ atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr, } return ret; } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ static void atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) @@ -1177,6 +1182,7 @@ static void atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, char *custom, char *end) { +#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom); if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) { @@ -1232,9 +1238,6 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, * so all are enabled for WPS... ugh. */ wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL); -#endif /* CONFIG_WPS */ -#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) -#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */ } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) { /* * Atheros driver uses a hack to pass Probe Request frames as a @@ -1250,40 +1253,46 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv, } atheros_raw_receive(drv, NULL, (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); +#endif /* CONFIG_WPS */ +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) } else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) { /* Format: "Manage.assoc_req <frame len>" | zero padding | * frame */ int len = atoi(custom + 17); if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { - wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/" - "assoc_req/auth event length %d", len); + wpa_printf(MSG_DEBUG, + "Invalid Manage.assoc_req event length %d", + len); return; } atheros_raw_receive(drv, NULL, (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); - } else if (strncmp(custom, "Manage.action ", 14) == 0) { - /* Format: "Manage.assoc_req <frame len>" | zero padding | - * frame */ - int len = atoi(custom + 14); - if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { - wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/" - "assoc_req/auth event length %d", len); + } else if (strncmp(custom, "Manage.auth ", 12) == 0) { + /* Format: "Manage.auth <frame len>" | zero padding | frame */ + int len = atoi(custom + 12); + if (len < 0 || + custom + MGMT_FRAM_TAG_SIZE + len > end) { + wpa_printf(MSG_DEBUG, + "Invalid Manage.auth event length %d", len); return; } atheros_raw_receive(drv, NULL, (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); - } else if (strncmp(custom, "Manage.auth ", 12) == 0) { - /* Format: "Manage.auth <frame len>" | zero padding | frame +#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */ +#ifdef ATHEROS_USE_RAW_RECEIVE + } else if (strncmp(custom, "Manage.action ", 14) == 0) { + /* Format: "Manage.assoc_req <frame len>" | zero padding | frame */ - int len = atoi(custom + 12); + int len = atoi(custom + 14); if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) { - wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/" - "assoc_req/auth event length %d", len); + wpa_printf(MSG_DEBUG, + "Invalid Manage.action event length %d", + len); return; } atheros_raw_receive(drv, NULL, (u8 *) custom + MGMT_FRAM_TAG_SIZE, len); -#endif /* CONFIG_WPS or CONFIG_IEEE80211R */ +#endif /* ATHEROS_USE_RAW_RECEIVE */ } } @@ -1682,8 +1691,7 @@ bad: l2_packet_deinit(drv->sock_xmit); if (drv->ioctl_sock >= 0) close(drv->ioctl_sock); - if (drv != NULL) - free(drv); + os_free(drv); return NULL; } @@ -1694,6 +1702,13 @@ atheros_deinit(void *priv) struct atheros_driver_data *drv = priv; atheros_reset_appfilter(drv); + + if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) { + wpabuf_free(drv->wpa_ie); + wpabuf_free(drv->wps_beacon_ie); + wpabuf_free(drv->wps_probe_resp_ie); + atheros_set_opt_ie(priv, NULL, 0); + } netlink_deinit(drv->netlink); (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0); if (drv->ioctl_sock >= 0) @@ -1704,10 +1719,7 @@ atheros_deinit(void *priv) l2_packet_deinit(drv->sock_xmit); if (drv->sock_raw) l2_packet_deinit(drv->sock_raw); - wpabuf_free(drv->wpa_ie); - wpabuf_free(drv->wps_beacon_ie); - wpabuf_free(drv->wps_probe_resp_ie); - free(drv); + os_free(drv); } static int @@ -1833,10 +1845,10 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) } -#ifdef CONFIG_IEEE80211R +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, - int noack) + int noack, unsigned int freq) { struct atheros_driver_data *drv = priv; u8 buf[1510]; @@ -1858,8 +1870,11 @@ static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm, sizeof(struct ieee80211req_mgmtbuf) + data_len); } +#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R + static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie, size_t tspec_ielen) { @@ -2139,10 +2154,12 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = { .set_ap_wps_ie = atheros_set_ap_wps_ie, .set_authmode = atheros_set_authmode, .set_ap = atheros_set_ap, -#ifdef CONFIG_IEEE80211R +#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W) .sta_assoc = atheros_sta_assoc, .sta_auth = atheros_sta_auth, .send_mlme = atheros_send_mgmt, +#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */ +#ifdef CONFIG_IEEE80211R .add_tspec = atheros_add_tspec, .add_sta_node = atheros_add_sta_node, #endif /* CONFIG_IEEE80211R */ diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c index 0f1a0f60f27d6..bab1f031d24cd 100644 --- a/src/drivers/driver_bsd.c +++ b/src/drivers/driver_bsd.c @@ -861,8 +861,7 @@ bad: if (drv->sock >= 0) close(drv->sock); os_free(drv->event_buf); - if (drv != NULL) - os_free(drv); + os_free(drv); return NULL; } @@ -895,7 +894,8 @@ bsd_commit(void *priv) static int bsd_set_sta_authorized(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) + unsigned int total_flags, unsigned int flags_or, + unsigned int flags_and) { int authorized = -1; diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c index 84b98fb8c87f3..a7aa5eff00bd9 100644 --- a/src/drivers/driver_hostap.c +++ b/src/drivers/driver_hostap.c @@ -140,7 +140,7 @@ static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf, static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) { struct ieee80211_hdr *hdr; - u16 fc, extra_len, type, stype; + u16 fc, type, stype; size_t data_len = len; int ver; union wpa_event_data event; @@ -165,19 +165,10 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len) ver = fc & WLAN_FC_PVER; - /* protocol version 3 is reserved for indicating extra data after the - * payload, version 2 for indicating ACKed frame (TX callbacks), and - * version 1 for indicating failed frame (no ACK, TX callbacks) */ - if (ver == 3) { - u8 *pos = buf + len - 2; - extra_len = WPA_GET_LE16(pos); - printf("extra data in frame (elen=%d)\n", extra_len); - if ((size_t) extra_len + 2 > len) { - printf(" extra data overflow\n"); - return; - } - len -= extra_len + 2; - } else if (ver == 1 || ver == 2) { + /* protocol version 2 is reserved for indicating ACKed frame (TX + * callbacks), and version 1 for indicating failed frame (no ACK, TX + * callbacks) */ + if (ver == 1 || ver == 2) { handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0); return; } else if (ver != 0) { @@ -266,7 +257,8 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr) } -static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack) +static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack, + unsigned int freq) { struct hostap_driver_data *drv = priv; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; @@ -315,20 +307,21 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, pos += 2; memcpy(pos, data, data_len); - res = hostap_send_mlme(drv, (u8 *) hdr, len, 0); + res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0); if (res < 0) { wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - " "failed: %d (%s)", (unsigned long) len, errno, strerror(errno)); } - free(hdr); + os_free(hdr); return res; } static int hostap_sta_set_flags(void *priv, const u8 *addr, - int total_flags, int flags_or, int flags_and) + unsigned int total_flags, unsigned int flags_or, + unsigned int flags_and) { struct hostap_driver_data *drv = priv; struct prism2_hostapd_param param; @@ -470,18 +463,18 @@ static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr, param = (struct prism2_hostapd_param *) buf; param->cmd = PRISM2_GET_ENCRYPTION; if (addr == NULL) - memset(param->sta_addr, 0xff, ETH_ALEN); + os_memset(param->sta_addr, 0xff, ETH_ALEN); else - memcpy(param->sta_addr, addr, ETH_ALEN); + os_memcpy(param->sta_addr, addr, ETH_ALEN); param->u.crypt.idx = idx; if (hostapd_ioctl(drv, param, blen)) { printf("Failed to get encryption.\n"); ret = -1; } else { - memcpy(seq, param->u.crypt.seq, 8); + os_memcpy(seq, param->u.crypt.seq, 8); } - free(buf); + os_free(buf); return ret; } @@ -1052,7 +1045,7 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.deauth.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), 0); + sizeof(mgmt.u.deauth), 0, 0); } @@ -1090,7 +1083,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.disassoc.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc), 0); + sizeof(mgmt.u.disassoc), 0, 0); } @@ -1168,7 +1161,7 @@ static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr, os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); - hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0); + hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0); } diff --git a/src/drivers/driver_hostap.h b/src/drivers/driver_hostap.h index a9d3e76cbe8f3..4c1e6d69f0a7c 100644 --- a/src/drivers/driver_hostap.h +++ b/src/drivers/driver_hostap.h @@ -192,7 +192,7 @@ struct prism2_hostapd_param { } mlme; struct { u8 ssid_len; - u8 ssid[32]; + u8 ssid[SSID_MAX_LEN]; } scan_req; } u; }; diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 4953af6a16b29..669f1b813c43f 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -709,11 +709,11 @@ static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv) /* Disconnect by setting SSID to random (i.e., likely not used). */ static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv) { - char ssid[32]; + char ssid[SSID_MAX_LEN]; int i; - for (i = 0; i < 32; i++) + for (i = 0; i < SSID_MAX_LEN; i++) ssid[i] = rand() & 0xff; - return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32); + return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, SSID_MAX_LEN); } @@ -806,7 +806,7 @@ static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid( if (wpa_scan_get_ie(r, WLAN_EID_SSID)) return r; /* SSID IE already present */ - if (ssid->SsidLength == 0 || ssid->SsidLength > 32) + if (ssid->SsidLength == 0 || ssid->SsidLength > SSID_MAX_LEN) return r; /* No valid SSID inside scan data */ nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength); diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index d7438683d8f01..00b173f3f85a3 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -87,7 +87,6 @@ static void nl80211_handle_destroy(struct nl_handle *handle) #undef nl_socket_set_nonblocking #define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h) -#define genl_ctrl_resolve android_genl_ctrl_resolve #endif /* ANDROID */ @@ -1187,6 +1186,7 @@ static int get_link_signal(struct nl_msg *msg, void *arg) static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = { [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, [NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 }, + [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 }, }; struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { @@ -1215,6 +1215,13 @@ static int get_link_signal(struct nl_msg *msg, void *arg) else sig_change->avg_signal = 0; + if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]) + sig_change->avg_beacon_signal = + (s8) + nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]); + else + sig_change->avg_beacon_signal = 0; + if (sinfo[NL80211_STA_INFO_TX_BITRATE]) { if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX, sinfo[NL80211_STA_INFO_TX_BITRATE], @@ -1871,6 +1878,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) ret = -1; } #endif /* CONFIG_TDLS */ +#ifdef CONFIG_FST + /* FST Action frames */ + if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0) + ret = -1; +#endif /* CONFIG_FST */ /* FT Action frames */ if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0) @@ -2493,7 +2505,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, { struct wpa_driver_nl80211_data *drv = bss->drv; int ifindex; - struct nl_msg *msg; + struct nl_msg *msg = NULL; int ret; int tdls = 0; @@ -2526,11 +2538,15 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, if (!msg) return -ENOBUFS; } else { + u32 suite; + + suite = wpa_alg_to_cipher_suite(alg, key_len); + if (!suite) + goto fail; msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY); if (!msg || nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) || - nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, - wpa_alg_to_cipher_suite(alg, key_len))) + nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, suite)) goto fail; wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len); } @@ -2632,9 +2648,15 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, const u8 *key, size_t key_len) { struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY); + u32 suite; + if (!key_attr) return -1; + suite = wpa_alg_to_cipher_suite(alg, key_len); + if (!suite) + return -1; + if (defkey && alg == WPA_ALG_IGTK) { if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT)) return -1; @@ -2644,8 +2666,7 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg, } if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) || - nla_put_u32(msg, NL80211_KEY_CIPHER, - wpa_alg_to_cipher_suite(alg, key_len)) || + nla_put_u32(msg, NL80211_KEY_CIPHER, suite) || (seq && seq_len && nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) || nla_put(msg, NL80211_KEY_DATA, key_len, key)) @@ -3237,7 +3258,7 @@ static int wpa_driver_nl80211_set_acl(void *priv, struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct nl_msg *msg; - struct nlattr *acl; + struct nl_msg *acl; unsigned int i; int ret; @@ -3250,23 +3271,26 @@ static int wpa_driver_nl80211_set_acl(void *priv, wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)", params->acl_policy ? "Accept" : "Deny", params->num_mac_acl); + acl = nlmsg_alloc(); + if (!acl) + return -ENOMEM; + for (i = 0; i < params->num_mac_acl; i++) { + if (nla_put(acl, i + 1, ETH_ALEN, params->mac_acl[i].addr)) { + nlmsg_free(acl); + return -ENOMEM; + } + } + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) || nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ? NL80211_ACL_POLICY_DENY_UNLESS_LISTED : NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) || - (acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS)) == NULL) { + nla_put_nested(msg, NL80211_ATTR_MAC_ADDRS, acl)) { nlmsg_free(msg); + nlmsg_free(acl); return -ENOMEM; } - - for (i = 0; i < params->num_mac_acl; i++) { - if (nla_put(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr)) { - nlmsg_free(msg); - return -ENOMEM; - } - } - - nla_nest_end(msg, acl); + nlmsg_free(acl); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { @@ -4233,8 +4257,9 @@ static int wpa_driver_nl80211_hapd_send_eapol( static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, - int total_flags, - int flags_or, int flags_and) + unsigned int total_flags, + unsigned int flags_or, + unsigned int flags_and) { struct i802_bss *bss = priv; struct nl_msg *msg; @@ -5658,8 +5683,8 @@ static void *i802_init(struct hostapd_data *hapd, struct wpa_driver_nl80211_data *drv; struct i802_bss *bss; size_t i; - char brname[IFNAMSIZ]; - int ifindex, br_ifindex; + char master_ifname[IFNAMSIZ]; + int ifindex, br_ifindex = 0; int br_added = 0; bss = wpa_driver_nl80211_drv_init(hapd, params->ifname, @@ -5670,15 +5695,21 @@ static void *i802_init(struct hostapd_data *hapd, drv = bss->drv; - if (linux_br_get(brname, params->ifname) == 0) { + if (linux_br_get(master_ifname, params->ifname) == 0) { wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s", - params->ifname, brname); - br_ifindex = if_nametoindex(brname); - os_strlcpy(bss->brname, brname, IFNAMSIZ); + params->ifname, master_ifname); + br_ifindex = if_nametoindex(master_ifname); + os_strlcpy(bss->brname, master_ifname, IFNAMSIZ); + } else if ((params->num_bridge == 0 || !params->bridge[0]) && + linux_master_get(master_ifname, params->ifname) == 0) { + wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s", + params->ifname, master_ifname); + /* start listening for EAPOL on the master interface */ + add_ifidx(drv, if_nametoindex(master_ifname)); } else { - brname[0] = '\0'; - br_ifindex = 0; + master_ifname[0] = '\0'; } + bss->br_ifindex = br_ifindex; for (i = 0; i < params->num_bridge; i++) { @@ -5698,7 +5729,7 @@ static void *i802_init(struct hostapd_data *hapd, if (i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0) goto failed; - if (os_strcmp(params->bridge[0], brname) != 0) + if (os_strcmp(params->bridge[0], master_ifname) != 0) br_added = 1; } @@ -5776,13 +5807,12 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type( return NL80211_IFTYPE_P2P_DEVICE; case WPA_IF_MESH: return NL80211_IFTYPE_MESH_POINT; + default: + return -1; } - return -1; } -#if defined(CONFIG_P2P) || defined(CONFIG_MESH) - static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr) { struct wpa_driver_nl80211_data *drv; @@ -5818,8 +5848,6 @@ static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr) return 0; } -#endif /* CONFIG_P2P || CONFIG_MESH */ - struct wdev_info { u64 wdev_id; @@ -5895,21 +5923,21 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, } if (!addr) { - if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) + if (nlmode == NL80211_IFTYPE_P2P_DEVICE) os_memcpy(if_addr, bss->addr, ETH_ALEN); else if (linux_get_ifhwaddr(drv->global->ioctl_sock, - bss->ifname, if_addr) < 0) { + ifname, if_addr) < 0) { if (added) nl80211_remove_iface(drv, ifidx); return -1; } } -#if defined(CONFIG_P2P) || defined(CONFIG_MESH) if (!addr && (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP || - type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) { - /* Enforce unique P2P Interface Address */ + type == WPA_IF_P2P_GO || type == WPA_IF_MESH || + type == WPA_IF_STATION)) { + /* Enforce unique address */ u8 new_addr[ETH_ALEN]; if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname, @@ -5920,8 +5948,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, } if (nl80211_addr_in_use(drv->global, new_addr)) { wpa_printf(MSG_DEBUG, "nl80211: Allocate new address " - "for %s interface", type == WPA_IF_MESH ? - "mesh" : "P2P group"); + "for interface %s type %d", ifname, type); if (nl80211_vif_addr(drv, new_addr) < 0) { if (added) nl80211_remove_iface(drv, ifidx); @@ -5936,7 +5963,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, } os_memcpy(if_addr, new_addr, ETH_ALEN); } -#endif /* CONFIG_P2P || CONFIG_MESH */ if (type == WPA_IF_AP_BSS) { struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss)); @@ -6514,47 +6540,6 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) } -static int wpa_driver_nl80211_shared_freq(void *priv) -{ - struct i802_bss *bss = priv; - struct wpa_driver_nl80211_data *drv = bss->drv; - struct wpa_driver_nl80211_data *driver; - int freq = 0; - - /* - * If the same PHY is in connected state with some other interface, - * then retrieve the assoc freq. - */ - wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s", - drv->phyname); - - dl_list_for_each(driver, &drv->global->interfaces, - struct wpa_driver_nl80211_data, list) { - if (drv == driver || - os_strcmp(drv->phyname, driver->phyname) != 0 || - !driver->associated) - continue; - - wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s " - MACSTR, - driver->phyname, driver->first_bss->ifname, - MAC2STR(driver->first_bss->addr)); - if (is_ap_interface(driver->nlmode)) - freq = driver->first_bss->freq; - else - freq = nl80211_get_assoc_freq(driver); - wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d", - drv->phyname, freq); - } - - if (!freq) - wpa_printf(MSG_DEBUG, "nl80211: No shared interface for " - "PHY (%s) in associated state", drv->phyname); - - return freq; -} - - static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len, int encrypt) { @@ -7275,11 +7260,12 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type, static int driver_nl80211_send_mlme(void *priv, const u8 *data, - size_t data_len, int noack) + size_t data_len, int noack, + unsigned int freq) { struct i802_bss *bss = priv; return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack, - 0, 0, 0, 0); + freq, 0, 0, 0); } @@ -7506,7 +7492,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) "capa.max_acl_mac_addrs=%u\n" "capa.num_multichan_concurrent=%u\n" "capa.mac_addr_rand_sched_scan_supported=%d\n" - "capa.mac_addr_rand_scan_supported=%d\n", + "capa.mac_addr_rand_scan_supported=%d\n" + "capa.conc_capab=%u\n" + "capa.max_conc_chan_2_4=%u\n" + "capa.max_conc_chan_5_0=%u\n", drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth, @@ -7522,7 +7511,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) drv->capa.max_acl_mac_addrs, drv->capa.num_multichan_concurrent, drv->capa.mac_addr_rand_sched_scan_supported, - drv->capa.mac_addr_rand_scan_supported); + drv->capa.mac_addr_rand_scan_supported, + drv->capa.conc_capab, + drv->capa.max_conc_chan_2_4, + drv->capa.max_conc_chan_5_0); if (os_snprintf_error(end - pos, res)) return pos - buf; pos += res; @@ -7837,7 +7829,7 @@ static int nl80211_set_wowlan(void *priv, wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan"); - if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) || + if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) || !(wowlan_triggers = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS)) || (triggers->any && @@ -8340,9 +8332,9 @@ static const char * drv_br_net_param_str(enum drv_br_net_param param) switch (param) { case DRV_BR_NET_PARAM_GARP_ACCEPT: return "arp_accept"; + default: + return NULL; } - - return NULL; } @@ -8354,6 +8346,13 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param, const char *param_txt; int ip_version = 4; + if (param == DRV_BR_MULTICAST_SNOOPING) { + os_snprintf(path, sizeof(path), + "/sys/devices/virtual/net/%s/bridge/multicast_snooping", + bss->brname); + goto set_val; + } + param_txt = drv_br_net_param_str(param); if (param_txt == NULL) return -EINVAL; @@ -8369,6 +8368,7 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param, os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s", ip_version, bss->brname, param_txt); +set_val: if (linux_write_system_file(path, val)) return -1; @@ -8387,12 +8387,34 @@ static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode) return QCA_ACS_MODE_IEEE80211A; case HOSTAPD_MODE_IEEE80211AD: return QCA_ACS_MODE_IEEE80211AD; + case HOSTAPD_MODE_IEEE80211ANY: + return QCA_ACS_MODE_IEEE80211ANY; default: return -1; } } +static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list) +{ + int i, len, ret; + u32 *freqs; + + if (!freq_list) + return 0; + len = int_array_len(freq_list); + freqs = os_malloc(sizeof(u32) * len); + if (!freqs) + return -1; + for (i = 0; i < len; i++) + freqs[i] = freq_list[i]; + ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST, + sizeof(u32) * len, freqs); + os_free(freqs); + return ret; +} + + static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params) { struct i802_bss *bss = priv; @@ -8415,12 +8437,25 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params) (params->ht_enabled && nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) || (params->ht40_enabled && - nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) { + nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) || + (params->vht_enabled && + nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) || + nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH, + params->ch_width) || + (params->ch_list_len && + nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len, + params->ch_list)) || + add_acs_freq_list(msg, params->freq_list)) { nlmsg_free(msg); return -ENOBUFS; } nla_nest_end(msg, data); + wpa_printf(MSG_DEBUG, + "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d CH_LIST_LEN: %u", + params->hw_mode, params->ht_enabled, params->ht40_enabled, + params->vht_enabled, params->ch_width, params->ch_list_len); + ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, @@ -8431,6 +8466,240 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params) } +static int nl80211_set_band(void *priv, enum set_band band) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *data; + int ret; + enum qca_set_band qca_band; + + if (!drv->setband_vendor_cmd_avail) + return -1; + + switch (band) { + case WPA_SETBAND_AUTO: + qca_band = QCA_SETBAND_AUTO; + break; + case WPA_SETBAND_5G: + qca_band = QCA_SETBAND_5G; + break; + case WPA_SETBAND_2G: + qca_band = QCA_SETBAND_2G; + break; + default: + return -1; + } + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_SETBAND) || + !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) || + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) { + nlmsg_free(msg); + return -ENOBUFS; + } + nla_nest_end(msg, data); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + if (ret) { + wpa_printf(MSG_DEBUG, + "nl80211: Driver setband function failed: %s", + strerror(errno)); + } + return ret; +} + + +struct nl80211_pcl { + unsigned int num; + unsigned int *freq_list; +}; + +static int preferred_freq_info_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + struct nl80211_pcl *param = arg; + struct nlattr *nl_vend, *attr; + enum qca_iface_type iface_type; + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + unsigned int num, max_num; + u32 *freqs; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + nl_vend = tb[NL80211_ATTR_VENDOR_DATA]; + if (!nl_vend) + return NL_SKIP; + + nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX, + nla_data(nl_vend), nla_len(nl_vend), NULL); + + attr = tb_vendor[ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE]; + if (!attr) { + wpa_printf(MSG_ERROR, "nl80211: iface_type couldn't be found"); + param->num = 0; + return NL_SKIP; + } + + iface_type = (enum qca_iface_type) nla_get_u32(attr); + wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d", + iface_type); + + attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST]; + if (!attr) { + wpa_printf(MSG_ERROR, + "nl80211: preferred_freq_list couldn't be found"); + param->num = 0; + return NL_SKIP; + } + + /* + * param->num has the maximum number of entries for which there + * is room in the freq_list provided by the caller. + */ + freqs = nla_data(attr); + max_num = nla_len(attr) / sizeof(u32); + if (max_num > param->num) + max_num = param->num; + for (num = 0; num < max_num; num++) + param->freq_list[num] = freqs[num]; + param->num = num; + + return NL_SKIP; +} + + +static int nl80211_get_pref_freq_list(void *priv, + enum wpa_driver_if_type if_type, + unsigned int *num, + unsigned int *freq_list) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + unsigned int i; + struct nlattr *params; + struct nl80211_pcl param; + enum qca_iface_type iface_type; + + if (!drv->get_pref_freq_list) + return -1; + + switch (if_type) { + case WPA_IF_STATION: + iface_type = QCA_IFACE_TYPE_STA; + break; + case WPA_IF_AP_BSS: + iface_type = QCA_IFACE_TYPE_AP; + break; + case WPA_IF_P2P_GO: + iface_type = QCA_IFACE_TYPE_P2P_GO; + break; + case WPA_IF_P2P_CLIENT: + iface_type = QCA_IFACE_TYPE_P2P_CLIENT; + break; + case WPA_IF_IBSS: + iface_type = QCA_IFACE_TYPE_IBSS; + break; + case WPA_IF_TDLS: + iface_type = QCA_IFACE_TYPE_TDLS; + break; + default: + return -1; + } + + param.num = *num; + param.freq_list = freq_list; + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST) || + !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) || + nla_put_u32(msg, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE, + iface_type)) { + wpa_printf(MSG_ERROR, + "%s: err in adding vendor_cmd and vendor_data", + __func__); + nlmsg_free(msg); + return -1; + } + nla_nest_end(msg, params); + + os_memset(freq_list, 0, *num * sizeof(freq_list[0])); + ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, ¶m); + if (ret) { + wpa_printf(MSG_ERROR, + "%s: err in send_and_recv_msgs", __func__); + return ret; + } + + *num = param.num; + + for (i = 0; i < *num; i++) { + wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d", + i, freq_list[i]); + } + + return 0; +} + + +static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int ret; + struct nlattr *params; + + if (!drv->set_prob_oper_freq) + return -1; + + wpa_printf(MSG_DEBUG, + "nl80211: Set P2P probable operating freq %u for ifindex %d", + freq, bss->ifindex); + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL) || + !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) || + nla_put_u32(msg, + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE, + QCA_IFACE_TYPE_P2P_CLIENT) || + nla_put_u32(msg, + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ, + freq)) { + wpa_printf(MSG_ERROR, + "%s: err in adding vendor_cmd and vendor_data", + __func__); + nlmsg_free(msg); + return -1; + } + nla_nest_end(msg, params); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs", + __func__); + return ret; + } + nlmsg_free(msg); + return 0; +} + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -8490,7 +8759,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .signal_monitor = nl80211_signal_monitor, .signal_poll = nl80211_signal_poll, .send_frame = nl80211_send_frame, - .shared_freq = wpa_driver_nl80211_shared_freq, .set_param = nl80211_set_param, .get_radio_name = nl80211_get_radio_name, .add_pmkid = nl80211_add_pmkid, @@ -8518,7 +8786,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie, #endif /* ANDROID_P2P */ #ifdef ANDROID +#ifndef ANDROID_LIB_STUB .driver_cmd = wpa_driver_nl80211_driver_cmd, +#endif /* !ANDROID_LIB_STUB */ #endif /* ANDROID */ .vendor_cmd = nl80211_vendor_cmd, .set_qos_map = nl80211_set_qos_map, @@ -8537,4 +8807,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .add_tx_ts = nl80211_add_ts, .del_tx_ts = nl80211_del_ts, .do_acs = wpa_driver_do_acs, + .set_band = nl80211_set_band, + .get_pref_freq_list = nl80211_get_pref_freq_list, + .set_prob_oper_freq = nl80211_set_prob_oper_freq, }; diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 802589aa75812..5c21e0faf55cd 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -110,7 +110,7 @@ struct wpa_driver_nl80211_data { u8 bssid[ETH_ALEN]; u8 prev_bssid[ETH_ALEN]; int associated; - u8 ssid[32]; + u8 ssid[SSID_MAX_LEN]; size_t ssid_len; enum nl80211_iftype nlmode; enum nl80211_iftype ap_scan_as_station; @@ -145,6 +145,9 @@ struct wpa_driver_nl80211_data { unsigned int get_features_vendor_cmd_avail:1; unsigned int set_rekey_offload:1; unsigned int p2p_go_ctwindow_supported:1; + unsigned int setband_vendor_cmd_avail:1; + unsigned int get_pref_freq_list:1; + unsigned int set_prob_oper_freq:1; u64 remain_on_chan_cookie; u64 send_action_cookie; @@ -169,7 +172,7 @@ struct wpa_driver_nl80211_data { /* From failed authentication command */ int auth_freq; u8 auth_bssid_[ETH_ALEN]; - u8 auth_ssid[32]; + u8 auth_ssid[SSID_MAX_LEN]; size_t auth_ssid_len; int auth_alg; u8 *auth_ie; @@ -232,7 +235,6 @@ int process_bss_event(struct nl_msg *msg, void *arg); #ifdef ANDROID int android_nl_socket_set_nonblocking(struct nl_handle *handle); -int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name); int android_pno_start(struct i802_bss *bss, struct wpa_driver_scan_params *params); int android_pno_stop(struct i802_bss *bss); @@ -270,5 +272,6 @@ int wpa_driver_nl80211_sched_scan(void *priv, int wpa_driver_nl80211_stop_sched_scan(void *priv); struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv); void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv); +const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie); #endif /* DRIVER_NL80211_H */ diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c index 3cc9a65867f64..ba47888843bbb 100644 --- a/src/drivers/driver_nl80211_android.c +++ b/src/drivers/driver_nl80211_android.c @@ -151,7 +151,7 @@ int android_pno_stop(struct i802_bss *bss) #ifdef ANDROID_P2P -#ifdef ANDROID_P2P_STUB +#ifdef ANDROID_LIB_STUB int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) { @@ -178,7 +178,7 @@ int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, return 0; } -#endif /* ANDROID_P2P_STUB */ +#endif /* ANDROID_LIB_STUB */ #endif /* ANDROID_P2P */ @@ -188,33 +188,3 @@ int android_nl_socket_set_nonblocking(struct nl_handle *handle) } -int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name) -{ - /* - * Android ICS has very minimal genl_ctrl_resolve() implementation, so - * need to work around that. - */ - struct nl_cache *cache = NULL; - struct genl_family *nl80211 = NULL; - int id = -1; - - if (genl_ctrl_alloc_cache(handle, &cache) < 0) { - wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic " - "netlink cache"); - goto fail; - } - - nl80211 = genl_ctrl_search_by_name(cache, name); - if (nl80211 == NULL) - goto fail; - - id = genl_family_get_id(nl80211); - -fail: - if (nl80211) - genl_family_put(nl80211); - if (cache) - nl_cache_free(cache); - - return id; -} diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index e0d1d233e2ad5..4cf31238aeb70 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -335,6 +335,33 @@ static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls, } +static int ext_feature_isset(const u8 *ext_features, int ext_features_len, + enum nl80211_ext_feature_index ftidx) +{ + u8 ft_byte; + + if ((int) ftidx / 8 >= ext_features_len) + return 0; + + ft_byte = ext_features[ftidx / 8]; + return (ft_byte & BIT(ftidx % 8)) != 0; +} + + +static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, + struct nlattr *tb) +{ + struct wpa_driver_capa *capa = info->capa; + + if (tb == NULL) + return; + + if (ext_feature_isset(nla_data(tb), nla_len(tb), + NL80211_EXT_FEATURE_VHT_IBSS)) + capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS; +} + + static void wiphy_info_feature_flags(struct wiphy_info_data *info, struct nlattr *tb) { @@ -509,6 +536,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) info->device_ap_sme = 1; wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]); + wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]); wiphy_info_probe_resp_offload(capa, tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]); @@ -547,22 +575,34 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) continue; } vinfo = nla_data(nl); - switch (vinfo->subcmd) { - case QCA_NL80211_VENDOR_SUBCMD_TEST: - drv->vendor_cmd_test_avail = 1; - break; - case QCA_NL80211_VENDOR_SUBCMD_ROAMING: - drv->roaming_vendor_cmd_avail = 1; - break; - case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: - drv->dfs_vendor_cmd_avail = 1; - break; - case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: - drv->get_features_vendor_cmd_avail = 1; - break; - case QCA_NL80211_VENDOR_SUBCMD_DO_ACS: - drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD; - break; + if (vinfo->vendor_id == OUI_QCA) { + switch (vinfo->subcmd) { + case QCA_NL80211_VENDOR_SUBCMD_TEST: + drv->vendor_cmd_test_avail = 1; + break; + case QCA_NL80211_VENDOR_SUBCMD_ROAMING: + drv->roaming_vendor_cmd_avail = 1; + break; + case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: + drv->dfs_vendor_cmd_avail = 1; + break; + case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: + drv->get_features_vendor_cmd_avail = 1; + break; + case QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST: + drv->get_pref_freq_list = 1; + break; + case QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL: + drv->set_prob_oper_freq = 1; + break; + case QCA_NL80211_VENDOR_SUBCMD_DO_ACS: + drv->capa.flags |= + WPA_DRIVER_FLAGS_ACS_OFFLOAD; + break; + case QCA_NL80211_VENDOR_SUBCMD_SETBAND: + drv->setband_vendor_cmd_avail = 1; + break; + } } wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", @@ -717,6 +757,7 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv) struct features_info { u8 *flags; size_t flags_len; + struct wpa_driver_capa *capa; }; @@ -742,6 +783,19 @@ static int features_info_handler(struct nl_msg *msg, void *arg) info->flags = nla_data(attr); info->flags_len = nla_len(attr); } + attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA]; + if (attr) + info->capa->conc_capab = nla_get_u32(attr); + + attr = tb_vendor[ + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND]; + if (attr) + info->capa->max_conc_chan_2_4 = nla_get_u32(attr); + + attr = tb_vendor[ + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND]; + if (attr) + info->capa->max_conc_chan_5_0 = nla_get_u32(attr); } return NL_SKIP; @@ -776,12 +830,16 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv) } os_memset(&info, 0, sizeof(info)); + info.capa = &drv->capa; ret = send_and_recv_msgs(drv, msg, features_info_handler, &info); if (ret || !info.flags) return; if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info)) drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD; + + if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info)) + drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY; } diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 87e412dc596a5..7b0f721e65842 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -271,6 +271,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, struct nlattr *ptk_kek) { union wpa_event_data event; + const u8 *ssid; u16 status_code; if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) { @@ -331,6 +332,16 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, if (req_ie) { event.assoc_info.req_ies = nla_data(req_ie); event.assoc_info.req_ies_len = nla_len(req_ie); + + if (cmd == NL80211_CMD_ROAM) { + ssid = nl80211_get_ie(event.assoc_info.req_ies, + event.assoc_info.req_ies_len, + WLAN_EID_SSID); + if (ssid && ssid[1] > 0 && ssid[1] <= 32) { + drv->ssid_len = ssid[1]; + os_memcpy(drv->ssid, ssid + 2, ssid[1]); + } + } } if (resp_ie) { event.assoc_info.resp_ies = nla_data(resp_ie); @@ -1480,6 +1491,25 @@ static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv, } +static enum hostapd_hw_mode get_qca_hw_mode(u8 hw_mode) +{ + switch (hw_mode) { + case QCA_ACS_MODE_IEEE80211B: + return HOSTAPD_MODE_IEEE80211B; + case QCA_ACS_MODE_IEEE80211G: + return HOSTAPD_MODE_IEEE80211G; + case QCA_ACS_MODE_IEEE80211A: + return HOSTAPD_MODE_IEEE80211A; + case QCA_ACS_MODE_IEEE80211AD: + return HOSTAPD_MODE_IEEE80211AD; + case QCA_ACS_MODE_IEEE80211ANY: + return HOSTAPD_MODE_IEEE80211ANY; + default: + return NUM_HOSTAPD_MODES; + } +} + + static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv, const u8 *data, size_t len) { @@ -1500,6 +1530,39 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv, nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]); event.acs_selected_channels.sec_channel = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]); + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) + event.acs_selected_channels.vht_seg0_center_ch = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]); + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) + event.acs_selected_channels.vht_seg1_center_ch = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]); + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]) + event.acs_selected_channels.ch_width = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]); + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) { + u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); + + event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode); + if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES || + event.acs_selected_channels.hw_mode == + HOSTAPD_MODE_IEEE80211ANY) { + wpa_printf(MSG_DEBUG, + "nl80211: Invalid hw_mode %d in ACS selection event", + hw_mode); + return; + } + } + + wpa_printf(MSG_INFO, + "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d", + event.acs_selected_channels.pri_channel, + event.acs_selected_channels.sec_channel, + event.acs_selected_channels.ch_width, + event.acs_selected_channels.vht_seg0_center_ch, + event.acs_selected_channels.vht_seg1_center_ch, + event.acs_selected_channels.hw_mode); + + /* Ignore ACS channel list check for backwards compatibility */ wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event); } diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 3911f485f72e4..4b762eafbe8ae 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -221,6 +221,9 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss, wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request"); drv->scan_for_auth = 0; + if (TEST_FAIL()) + return -1; + msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params); if (!msg) return -1; @@ -433,7 +436,7 @@ int wpa_driver_nl80211_stop_sched_scan(void *priv) } -static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie) +const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie) { const u8 *end, *pos; @@ -583,6 +586,11 @@ int bss_info_handler(struct nl_msg *msg, void *arg) r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID; if (bss[NL80211_BSS_TSF]) r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]); + if (bss[NL80211_BSS_BEACON_TSF]) { + u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]); + if (tsf > r->tsf) + r->tsf = tsf; + } if (bss[NL80211_BSS_SEEN_MS_AGO]) r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]); r->ie_len = ie_len; diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c index de23fbd2b9fe1..1f1676a20ac58 100644 --- a/src/drivers/driver_privsep.c +++ b/src/drivers/driver_privsep.c @@ -220,6 +220,56 @@ static int wpa_driver_privsep_set_key(const char *ifname, void *priv, } +static int wpa_driver_privsep_authenticate( + void *priv, struct wpa_driver_auth_params *params) +{ + struct wpa_driver_privsep_data *drv = priv; + struct privsep_cmd_authenticate *data; + int i, res; + size_t buflen; + u8 *pos; + + wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d bssid=" MACSTR + " auth_alg=%d local_state_change=%d p2p=%d", + __func__, priv, params->freq, MAC2STR(params->bssid), + params->auth_alg, params->local_state_change, params->p2p); + + buflen = sizeof(*data) + params->ie_len + params->sae_data_len; + data = os_zalloc(buflen); + if (data == NULL) + return -1; + + data->freq = params->freq; + os_memcpy(data->bssid, params->bssid, ETH_ALEN); + os_memcpy(data->ssid, params->ssid, params->ssid_len); + data->ssid_len = params->ssid_len; + data->auth_alg = params->auth_alg; + data->ie_len = params->ie_len; + for (i = 0; i < 4; i++) { + if (params->wep_key[i]) + os_memcpy(data->wep_key[i], params->wep_key[i], + params->wep_key_len[i]); + data->wep_key_len[i] = params->wep_key_len[i]; + } + data->wep_tx_keyidx = params->wep_tx_keyidx; + data->local_state_change = params->local_state_change; + data->p2p = params->p2p; + pos = (u8 *) (data + 1); + if (params->ie_len) { + os_memcpy(pos, params->ie, params->ie_len); + pos += params->ie_len; + } + if (params->sae_data_len) + os_memcpy(pos, params->sae_data, params->sae_data_len); + + res = wpa_priv_cmd(drv, PRIVSEP_CMD_AUTHENTICATE, data, buflen, + NULL, NULL); + os_free(data); + + return res; +} + + static int wpa_driver_privsep_associate( void *priv, struct wpa_driver_associate_params *params) { @@ -281,14 +331,15 @@ static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid) { struct wpa_driver_privsep_data *drv = priv; int res, ssid_len; - u8 reply[sizeof(int) + 32]; + u8 reply[sizeof(int) + SSID_MAX_LEN]; size_t len = sizeof(reply); res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len); if (res < 0 || len < sizeof(int)) return -1; os_memcpy(&ssid_len, reply, sizeof(int)); - if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) { + if (ssid_len < 0 || ssid_len > SSID_MAX_LEN || + sizeof(int) + ssid_len > len) { wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply"); return -1; } @@ -308,6 +359,32 @@ static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr, } +static void wpa_driver_privsep_event_auth(void *ctx, u8 *buf, size_t len) +{ + union wpa_event_data data; + struct privsep_event_auth *auth; + + os_memset(&data, 0, sizeof(data)); + if (len < sizeof(*auth)) + return; + auth = (struct privsep_event_auth *) buf; + if (len < sizeof(*auth) + auth->ies_len) + return; + + os_memcpy(data.auth.peer, auth->peer, ETH_ALEN); + os_memcpy(data.auth.bssid, auth->bssid, ETH_ALEN); + data.auth.auth_type = auth->auth_type; + data.auth.auth_transaction = auth->auth_transaction; + data.auth.status_code = auth->status_code; + if (auth->ies_len) { + data.auth.ies = (u8 *) (auth + 1); + data.auth.ies_len = auth->ies_len; + } + + wpa_supplicant_event(ctx, EVENT_AUTH, &data); +} + + static void wpa_driver_privsep_event_assoc(void *ctx, enum wpa_event_type event, u8 *buf, size_t len) @@ -467,6 +544,9 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx, case PRIVSEP_EVENT_SCAN_RESULTS: wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL); break; + case PRIVSEP_EVENT_SCAN_STARTED: + wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL); + break; case PRIVSEP_EVENT_ASSOC: wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC, event_buf, event_len); @@ -502,6 +582,9 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx, wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf, event_len); break; + case PRIVSEP_EVENT_AUTH: + wpa_driver_privsep_event_auth(drv->ctx, event_buf, event_len); + break; } os_free(buf); @@ -702,6 +785,10 @@ static int wpa_driver_privsep_get_capa(void *priv, res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len); if (res < 0 || len != sizeof(*capa)) return -1; + /* For now, no support for passing extended_capa pointers */ + capa->extended_capa = NULL; + capa->extended_capa_mask = NULL; + capa->extended_capa_len = 0; return 0; } @@ -734,6 +821,7 @@ struct wpa_driver_ops wpa_driver_privsep_ops = { .set_param = wpa_driver_privsep_set_param, .scan2 = wpa_driver_privsep_scan, .deauthenticate = wpa_driver_privsep_deauthenticate, + .authenticate = wpa_driver_privsep_authenticate, .associate = wpa_driver_privsep_associate, .get_capa = wpa_driver_privsep_get_capa, .get_mac_addr = wpa_driver_privsep_get_mac_addr, @@ -742,7 +830,7 @@ struct wpa_driver_ops wpa_driver_privsep_ops = { }; -struct wpa_driver_ops *wpa_drivers[] = +const struct wpa_driver_ops *const wpa_drivers[] = { &wpa_driver_privsep_ops, NULL diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index a1581b8c9cb1a..01defdff4f155 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -1,6 +1,6 @@ /* * Driver interaction with generic Linux Wireless Extensions - * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -18,6 +18,7 @@ #include <sys/stat.h> #include <fcntl.h> #include <net/if_arp.h> +#include <dirent.h> #include "linux_wext.h" #include "common.h" @@ -131,7 +132,7 @@ int wpa_driver_wext_get_ssid(void *priv, u8 *ssid) 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; + iwr.u.essid.length = SSID_MAX_LEN; if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) { wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s", @@ -139,8 +140,8 @@ int wpa_driver_wext_get_ssid(void *priv, u8 *ssid) ret = -1; } else { ret = iwr.u.essid.length; - if (ret > 32) - ret = 32; + if (ret > SSID_MAX_LEN) + ret = SSID_MAX_LEN; /* 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 @@ -168,7 +169,7 @@ int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len) int ret = 0; char buf[33]; - if (ssid_len > 32) + if (ssid_len > SSID_MAX_LEN) return -1; os_memset(&iwr, 0, sizeof(iwr)); @@ -874,6 +875,105 @@ static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx) } +static int wext_hostap_ifname(struct wpa_driver_wext_data *drv, + const char *ifname) +{ + char buf[200], *res; + int type; + FILE *f; + + if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0) + return -1; + + snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type", + drv->ifname, ifname); + + f = fopen(buf, "r"); + if (!f) + return -1; + res = fgets(buf, sizeof(buf), f); + fclose(f); + + type = res ? atoi(res) : -1; + wpa_printf(MSG_DEBUG, "WEXT: hostap ifname %s type %d", ifname, type); + + if (type == ARPHRD_IEEE80211) { + wpa_printf(MSG_DEBUG, + "WEXT: Found hostap driver wifi# interface (%s)", + ifname); + wpa_driver_wext_alternative_ifindex(drv, ifname); + return 0; + } + return -1; +} + + +static int wext_add_hostap(struct wpa_driver_wext_data *drv) +{ + char buf[200]; + int n; + struct dirent **names; + int ret = -1; + + snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net", drv->ifname); + n = scandir(buf, &names, NULL, alphasort); + if (n < 0) + return -1; + + while (n--) { + if (ret < 0 && wext_hostap_ifname(drv, names[n]->d_name) == 0) + ret = 0; + free(names[n]); + } + free(names); + + return ret; +} + + +static void wext_check_hostap(struct wpa_driver_wext_data *drv) +{ + char buf[200], *pos; + ssize_t res; + + /* + * Host AP driver may use both wlan# and wifi# interface in wireless + * events. Since some of the versions included WE-18 support, let's add + * the alternative ifindex also from driver_wext.c for the time being. + * This may be removed at some point once it is believed that old + * versions of the driver are not in use anymore. However, it looks like + * the wifi# interface is still used in the current kernel tree, so it + * may not really be possible to remove this before the Host AP driver + * gets removed from the kernel. + */ + + /* First, try to see if driver information is available from sysfs */ + snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver", + drv->ifname); + res = readlink(buf, buf, sizeof(buf) - 1); + if (res > 0) { + buf[res] = '\0'; + pos = strrchr(buf, '/'); + if (pos) + pos++; + else + pos = buf; + wpa_printf(MSG_DEBUG, "WEXT: Driver: %s", pos); + if (os_strncmp(pos, "hostap", 6) == 0 && + wext_add_hostap(drv) == 0) + return; + } + + /* Second, use the old design with hardcoded ifname */ + if (os_strncmp(drv->ifname, "wlan", 4) == 0) { + char ifname2[IFNAMSIZ + 1]; + os_strlcpy(ifname2, drv->ifname, sizeof(ifname2)); + os_memcpy(ifname2, "wifi", 4); + wpa_driver_wext_alternative_ifindex(drv, ifname2); + } +} + + static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) { int send_rfkill_event = 0; @@ -914,20 +1014,7 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv) drv->ifindex = if_nametoindex(drv->ifname); - if (os_strncmp(drv->ifname, "wlan", 4) == 0) { - /* - * Host AP driver may use both wlan# and wifi# interface in - * wireless events. Since some of the versions included WE-18 - * support, let's add the alternative ifindex also from - * driver_wext.c for the time being. This may be removed at - * some point once it is believed that old versions of the - * driver are not in use anymore. - */ - char ifname2[IFNAMSIZ + 1]; - os_strlcpy(ifname2, drv->ifname, sizeof(ifname2)); - os_memcpy(ifname2, "wifi", 4); - wpa_driver_wext_alternative_ifindex(drv, ifname2); - } + wext_check_hostap(drv); netlink_send_oper_ifla(drv->netlink, drv->ifindex, 1, IF_OPER_DORMANT); @@ -1112,7 +1199,7 @@ struct wext_scan_data { struct wpa_scan_res res; u8 *ie; size_t ie_len; - u8 ssid[32]; + u8 ssid[SSID_MAX_LEN]; size_t ssid_len; int maxrate; }; @@ -1865,7 +1952,7 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) { struct iwreq iwr; const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - u8 ssid[32]; + u8 ssid[SSID_MAX_LEN]; int i; /* @@ -1907,9 +1994,9 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv) * SIOCSIWMLME commands (or tries to associate automatically * after deauth/disassoc). */ - for (i = 0; i < 32; i++) + for (i = 0; i < SSID_MAX_LEN; i++) ssid[i] = rand() & 0xFF; - if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) { + if (wpa_driver_wext_set_ssid(drv, ssid, SSID_MAX_LEN) < 0) { wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus " "SSID to disconnect"); } diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c index f0c3bb3c63ba0..a98af9ac7d711 100644 --- a/src/drivers/drivers.c +++ b/src/drivers/drivers.c @@ -47,7 +47,7 @@ extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */ #endif /* CONFIG_DRIVER_NONE */ -struct wpa_driver_ops *wpa_drivers[] = +const struct wpa_driver_ops *const wpa_drivers[] = { #ifdef CONFIG_DRIVER_NL80211 &wpa_driver_nl80211_ops, diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index 9434078757018..3dd43c73803e7 100644 --- a/src/drivers/drivers.mak +++ b/src/drivers/drivers.mak @@ -54,7 +54,9 @@ else ifdef CONFIG_LIBNL_TINY DRV_LIBS += -lnl-tiny else - DRV_LIBS += -lnl + ifndef CONFIG_OSX + DRV_LIBS += -lnl + endif endif ifdef CONFIG_LIBNL20 diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c index 837971d25c99e..e21147af1bcd6 100644 --- a/src/drivers/linux_ioctl.c +++ b/src/drivers/linux_ioctl.c @@ -219,3 +219,26 @@ int linux_br_get(char *brname, const char *ifname) os_strlcpy(brname, pos, IFNAMSIZ); return 0; } + + +int linux_master_get(char *master_ifname, const char *ifname) +{ + char buf[128], masterlink[128], *pos; + ssize_t res; + + /* check whether there is a master */ + os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", ifname); + + res = readlink(buf, masterlink, sizeof(masterlink)); + if (res < 0 || (size_t) res >= sizeof(masterlink)) + return -1; + + masterlink[res] = '\0'; + + pos = os_strrchr(masterlink, '/'); + if (pos == NULL) + return -1; + pos++; + os_strlcpy(master_ifname, pos, IFNAMSIZ); + return 0; +} diff --git a/src/drivers/linux_ioctl.h b/src/drivers/linux_ioctl.h index c03fe6e9a3fd2..6de4d9b882751 100644 --- a/src/drivers/linux_ioctl.h +++ b/src/drivers/linux_ioctl.h @@ -18,5 +18,6 @@ int linux_br_del(int sock, const char *brname); int linux_br_add_if(int sock, const char *brname, const char *ifname); int linux_br_del_if(int sock, const char *brname, const char *ifname); int linux_br_get(char *brname, const char *ifname); +int linux_master_get(char *master_ifname, const char *ifname); #endif /* LINUX_IOCTL_H */ diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index b37bd5a1cb825..ae16ba9cb1e31 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -25,10 +25,30 @@ * */ +/* + * This header file defines the userspace API to the wireless stack. Please + * be careful not to break things - i.e. don't move anything around or so + * unless you can demonstrate that it breaks neither API nor ABI. + * + * Additions to the API should be accompanied by actual implementations in + * an upstream driver, so that example implementations exist in case there + * are ever concerns about the precise semantics of the API or changes are + * needed, and to ensure that code for dead (no longer implemented) API + * can actually be identified and removed. + * Nonetheless, semantics should also be documented carefully in this file. + */ + #include <linux/types.h> #define NL80211_GENL_NAME "nl80211" +#define NL80211_MULTICAST_GROUP_CONFIG "config" +#define NL80211_MULTICAST_GROUP_SCAN "scan" +#define NL80211_MULTICAST_GROUP_REG "regulatory" +#define NL80211_MULTICAST_GROUP_MLME "mlme" +#define NL80211_MULTICAST_GROUP_VENDOR "vendor" +#define NL80211_MULTICAST_GROUP_TESTMODE "testmode" + /** * DOC: Station handling * @@ -173,8 +193,8 @@ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME. * * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration; - * either a dump request on a %NL80211_ATTR_WIPHY or a specific get - * on an %NL80211_ATTR_IFINDEX is supported. + * either a dump request for all interfaces or a specific get with a + * single %NL80211_ATTR_IFINDEX is supported. * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE. * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response @@ -252,7 +272,18 @@ * %NL80211_ATTR_IFINDEX. * * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set - * regulatory domain. + * regulatory domain. If %NL80211_ATTR_WIPHY is specified and the device + * has a private regulatory domain, it will be returned. Otherwise, the + * global regdomain will be returned. + * A device will have a private regulatory domain if it uses the + * regulatory_hint() API. Even when a private regdomain is used the channel + * information will still be mended according to further hints from + * the regulatory core to help with compliance. A dump version of this API + * is now available which will returns the global regdomain as well as + * all private regdomains of present wiphys (for those that have it). + * If a wiphy is self-managed (%NL80211_ATTR_WIPHY_SELF_MANAGED_REG), then + * its private regdomain is the only valid one for it. The regulatory + * core is not used to help with compliance in this case. * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command * after being queried by the kernel. CRDA replies by sending a regulatory * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our @@ -306,7 +337,9 @@ * if passed, define which channels should be scanned; if not * passed, all channels allowed for the current regulatory domain * are used. Extra IEs can also be passed from the userspace by - * using the %NL80211_ATTR_IE attribute. + * using the %NL80211_ATTR_IE attribute. The first cycle of the + * scheduled scan can be delayed by %NL80211_ATTR_SCHED_SCAN_DELAY + * is supplied. * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if * scheduled scan is not running. The caller may assume that as soon * as the call returns, it is safe to start a new scheduled scan again. @@ -774,6 +807,10 @@ * peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel * when this command completes. * + * @NL80211_CMD_WIPHY_REG_CHANGE: Similar to %NL80211_CMD_REG_CHANGE, but used + * as an event to indicate changes for devices with wiphy-specific regdom + * management. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -958,6 +995,8 @@ enum nl80211_commands { NL80211_CMD_TDLS_CHANNEL_SWITCH, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH, + NL80211_CMD_WIPHY_REG_CHANGE, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1655,6 +1694,13 @@ enum nl80211_commands { * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface * creation then the new interface will be owned by the netlink socket * that created it and will be destroyed when the socket is closed. + * If set during scheduled scan start then the new scan req will be + * owned by the netlink socket that created it and the scheduled scan will + * be stopped when the socket is closed. + * If set during configuration of regulatory indoor operation then the + * regulatory indoor configuration would be owned by the netlink socket + * that configured the indoor setting, and the indoor operation would be + * cleared when the socket is closed. * * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is * the TDLS link initiator. @@ -1688,6 +1734,32 @@ enum nl80211_commands { * * @NL80211_ATTR_MAC_MASK: MAC address mask * + * @NL80211_ATTR_WIPHY_SELF_MANAGED_REG: flag attribute indicating this device + * is self-managing its regulatory information and any regulatory domain + * obtained from it is coming from the device's wiphy and not the global + * cfg80211 regdomain. + * + * @NL80211_ATTR_EXT_FEATURES: extended feature flags contained in a byte + * array. The feature flags are identified by their bit index (see &enum + * nl80211_ext_feature_index). The bit index is ordered starting at the + * least-significant bit of the first byte in the array, ie. bit index 0 + * is located at bit 0 of byte 0. bit index 25 would be located at bit 1 + * of byte 3 (u8 array). + * + * @NL80211_ATTR_SURVEY_RADIO_STATS: Request overall radio statistics to be + * returned along with other survey data. If set, @NL80211_CMD_GET_SURVEY + * may return a survey entry without a channel indicating global radio + * statistics (only some values are valid and make sense.) + * For devices that don't return such an entry even then, the information + * should be contained in the result as the sum of the respective counters + * over all channels. + * + * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a + * WoWLAN net-detect scan) is started, u32 in seconds. + + * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device + * is operating in an indoor environment. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2045,6 +2117,18 @@ enum nl80211_attrs { NL80211_ATTR_MAC_MASK, + NL80211_ATTR_WIPHY_SELF_MANAGED_REG, + + NL80211_ATTR_EXT_FEATURES, + + NL80211_ATTR_SURVEY_RADIO_STATS, + + NL80211_ATTR_NETNS_FD, + + NL80211_ATTR_SCHED_SCAN_DELAY, + + NL80211_ATTR_REG_INDOOR, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2085,7 +2169,7 @@ enum nl80211_attrs { #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_HT_RATES 77 -#define NL80211_MAX_SUPP_REG_RULES 32 +#define NL80211_MAX_SUPP_REG_RULES 64 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 @@ -2225,8 +2309,15 @@ struct nl80211_sta_flag_update { * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8) * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8) * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate - * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate + * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: unused - 80+80 is treated the + * same as 160 for purposes of the bitrates * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate + * @NL80211_RATE_INFO_10_MHZ_WIDTH: 10 MHz width - note that this is + * a legacy rate and will be reported as the actual bitrate, i.e. + * half the base (20 MHz) rate + * @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is + * a legacy rate and will be reported as the actual bitrate, i.e. + * a quarter of the base (20 MHz) rate * @__NL80211_RATE_INFO_AFTER_LAST: internal use */ enum nl80211_rate_info { @@ -2241,6 +2332,8 @@ enum nl80211_rate_info { NL80211_RATE_INFO_80_MHZ_WIDTH, NL80211_RATE_INFO_80P80_MHZ_WIDTH, NL80211_RATE_INFO_160_MHZ_WIDTH, + NL80211_RATE_INFO_10_MHZ_WIDTH, + NL80211_RATE_INFO_5_MHZ_WIDTH, /* keep last */ __NL80211_RATE_INFO_AFTER_LAST, @@ -2285,18 +2378,24 @@ enum nl80211_sta_bss_param { * * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) - * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) - * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) - * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station) - * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station) + * @NL80211_STA_INFO_RX_BYTES: total received bytes (MPDU length) + * (u32, from this station) + * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (MPDU length) + * (u32, to this station) + * @NL80211_STA_INFO_RX_BYTES64: total received bytes (MPDU length) + * (u64, from this station) + * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (MPDU length) + * (u64, to this station) * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute * containing info as possible, see &enum nl80211_rate_info - * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) - * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this - * station) - * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station) - * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station) + * @NL80211_STA_INFO_RX_PACKETS: total received packet (MSDUs and MMPDUs) + * (u32, from this station) + * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (MSDUs and MMPDUs) + * (u32, to this station) + * @NL80211_STA_INFO_TX_RETRIES: total retries (MPDUs) (u32, to this station) + * @NL80211_STA_INFO_TX_FAILED: total failed packets (MPDUs) + * (u32, to this station) * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm) * @NL80211_STA_INFO_LLID: the station's mesh LLID * @NL80211_STA_INFO_PLID: the station's mesh PLID @@ -2320,6 +2419,16 @@ enum nl80211_sta_bss_param { * Same format as NL80211_STA_INFO_CHAIN_SIGNAL. * @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput considering also the * 802.11 header (u32, kbps) + * @NL80211_STA_INFO_RX_DROP_MISC: RX packets dropped for unspecified reasons + * (u64) + * @NL80211_STA_INFO_BEACON_RX: number of beacons received from this peer (u64) + * @NL80211_STA_INFO_BEACON_SIGNAL_AVG: signal strength average + * for beacons only (u8, dBm) + * @NL80211_STA_INFO_TID_STATS: per-TID statistics (see &enum nl80211_tid_stats) + * This is a nested attribute where each the inner attribute number is the + * TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames; + * each one of those is again nested with &enum nl80211_tid_stats + * attributes carrying the actual values. * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -2352,6 +2461,10 @@ enum nl80211_sta_info { NL80211_STA_INFO_CHAIN_SIGNAL, NL80211_STA_INFO_CHAIN_SIGNAL_AVG, NL80211_STA_INFO_EXPECTED_THROUGHPUT, + NL80211_STA_INFO_RX_DROP_MISC, + NL80211_STA_INFO_BEACON_RX, + NL80211_STA_INFO_BEACON_SIGNAL_AVG, + NL80211_STA_INFO_TID_STATS, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, @@ -2359,6 +2472,31 @@ enum nl80211_sta_info { }; /** + * enum nl80211_tid_stats - per TID statistics attributes + * @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved + * @NL80211_TID_STATS_RX_MSDU: number of MSDUs received (u64) + * @NL80211_TID_STATS_TX_MSDU: number of MSDUs transmitted (or + * attempted to transmit; u64) + * @NL80211_TID_STATS_TX_MSDU_RETRIES: number of retries for + * transmitted MSDUs (not counting the first attempt; u64) + * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted + * MSDUs (u64) + * @NUM_NL80211_TID_STATS: number of attributes here + * @NL80211_TID_STATS_MAX: highest numbered attribute here + */ +enum nl80211_tid_stats { + __NL80211_TID_STATS_INVALID, + NL80211_TID_STATS_RX_MSDU, + NL80211_TID_STATS_TX_MSDU, + NL80211_TID_STATS_TX_MSDU_RETRIES, + NL80211_TID_STATS_TX_MSDU_FAILED, + + /* keep last */ + NUM_NL80211_TID_STATS, + NL80211_TID_STATS_MAX = NUM_NL80211_TID_STATS - 1 +}; + +/** * enum nl80211_mpath_flags - nl80211 mesh path flags * * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active @@ -2772,16 +2910,18 @@ enum nl80211_user_reg_hint_type { * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used - * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio - * spent on this channel - * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary + * @NL80211_SURVEY_INFO_TIME: amount of time (in ms) that the radio + * was turned on (on channel or globally) + * @NL80211_SURVEY_INFO_TIME_BUSY: amount of the time the primary * channel was sensed busy (either due to activity or energy detect) - * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension + * @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension * channel was sensed busy - * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent - * receiving data - * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent - * transmitting data + * @NL80211_SURVEY_INFO_TIME_RX: amount of time the radio spent + * receiving data (on channel or globally) + * @NL80211_SURVEY_INFO_TIME_TX: amount of time the radio spent + * transmitting data (on channel or globally) + * @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan + * (on this channel or globally) * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number * currently defined * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use @@ -2791,17 +2931,25 @@ enum nl80211_survey_info { NL80211_SURVEY_INFO_FREQUENCY, NL80211_SURVEY_INFO_NOISE, NL80211_SURVEY_INFO_IN_USE, - NL80211_SURVEY_INFO_CHANNEL_TIME, - NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, - NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY, - NL80211_SURVEY_INFO_CHANNEL_TIME_RX, - NL80211_SURVEY_INFO_CHANNEL_TIME_TX, + NL80211_SURVEY_INFO_TIME, + NL80211_SURVEY_INFO_TIME_BUSY, + NL80211_SURVEY_INFO_TIME_EXT_BUSY, + NL80211_SURVEY_INFO_TIME_RX, + NL80211_SURVEY_INFO_TIME_TX, + NL80211_SURVEY_INFO_TIME_SCAN, /* keep last */ __NL80211_SURVEY_INFO_AFTER_LAST, NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1 }; +/* keep old names for compatibility */ +#define NL80211_SURVEY_INFO_CHANNEL_TIME NL80211_SURVEY_INFO_TIME +#define NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY NL80211_SURVEY_INFO_TIME_BUSY +#define NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY NL80211_SURVEY_INFO_TIME_EXT_BUSY +#define NL80211_SURVEY_INFO_CHANNEL_TIME_RX NL80211_SURVEY_INFO_TIME_RX +#define NL80211_SURVEY_INFO_CHANNEL_TIME_TX NL80211_SURVEY_INFO_TIME_TX + /** * enum nl80211_mntr_flags - monitor configuration flags * @@ -2966,7 +3114,8 @@ enum nl80211_mesh_power_mode { * * @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've * established peering with for longer than this time (in seconds), then - * remove it from the STA's list of peers. Default is 30 minutes. + * remove it from the STA's list of peers. You may set this to 0 to disable + * the removal of the STA. Default is 30 minutes. * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use */ @@ -3238,6 +3387,9 @@ enum nl80211_bss { /** * enum nl80211_bss_status - BSS "status" * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS. + * Note that this is no longer used since cfg80211 no longer + * keeps track of whether or not authentication was done with + * a given BSS. * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS. * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS. * @@ -3565,6 +3717,8 @@ struct nl80211_pattern_support { * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put * the chip into a special state -- works best with chips that have * support for low-power operation already (flag) + * Note that this mode is incompatible with all of the others, if + * any others are even supported by the device. * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect * is detected is implementation-specific (flag) * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed @@ -3621,9 +3775,12 @@ struct nl80211_pattern_support { * @NL80211_WOWLAN_TRIG_NET_DETECT: wake up when a configured network * is detected. This is a nested attribute that contains the * same attributes used with @NL80211_CMD_START_SCHED_SCAN. It - * specifies how the scan is performed (e.g. the interval and the - * channels to scan) as well as the scan results that will - * trigger a wake (i.e. the matchsets). + * specifies how the scan is performed (e.g. the interval, the + * channels to scan and the initial delay) as well as the scan + * results that will trigger a wake (i.e. the matchsets). This + * attribute is also sent in a response to + * @NL80211_CMD_GET_WIPHY, indicating the number of match sets + * supported by the driver (u32). * @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute * containing an array with information about what triggered the * wake up. If no elements are present in the array, it means @@ -4194,6 +4351,21 @@ enum nl80211_feature_flags { }; /** + * enum nl80211_ext_feature_index - bit index of extended features. + * @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates. + * + * @NUM_NL80211_EXT_FEATURES: number of extended features. + * @MAX_NL80211_EXT_FEATURES: highest extended feature index. + */ +enum nl80211_ext_feature_index { + NL80211_EXT_FEATURE_VHT_IBSS, + + /* add new features before the definition below */ + NUM_NL80211_EXT_FEATURES, + MAX_NL80211_EXT_FEATURES = NUM_NL80211_EXT_FEATURES - 1 +}; + +/** * enum nl80211_probe_resp_offload_support_attr - optional supported * protocols for probe-response offloading by the driver/FW. * To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute. |
