diff options
| author | Brint E. Kriebel <bekit@cyngn.com> | 2014-06-30 19:11:53 -0700 |
|---|---|---|
| committer | Brint E. Kriebel <bekit@cyngn.com> | 2014-06-30 19:11:53 -0700 |
| commit | d00e77faedf730376b0ef1fbf13993c73eff146b (patch) | |
| tree | df8bf02fdf600bb8cc09087a7775e7e7f59c5398 | |
| parent | e2d64c3ae308a10f6010c7cb162190b104604c7d (diff) | |
| parent | 7b4ceed0292e1faa84549e5630be193573d1561b (diff) | |
| download | android_external_wpa_supplicant_8-d00e77faedf730376b0ef1fbf13993c73eff146b.tar.gz android_external_wpa_supplicant_8-d00e77faedf730376b0ef1fbf13993c73eff146b.tar.bz2 android_external_wpa_supplicant_8-d00e77faedf730376b0ef1fbf13993c73eff146b.zip | |
Merge branch 'cm-11.0' into stable/cm-11.0cm-11.0-XNPH33R-bacon-3628510d76cm-11.0-XNPH30O-bacon-4f280f505a
45 files changed, 3793 insertions, 385 deletions
diff --git a/hostapd/Makefile b/hostapd/Makefile index fda4e4e3..a559bab6 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -6,6 +6,8 @@ ifndef CFLAGS CFLAGS = -MMD -O2 -Wall -g endif +export BINDIR ?= /usr/local/bin/ + CFLAGS += -I../src CFLAGS += -I../src/utils @@ -865,9 +867,10 @@ verify_config: exit 1; \ fi -install: all - mkdir -p $(DESTDIR)/usr/local/bin - for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/local/bin/$$i; done +$(DESTDIR)$(BINDIR)/%: % + install -D $(<) $(@) + +install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL)) ../src/drivers/build.hostapd: @if [ -f ../src/drivers/build.wpa_supplicant ]; then \ diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 3852d146..13008963 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1511,6 +1511,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta, * IEEE 802.1X/WPA code will start accounting after the station has * been authorized. */ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) { + ap_sta_set_authorized(hapd, sta, 1); os_get_time(&sta->connected_time); accounting_sta_start(hapd, sta); } diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 137c3090..e8550ded 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -221,10 +221,12 @@ #define WLAN_EID_QOS 46 #define WLAN_EID_RSN 48 #define WLAN_EID_EXT_SUPP_RATES 50 +#define WLAN_EID_NEIGHBOR_REPORT 52 #define WLAN_EID_MOBILITY_DOMAIN 54 #define WLAN_EID_FAST_BSS_TRANSITION 55 #define WLAN_EID_TIMEOUT_INTERVAL 56 #define WLAN_EID_RIC_DATA 57 +#define WLAN_EID_SUPPORTED_OPERATING_CLASSES 59 #define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62 #define WLAN_EID_WAPI 68 diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h new file mode 100644 index 00000000..0d83920a --- /dev/null +++ b/src/common/qca-vendor.h @@ -0,0 +1,51 @@ +/* + * Qualcomm Atheros OUI and vendor specific assignments + * Copyright (c) 2014, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef QCA_VENDOR_H +#define QCA_VENDOR_H + +/* + * This file is a registry of identifier assignments from the Qualcomm Atheros + * OUI 00:13:74 for purposes other than MAC address assignment. New identifiers + * can be assigned through normal review process for changes to the upstream + * hostap.git repository. + */ + +#define OUI_QCA 0x001374 + +/** + * enum qca_nl80211_vendor_subcmds - QCA nl80211 vendor command identifiers + * + * @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Reserved value 0 + * + * @QCA_NL80211_VENDOR_SUBCMD_TEST: Test command/event + * + * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency + * ranges to avoid to reduce issues due to interference or internal + * co-existence information in the driver. The event data structure is + * defined in struct qca_avoid_freq_list. + */ +enum qca_nl80211_vendor_subcmds { + QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, + QCA_NL80211_VENDOR_SUBCMD_TEST = 1, + /* subcmds 2..9 not yet allocated */ + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10, +}; + + +struct qca_avoid_freq_range { + u32 start_freq; + u32 end_freq; +} STRUCT_PACKED; + +struct qca_avoid_freq_list { + u32 count; + struct qca_avoid_freq_range range[0]; +} STRUCT_PACKED; + +#endif /* QCA_VENDOR_H */ diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 1156043f..efe8c487 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -54,6 +54,8 @@ extern "C" { #define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED " /** Temporarily disabled network block re-enabled */ #define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED " +/** New scan started */ +#define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED " /** New scan results available */ #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS " /** wpa_supplicant state change */ @@ -66,6 +68,8 @@ extern "C" { /** Notify the Userspace about the freq conflict */ #define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT " #endif +/** Frequency ranges that the driver recommends to avoid */ +#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ " /** RSN IBSS 4-way handshakes completed with specified peer */ #define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED " @@ -146,6 +150,7 @@ extern "C" { /* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */ #define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT " +#define P2P_EVENT_REMOVE_AND_REFORM_GROUP "P2P-REMOVE-AND-REFORM-GROUP " #define INTERWORKING_AP "INTERWORKING-AP " #define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH " diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 92db1575..ccbcab6e 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -983,6 +983,10 @@ struct hostapd_sta_add_params { u8 qosinfo; const u8 *ext_capab; size_t ext_capab_len; + const u8 *supp_channels; + size_t supp_channels_len; + const u8 *supp_oper_classes; + size_t supp_oper_classes_len; }; struct hostapd_freq_params { @@ -1158,6 +1162,13 @@ struct wpa_signal_info { int center_frq2; }; +/* TDLS peer capabilities for send_tdls_mgmt() */ +enum tdls_peer_capability { + TDLS_PEER_HT = BIT(0), + TDLS_PEER_VHT = BIT(1), + TDLS_PEER_WMM = BIT(2), +}; + /** * struct wpa_driver_ops - Driver interface API definition * @@ -2551,6 +2562,7 @@ struct wpa_driver_ops { * @action_code: TDLS action code for the mssage * @dialog_token: Dialog Token to use in the message (if needed) * @status_code: Status Code or Reason Code to use (if needed) + * @peer_capab: TDLS peer capability (TDLS_PEER_* bitfield) * @buf: TDLS IEs to add to the message * @len: Length of buf in octets * Returns: 0 on success, negative (<0) on failure @@ -2559,7 +2571,7 @@ struct wpa_driver_ops { * responsible for receiving and sending all TDLS packets. */ int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code, - u8 dialog_token, u16 status_code, + u8 dialog_token, u16 status_code, u32 peer_capab, const u8 *buf, size_t len); /** @@ -3297,7 +3309,26 @@ enum wpa_event_type { * entry for one frequency. The survey data can be os_malloc()'d and * then os_free()'d, so the event callback must only copy data. */ - EVENT_SURVEY + EVENT_SURVEY, + + /** + * EVENT_SCAN_STARTED - Scan started + * + * This indicates that driver has started a scan operation either based + * on a request from wpa_supplicant/hostapd or from another application. + * EVENT_SCAN_RESULTS is used to indicate when the scan has been + * completed (either successfully or by getting cancelled). + */ + EVENT_SCAN_STARTED, + + /** + * EVENT_AVOID_FREQUENCIES - Received avoid frequency range + * + * This event indicates a set of frequency ranges that should be avoided + * to reduce issues due to interference or internal co-existence + * information in the driver. + */ + EVENT_AVOID_FREQUENCIES }; @@ -3996,6 +4027,13 @@ union wpa_event_data { struct channel_list_changed { enum reg_change_initiator initiator; } channel_list_changed; + + /** + * freq_range - List of frequency ranges + * + * This is used as the data with EVENT_AVOID_FREQUENCIES. + */ + struct wpa_freq_range_list freq_range; }; /** diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 8d1d22eb..043895f3 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -85,6 +85,8 @@ const char * event_to_string(enum wpa_event_type event) E2S(DFS_CAC_ABORTED); E2S(DFS_NOP_FINISHED); E2S(SURVEY); + E2S(SCAN_STARTED); + E2S(AVOID_FREQUENCIES); } return "UNKNOWN"; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index c51792d4..a98a3cd4 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -28,6 +28,7 @@ #include "common.h" #include "eloop.h" #include "utils/list.h" +#include "common/qca-vendor.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "l2_packet/l2_packet.h" @@ -264,7 +265,7 @@ struct wpa_driver_nl80211_data { struct wpa_driver_scan_filter *filter_ssids; size_t num_filter_ssids; - struct i802_bss first_bss; + struct i802_bss *first_bss; int eapol_tx_sock; @@ -477,6 +478,11 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd) C2S(NL80211_CMD_FT_EVENT) C2S(NL80211_CMD_CRIT_PROTOCOL_START) C2S(NL80211_CMD_CRIT_PROTOCOL_STOP) + C2S(NL80211_CMD_GET_COALESCE) + C2S(NL80211_CMD_SET_COALESCE) + C2S(NL80211_CMD_CHANNEL_SWITCH) + C2S(NL80211_CMD_VENDOR) + C2S(NL80211_CMD_SET_QOS_MAP) default: return "NL80211_CMD_UNKNOWN"; } @@ -1017,7 +1023,8 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv, event.interface_status.ifname, del ? "removed" : "added"); - if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) { + if (os_strcmp(drv->first_bss->ifname, event.interface_status.ifname) == + 0) { if (del) { if (drv->if_removed) { wpa_printf(MSG_DEBUG, "nl80211: if_removed " @@ -1026,11 +1033,11 @@ static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv, } drv->if_removed = 1; } else { - if (if_nametoindex(drv->first_bss.ifname) == 0) { + if (if_nametoindex(drv->first_bss->ifname) == 0) { wpa_printf(MSG_DEBUG, "nl80211: Interface %s " "does not exist - ignore " "RTM_NEWLINK", - drv->first_bss.ifname); + drv->first_bss->ifname); return; } if (!drv->if_removed) { @@ -1058,8 +1065,8 @@ static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv, rta_len = RTA_ALIGN(sizeof(struct rtattr)); while (RTA_OK(attr, attrlen)) { if (attr->rta_type == IFLA_IFNAME) { - if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname) - == 0) + if (os_strcmp(((char *) attr) + rta_len, + drv->first_bss->ifname) == 0) return 1; else break; @@ -1131,7 +1138,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) { if (if_indextoname(ifi->ifi_index, namebuf) && linux_iface_up(drv->global->ioctl_sock, - drv->first_bss.ifname) > 0) { + drv->first_bss->ifname) > 0) { wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down " "event since interface %s is up", namebuf); return; @@ -1151,18 +1158,18 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) { if (if_indextoname(ifi->ifi_index, namebuf) && linux_iface_up(drv->global->ioctl_sock, - drv->first_bss.ifname) == 0) { + drv->first_bss->ifname) == 0) { wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up " "event since interface %s is down", namebuf); - } else if (if_nametoindex(drv->first_bss.ifname) == 0) { + } else if (if_nametoindex(drv->first_bss->ifname) == 0) { wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up " "event since interface %s does not exist", - drv->first_bss.ifname); + drv->first_bss->ifname); } else if (drv->if_removed) { wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up " "event since interface %s is marked " - "removed", drv->first_bss.ifname); + "removed", drv->first_bss->ifname); } else { wpa_printf(MSG_DEBUG, "nl80211: Interface up"); drv->if_disabled = 0; @@ -1684,7 +1691,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, if (type == EVENT_DISASSOC) { event.disassoc_info.locally_generated = - !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN); + !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); #if defined (LEGACY_STA_EVENTS) if (drv->nlmode == NL80211_IFTYPE_AP || @@ -1692,6 +1699,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, event.disassoc_info.addr = mgmt->sa; } else #endif + event.disassoc_info.addr = bssid; event.disassoc_info.reason_code = reason_code; if (frame + len > mgmt->u.disassoc.variable) { @@ -1701,7 +1709,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, } } else { event.deauth_info.locally_generated = - !os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN); + !os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN); #if defined (LEGACY_STA_EVENTS) if (drv->nlmode == NL80211_IFTYPE_AP || @@ -1709,6 +1717,7 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, event.deauth_info.addr = mgmt->sa; } else #endif + event.deauth_info.addr = bssid; event.deauth_info.reason_code = reason_code; if (frame + len > mgmt->u.deauth.variable) { @@ -1891,7 +1900,7 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); /* register for any AUTH message */ - nl80211_register_frame(&drv->first_bss, drv->first_bss.nl_mgmt, + nl80211_register_frame(drv->first_bss, drv->first_bss->nl_mgmt, type, NULL, 0); drv->associated = 1; @@ -2604,6 +2613,114 @@ static void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb, } +static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv, + const u8 *data, size_t len) +{ + u32 i, count; + union wpa_event_data event; + struct wpa_freq_range *range = NULL; + const struct qca_avoid_freq_list *freq_range; + + freq_range = (const struct qca_avoid_freq_list *) data; + if (len < sizeof(freq_range->count)) + return; + + count = freq_range->count; + if (len < sizeof(freq_range->count) + + count * sizeof(struct qca_avoid_freq_range)) { + wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)", + (unsigned int) len); + return; + } + + if (count > 0) { + range = os_calloc(count, sizeof(struct wpa_freq_range)); + if (range == NULL) + return; + } + + os_memset(&event, 0, sizeof(event)); + for (i = 0; i < count; i++) { + unsigned int idx = event.freq_range.num; + range[idx].min = freq_range->range[i].start_freq; + range[idx].max = freq_range->range[i].end_freq; + wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u", + range[idx].min, range[idx].max); + if (range[idx].min > range[idx].max) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range"); + continue; + } + event.freq_range.num++; + } + event.freq_range.range = range; + + wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event); + + os_free(range); +} + + +static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, + u32 subcmd, u8 *data, size_t len) +{ + switch (subcmd) { + case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: + qca_nl80211_avoid_freq(drv, data, len); + break; + default: + wpa_printf(MSG_DEBUG, + "nl80211: Ignore unsupported QCA vendor event %u", + subcmd); + break; + } +} + + +static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + u32 vendor_id, subcmd, wiphy = 0; + int wiphy_idx; + u8 *data = NULL; + size_t len = 0; + + if (!tb[NL80211_ATTR_VENDOR_ID] || + !tb[NL80211_ATTR_VENDOR_SUBCMD]) + return; + + vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]); + subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]); + + if (tb[NL80211_ATTR_WIPHY]) + wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); + + wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u", + wiphy, vendor_id, subcmd); + + if (tb[NL80211_ATTR_VENDOR_DATA]) { + data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]); + len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]); + wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len); + } + + wiphy_idx = nl80211_get_wiphy_index(drv->first_bss); + if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) { + wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)", + wiphy, wiphy_idx); + return; + } + + switch (vendor_id) { + case OUI_QCA: + nl80211_vendor_event_qca(drv, subcmd, data, len); + break; + default: + wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); + break; + } +} + + static void do_process_drv_event(struct i802_bss *bss, int cmd, struct nlattr **tb) { @@ -2616,7 +2733,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED && (cmd == NL80211_CMD_NEW_SCAN_RESULTS || cmd == NL80211_CMD_SCAN_ABORTED)) { - wpa_driver_nl80211_set_mode(&drv->first_bss, + wpa_driver_nl80211_set_mode(drv->first_bss, drv->ap_scan_as_station); drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } @@ -2624,6 +2741,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, switch (cmd) { case NL80211_CMD_TRIGGER_SCAN: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger"); + wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL); break; case NL80211_CMD_START_SCHED_SCAN: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started"); @@ -2765,6 +2883,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_STOP_AP: nl80211_stop_ap(drv, tb); break; + case NL80211_CMD_VENDOR: + nl80211_vendor_event(drv, tb); + break; default: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd); @@ -2787,7 +2908,7 @@ static int process_drv_event(struct nl_msg *msg, void *arg) if (tb[NL80211_ATTR_IFINDEX]) { ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]); - for (bss = &drv->first_bss; bss; bss = bss->next) + for (bss = drv->first_bss; bss; bss = bss->next) if (ifidx == -1 || ifidx == bss->ifindex) { do_process_drv_event(bss, gnlh->cmd, tb); return NL_SKIP; @@ -2798,7 +2919,7 @@ static int process_drv_event(struct nl_msg *msg, void *arg) } else if (tb[NL80211_ATTR_WDEV]) { u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]); wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device"); - for (bss = &drv->first_bss; bss; bss = bss->next) { + for (bss = drv->first_bss; bss; bss = bss->next) { if (bss->wdev_id_set && wdev_id == bss->wdev_id) { do_process_drv_event(bss, gnlh->cmd, tb); return NL_SKIP; @@ -2836,7 +2957,7 @@ static int process_global_event(struct nl_msg *msg, void *arg) dl_list_for_each_safe(drv, tmp, &global->interfaces, struct wpa_driver_nl80211_data, list) { - for (bss = &drv->first_bss; bss; bss = bss->next) { + for (bss = drv->first_bss; bss; bss = bss->next) { if ((ifidx == -1 && !wdev_id_set) || ifidx == bss->ifindex || (wdev_id_set && bss->wdev_id_set && @@ -3341,6 +3462,38 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) } } + if (tb[NL80211_ATTR_VENDOR_DATA]) { + struct nlattr *nl; + int rem; + + nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) { + struct nl80211_vendor_cmd_info *vinfo; + if (nla_len(nl) != sizeof(*vinfo)) { + wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info"); + continue; + } + vinfo = nla_data(nl); + wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", + vinfo->vendor_id, vinfo->subcmd); + } + } + + if (tb[NL80211_ATTR_VENDOR_EVENTS]) { + struct nlattr *nl; + int rem; + + nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) { + struct nl80211_vendor_cmd_info *vinfo; + if (nla_len(nl) != sizeof(*vinfo)) { + wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info"); + continue; + } + vinfo = nla_data(nl); + wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u", + vinfo->vendor_id, vinfo->subcmd); + } + } + return NL_SKIP; } @@ -3366,7 +3519,7 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY); NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP); - if (nl80211_set_iface_id(msg, &drv->first_bss) < 0) + if (nl80211_set_iface_id(msg, drv->first_bss) < 0) goto nla_put_failure; if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info)) @@ -3580,6 +3733,16 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) /* Continue without regulatory events */ } + ret = nl_get_multicast_id(global, "nl80211", "vendor"); + if (ret >= 0) + ret = nl_socket_add_membership(global->nl_event, ret); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " + "membership for vendor events: %d (%s)", + ret, strerror(-ret)); + /* Continue without vendor events */ + } + nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, @@ -3631,7 +3794,7 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx) { struct wpa_driver_nl80211_data *drv = ctx; wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked"); - if (i802_set_iface_flags(&drv->first_bss, 1)) { + if (i802_set_iface_flags(drv->first_bss, 1)) { wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP " "after rfkill unblock"); return; @@ -3743,7 +3906,13 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, return NULL; drv->global = global_priv; drv->ctx = ctx; - bss = &drv->first_bss; + + drv->first_bss = os_zalloc(sizeof(*drv->first_bss)); + if (!drv->first_bss) { + os_free(drv); + return NULL; + } + bss = drv->first_bss; bss->drv = drv; bss->ctx = ctx; @@ -4147,7 +4316,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv) #ifndef HOSTAPD enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION; #endif /* HOSTAPD */ - struct i802_bss *bss = &drv->first_bss; + struct i802_bss *bss = drv->first_bss; int send_rfkill_event = 0; drv->ifindex = if_nametoindex(bss->ifname); @@ -4312,7 +4481,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) } nl_cb_put(drv->nl_cb); - nl80211_destroy_bss(&drv->first_bss); + nl80211_destroy_bss(drv->first_bss); os_free(drv->filter_ssids); @@ -4323,6 +4492,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) os_free(drv->extended_capa); os_free(drv->extended_capa_mask); + os_free(drv->first_bss); os_free(drv); } @@ -4339,7 +4509,7 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_nl80211_data *drv = eloop_ctx; if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) { - wpa_driver_nl80211_set_mode(&drv->first_bss, + wpa_driver_nl80211_set_mode(drv->first_bss, drv->ap_scan_as_station); drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED; } @@ -4943,7 +5113,7 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) goto nla_put_failure; nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN); - if (nl80211_set_iface_id(msg, &drv->first_bss) < 0) + if (nl80211_set_iface_id(msg, drv->first_bss) < 0) goto nla_put_failure; arg.drv = drv; @@ -5586,7 +5756,7 @@ static int wpa_driver_nl80211_authenticate_retry( struct wpa_driver_nl80211_data *drv) { struct wpa_driver_auth_params params; - struct i802_bss *bss = &drv->first_bss; + struct i802_bss *bss = drv->first_bss; int i; wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again"); @@ -5676,10 +5846,8 @@ static void phy_info_freq(struct hostapd_hw_modes *mode, if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) chan->flag |= HOSTAPD_CHAN_DISABLED; - if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) - chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS]) - chan->flag |= HOSTAPD_CHAN_NO_IBSS; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR]) + chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | HOSTAPD_CHAN_NO_IBSS; if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) chan->flag |= HOSTAPD_CHAN_RADAR; @@ -5712,8 +5880,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info, static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, [NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 }, @@ -6792,6 +6959,23 @@ static int wpa_driver_nl80211_sta_add(void *priv, } #endif + + if (params->supp_channels) { + wpa_hexdump(MSG_DEBUG, " * supported channels", + params->supp_channels, params->supp_channels_len); + NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS, + params->supp_channels_len, params->supp_channels); + } + + if (params->supp_oper_classes) { + wpa_hexdump(MSG_DEBUG, " * supported operating classes", + params->supp_oper_classes, + params->supp_oper_classes_len); + NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES, + params->supp_oper_classes_len, + params->supp_oper_classes); + } + os_memset(&upd, 0, sizeof(upd)); upd.mask = sta_flags_nl80211(params->flags); upd.set = upd.mask; @@ -6931,7 +7115,7 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv, return -1; nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE); - if (nl80211_set_iface_id(msg, &drv->first_bss) < 0) + if (nl80211_set_iface_id(msg, drv->first_bss) < 0) goto nla_put_failure; NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname); NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype); @@ -7336,17 +7520,17 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv) return 0; } - if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) { + if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) { /* * P2P interface name is of the format p2p-%s-%d. For monitor * interface name corresponding to P2P GO, replace "p2p-" with * "mon-" to retain the same interface name length and to * indicate that it is a monitor interface. */ - snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4); + snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4); } else { /* Non-P2P interface with AP functionality. */ - snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname); + snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname); } buf[IFNAMSIZ - 1] = '\0'; @@ -7659,14 +7843,14 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, nlmode = NL80211_IFTYPE_AP; old_mode = drv->nlmode; - if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) { + if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) { nl80211_remove_monitor_interface(drv); return -1; } - if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) { + if (wpa_driver_nl80211_set_freq(drv->first_bss, &freq)) { if (old_mode != nlmode) - wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode); + wpa_driver_nl80211_set_mode(drv->first_bss, old_mode); nl80211_remove_monitor_interface(drv); return -1; } @@ -7712,7 +7896,7 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); - if (wpa_driver_nl80211_set_mode(&drv->first_bss, + if (wpa_driver_nl80211_set_mode(drv->first_bss, NL80211_IFTYPE_ADHOC)) { wpa_printf(MSG_INFO, "nl80211: Failed to set interface into " "IBSS mode"); @@ -8225,7 +8409,7 @@ static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv, return -ENOMEM; nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE); - if (nl80211_set_iface_id(msg, &drv->first_bss) < 0) + if (nl80211_set_iface_id(msg, drv->first_bss) < 0) goto nla_put_failure; NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode); @@ -9130,7 +9314,7 @@ static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr) struct wpa_driver_nl80211_data *drv; dl_list_for_each(drv, &global->interfaces, struct wpa_driver_nl80211_data, list) { - if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0) + if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0) return 1; } return 0; @@ -9145,9 +9329,9 @@ static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv, if (!drv->global) return -1; - os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN); + os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN); for (idx = 0; idx < 64; idx++) { - new_addr[0] = drv->first_bss.addr[0] | 0x02; + new_addr[0] = drv->first_bss->addr[0] | 0x02; new_addr[0] ^= idx << 2; if (!nl80211_addr_in_use(drv->global, new_addr)) break; @@ -9305,10 +9489,10 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, os_memcpy(new_bss->addr, if_addr, ETH_ALEN); new_bss->ifindex = ifidx; new_bss->drv = drv; - new_bss->next = drv->first_bss.next; - new_bss->freq = drv->first_bss.freq; + new_bss->next = drv->first_bss->next; + new_bss->freq = drv->first_bss->freq; new_bss->ctx = bss_ctx; - drv->first_bss.next = new_bss; + drv->first_bss->next = new_bss; if (drv_priv) *drv_priv = new_bss; nl80211_init_bss(new_bss); @@ -9358,10 +9542,10 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss, bss->brname, strerror(errno)); } - if (bss != &drv->first_bss) { + if (bss != drv->first_bss) { struct i802_bss *tbss; - for (tbss = &drv->first_bss; tbss; tbss = tbss->next) { + for (tbss = drv->first_bss; tbss; tbss = tbss->next) { if (tbss->next == bss) { tbss->next = bss->next; /* Unsubscribe management frames */ @@ -10011,10 +10195,10 @@ static int wpa_driver_nl80211_shared_freq(void *priv) wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s " MACSTR, - driver->phyname, driver->first_bss.ifname, - MAC2STR(driver->first_bss.addr)); + driver->phyname, driver->first_bss->ifname, + MAC2STR(driver->first_bss->addr)); if (is_ap_interface(driver->nlmode)) - freq = driver->first_bss.freq; + freq = driver->first_bss->freq; else freq = nl80211_get_assoc_freq(driver); wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d", @@ -10566,7 +10750,7 @@ nla_put_failure: static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, - const u8 *buf, size_t len) + u32 peer_capab, const u8 *buf, size_t len) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -10588,6 +10772,15 @@ static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code); NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token); NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code); + if (peer_capab) { + /* + * The internal enum tdls_peer_capability definition is + * currently identical with the nl80211 enum + * nl80211_tdls_peer_capability, so no conversion is needed + * here. + */ + NLA_PUT_U32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY, peer_capab); + } NLA_PUT(msg, NL80211_ATTR_IE, len, buf); return send_and_recv_msgs(drv, msg, NULL, NULL); diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index 32b060ea..9d87dbe8 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -126,6 +126,31 @@ */ /** + * DOC: packet coalesce support + * + * In most cases, host that receives IPv4 and IPv6 multicast/broadcast + * packets does not do anything with these packets. Therefore the + * reception of these unwanted packets causes unnecessary processing + * and power consumption. + * + * Packet coalesce feature helps to reduce number of received interrupts + * to host by buffering these packets in firmware/hardware for some + * predefined time. Received interrupt will be generated when one of the + * following events occur. + * a) Expiration of hardware timer whose expiration time is set to maximum + * coalescing delay of matching coalesce rule. + * b) Coalescing buffer in hardware reaches it's limit. + * c) Packet doesn't match any of the configured coalesce rules. + * + * User needs to configure following parameters for creating a coalesce + * rule. + * a) Maximum coalescing delay + * b) List of packet patterns which needs to be matched + * c) Condition for coalescence. pattern 'match' or 'no match' + * Multiple such rules can be created. + */ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors @@ -278,8 +303,9 @@ * 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. - * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT - * if scheduled scan is not running. + * @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. * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan * results available. * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has @@ -393,8 +419,18 @@ * %NL80211_ATTR_SSID attribute, and can optionally specify the association * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, - * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and - * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT. + * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, + * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, %NL80211_ATTR_MAC_HINT, and + * %NL80211_ATTR_WIPHY_FREQ_HINT. + * If included, %NL80211_ATTR_MAC and %NL80211_ATTR_WIPHY_FREQ are + * restrictions on BSS selection, i.e., they effectively prevent roaming + * within the ESS. %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT + * can be included to provide a recommendation of the initial BSS while + * allowing the driver to roam to other BSSes within the ESS and also to + * ignore this recommendation if the indicated BSS is not ideal. Only one + * set of BSSID,frequency parameters is used (i.e., either the enforcing + * %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict + * %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT). * Background scan period can optionally be * specified in %NL80211_ATTR_BG_SCAN_PERIOD, * if not specified default background scan configuration @@ -556,7 +592,14 @@ * operation, %NL80211_ATTR_MAC contains the peer MAC address, and * %NL80211_ATTR_REASON_CODE the reason code to be used (only with * %NL80211_TDLS_TEARDOWN). - * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. + * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The + * %NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be + * sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as + * 802.11 management frames, while TDLS action codes (802.11-2012 + * 8.5.13.1) will be encapsulated and sent as data frames. The currently + * supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES + * and the currently supported TDLS actions codes are given in + * &enum ieee80211_tdls_actioncode. * * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP * (or GO) interface (i.e. hostapd) to ask for unexpected frames to @@ -648,6 +691,34 @@ * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can * return back to normal. * + * @NL80211_CMD_GET_COALESCE: Get currently supported coalesce rules. + * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules. + * + * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the + * the new channel information (Channel Switch Announcement - CSA) + * in the beacon for some time (as defined in the + * %NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the + * new channel. Userspace provides the new channel information (using + * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel + * width). %NL80211_ATTR_CH_SWITCH_BLOCK_TX may be supplied to inform + * other station that transmission must be blocked until the channel + * switch is complete. + * + * @NL80211_CMD_VENDOR: Vendor-specified command/event. The command is specified + * by the %NL80211_ATTR_VENDOR_ID attribute and a sub-command in + * %NL80211_ATTR_VENDOR_SUBCMD. Parameter(s) can be transported in + * %NL80211_ATTR_VENDOR_DATA. + * For feature advertisement, the %NL80211_ATTR_VENDOR_DATA attribute is + * used in the wiphy data as a nested attribute containing descriptions + * (&struct nl80211_vendor_cmd_info) of the supported vendor commands. + * This may also be sent as an event with the same attributes. + * + * @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values. + * The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If + * that attribute is not included, QoS mapping is disabled. Since this + * QoS mapping is relevant for IP packets, it is only valid during an + * association. This is cleared on disassociation and AP restart. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -810,6 +881,15 @@ enum nl80211_commands { NL80211_CMD_CRIT_PROTOCOL_START, NL80211_CMD_CRIT_PROTOCOL_STOP, + NL80211_CMD_GET_COALESCE, + NL80211_CMD_SET_COALESCE, + + NL80211_CMD_CHANNEL_SWITCH, + + NL80211_CMD_VENDOR, + + NL80211_CMD_SET_QOS_MAP, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -945,7 +1025,7 @@ enum nl80211_commands { * to query the CRDA to retrieve one regulatory domain. This attribute can * also be used by userspace to query the kernel for the currently set * regulatory domain. We chose an alpha2 as that is also used by the - * IEEE-802.11d country information element to identify a country. + * IEEE-802.11 country information element to identify a country. * Users can also simply ask the wireless core to set regulatory domain * to a specific alpha2. * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory @@ -1436,6 +1516,69 @@ enum nl80211_commands { * allowed to be used with the first @NL80211_CMD_SET_STATION command to * update a TDLS peer STA entry. * + * @NL80211_ATTR_COALESCE_RULE: Coalesce rule information. + * + * @NL80211_ATTR_CH_SWITCH_COUNT: u32 attribute specifying the number of TBTT's + * until the channel switch event. + * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission + * must be blocked on the current channel (before the channel switch + * operation). + * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information + * for the time while performing a channel switch. + * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter + * field in the beacons tail (%NL80211_ATTR_BEACON_TAIL). + * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter + * field in the probe response (%NL80211_ATTR_PROBE_RESP). + * + * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32. + * As specified in the &enum nl80211_rxmgmt_flags. + * + * @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels. + * + * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported + * supported operating classes. + * + * @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space + * controls DFS operation in IBSS mode. If the flag is included in + * %NL80211_CMD_JOIN_IBSS request, the driver will allow use of DFS + * channels and reports radar events to userspace. Userspace is required + * to react to radar events, e.g. initiate a channel switch or leave the + * IBSS network. + * + * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports + * 5 MHz channel bandwidth. + * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports + * 10 MHz channel bandwidth. + * + * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode + * Notification Element based on association request when used with + * %NL80211_CMD_NEW_STATION; u8 attribute. + * + * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if + * %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet) + * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command + * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this + * attribute is also used for vendor command feature advertisement + * @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy + * info, containing a nested array of possible events + * + * @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This + * data is in the format defined for the payload of the QoS Map Set element + * in IEEE Std 802.11-2012, 8.4.2.97. + * + * @NL80211_ATTR_MAC_HINT: MAC address recommendation as initial BSS + * @NL80211_ATTR_WIPHY_FREQ_HINT: frequency of the recommended initial BSS + * + * @NL80211_ATTR_MAX_AP_ASSOC_STA: Device attribute that indicates how many + * associated stations are supported in AP mode (including P2P GO); u32. + * Since drivers may not have a fixed limit on the maximum number (e.g., + * other concurrent operations may affect this), drivers are allowed to + * advertise values that cannot always be met. In such cases, an attempt + * to add a new station entry with @NL80211_CMD_NEW_STATION may fail. + * + * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32. + * As specified in the &enum nl80211_tdls_peer_capability. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1736,6 +1879,41 @@ enum nl80211_attrs { NL80211_ATTR_PEER_AID, + NL80211_ATTR_COALESCE_RULE, + + NL80211_ATTR_CH_SWITCH_COUNT, + NL80211_ATTR_CH_SWITCH_BLOCK_TX, + NL80211_ATTR_CSA_IES, + NL80211_ATTR_CSA_C_OFF_BEACON, + NL80211_ATTR_CSA_C_OFF_PRESP, + + NL80211_ATTR_RXMGMT_FLAGS, + + NL80211_ATTR_STA_SUPPORTED_CHANNELS, + + NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES, + + NL80211_ATTR_HANDLE_DFS, + + NL80211_ATTR_SUPPORT_5_MHZ, + NL80211_ATTR_SUPPORT_10_MHZ, + + NL80211_ATTR_OPMODE_NOTIF, + + NL80211_ATTR_VENDOR_ID, + NL80211_ATTR_VENDOR_SUBCMD, + NL80211_ATTR_VENDOR_DATA, + NL80211_ATTR_VENDOR_EVENTS, + + NL80211_ATTR_QOS_MAP, + + NL80211_ATTR_MAC_HINT, + NL80211_ATTR_WIPHY_FREQ_HINT, + + NL80211_ATTR_MAX_AP_ASSOC_STA, + + NL80211_ATTR_TDLS_PEER_CAPABILITY, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2136,10 +2314,9 @@ enum nl80211_band_attr { * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current * regulatory domain. - * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is - * permitted on this channel in current regulatory domain. - * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted - * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation + * are permitted on this channel, this includes sending probe + * requests, or modes of operation that require beaconing. * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm @@ -2158,6 +2335,7 @@ enum nl80211_band_attr { * @NL80211_FREQUENCY_ATTR_NO_160MHZ: any 160 MHz (but not 80+80) channel * using this channel as the primary or any of the secondary channels * isn't possible + * @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds. * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use @@ -2166,8 +2344,8 @@ enum nl80211_frequency_attr { __NL80211_FREQUENCY_ATTR_INVALID, NL80211_FREQUENCY_ATTR_FREQ, NL80211_FREQUENCY_ATTR_DISABLED, - NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, - NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_NO_IR, + __NL80211_FREQUENCY_ATTR_NO_IBSS, NL80211_FREQUENCY_ATTR_RADAR, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, NL80211_FREQUENCY_ATTR_DFS_STATE, @@ -2176,6 +2354,7 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_NO_HT40_PLUS, NL80211_FREQUENCY_ATTR_NO_80MHZ, NL80211_FREQUENCY_ATTR_NO_160MHZ, + NL80211_FREQUENCY_ATTR_DFS_CAC_TIME, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -2183,6 +2362,9 @@ enum nl80211_frequency_attr { }; #define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER +#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR +#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR /** * enum nl80211_bitrate_attr - bitrate attributes @@ -2263,12 +2445,14 @@ enum nl80211_reg_type { * in KHz. This is not a center a frequency but an actual regulatory * band edge. * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this - * frequency range, in KHz. + * frequency range, in KHz. * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain * for a given frequency range. The value is in mBi (100 * dBi). * If you don't have one then don't send this. * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for * a given frequency range. The value is in mBm (100 * dBm). + * @NL80211_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds. + * If not present or 0 default CAC time will be used. * @NL80211_REG_RULE_ATTR_MAX: highest regulatory rule attribute number * currently defined * @__NL80211_REG_RULE_ATTR_AFTER_LAST: internal use @@ -2284,6 +2468,8 @@ enum nl80211_reg_rule_attr { NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN, NL80211_ATTR_POWER_RULE_MAX_EIRP, + NL80211_ATTR_DFS_CAC_TIME, + /* keep last */ __NL80211_REG_RULE_ATTR_AFTER_LAST, NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1 @@ -2293,9 +2479,15 @@ enum nl80211_reg_rule_attr { * enum nl80211_sched_scan_match_attr - scheduled scan match attributes * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, - * only report BSS with matching SSID. + * only report BSS with matching SSID. * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a - * BSS in scan results. Filtering is turned off if not specified. + * BSS in scan results. Filtering is turned off if not specified. Note that + * if this attribute is in a match set of its own, then it is treated as + * the default value for all matchsets with an SSID, rather than being a + * matchset of its own without an RSSI filter. This is due to problems with + * how this API was implemented in the past. Also, due to the same problem, + * the only way to create a matchset with only an RSSI filter (with this + * attribute) is if there's only a single matchset with the RSSI attribute. * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter * attribute number currently defined * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use @@ -2325,8 +2517,12 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_DFS: DFS support is required to be used * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links - * @NL80211_RRF_PASSIVE_SCAN: passive scan is required - * @NL80211_RRF_NO_IBSS: no IBSS is allowed + * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, + * this includes probe requests or modes of operation that require + * beaconing. + * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated + * base on contiguous rules and wider channels will be allowed to cross + * multiple contiguous/overlapping frequency ranges. */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -2336,10 +2532,18 @@ enum nl80211_reg_rule_flags { NL80211_RRF_DFS = 1<<4, NL80211_RRF_PTP_ONLY = 1<<5, NL80211_RRF_PTMP_ONLY = 1<<6, - NL80211_RRF_PASSIVE_SCAN = 1<<7, - NL80211_RRF_NO_IBSS = 1<<8, + NL80211_RRF_NO_IR = 1<<7, + __NL80211_RRF_NO_IBSS = 1<<8, + NL80211_RRF_AUTO_BW = 1<<11, }; +#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR +#define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR +#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR + +/* For backport compatibility with older userspace */ +#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS) + /** * enum nl80211_dfs_regions - regulatory DFS regions * @@ -2428,6 +2632,8 @@ enum nl80211_survey_info { * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. * overrides all other flags. + * @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address + * and ACK incoming unicast packets. * * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag @@ -2439,6 +2645,7 @@ enum nl80211_mntr_flags { NL80211_MNTR_FLAG_CONTROL, NL80211_MNTR_FLAG_OTHER_BSS, NL80211_MNTR_FLAG_COOK_FRAMES, + NL80211_MNTR_FLAG_ACTIVE, /* keep last */ __NL80211_MNTR_FLAG_AFTER_LAST, @@ -2574,6 +2781,10 @@ enum nl80211_mesh_power_mode { * * @NL80211_MESHCONF_AWAKE_WINDOW: awake window duration (in TUs) * + * @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. + * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use */ enum nl80211_meshconf_params { @@ -2605,6 +2816,7 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, NL80211_MESHCONF_POWER_MODE, NL80211_MESHCONF_AWAKE_WINDOW, + NL80211_MESHCONF_PLINK_TIMEOUT, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, @@ -2750,6 +2962,8 @@ enum nl80211_channel_type { * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1 * attribute must be provided as well + * @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel + * @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel */ enum nl80211_chan_width { NL80211_CHAN_WIDTH_20_NOHT, @@ -2758,6 +2972,23 @@ enum nl80211_chan_width { NL80211_CHAN_WIDTH_80, NL80211_CHAN_WIDTH_80P80, NL80211_CHAN_WIDTH_160, + NL80211_CHAN_WIDTH_5, + NL80211_CHAN_WIDTH_10, +}; + +/** + * enum nl80211_bss_scan_width - control channel width for a BSS + * + * These values are used with the %NL80211_BSS_CHAN_WIDTH attribute. + * + * @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible + * @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide + * @NL80211_BSS_CHAN_WIDTH_5: control channel is 5 MHz wide + */ +enum nl80211_bss_scan_width { + NL80211_BSS_CHAN_WIDTH_20, + NL80211_BSS_CHAN_WIDTH_10, + NL80211_BSS_CHAN_WIDTH_5, }; /** @@ -2784,6 +3015,8 @@ enum nl80211_chan_width { * @NL80211_BSS_BEACON_IES: binary attribute containing the raw information * elements from a Beacon frame (bin); not present if no Beacon frame has * yet been received + * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel + * (u32, enum nl80211_bss_scan_width) * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -2800,6 +3033,7 @@ enum nl80211_bss { NL80211_BSS_STATUS, NL80211_BSS_SEEN_MS_AGO, NL80211_BSS_BEACON_IES, + NL80211_BSS_CHAN_WIDTH, /* keep last */ __NL80211_BSS_AFTER_LAST, @@ -2940,21 +3174,43 @@ enum nl80211_key_attributes { * in an array of rates as defined in IEEE 802.11 7.3.2.2 (u8 values with * 1 = 500 kbps) but without the IE length restriction (at most * %NL80211_MAX_SUPP_RATES in a single array). - * @NL80211_TXRATE_MCS: HT (MCS) rates allowed for TX rate selection + * @NL80211_TXRATE_HT: HT (MCS) rates allowed for TX rate selection * in an array of MCS numbers. + * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection, + * see &struct nl80211_txrate_vht + * @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ enum nl80211_tx_rate_attributes { __NL80211_TXRATE_INVALID, NL80211_TXRATE_LEGACY, - NL80211_TXRATE_MCS, + NL80211_TXRATE_HT, + NL80211_TXRATE_VHT, + NL80211_TXRATE_GI, /* keep last */ __NL80211_TXRATE_AFTER_LAST, NL80211_TXRATE_MAX = __NL80211_TXRATE_AFTER_LAST - 1 }; +#define NL80211_TXRATE_MCS NL80211_TXRATE_HT +#define NL80211_VHT_NSS_MAX 8 + +/** + * struct nl80211_txrate_vht - VHT MCS/NSS txrate bitmap + * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.) + */ +struct nl80211_txrate_vht { + __u16 mcs[NL80211_VHT_NSS_MAX]; +}; + +enum nl80211_txrate_gi { + NL80211_TXRATE_DEFAULT_GI, + NL80211_TXRATE_FORCE_SGI, + NL80211_TXRATE_FORCE_LGI, +}; + /** * enum nl80211_band - Frequency band * @NL80211_BAND_2GHZ: 2.4 GHz ISM band @@ -3048,11 +3304,11 @@ enum nl80211_tx_power_setting { }; /** - * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute - * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute - * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has + * enum nl80211_packet_pattern_attr - packet pattern attribute + * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute + * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has * a zero bit are ignored - * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have + * @NL80211_PKTPAT_MASK: pattern mask, must be long enough to have * a bit for each byte in the pattern. The lowest-order bit corresponds * to the first byte of the pattern, but the bytes of the pattern are * in a little-endian-like format, i.e. the 9th byte of the pattern @@ -3063,39 +3319,50 @@ enum nl80211_tx_power_setting { * Note that the pattern matching is done as though frames were not * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked * first (including SNAP header unpacking) and then matched. - * @NL80211_WOWLAN_PKTPAT_OFFSET: packet offset, pattern is matched after + * @NL80211_PKTPAT_OFFSET: packet offset, pattern is matched after * these fixed number of bytes of received packet - * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes - * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number + * @NUM_NL80211_PKTPAT: number of attributes + * @MAX_NL80211_PKTPAT: max attribute number */ -enum nl80211_wowlan_packet_pattern_attr { - __NL80211_WOWLAN_PKTPAT_INVALID, - NL80211_WOWLAN_PKTPAT_MASK, - NL80211_WOWLAN_PKTPAT_PATTERN, - NL80211_WOWLAN_PKTPAT_OFFSET, - - NUM_NL80211_WOWLAN_PKTPAT, - MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1, +enum nl80211_packet_pattern_attr { + __NL80211_PKTPAT_INVALID, + NL80211_PKTPAT_MASK, + NL80211_PKTPAT_PATTERN, + NL80211_PKTPAT_OFFSET, + + NUM_NL80211_PKTPAT, + MAX_NL80211_PKTPAT = NUM_NL80211_PKTPAT - 1, }; /** - * struct nl80211_wowlan_pattern_support - pattern support information + * struct nl80211_pattern_support - packet pattern support information * @max_patterns: maximum number of patterns supported * @min_pattern_len: minimum length of each pattern * @max_pattern_len: maximum length of each pattern * @max_pkt_offset: maximum Rx packet offset * * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when - * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the - * capability information given by the kernel to userspace. + * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED or in + * %NL80211_ATTR_COALESCE_RULE_PKT_PATTERN when that is part of + * %NL80211_ATTR_COALESCE_RULE in the capability information given + * by the kernel to userspace. */ -struct nl80211_wowlan_pattern_support { +struct nl80211_pattern_support { __u32 max_patterns; __u32 min_pattern_len; __u32 max_pattern_len; __u32 max_pkt_offset; } __attribute__((packed)); +/* only for backward compatibility */ +#define __NL80211_WOWLAN_PKTPAT_INVALID __NL80211_PKTPAT_INVALID +#define NL80211_WOWLAN_PKTPAT_MASK NL80211_PKTPAT_MASK +#define NL80211_WOWLAN_PKTPAT_PATTERN NL80211_PKTPAT_PATTERN +#define NL80211_WOWLAN_PKTPAT_OFFSET NL80211_PKTPAT_OFFSET +#define NUM_NL80211_WOWLAN_PKTPAT NUM_NL80211_PKTPAT +#define MAX_NL80211_WOWLAN_PKTPAT MAX_NL80211_PKTPAT +#define nl80211_wowlan_pattern_support nl80211_pattern_support + /** * enum nl80211_wowlan_triggers - WoWLAN trigger definitions * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes @@ -3115,7 +3382,7 @@ struct nl80211_wowlan_pattern_support { * pattern matching is done after the packet is converted to the MSDU. * * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute - * carrying a &struct nl80211_wowlan_pattern_support. + * carrying a &struct nl80211_pattern_support. * * When reporting wakeup. it is a u32 attribute containing the 0-based * index of the pattern that caused the wakeup, in the patterns passed @@ -3272,7 +3539,7 @@ struct nl80211_wowlan_tcp_data_token_feature { * @NL80211_WOWLAN_TCP_WAKE_PAYLOAD: wake packet payload, for advertising a * u32 attribute holding the maximum length * @NL80211_WOWLAN_TCP_WAKE_MASK: Wake packet payload mask, not used for - * feature advertising. The mask works like @NL80211_WOWLAN_PKTPAT_MASK + * feature advertising. The mask works like @NL80211_PKTPAT_MASK * but on the TCP payload only. * @NUM_NL80211_WOWLAN_TCP: number of TCP attributes * @MAX_NL80211_WOWLAN_TCP: highest attribute number @@ -3297,6 +3564,55 @@ enum nl80211_wowlan_tcp_attrs { }; /** + * struct nl80211_coalesce_rule_support - coalesce rule support information + * @max_rules: maximum number of rules supported + * @pat: packet pattern support information + * @max_delay: maximum supported coalescing delay in msecs + * + * This struct is carried in %NL80211_ATTR_COALESCE_RULE in the + * capability information given by the kernel to userspace. + */ +struct nl80211_coalesce_rule_support { + __u32 max_rules; + struct nl80211_pattern_support pat; + __u32 max_delay; +} __attribute__((packed)); + +/** + * enum nl80211_attr_coalesce_rule - coalesce rule attribute + * @__NL80211_COALESCE_RULE_INVALID: invalid number for nested attribute + * @NL80211_ATTR_COALESCE_RULE_DELAY: delay in msecs used for packet coalescing + * @NL80211_ATTR_COALESCE_RULE_CONDITION: condition for packet coalescence, + * see &enum nl80211_coalesce_condition. + * @NL80211_ATTR_COALESCE_RULE_PKT_PATTERN: packet offset, pattern is matched + * after these fixed number of bytes of received packet + * @NUM_NL80211_ATTR_COALESCE_RULE: number of attributes + * @NL80211_ATTR_COALESCE_RULE_MAX: max attribute number + */ +enum nl80211_attr_coalesce_rule { + __NL80211_COALESCE_RULE_INVALID, + NL80211_ATTR_COALESCE_RULE_DELAY, + NL80211_ATTR_COALESCE_RULE_CONDITION, + NL80211_ATTR_COALESCE_RULE_PKT_PATTERN, + + /* keep last */ + NUM_NL80211_ATTR_COALESCE_RULE, + NL80211_ATTR_COALESCE_RULE_MAX = NUM_NL80211_ATTR_COALESCE_RULE - 1 +}; + +/** + * enum nl80211_coalesce_condition - coalesce rule conditions + * @NL80211_COALESCE_CONDITION_MATCH: coalaesce Rx packets when patterns + * in a rule are matched. + * @NL80211_COALESCE_CONDITION_NO_MATCH: coalesce Rx packets when patterns + * in a rule are not matched. + */ +enum nl80211_coalesce_condition { + NL80211_COALESCE_CONDITION_MATCH, + NL80211_COALESCE_CONDITION_NO_MATCH +}; + +/** * enum nl80211_iface_limit_attrs - limit attributes * @NL80211_IFACE_LIMIT_UNSPEC: (reserved) * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that @@ -3540,11 +3856,6 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested * to work properly to suppport receiving regulatory hints from * cellular base stations. - * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active - * P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel - * in the interface combinations, even when it's only used for scan - * and remain-on-channel. This could be due to, for example, the - * remain-on-channel implementation requiring a channel context. * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station * mode @@ -3576,13 +3887,17 @@ enum nl80211_ap_sme_features { * Peering Management entity which may be implemented by registering for * beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is * still generated by the driver. + * @NL80211_FEATURE_ACTIVE_MONITOR: This driver supports an active monitor + * interface. An active monitor interface behaves like a normal monitor + * interface, but gets added to the driver. It ensures that incoming + * unicast packets directed at the configured interface address get ACKed. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, NL80211_FEATURE_HT_IBSS = 1 << 1, NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, - NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4, + /* bit 4 is reserved - don't use */ NL80211_FEATURE_SAE = 1 << 5, NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, NL80211_FEATURE_SCAN_FLUSH = 1 << 7, @@ -3595,6 +3910,7 @@ enum nl80211_feature_flags { NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, NL80211_FEATURE_USERSPACE_MPM = 1 << 16, + NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17, }; /** @@ -3695,13 +4011,12 @@ enum nl80211_radar_event { * * Channel states used by the DFS code. * - * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability + * @NL80211_DFS_USABLE: The channel can be used, but channel availability * check (CAC) must be performed before using it for AP or IBSS. - * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it + * @NL80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it * is therefore marked as not available. - * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available. + * @NL80211_DFS_AVAILABLE: The channel has been CAC checked and is available. */ - enum nl80211_dfs_state { NL80211_DFS_USABLE, NL80211_DFS_UNAVAILABLE, @@ -3741,4 +4056,51 @@ enum nl80211_crit_proto_id { /* maximum duration for critical protocol measures */ #define NL80211_CRIT_PROTO_MAX_DURATION 5000 /* msec */ +/** + * enum nl80211_rxmgmt_flags - flags for received management frame. + * + * Used by cfg80211_rx_mgmt() + * + * @NL80211_RXMGMT_FLAG_ANSWERED: frame was answered by device/driver. + */ +enum nl80211_rxmgmt_flags { + NL80211_RXMGMT_FLAG_ANSWERED = 1 << 0, +}; + +/* + * If this flag is unset, the lower 24 bits are an OUI, if set + * a Linux nl80211 vendor ID is used (no such IDs are allocated + * yet, so that's not valid so far) + */ +#define NL80211_VENDOR_ID_IS_LINUX 0x80000000 + +/** + * struct nl80211_vendor_cmd_info - vendor command data + * @vendor_id: If the %NL80211_VENDOR_ID_IS_LINUX flag is clear, then the + * value is a 24-bit OUI; if it is set then a separately allocated ID + * may be used, but no such IDs are allocated yet. New IDs should be + * added to this file when needed. + * @subcmd: sub-command ID for the command + */ +struct nl80211_vendor_cmd_info { + __u32 vendor_id; + __u32 subcmd; +}; + +/** + * enum nl80211_tdls_peer_capability - TDLS peer flags. + * + * Used by tdls_mgmt() to determine which conditional elements need + * to be added to TDLS Setup frames. + * + * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable. + * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable. + * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable. + */ +enum nl80211_tdls_peer_capability { + NL80211_TDLS_PEER_HT = 1<<0, + NL80211_TDLS_PEER_VHT = 1<<1, + NL80211_TDLS_PEER_WMM = 1<<2, +}; + #endif /* __LINUX_NL80211_H */ diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h index 42f525b9..b8a0bd00 100644 --- a/src/eap_peer/eap_config.h +++ b/src/eap_peer/eap_config.h @@ -643,6 +643,14 @@ struct eap_peer_config { * 2 = require valid OCSP stapling response */ int ocsp; + + /** + * sim_num - User selected SIM identifier + * + * This variable is used for identifying which SIM is used if the system + * has more than one. + */ + int sim_num; }; diff --git a/src/eap_peer/eap_proxy_qmi.c b/src/eap_peer/eap_proxy_qmi.c new file mode 100644 index 00000000..c640d8fd --- /dev/null +++ b/src/eap_peer/eap_proxy_qmi.c @@ -0,0 +1,1944 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + +#include "includes.h" +#include "common.h" +#include "eap_proxy_qmi.h" + +#ifdef CONFIG_EAP_PROXY +#include "qmi_uim_srvc.h" +#include "qmi_client.h" +#include "qmi_idl_lib.h" +#include "user_identity_module_v01.h" +#include "eap_config.h" +#include "common/wpa_ctrl.h" +#include <cutils/properties.h> +#if defined(__BIONIC_FORTIFY) +#include <sys/system_properties.h> +#endif + +#define IMSI_LENGTH 15 +#define WPA_UIM_QMI_EVENT_MASK_CARD_STATUS \ + (1 << QMI_UIM_EVENT_CARD_STATUS_BIT_V01) +#define WPA_UIM_QMI_EVENT_READ_TRANSPARENT_REQ \ + (1 << QMI_UIM_READ_TRANSPARENT_REQ_V01) + +/* Default timeout (in milli-seconds) for synchronous QMI message */ +#define WPA_UIM_QMI_DEFAULT_TIMEOUT 5000 + +#define EAP_PROXY_PROPERTY_BASEBAND "ro.baseband" +#if defined(__BIONIC_FORTIFY) +#define EAP_PROXY_PROPERTY_BASEBAND_SIZE PROP_VALUE_MAX +#else +#define EAP_PROXY_PROPERTY_BASEBAND_SIZE 10 +#endif +#define EAP_PROXY_BASEBAND_VALUE_MSM "msm" +#define EAP_PROXY_BASEBAND_VALUE_APQ "apq" +#define EAP_PROXY_BASEBAND_VALUE_SVLTE1 "svlte1" +#define EAP_PROXY_BASEBAND_VALUE_SVLTE2A "svlte2a" +#define EAP_PROXY_BASEBAND_VALUE_SGLTE "sglte" +#define EAP_PROXY_BASEBAND_VALUE_CSFB "csfb" +#define EAP_PROXY_BASEBAND_VALUE_MDMUSB "mdm" +#define EAP_PROXY_BASEBAND_VALUE_UNDEFINED "undefined" + +#ifdef SIM_AKA_IDENTITY_IMSI +typedef struct { + uim_card_state_enum_v01 card_state; + uim_card_error_code_enum_v01 card_error_code; + u8 app_state; + u8 app_type; +} wpa_uim_card_info_type; + +typedef struct { + int card_ready_idx; + wpa_uim_card_info_type card_info[QMI_UIM_CARDS_MAX_V01]; + qmi_client_type qmi_uim_svc_client_ptr; + int qmi_msg_lib_handle; +} wpa_uim_struct_type; + +/* Global variable with the card status */ +wpa_uim_struct_type wpa_uim[MAX_NO_OF_SIM_SUPPORTED]; +#endif /* SIM_AKA_IDENTITY_IMSI */ + +static int eap_proxy_qmi_init_handle; +static qmi_client_type qmi_uim_svc_client_ptr; +#ifdef CONFIG_EAP_PROXY_DUAL_SIM +static int eap_auth_session_flag[MAX_NO_OF_SIM_SUPPORTED] = {FALSE, FALSE}; +static Boolean qmi_uim_svc_client_initialized[MAX_NO_OF_SIM_SUPPORTED] = {FALSE, FALSE}; +#else +static int eap_auth_session_flag[MAX_NO_OF_SIM_SUPPORTED] = {FALSE}; +static Boolean qmi_uim_svc_client_initialized[MAX_NO_OF_SIM_SUPPORTED] = {FALSE}; +#endif /* CONFIG_EAP_PROXY_DUAL_SIM */ + +static void eap_proxy_eapol_sm_set_bool(struct eap_proxy_sm *sm, + enum eapol_bool_var var, Boolean value); +static Boolean eap_proxy_eapol_sm_get_bool(struct eap_proxy_sm *sm, + enum eapol_bool_var var); + +/* Call-back function to process an authenticationr result indication from + * QMI EAP service */ +static void handle_qmi_eap_ind(int userHandle, qmi_service_id_type serviceId, + void *userData, qmi_eap_indication_id_type indId, + qmi_eap_indication_data_type *indData); + +/* Call-back function to process an EAP response from QMI EAP service */ +static void handle_qmi_eap_reply(int userHandle, qmi_service_id_type serviceId, + int sysErrCode, int qmiErrCode, void *userData, + qmi_eap_async_rsp_id_type rspId, qmi_eap_async_rsp_data_type *rspData); + +static u8 *eap_proxy_getKey(struct eap_proxy_sm *eap_proxy); +static enum eap_proxy_status eap_proxy_qmi_response_wait(struct eap_proxy_sm *eap_proxy); +static int eap_proxy_is_state_changed(struct eap_proxy_sm *sm); +static enum eap_proxy_status eap_proxy_process(struct eap_proxy_sm *eap_proxy, + u8 *eapReqData, int eapReqDataLen, struct eap_sm *eap_sm); +static char bin_to_hexchar(u8 ch); + +static void wpa_qmi_client_indication_cb +( + qmi_client_type user_handle, + unsigned long msg_id, + unsigned char *ind_buf_ptr, + int ind_buf_len, + void *ind_cb_data +); +static void dump_buff(u8 *buff, int len); +#ifdef CONFIG_CTRL_IFACE +static const char *eap_proxy_sm_state_txt(int state); +#endif /* CONFIG_CTRL_IFACE */ +static Boolean eap_proxy_build_identity(struct eap_proxy_sm *eap_proxy, u8 id, + struct eap_sm *eap_sm); + +#ifdef SIM_AKA_IDENTITY_IMSI +static char *imsi; +static int imsi_len_g = 0; +static int card_mnc_len = -1; +#ifdef CONFIG_EAP_PROXY_DUAL_SIM +static unsigned int slot = 0; +static unsigned int session_type; +#endif /* CONFIG_EAP_PROXY_DUAL_SIM */ + +static Boolean wpa_qmi_register_events(int sim_num); +static Boolean wpa_qmi_read_card_imsi(int sim_num); +static Boolean wpa_qmi_read_card_status(int sim_num); + +#endif +#define EAP_SUB_TYPE_SIM_START 0x0a +#define EAP_SUB_TYPE_AKA_IDENTITY 0x05 +#define EAP_RESP_TYPE_NAK 3 + +/* Call-back function to process QMI system events */ +void handle_qmi_sys_events(qmi_sys_event_type eventId, +const qmi_sys_event_info_type *eventInfo, void *userData) +{ + +/* Based on the qmi sys events we need to update our qmi and eap states.*/ + wpa_printf(MSG_INFO, "handleQmiSysEvent\n"); + wpa_printf(MSG_INFO, "Event Id=%d;\n", eventId); +} + +#ifdef SIM_AKA_IDENTITY_IMSI +static void wpa_qmi_client_indication_cb +( + qmi_client_type user_handle, + unsigned long msg_id, + unsigned char *ind_buf_ptr, + int ind_buf_len, + void *ind_cb_data +) +{ + /* we currently not need the card status changes */ + /* Making this a dummy CB handler */ +} + +static Boolean wpa_qmi_register_events(int sim_num) +{ + qmi_client_error_type qmi_err_code = 0; + uim_get_card_status_resp_msg_v01 *qmi_response_ptr = NULL; + uim_event_reg_req_msg_v01 event_reg_params; + + qmi_response_ptr = (uim_get_card_status_resp_msg_v01 *) + os_malloc(sizeof(uim_get_card_status_resp_msg_v01)); + if (qmi_response_ptr == NULL) { + wpa_printf(MSG_ERROR, + "Couldn't allocate memory for qmi_response_ptr\n"); + return FALSE; + } + + /* Register for events first */ + os_memset(qmi_response_ptr, 0, + sizeof(uim_get_card_status_resp_msg_v01)); + os_memset(&event_reg_params, 0, sizeof(uim_event_reg_req_msg_v01)); + + event_reg_params.event_mask |= (WPA_UIM_QMI_EVENT_MASK_CARD_STATUS); + + qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr, + QMI_UIM_EVENT_REG_REQ_V01, + (void *) &event_reg_params, + sizeof(uim_event_reg_req_msg_v01), + (void *) qmi_response_ptr, + sizeof(*qmi_response_ptr), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + wpa_printf(MSG_ERROR, " QMI_UIM_EVENT_REG_REQ_V01, qmi_err_code: 0x%x\n", + qmi_err_code); + if (qmi_err_code != QMI_NO_ERR) { + wpa_printf(MSG_ERROR, + "Error for QMI_UIM_EVENT_REG_REQ_V01, qmi_err_code: 0x%x\n", + qmi_err_code); + free(qmi_response_ptr); + return FALSE; + } + /* Free the allocated response buffer */ + if (qmi_response_ptr) + { + free(qmi_response_ptr); + qmi_response_ptr = NULL; + } + + if (wpa_qmi_read_card_status(sim_num)) + return TRUE; + else { + wpa_printf(MSG_ERROR, + "Error while reading SIM card status\n"); + return FALSE; + } +} + +static Boolean wpa_qmi_read_card_status(int sim_num) +{ + unsigned int i = 0, j = 0; + Boolean card_found = FALSE; + qmi_client_error_type qmi_err_code = 0; + uim_get_card_status_resp_msg_v01 *qmi_response_ptr = NULL; + + wpa_printf (MSG_ERROR, "eap_proxy: reading card %d values\n", sim_num+1); + qmi_response_ptr = (uim_get_card_status_resp_msg_v01 *) + os_malloc(sizeof(uim_get_card_status_resp_msg_v01)); + if (qmi_response_ptr == NULL) { + wpa_printf(MSG_ERROR, + "Couldn't allocate memory for qmi_response_ptr !\n"); + return FALSE; + } + + os_memset(qmi_response_ptr, + 0, + sizeof(uim_get_card_status_resp_msg_v01)); + qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr, + QMI_UIM_GET_CARD_STATUS_REQ_V01, + NULL, + 0, + (void *) qmi_response_ptr, + sizeof(*qmi_response_ptr), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + wpa_printf(MSG_ERROR, + "QMI_UIM_GET_CARD_STATUS_REQ_V01, qmi_err_code: 0x%x\n", + qmi_err_code); + if (qmi_err_code != QMI_NO_ERR) { + wpa_printf(MSG_ERROR, + "Error for QMI_UIM_GET_CARD_STATUS_REQ_V01, qmi_err_code: 0x%x\n", + qmi_err_code); + free(qmi_response_ptr); + return FALSE; + } + + /* Updated global card status if needed */ + if (!qmi_response_ptr->card_status_valid || + (qmi_response_ptr->resp.result != QMI_RESULT_SUCCESS_V01)) { + wpa_printf(MSG_ERROR, "card_status is not valid !\n"); + free(qmi_response_ptr); + return FALSE; + } + /* Update global in case of new card state or error code */ + i = sim_num; + if ( i < QMI_UIM_CARDS_MAX_V01 && + i < qmi_response_ptr->card_status.card_info_len ) { + wpa_printf(MSG_ERROR, "card_info[i].card_state: 0x%x\n", + qmi_response_ptr->card_status.card_info[i].card_state); + wpa_printf(MSG_ERROR, "card_info[i].error_code: 0x%x\n", + qmi_response_ptr->card_status.card_info[i].error_code); + + wpa_uim[sim_num].card_info[i].card_state = + qmi_response_ptr->card_status.card_info[i].card_state; + + wpa_uim[sim_num].card_info[i].card_error_code = + qmi_response_ptr->card_status.card_info[i].error_code; +#ifdef CONFIG_EAP_PROXY_DUAL_SIM + do { + if (qmi_response_ptr->card_status.index_gw_pri != 0xFFFF) { + slot = (qmi_response_ptr->card_status.index_gw_pri & 0xFF00) >> 8; + if (slot == i) { + session_type = QMI_UIM_SESSION_TYPE_PRI_GW_PROV; + wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: prime slot = %d\n", slot); + break; + } + } + if (qmi_response_ptr->card_status.index_gw_sec != 0xFFFF) { + slot = (qmi_response_ptr->card_status.index_gw_sec & 0xFF00) >> 8; + if (slot == i) { + session_type = QMI_UIM_SESSION_TYPE_SEC_GW_PROV; + wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: second slot = %d\n", slot); + break; + } + } + wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: Not GW it's 1x\n"); + return FALSE; + }while(0); + + if (slot > 1){ + wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: INVALID slot = %d and i = %d\n", slot, i); + return FALSE; + } +#endif /* CONFIG_EAP_PROXY_DUAL_SIM */ + + if (qmi_response_ptr->card_status.card_info[i].card_state == + UIM_CARD_STATE_PRESENT_V01) { + for (j = 0 ; j < QMI_UIM_APPS_MAX_V01 ; j++) { + wpa_uim[sim_num].card_info[i].app_type = + qmi_response_ptr->card_status.card_info[i].app_info[j].app_type; + + wpa_uim[sim_num].card_info[i].app_state = + qmi_response_ptr->card_status.card_info[i].app_info[j].app_state; + + if (((qmi_response_ptr->card_status.card_info[i].app_info[j].app_type == 1) || + (qmi_response_ptr->card_status.card_info[i].app_info[j].app_type == 2)) && + (qmi_response_ptr->card_status.card_info[i].app_info[j].app_state == + UIM_APP_STATE_READY_V01)) { + wpa_printf(MSG_ERROR, "card READY\n"); + wpa_printf(MSG_ERROR, "card_info[i].app_type : 0x%x\n", + qmi_response_ptr->card_status.card_info[i].app_info[j].app_type); + wpa_printf(MSG_ERROR, "card_info[i].app_state : 0x%x\n", + qmi_response_ptr->card_status.card_info[i].app_info[j].app_state); + card_found = TRUE; + break; + } + } + } + + if (card_found) { + wpa_printf(MSG_ERROR, "card found for SIM = %d\n", sim_num+1); + } + } + + if ((!card_found) || (i ==QMI_UIM_CARDS_MAX_V01) || + (j == QMI_UIM_APPS_MAX_V01)) { + if (qmi_response_ptr) { + free(qmi_response_ptr); + qmi_response_ptr = NULL; + } + wpa_printf(MSG_ERROR, "SIM/USIM not ready\n"); + return FALSE; + } + + wpa_printf(MSG_ERROR, "SIM/USIM ready\n"); + wpa_uim[sim_num].card_ready_idx = i; + + /* Free the allocated response buffer */ + if (qmi_response_ptr) { + free(qmi_response_ptr); + wpa_printf(MSG_ERROR, "Free the allocated response buffer\n"); + qmi_response_ptr = NULL; + } + + return TRUE; +} /* wpa_qmi_read_card_status */ + +static Boolean wpa_qmi_read_card_imsi(int sim_num) +{ + int length; + unsigned char *data; + int src = 0, dst = 0; + Boolean card_found = FALSE, + qmi_status = TRUE; + qmi_client_error_type qmi_err_code = 0; + uim_read_transparent_req_msg_v01 *qmi_read_trans_req_ptr = NULL; + uim_read_transparent_resp_msg_v01 *qmi_read_trans_resp_ptr = NULL; + + qmi_read_trans_req_ptr = (uim_read_transparent_req_msg_v01 *) + os_malloc(sizeof(uim_read_transparent_req_msg_v01)); + if (qmi_read_trans_req_ptr == NULL) { + wpa_printf(MSG_ERROR, + "Couldn't allocate memory for qmi_read_trans_req_ptr !\n"); + return FALSE; + } + qmi_read_trans_resp_ptr = (uim_read_transparent_resp_msg_v01 *) + os_malloc(sizeof(uim_read_transparent_resp_msg_v01)); + if (qmi_read_trans_resp_ptr == NULL) { + wpa_printf(MSG_ERROR, + "Couldn't allocate memory for qmi_read_trans_resp_ptr !\n"); + + if (qmi_read_trans_req_ptr) { + free(qmi_read_trans_req_ptr); + qmi_read_trans_req_ptr = NULL; + } + return FALSE; + } + + os_memset(qmi_read_trans_resp_ptr, 0, + sizeof(uim_read_transparent_resp_msg_v01)); + os_memset(qmi_read_trans_req_ptr, 0, + sizeof(uim_read_transparent_req_msg_v01)); + + qmi_read_trans_req_ptr->read_transparent.length = 0; + qmi_read_trans_req_ptr->read_transparent.offset = 0; + qmi_read_trans_req_ptr->file_id.file_id = 0x6F07; + qmi_read_trans_req_ptr->file_id.path_len = 4; + +#ifdef CONFIG_EAP_PROXY_DUAL_SIM + wpa_printf (MSG_ERROR, "eap_proxy: read_card_imsi: session_type = %d\n", session_type); + qmi_read_trans_req_ptr->session_information.session_type = session_type; +#else + qmi_read_trans_req_ptr->session_information.session_type = + QMI_UIM_SESSION_TYPE_PRI_GW_PROV; +#endif /* CONFIG_EAP_PROXY_DUAL_SIM */ + qmi_read_trans_req_ptr->session_information.aid_len = 0; + + /* For USIM*/ + if ((wpa_uim[sim_num].card_info[wpa_uim[sim_num].card_ready_idx].app_type == + UIM_APP_TYPE_USIM_V01)) { + qmi_read_trans_req_ptr->file_id.path[0] = 0x00; + qmi_read_trans_req_ptr->file_id.path[1] = 0x3F; + qmi_read_trans_req_ptr->file_id.path[2] = 0xFF; + qmi_read_trans_req_ptr->file_id.path[3] = 0x7F; + + } else /* For SIM*/ + if ((wpa_uim[sim_num].card_info[wpa_uim[sim_num].card_ready_idx].app_type == + UIM_APP_TYPE_SIM_V01)) { + qmi_read_trans_req_ptr->file_id.path[0] = 0x00; + qmi_read_trans_req_ptr->file_id.path[1] = 0x3F; + qmi_read_trans_req_ptr->file_id.path[2] = 0x20; + qmi_read_trans_req_ptr->file_id.path[3] = 0x7F; + } + else { + if (qmi_read_trans_req_ptr) { + free(qmi_read_trans_req_ptr); + qmi_read_trans_req_ptr = NULL; + } + if (qmi_read_trans_resp_ptr) { + free(qmi_read_trans_resp_ptr); + qmi_read_trans_resp_ptr = NULL; + } + return FALSE; + } + + qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr, + QMI_UIM_READ_TRANSPARENT_REQ_V01, + (void *)qmi_read_trans_req_ptr, + sizeof(*qmi_read_trans_req_ptr), + (void *) qmi_read_trans_resp_ptr, + sizeof(*qmi_read_trans_resp_ptr), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + + if (QMI_NO_ERR == qmi_err_code) { + if (qmi_read_trans_resp_ptr->read_result_valid) { + length = + qmi_read_trans_resp_ptr->read_result.content_len; + data = + qmi_read_trans_resp_ptr->read_result.content; + wpa_printf(MSG_ERROR, + "IMSI SIM content length = %d\n", + length); + + /* Received IMSI is in the 3GPP format + converting it into ascii string */ + imsi = os_malloc((2 * length)); + os_memset(imsi, 0, (2 * length)); + for (src = 1, dst = 0; + (src < length) && (dst < (length * 2)); + src++) { + wpa_printf(MSG_ERROR, + "IMSI read from SIM = %d src %d\n", + data[src], src); + if(data[src] == 0xFF) { + break; + } + if (src > 1) { + imsi[dst] = bin_to_hexchar(data[src] & 0x0F); + dst++; + wpa_printf(MSG_ERROR, + "IMSI dst = %d dst %d\n", + imsi[dst-1], dst); + } + /* Process upper part of byte for all bytes */ + imsi[dst] = bin_to_hexchar(data[src] >> 4); + dst++; + wpa_printf(MSG_ERROR, + "IMSI dst = %d dst %d\n", + imsi[dst-1], dst); + } + imsi_len_g = (data[0]*2 - 1); //dst; + wpa_printf(MSG_ERROR, + "IMSI first digit = %d read length = %d imsi %20s\n", + data[0],imsi_len_g, imsi); + } else{ + wpa_printf(MSG_ERROR, + "IMSI read failure read_result_valid = %d\n", + qmi_read_trans_resp_ptr->read_result_valid); + qmi_status = FALSE; + } + } else { + wpa_printf(MSG_ERROR, + "Unable to read IMSI from UIM service qmi_err_code=%x\n", + qmi_err_code); + qmi_status = FALSE; + } + + /* READ EF_AD */ + /* if qmi_status is FALSE, UIM read for mnc may not be required - To Do */ + qmi_read_trans_req_ptr->file_id.file_id = 0x6FAD; + qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr, + QMI_UIM_READ_TRANSPARENT_REQ_V01, + (void *)qmi_read_trans_req_ptr, + sizeof(*qmi_read_trans_req_ptr), + (void *) qmi_read_trans_resp_ptr, + sizeof(*qmi_read_trans_resp_ptr), + WPA_UIM_QMI_DEFAULT_TIMEOUT); + if (QMI_NO_ERR == qmi_err_code) { + if (qmi_read_trans_resp_ptr->read_result_valid) { + length = + qmi_read_trans_resp_ptr->read_result.content_len; + data = + qmi_read_trans_resp_ptr->read_result.content; + + card_mnc_len = data[3]; + } + } + else{ + qmi_status = FALSE; + wpa_printf(MSG_ERROR, + "MNC read failed=%x\n",qmi_err_code); + } + + /* Free the allocated read request buffer */ + if (qmi_read_trans_req_ptr) { + free(qmi_read_trans_req_ptr); + qmi_read_trans_req_ptr = NULL; + } + + /* Free the allocated read response buffer */ + if (qmi_read_trans_resp_ptr) { + free(qmi_read_trans_resp_ptr); + qmi_read_trans_resp_ptr = NULL; + } + return qmi_status; +} /* wpa_qmi_read_card_imsi */ +#endif /* SIM_AKA_IDENTITY_IMSI */ + +const char * eap_proxy_get_port(void) +{ + int ret = 0; + const char* eap_proxy_port = NULL; + + char args[EAP_PROXY_PROPERTY_BASEBAND_SIZE] = {0}; + char def[EAP_PROXY_PROPERTY_BASEBAND_SIZE] = {0}; + + ret = property_get(EAP_PROXY_PROPERTY_BASEBAND, args, def); + if (ret > EAP_PROXY_PROPERTY_BASEBAND_SIZE){ + wpa_printf(MSG_ERROR,"property [%s] has size [%d] that exceeds max [%d]", + EAP_PROXY_PROPERTY_BASEBAND, + ret, + EAP_PROXY_PROPERTY_BASEBAND_SIZE); + return NULL; + } + + if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_MSM, args, 3)) { + wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args); + eap_proxy_port = QMI_PORT_RMNET_1; + } + else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_APQ, args, 3)) { + wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args); + eap_proxy_port = QMI_PORT_RMNET_1; + } + else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_SVLTE1, args, 6)) { + wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args); + eap_proxy_port = QMI_PORT_RMNET_1; + } + else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_SVLTE2A, args, 7)) { + wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args); + eap_proxy_port = QMI_PORT_RMNET_1; + } + else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_CSFB, args, 4)) { + eap_proxy_port = QMI_PORT_RMNET_SDIO_0; + } + else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_MDMUSB, args, 6)) { + wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args); + eap_proxy_port = QMI_PORT_RMNET_USB_0; + } + else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_SGLTE, args, 5)) { + wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args); + eap_proxy_port = QMI_PORT_RMNET_1; + } + return eap_proxy_port; +} + + +struct eap_proxy_sm * +eap_proxy_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb, + void *msg_ctx) +{ + int qmiErrorCode; + int qmiRetCode; + struct eap_proxy_sm *eap_proxy; + qmi_idl_service_object_type qmi_client_service_obj[MAX_NO_OF_SIM_SUPPORTED]; + const char *eap_qmi_port[MAX_NO_OF_SIM_SUPPORTED]; + int index; + static Boolean flag = FALSE; + + eap_proxy = os_malloc(sizeof(struct eap_proxy_sm)); + if (NULL == eap_proxy) { + wpa_printf(MSG_ERROR, "Error memory alloc for eap_proxy" + "eap_proxy_init\n"); + return NULL; + } + os_memset(eap_proxy, 0, sizeof(*eap_proxy)); + + eap_proxy->ctx = eapol_ctx; + eap_proxy->eapol_cb = eapol_cb; + eap_proxy->msg_ctx = msg_ctx; + eap_proxy->proxy_state = EAP_PROXY_INITIALIZE; + eap_proxy->qmi_state = QMI_STATE_IDLE; + eap_proxy->key = NULL; + eap_proxy->iskey_valid = FALSE; + eap_proxy->is_state_changed = FALSE; + eap_proxy->isEap = FALSE; + eap_proxy->eap_type = EAP_TYPE_NONE; + eap_proxy->user_selected_sim = 0; + +#ifdef CONFIG_EAP_PROXY_DUAL_SIM + wpa_printf (MSG_ERROR, "eap_proxy Initializing for DUAL SIM build %d ", MAX_NO_OF_SIM_SUPPORTED); +#else + wpa_printf (MSG_ERROR, "eap_proxy Initializing for Single SIM build %d ", MAX_NO_OF_SIM_SUPPORTED); +#endif + + /* initialize QMI */ + eap_proxy_qmi_init_handle = qmi_init(handle_qmi_sys_events, NULL); + if (eap_proxy_qmi_init_handle < 0) { + wpa_printf(MSG_ERROR, "Error in qmi_init\n"); + os_free(eap_proxy); + return NULL; + } + + for (index = 0; index < MAX_NO_OF_SIM_SUPPORTED; ++index) { + /*Get the available port using property get*/ + eap_qmi_port[index] = eap_proxy_get_port(); + + /* initialize the QMI connection */ + qmiRetCode = qmi_dev_connection_init(eap_qmi_port[index], &qmiErrorCode); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf(MSG_ERROR, "Error in qmi_connection_init\n"); + flag = FALSE; + continue; + } + + /* initialize the QMI EAP Service for client n or SIM n*/ + wpa_printf(MSG_INFO, "eap_proxy: Initializing the QMI EAP Services for client %d\n", index+1); + eap_proxy->qmihandle[index] = qmi_eap_srvc_init_client(eap_qmi_port[index], + &handle_qmi_eap_ind, + eap_proxy, &qmiErrorCode); + + if (0 >= eap_proxy->qmihandle[index]) { + wpa_printf(MSG_ERROR, "Unable to initialize service client %d;" + " error_ret=%d; error_code=%d\n", + index+1, eap_proxy->qmihandle[index], qmiErrorCode); + flag = FALSE; + continue; + } + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_init: qmihandle[%d] = %d\n", + index, eap_proxy->qmihandle[index]); + +#ifdef SIM_AKA_IDENTITY_IMSI + if (FALSE == qmi_uim_svc_client_initialized[index]) { + /* Init QMI_UIM service for EAP-SIM/AKA */ + qmi_client_service_obj[index] = uim_get_service_object_v01(); + + qmiErrorCode = qmi_client_init(eap_qmi_port[index], + qmi_client_service_obj[index], + wpa_qmi_client_indication_cb, + qmi_client_service_obj[index], + &wpa_uim[index].qmi_uim_svc_client_ptr); + + if ((wpa_uim[index].qmi_uim_svc_client_ptr == NULL) || (qmiErrorCode > 0)) { + wpa_printf(MSG_ERROR, "Could not register with QMI UIM Service," + "qmi_uim_svc_client_ptr: %p,qmi_err_code: %d\n", + wpa_uim[index].qmi_uim_svc_client_ptr, qmiErrorCode); + wpa_uim[index].qmi_uim_svc_client_ptr = NULL; + flag = FALSE; + continue; + } + qmi_uim_svc_client_initialized[index] = TRUE; + + /* Register the card events with the QMI / UIM */ + wpa_qmi_register_events(index); + flag = TRUE; + } else { + wpa_printf (MSG_ERROR, "QMI EAP service client is already initialized\n"); + } +#endif /* SIM_AKA_IDENTITY_IMSI */ + } + + if ( flag == FALSE ) { + wpa_printf(MSG_ERROR, "eap_proxy: flag = %d proxy init failed\n", flag); + os_free(eap_proxy); + return NULL; + } + + eap_proxy->proxy_state = EAP_PROXY_IDLE; + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapSuccess, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapFail, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapRestart, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapResp, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapNoResp, FALSE); + wpa_printf (MSG_ERROR, "Eap_proxy initialized successfully\n"); + + return eap_proxy; +} + + +void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy) +{ + int qmiRetCode; + int qmiErrorCode; + int index; + + if (NULL == eap_proxy) + return; + + eap_proxy->proxy_state = EAP_PROXY_DISABLED; + + for (index = 0; index < MAX_NO_OF_SIM_SUPPORTED; ++index) { + if (TRUE == eap_auth_session_flag[index]) { + wpa_printf (MSG_ERROR, "eap_proxy: in eap_proxy_deinit qmihandle[%d] = %d\n", + index, eap_proxy->qmihandle[index]); + /* end the current EAP session */ + qmiRetCode = qmi_eap_auth_end_eap_session( + eap_proxy->qmihandle[index], + &qmiErrorCode); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf(MSG_ERROR, "eap_proxy: Unable to end the EAP session for " + "client %d; error_ret=%d; error_code=%d\n", + index+1, qmiRetCode, + qmiErrorCode); + } else { + wpa_printf(MSG_ERROR, "eap_proxy: Ended the QMI EAP session for " + "client %d\n", + index+1); + eap_auth_session_flag[index] = FALSE; + } + } else { + wpa_printf (MSG_ERROR, "eap_proxy: session not started for client = %d\n", index+1); + continue; + } + + if (TRUE == qmi_uim_svc_client_initialized[index]) { + qmiRetCode = qmi_client_release(wpa_uim[index].qmi_uim_svc_client_ptr); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf (MSG_ERROR, "Unable to Releas the connection" + " to a service for client=%d; error_ret=%d\n;", + index+1, qmiRetCode); + } + + qmiRetCode = qmi_eap_srvc_release_client(eap_proxy->qmihandle[index], + &qmiErrorCode); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf (MSG_ERROR, "Unable to release the QMI EAP" + "service client = %d; error_ret=%d;" + "error_code=%d\n\n", index+1, qmiRetCode, + qmiErrorCode); + } else { + wpa_printf(MSG_ERROR, "Released QMI EAP service client\n"); + qmi_uim_svc_client_initialized[index] = FALSE; + } + } else { + wpa_printf (MSG_ERROR, "eap_proxy: Service client %d is not initilaized\n", index+1); + continue; + } + } + + if (NULL != eap_proxy->key) + os_free(eap_proxy->key); + + /* Release QMI */ + qmi_release(eap_proxy_qmi_init_handle); + + eap_proxy->iskey_valid = FALSE; + eap_proxy->is_state_changed = FALSE; + eap_proxy->user_selected_sim = 0; + + os_free(eap_proxy); + eap_proxy = NULL; + wpa_printf(MSG_INFO, "eap_proxy Deinitialzed\n"); +} + +/* Call-back function to process an authentication result indication +* from QMI EAP service */ +static void handle_qmi_eap_ind +( + int userHandle, qmi_service_id_type serviceId, + void *userData, qmi_eap_indication_id_type indId, + qmi_eap_indication_data_type *indData +) +{ + struct eap_proxy_sm *sm = (struct eap_proxy_sm *)userData; + wpa_printf(MSG_ERROR, "Handle_qmi_eap_ind serviceId =%d indId = %d \n", serviceId , indId); + + if (NULL == sm || (QMI_EAP_SERVICE != serviceId)) { + wpa_printf(MSG_ERROR, "Bad param: serviceId=%d\n", serviceId); + return; + } + + wpa_printf(MSG_ERROR, "eap_proxy: user_selected_sim = %d\n", sm->user_selected_sim+1); + wpa_printf(MSG_ERROR, "eap_proxy: qmihandle = %d\n", sm->qmihandle[sm->user_selected_sim]); + wpa_printf(MSG_ERROR, "eap_proxy: from call userHandle = %d\n", userHandle); + if (sm->qmihandle[sm->user_selected_sim] != userHandle) { + wpa_printf(MSG_ERROR, "User handle is invalid: cached=%d;" + " given=%d\n", + sm->qmihandle[sm->user_selected_sim], userHandle); + return; + } + + switch (indId) { + case QMI_EAP_SRVC_INVALID_IND_MSG: + sm->srvc_result = EAP_PROXY_QMI_SRVC_FAILURE; + break; + + case QMI_EAP_SRVC_SESSION_RESULT_IND_MSG: + if (NULL != indData) { + if ((indData->auth_result == QMI_EAP_AUTHENTICATION_SUCCESS) && + (QMI_STATE_RESP_TIME_OUT != sm->qmi_state)) { + sm->proxy_state = EAP_PROXY_AUTH_SUCCESS; + sm->qmi_state = QMI_STATE_RESP_RECEIVED; + wpa_printf(MSG_ERROR, "Handle_qmi_eap_ind EAP PROXY AUTH SUCCESS \n"); + } else { + sm->proxy_state = EAP_PROXY_AUTH_FAILURE; + wpa_printf(MSG_ERROR, "Handle_qmi_eap_ind EAP PROXY AUTH FAILURE \n"); + } + sm->srvc_result = EAP_PROXY_QMI_SRVC_SUCCESS; + } else { + wpa_printf(MSG_ERROR, "Receving a NULL auth result\n"); + sm->srvc_result = EAP_PROXY_QMI_SRVC_FAILURE; + sm->proxy_state = EAP_PROXY_AUTH_FAILURE; + } + break; + + default: + wpa_printf(MSG_ERROR, "An unexpected indication Id=%d" + " is given\n", indId); + break; + } + return; +} + + +/* Call-back function to process an EAP response from QMI EAP service */ +static void handle_qmi_eap_reply( + int userHandle, qmi_service_id_type serviceId, int sysErrCode, + int qmiErrCode, void *userData, qmi_eap_async_rsp_id_type rspId, + qmi_eap_async_rsp_data_type *rspData +) +{ + struct eap_proxy_sm *eap_proxy = (struct eap_proxy_sm *)userData; + u8 *resp_data; + u32 length; + + if (QMI_STATE_RESP_PENDING == eap_proxy->qmi_state) { + if (NULL == eap_proxy || QMI_EAP_SERVICE != serviceId || + QMI_EAP_SEND_EAP_PKT_RSP_ID != rspId) { + wpa_printf(MSG_ERROR, "Bad Param: serviceId=%d;" + " rspId=%d\n", serviceId, rspId); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + return; + } + + wpa_printf(MSG_ERROR, "eap_proxy: user_selected_sim = %d\n", eap_proxy->user_selected_sim+1); + wpa_printf(MSG_ERROR, "eap_proxy: qmihandle = %d\n", + eap_proxy->qmihandle[eap_proxy->user_selected_sim]); + wpa_printf(MSG_ERROR, "eap_proxy: from call userHandle = %d\n", userHandle); + if (eap_proxy->qmihandle[eap_proxy->user_selected_sim] != userHandle) { + wpa_printf(MSG_ERROR, "User handle is invalid:" + " cached=%d; given=%d\n", + eap_proxy->qmihandle[eap_proxy->user_selected_sim], + userHandle); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + return; + } + + if (QMI_NO_ERR != sysErrCode) { + wpa_printf(MSG_ERROR, "An error is encountered with" + " the request: sysErrorCode=%d; qmiErrCode=%d\n", + sysErrCode, qmiErrCode); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + return; + } + + if (NULL == rspData) { + wpa_printf(MSG_ERROR, "Response data is NULL\n"); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + return; + } + + /* ensure the reply packet exists */ + if (!rspData->eap_send_pkt_resp.resp_data) { + wpa_printf(MSG_ERROR, "Reply packet is NULL\n"); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + return; + } + + length = rspData->eap_send_pkt_resp.length; + eap_proxy->qmi_resp_data.eap_send_pkt_resp.length = length; +/* allocate a buffer to store the response data; size is EAP resp len field */ + eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data = + os_malloc(rspData->eap_send_pkt_resp.length); + + resp_data = + (u8 *)eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data; + + if (NULL == resp_data) { + wpa_printf(MSG_ERROR, "Unable to allocate memory for" + " reply packet\n"); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + + return; + } + + /* copy the response data to the allocated buffer */ + os_memcpy(resp_data, + rspData->eap_send_pkt_resp.resp_data, length); + eap_proxy->qmi_state = QMI_STATE_RESP_RECEIVED; + wpa_printf(MSG_ERROR, "*****************HANDLE_QMI_EAP_REPLY CALLBACK ENDDED ********************* "); + + wpa_printf(MSG_ERROR, "Dump Resp Data len %d\n", length); + dump_buff(resp_data, length); + + } + return; +} + +static enum eap_proxy_status eap_proxy_process(struct eap_proxy_sm *eap_proxy, + u8 *eapReqData, int eapReqDataLen, struct eap_sm *eap_sm) +{ + struct eap_hdr *hdr; + int qmiErrorCode; + enum eap_proxy_status proxy_status = EAP_PROXY_SUCCESS; + + hdr = (struct eap_hdr *)eapReqData; + if ((EAP_CODE_REQUEST == hdr->code) && + (EAP_TYPE_IDENTITY == eapReqData[4])) { + if (eap_proxy_eapol_sm_get_bool(eap_proxy, EAPOL_eapRestart) && + eap_proxy_eapol_sm_get_bool(eap_proxy, EAPOL_portEnabled)) { + wpa_printf (MSG_ERROR, "eap_proxy: Already Authenticated. " + "Clear all the flags"); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapSuccess, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapFail, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapResp, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapNoResp, FALSE); + if (eap_proxy->key) { + os_free(eap_proxy->key); + eap_proxy->key = NULL; + } + eap_proxy->iskey_valid = FALSE; + eap_proxy->is_state_changed = TRUE; + } + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapRestart, FALSE); + + if(eap_proxy_build_identity(eap_proxy, hdr->identifier, eap_sm)) { + eap_proxy->proxy_state = EAP_PROXY_IDENTITY; + } + else { + wpa_printf(MSG_ERROR, "Error in build identity\n"); + return EAP_PROXY_FAILURE; + } + } + wpa_printf(MSG_ERROR, "Dump ReqData len %d\n", eapReqDataLen); + dump_buff(eapReqData, eapReqDataLen); + + wpa_printf(MSG_ERROR, "eap_proxy: SIM selected by User: Selected sim = %d\n", eap_proxy->user_selected_sim+1); + if (eap_proxy->qmi_state != QMI_STATE_IDLE) { + wpa_printf(MSG_ERROR, "Error in QMI state=%d\n", + eap_proxy->qmi_state); + return EAP_PROXY_FAILURE; + } + + eap_proxy->qmi_state = QMI_STATE_RESP_PENDING; + + eap_proxy->qmiTransactionId = qmi_eap_auth_send_eap_packet( + eap_proxy->qmihandle[eap_proxy->user_selected_sim], + &handle_qmi_eap_reply, eap_proxy, + eapReqData, eapReqDataLen, &qmiErrorCode); + + if (0 <= eap_proxy->qmiTransactionId) { + wpa_printf (MSG_ERROR, "eap_proxy: In eap_proxy_process case %d\n", hdr->code); + switch (hdr->code) { + case EAP_CODE_SUCCESS: + if (EAP_PROXY_SUCCESS != + eap_proxy_qmi_response_wait(eap_proxy)) { + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + return EAP_PROXY_FAILURE; + } else if( eap_proxy->proxy_state == EAP_PROXY_AUTH_SUCCESS ) { + eap_proxy_getKey(eap_proxy); + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapSuccess, TRUE); + /* + * RFC 4137 does not clear eapReq here, but this seems to be required + * to avoid processing the same request twice when state machine is + * initialized. + */ + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapReq, FALSE); + + /* + * RFC 4137 does not set eapNoResp here, but this seems to be required + * to get EAPOL Supplicant backend state machine into SUCCESS state. In + * addition, either eapResp or eapNoResp is required to be set after + * processing the received EAP frame. + */ + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + + wpa_msg(eap_proxy->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS + "EAP authentication completed successfully"); + + eap_proxy->is_state_changed = TRUE; + + /* Retrieve the keys and store*/ + } else if( eap_proxy->proxy_state == EAP_PROXY_AUTH_FAILURE ){ + + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapFail, TRUE); + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapReq, FALSE); + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + eap_proxy->is_state_changed = TRUE; + + } + + break; + + case EAP_CODE_FAILURE: + wpa_printf (MSG_ERROR, "in eap_proxy_process case EAP_CODE_FAILURE\n"); + eap_proxy->proxy_state = EAP_PROXY_AUTH_FAILURE; + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapFail, TRUE); + + /* + * RFC 4137 does not clear eapReq here, but this seems to be required + * to avoid processing the same request twice when state machine is + * initialized. + */ + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapReq, FALSE); + + /* + * RFC 4137 does not set eapNoResp here. However, either eapResp or + * eapNoResp is required to be set after processing the received EAP + * frame. + */ + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + + wpa_msg(eap_proxy->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE + "EAP authentication failed"); + + eap_proxy->is_state_changed = TRUE; + break; + + case EAP_CODE_REQUEST: + eap_proxy->proxy_state = EAP_PROXY_SEND_RESPONSE; + if (EAP_PROXY_SUCCESS != + eap_proxy_qmi_response_wait(eap_proxy)) { + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + return EAP_PROXY_FAILURE; + } else { + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapResp, TRUE); + eap_proxy->proxy_state = + EAP_PROXY_SEND_RESPONSE; + } + + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapReq, FALSE); + eap_proxy->is_state_changed = TRUE; + break; + + default: + wpa_printf(MSG_ERROR, "Error in sending EAP packet;" + " error_code=%d\n", qmiErrorCode); + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + eap_proxy_eapol_sm_set_bool(eap_proxy, + EAPOL_eapNoResp, TRUE); + return EAP_PROXY_FAILURE; + } + } else { + wpa_printf(MSG_ERROR, "Error in sending EAP packet;" + " error_code=%d\n", qmiErrorCode); + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapNoResp, TRUE); + return EAP_PROXY_FAILURE; + } + + return EAP_PROXY_SUCCESS; +} + + + +static u8 *eap_proxy_getKey(struct eap_proxy_sm *eap_proxy) +{ + int qmiErrorCode; + int qmiRetCode; + + if (NULL == eap_proxy->key) + eap_proxy->key = os_malloc(EAP_PROXY_KEYING_DATA_LEN); + + if (NULL == eap_proxy->key) + return NULL; + + qmiRetCode = qmi_eap_auth_get_session_keys(eap_proxy->qmihandle[eap_proxy->user_selected_sim], + eap_proxy->key, EAP_PROXY_KEYING_DATA_LEN, &qmiErrorCode); + + /* see if the MSK is acquired successfully */ + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf(MSG_ERROR, "Unable to get session keys;" + " qmiErrorCode=%d", qmiErrorCode); + os_free(eap_proxy->key); + return NULL; + } + eap_proxy->iskey_valid = TRUE; + eap_proxy->proxy_state = EAP_PROXY_AUTH_SUCCESS; + + wpa_printf(MSG_ERROR, "eap_proxy_getkey EAP KEYS "); + dump_buff(eap_proxy->key, EAP_PROXY_KEYING_DATA_LEN); + return eap_proxy->key; +} + + +/** + * eap_key_available - Get key availability (eapKeyAvailable variable) + * @sm: Pointer to EAP state machine allocated with eap_sm_init() + * Returns: 1 if EAP keying material is available, 0 if not + */ +int eap_proxy_key_available(struct eap_proxy_sm *sm) +{ + return sm ? sm->iskey_valid : 0; +} + + +static int eap_proxy_is_state_changed(struct eap_proxy_sm *sm) +{ + if (NULL == sm) + return 0; + + if (TRUE == sm->is_state_changed) { + sm->is_state_changed = FALSE; + return 1; + } else { + return 0; + } +} + + +/** + * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine + * @sm: Pointer to EAP state machine allocated with eap_sm_init() + * @len: Pointer to variable that will be set to number of bytes in the key + * Returns: Pointer to the EAP keying data or %NULL on failure + * + * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The + * key is available only after a successful authentication. EAP state machine + * continues to manage the key data and the caller must not change or free the + * returned data. + */ +const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len) +{ + if (sm == NULL || sm->key == NULL) { + *len = 0; + return NULL; + } + + *len = EAP_PROXY_KEYING_DATA_LEN; + return sm->key; +} + +/** + * eap_proxy_get_eapRespData - Get EAP response data + * @sm: Pointer to EAP state machine allocated with eap_sm_init() + * @len: Pointer to variable that will be set to the length of the response + * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure + * + * Fetch EAP response (eapRespData) from the EAP state machine. This data is + * available when EAP state machine has processed an incoming EAP request. The + * EAP state machine does not maintain a reference to the response after this + * function is called and the caller is responsible for freeing the data. + */ +struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *eap_proxy) +{ + struct wpabuf *resp; + int len; +// int i; + + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_get_eapRespData"); + if ( (eap_proxy == NULL) || + (eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data == NULL) + ) + { + return NULL; + } + + len = eap_proxy->qmi_resp_data.eap_send_pkt_resp.length; + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_get_eapRespData len = %d", len); + resp = wpabuf_alloc(len); + if (resp == NULL) { + wpa_printf(MSG_ERROR, "eap_proxy: buf allocation failed\n"); + return NULL; + } + + resp->used = sizeof(struct wpabuf) + len; + os_memcpy(resp->buf, eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data, + len); +/* + for (i = 0; i < len; i++) { + wpa_printf (MSG_ERROR, "%c", resp->buf[i]); + } +*/ + eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data = NULL; + eap_proxy->qmi_resp_data.eap_send_pkt_resp.length = 0; + + return resp; +} + + +static enum eap_proxy_status eap_proxy_qmi_response_wait(struct eap_proxy_sm *eap_proxy) +{ + + int count = 0; + + wpa_printf(MSG_DEBUG, "eap_proxy_qmi_response_wait: Start blocking " + "wait"); + do { + count++; + if (count > QMI_RESP_TIME_OUT / 2) { + wpa_printf(MSG_ERROR, + "eap_proxy_qmi_response_wait " + "!QMI STATE %d TIME_OUT\n", + eap_proxy->qmi_state); + eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT; + break; + } + + os_sleep(0, 2000); + + if ((QMI_STATE_RESP_RECEIVED == eap_proxy->qmi_state) || + (QMI_STATE_RESP_TIME_OUT == eap_proxy->qmi_state)) + break; + } while (1); + + wpa_printf(MSG_DEBUG, "eap_proxy_qmi_response_wait: Wait done after %d " + "iterations: qmi_state=%d", count, + eap_proxy->qmi_state); + + if (QMI_STATE_RESP_TIME_OUT == eap_proxy->qmi_state) { + wpa_printf(MSG_ERROR, "QMI state Response Time out\n"); + eap_proxy->proxy_state = EAP_PROXY_DISCARD; + return EAP_PROXY_FAILURE; + } + eap_proxy->qmi_state = QMI_STATE_IDLE; + + return EAP_PROXY_SUCCESS; +} + + +static void eap_proxy_eapol_sm_set_bool(struct eap_proxy_sm *sm, + enum eapol_bool_var var, Boolean value) +{ + sm->eapol_cb->set_bool(sm->ctx, var, value); +} + + +static Boolean eap_proxy_eapol_sm_get_bool(struct eap_proxy_sm *sm, + enum eapol_bool_var var) +{ + return sm->eapol_cb->get_bool(sm->ctx, var); +} + + +int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm) +{ + if ((sm->proxy_state != EAP_PROXY_INITIALIZE) && + (sm->proxy_state != EAP_PROXY_DISABLED)) { + if (TRUE == sm->isEap) { + if(!eap_proxy_process(sm, sm->eapReqData, + sm->eapReqDataLen,eap_sm)) { + sm->proxy_state = EAP_PROXY_AUTH_FAILURE; + eap_proxy_eapol_sm_set_bool(sm, EAPOL_eapRestart, TRUE); + } + sm->isEap = FALSE; + } + } + return eap_proxy_is_state_changed(sm); +} + + +enum eap_proxy_status +eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData, + int eapReqDataLen) +{ + eap_proxy->eapReqData = eapReqData; + eap_proxy->eapReqDataLen = eapReqDataLen; + eap_proxy->isEap = TRUE; + return EAP_PROXY_SUCCESS; +} + + +static void dump_buff(u8 *buff, int len) +{ + int i ; + + wpa_printf(MSG_ERROR, "---- EAP Buffer----LEN %d\n",len); + for (i = 0; i < len; i++) { + if (0 == i%8) + wpa_printf(MSG_DEBUG, " \n"); + wpa_printf(MSG_ERROR, "0x%x ", buff[i]); + } + return; +} +static char bin_to_hexchar(u8 ch) +{ + if (ch < 0x0a) { + return ch + '0'; + } + return ch + 'a' - 10; +} + +static Boolean eap_proxy_build_identity(struct eap_proxy_sm *eap_proxy, u8 id, struct eap_sm *eap_sm) +{ + struct eap_hdr *resp; + unsigned int len; + u8 identity_len = 0, ret; + u8 imsi_id_len = 0; + int mnc_len = -1; + u8 *pos; + int qmiRetCode; + int qmiErrorCode; + u8 idx = 0, mcc_idx = 0; + unsigned char *identity = NULL; + unsigned char *imsi_identity = NULL; + qmi_eap_auth_start_eap_params_type eap_auth_start; + struct eap_method_type *m; + eap_identity_format_e identity_format = EAP_IDENTITY_ANNONYMOUS; + Boolean simEnabled = FALSE, akaEnabled = FALSE; + struct eap_peer_config *config = eap_get_config(eap_sm); + const char *realm_3gpp = "@wlan.mnc000.mcc000.3gppnetwork.org"; + int sim_num; + + wpa_printf(MSG_ERROR, "eap_proxy: %s\n", __func__); + sim_num = config->sim_num - 1; + eap_auth_start.params_mask = 0; + eap_auth_start.user_id = NULL; + eap_auth_start.user_id_len = 0; + eap_auth_start.eap_meta_id = 0; + eap_auth_start.eap_method_mask = QMI_EAP_METHOD_MASK_UNSET; + m = config->eap_methods; + + if (sim_num >= MAX_NO_OF_SIM_SUPPORTED || sim_num < 0) { + wpa_printf (MSG_ERROR, "eap_proxy: Invalid SIM selected sim by user = %d\n", + sim_num+1); + return FALSE; + } + wpa_printf(MSG_ERROR, "eap_proxy: User selected sim = %d\n", sim_num+1); + + for (idx = 0; m[idx].vendor != EAP_VENDOR_IETF || + m[idx].method != EAP_TYPE_NONE; idx++) { + if (m[idx].method == EAP_TYPE_AKA) { + akaEnabled = TRUE; + eap_auth_start.eap_method_mask |= QMI_EAP_AKA_METHOD_MASK; + wpa_printf(MSG_ERROR, "AKA Enabled\n"); + } else if (m[idx].method == EAP_TYPE_SIM) { + simEnabled = TRUE; + eap_auth_start.eap_method_mask |= QMI_EAP_SIM_METHOD_MASK; + wpa_printf(MSG_ERROR, "SIM Enabled\n"); +#ifdef CONFIG_EAP_PROXY_AKA_PRIME + } else if (m[idx].method == EAP_TYPE_AKA_PRIME) { + eap_auth_start.eap_method_mask |= QMI_EAP_AKA_PRIME_METHOD_MASK; + wpa_printf(MSG_ERROR, "AKA Prime Enabled\n"); +#endif /* CONFIG_EAP_PROXY_AKA_PRIME */ + } + } + + eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_METHOD_MASK_PARAM; + + idx = 0; +#ifdef SIM_AKA_IMSI_RAW_ENABLED + + identity_format = EAP_IDENTITY_IMSI_RAW; + eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM; + wpa_printf(MSG_ERROR, "EAP_IDENTITY_IMSI_RAW selected %d \n", eap_auth_start.user_id_len); + +#else /* SIM_AKA_IMSI_RAW_ENABLED */ + + if (config->identity_len && config->identity != NULL) { + for (idx = 0; idx < config->identity_len; idx++) { + if (config->identity[idx] == 64) { + wpa_printf(MSG_ERROR, "@ found \n"); + mcc_idx = idx; + if ((mcc_idx + 18) > config->identity_len) + mcc_idx = 0; + else { + /* Looking for mnc and mcc pattern */ + if (109 == config->identity[mcc_idx + 6] && + (110 == config->identity[mcc_idx + 7]) && + (99 == config->identity[mcc_idx + 8]) && + (109 == config->identity[mcc_idx + 13]) && + (99 == config->identity[mcc_idx + 14]) && + (99 == config->identity[mcc_idx + 15])) { + mcc_idx += 9; + } else + mcc_idx = 0; + } + break; + } + } + + wpa_printf(MSG_ERROR, "idx %d\n", idx); + wpa_printf(MSG_ERROR, "mcc idx %d\n", mcc_idx); + + if (!idx && (config->identity_len == 1)) { + /* config file : @ */ + config->identity_len = 0; + identity_format = EAP_IDENTITY_IMSI_3GPP_REALM; + wpa_printf(MSG_ERROR, "EAP_IDENTITY_IMSI_3GPP_REALM selected \n"); + } else if (idx && (idx < config->identity_len) && (config->identity != NULL)) { + + /* config file : <>@<> or <>@<wlan.mnc000.mcc000.<>.<> */ + identity_len = config->identity_len; + identity = os_malloc(config->identity_len); + + if (NULL != identity) { + os_memset(identity, 0, config->identity_len); + os_memcpy(identity, config->identity, + config->identity_len); + } + + /* To Do for 3GPP realm */ + identity_format = EAP_IDENTITY_CFG_3GPP_REALM; + eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM; + wpa_printf(MSG_ERROR, "EAP_IDENTITY_CFG_3GPP_REALM selected %d \n", eap_auth_start.user_id_len); + + } else if ((idx == config->identity_len) && config->identity_len && + (config->identity != NULL)) { + + /* config file : <identity in RAW format >*/ + identity_len = config->identity_len; + identity = os_malloc(config->identity_len); + + if (NULL != identity) { + os_memset(identity, 0, config->identity_len); + os_memcpy(identity, config->identity, + config->identity_len); + } + + identity_format = EAP_IDENTITY_CFG_RAW; + eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM; + wpa_printf(MSG_ERROR, "EAP_IDENTITY_CFG_RAW selected %d \n", eap_auth_start.user_id_len); + } else if (!idx && mcc_idx) { + + /* config file: @wlan.mnc000.mcc000.<>.<> */ + identity_len = config->identity_len; + identity = os_malloc(config->identity_len); + + if (NULL != identity) { + os_memset(identity, 0, config->identity_len); + os_memcpy(identity, config->identity, + config->identity_len); + } + + identity_format = EAP_IDENTITY_IMSI_3GPP_REALM; + eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM; + wpa_printf(MSG_ERROR, "config EAP_IDENTITY_IMSI_3GPP_REALM selected %d \n", eap_auth_start.user_id_len); + } + } else { + + if (config->anonymous_identity_len && config->anonymous_identity != NULL) { + + eap_auth_start.eap_meta_id_len = config->anonymous_identity_len; + eap_auth_start.eap_meta_id = os_malloc(config->anonymous_identity_len); + + if (eap_auth_start.eap_meta_id != NULL) { + os_memcpy(eap_auth_start.eap_meta_id , + config->anonymous_identity , + config->anonymous_identity_len); + } + + identity_format = EAP_IDENTITY_ANNONYMOUS; + eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_META_ID_PARAM; + wpa_printf(MSG_ERROR, "EAP_IDENTITY_ANNONYMOUS selected user id %d, annonymous %d\n", + eap_auth_start.user_id_len, eap_auth_start.eap_meta_id_len); + } else { + /* config file doesn't contain any identity + generating IMSI@realm */ + identity_format = EAP_IDENTITY_IMSI_3GPP_REALM; + eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM; + wpa_printf(MSG_ERROR, "EAP_IDENTITY_IMSI_3GPP_REALM id len %d \n", eap_auth_start.user_id_len); + } + } +#endif /* SIM_AKA_IMSI_RAW_ENABLED */ + if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM || + identity_format == EAP_IDENTITY_IMSI_RAW || mcc_idx) { + + wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_IMSI_3GPP_REALM is selected\n"); + if (!wpa_qmi_read_card_status(sim_num)) { + wpa_printf(MSG_INFO, "Read Card Status failed, return\n"); + if (eap_auth_start.eap_meta_id != NULL) + os_free(eap_auth_start.eap_meta_id); + if (eap_auth_start.user_id != NULL) + os_free(eap_auth_start.user_id); + if (NULL != identity) { + os_free(identity); + identity = NULL; + } + return FALSE; + } + + if (!wpa_qmi_read_card_imsi(sim_num)) { + wpa_printf(MSG_INFO, "Read Card IMSI failed, return\n"); + if (eap_auth_start.eap_meta_id != NULL) + os_free(eap_auth_start.eap_meta_id); + if (eap_auth_start.user_id != NULL) + os_free(eap_auth_start.user_id); + if (NULL != identity) { + os_free(identity); + identity = NULL; + } + return FALSE; + } + + if (imsi == NULL) { + wpa_printf(MSG_INFO, "IMSI not available, return\n"); + if (eap_auth_start.eap_meta_id != NULL) + os_free(eap_auth_start.eap_meta_id); + if (eap_auth_start.user_id != NULL) + os_free(eap_auth_start.user_id); + if (NULL != identity) { + os_free(identity); + identity = NULL; + } + return FALSE; + } else { + wpa_printf(MSG_ERROR, "IMSI not NULL \n"); + if (NULL == identity) + wpa_printf(MSG_ERROR, "config file doesn't contain identity \n"); + else + wpa_printf(MSG_ERROR, "config file contains identity \n"); + + wpa_printf(MSG_ERROR, "eap_type: %d\n", eap_proxy->eap_type); + + if (!idx) { + + /* IMSI is expected as username */ + wpa_printf(MSG_ERROR, " username is not available in config picking IMSI \n"); + + if (config->identity_len > 1) + /* @realm provided in config */ + imsi_identity = os_malloc(1 + IMSI_LENGTH + config->identity_len); + else if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM) + /* IMSI@realm not provided through config */ + imsi_identity = os_malloc(1 + IMSI_LENGTH + os_strlen(realm_3gpp)); + else + /* IMSI RAW */ + imsi_identity = os_malloc(1 + IMSI_LENGTH); + + if (NULL == imsi_identity) { + wpa_printf(MSG_ERROR, "Memory not available\n"); + if (eap_auth_start.eap_meta_id != NULL) + os_free(eap_auth_start.eap_meta_id); + if (eap_auth_start.user_id != NULL) + os_free(eap_auth_start.user_id); + if (NULL != identity) { + os_free(identity); + identity = NULL; + } + return FALSE; + } else { + if (config->identity_len > 1) + os_memset(imsi_identity, 0, (1 + IMSI_LENGTH + config->identity_len)); + else if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM) + os_memset(imsi_identity, 0, (1 + IMSI_LENGTH + os_strlen(realm_3gpp))); + else + os_memset(imsi_identity, 0, (1 + IMSI_LENGTH)); + + if (eap_proxy->eap_type == EAP_TYPE_SIM) + imsi_identity[0] = '1'; + else if (eap_proxy->eap_type == EAP_TYPE_AKA) + imsi_identity[0] = '0'; +#ifdef CONFIG_EAP_PROXY_AKA_PRIME + else if (eap_proxy->eap_type == EAP_TYPE_AKA_PRIME) + imsi_identity[0] = '6'; +#endif /* CONFIG_EAP_PROXY_AKA_PRIME */ + else + /* Default value is set as SIM */ + imsi_identity[0] = '1'; + + /* copying IMSI value */ + os_memcpy(imsi_identity + 1 , imsi , imsi_len_g); + + if (config->identity_len > 1 && NULL != identity) { + /* copying realm tag */ + os_memcpy(imsi_identity + 1 + imsi_len_g , identity , config->identity_len); + imsi_id_len = imsi_len_g + 1 + config->identity_len; + os_free(identity); + identity = NULL; + } else if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM) { + /* realm is not available so append it */ + os_memcpy(imsi_identity + 1 + imsi_len_g , realm_3gpp, os_strlen(realm_3gpp)); + imsi_id_len = imsi_len_g + 1 + os_strlen(realm_3gpp); + } else + /* IMSI RAW */ + imsi_id_len = imsi_len_g + 1; + } + } else { + /* idx is non-zero implies username available */ + imsi_identity = identity; + imsi_id_len = config->identity_len; + } + } + + if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM || mcc_idx) { + + if (0 == idx) { + /* id = @wlan.mnc000.mcc000.<>.<> realm exist + but need to insert mnc and mcc values */ + idx = imsi_len_g + 1; + } + + /* mcc valus */ + imsi_identity[idx + 16] = imsi[0]; + imsi_identity[idx + 17] = imsi[1]; + imsi_identity[idx + 18] = imsi[2]; + + /* mnc valus */ + mnc_len = card_mnc_len; + wpa_printf(MSG_ERROR, "card mnc len %d\n", card_mnc_len); + + if (mnc_len < 0) { + wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM " + "assuming 3 in build_id"); + mnc_len = 3; + } + + if (mnc_len == 2) { + imsi_identity[idx + 9] = '0'; + imsi_identity[idx + 10] = imsi[3]; + imsi_identity[idx + 11] = imsi[4]; + } else if (mnc_len == 3) { + imsi_identity[idx + 9] = imsi[3]; + imsi_identity[idx + 10] = imsi[4]; + imsi_identity[idx + 11] = imsi[5]; + } + wpa_printf(MSG_ERROR, " Appending 3gpp realm\n "); + } + identity = imsi_identity; + identity_len = imsi_id_len; + eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM; + } + + eap_auth_start.user_id_len = identity_len; + eap_auth_start.user_id = identity; + eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM; + + wpa_printf(MSG_ERROR, " eap auth user identity - %20s length-%d\n ", + eap_auth_start.user_id, eap_auth_start.user_id_len); + + if ( (sim_num < 0) || (sim_num >= MAX_NO_OF_SIM_SUPPORTED)) { + wpa_printf(MSG_ERROR, "eap_proxy: SIM: Invalid SIM selected by " + "User: Selected sim = %d\n", sim_num+1); + return FALSE; + } + + if (0 >= eap_proxy->qmihandle[sim_num]) { + wpa_printf(MSG_ERROR, "eap_proxy: Failed to get the qmihandle " + "(value = %d) for the Sim %d\n", + eap_proxy->qmihandle[sim_num], sim_num+1); + return FALSE; + } + + eap_proxy->user_selected_sim = sim_num; + wpa_printf(MSG_ERROR, "eap_proxy: SIM selected by User: Selected sim = %d\n", + eap_proxy->user_selected_sim+1); + wpa_printf (MSG_ERROR, "eap_proxy: in eap_proxy_build_identity qmihandle[%d] = %d\n", + sim_num, eap_proxy->qmihandle[sim_num]); +#ifdef CONFIG_EAP_PROXY_DUAL_SIM + if (sim_num == 0) { + qmiRetCode = qmi_auth_set_subscription_binding(eap_proxy->qmihandle[sim_num], + QMI_AUTH_SUBS_TYPE_PRIMARY, + &qmiErrorCode); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf(MSG_ERROR, "Unable to get the qmi_auth_set_subscription_binding for" + " sim 1; error_ret=%d; error_code=%d\n", qmiRetCode, + qmiErrorCode); + return FALSE; + } + wpa_printf (MSG_ERROR, "Binded with PRIMARY Subscription\n"); + } else if (sim_num == 1) { + qmiRetCode = qmi_auth_set_subscription_binding(eap_proxy->qmihandle[sim_num], + QMI_AUTH_SUBS_TYPE_SECONDARY, + &qmiErrorCode); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf(MSG_ERROR, "Unable to get the qmi_auth_bind_subscription for sim 2;" + " error_ret=%d; error_code=%d\n", qmiRetCode, + qmiErrorCode); + return FALSE; + } + wpa_printf (MSG_ERROR, "Binded with SECONDARY Subscription\n"); + } else { + wpa_printf(MSG_ERROR, "Invalid SIM selected by User: Selected sim = %d\n", sim_num+1); + return FALSE; + } +#endif + if (TRUE == eap_auth_session_flag[sim_num]) { + if (eap_proxy->qmihandle[sim_num] != 0) { + qmiRetCode = qmi_eap_auth_end_eap_session(eap_proxy->qmihandle[sim_num], + &qmiErrorCode); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf(MSG_ERROR, "Unable to end the EAP session;" + " error_ret=%d; error_code=%d\n", qmiRetCode, + qmiErrorCode); + } + eap_auth_session_flag[sim_num] = FALSE; + } + } + + if (FALSE == eap_auth_session_flag[sim_num]) { + if (eap_proxy->qmihandle[sim_num] != 0) { + wpa_printf(MSG_ERROR, "eap_proxy: qmihandle[%d] = %d\n", sim_num, eap_proxy->qmihandle[sim_num]); + wpa_printf(MSG_ERROR, "eap_auth_start values\n"); + wpa_printf(MSG_ERROR, "eap_auth_start.eap_method_mask = %ld\n", eap_auth_start.eap_method_mask); + wpa_printf(MSG_ERROR, "eap_auth_start.user_id_len = %d\n", eap_auth_start.user_id_len); + wpa_printf(MSG_ERROR, "eap_auth_start.eap_meta_id_len = %d\n", eap_auth_start.eap_meta_id_len); + wpa_printf(MSG_ERROR, "eap_auth_start.eap_sim_aka_algo = %d\n", eap_auth_start.eap_sim_aka_algo); + qmiRetCode = qmi_eap_auth_start_eap_session_ex(eap_proxy->qmihandle[sim_num], + &eap_auth_start, &qmiErrorCode); + if (QMI_NO_ERR != qmiRetCode) { + wpa_printf(MSG_ERROR, "Unable to start the EAP session;" + " error_ret=%d; error_code=%d\n", qmiRetCode, + qmiErrorCode); + return FALSE; + } + eap_auth_session_flag[sim_num] = TRUE; + eap_proxy->qmi_state = QMI_STATE_IDLE; + if (NULL != eap_auth_start.user_id) { + os_free (eap_auth_start.user_id); + eap_auth_start.user_id = NULL; + } + if (NULL != eap_auth_start.eap_meta_id) { + os_free (eap_auth_start.eap_meta_id); + eap_auth_start.eap_meta_id = NULL; + } + wpa_printf(MSG_ERROR, "EAP session started" + " error_ret=%d; error_code=%d\n", qmiRetCode, + qmiErrorCode); + } + } + + return TRUE; +} + + + +#ifdef CONFIG_CTRL_IFACE + +/** + * eap_proxyl_sm_get_status - Get EAP state machine status + * @sm: Pointer to EAP state machine allocated with eap_sm_init() + * @buf: Buffer for status information + * @buflen: Maximum buffer length + * @verbose: Whether to include verbose status information + * Returns: Number of bytes written to buf. + * + * Query EAP state machine for status information. This function fills in a + * text area with current status information from the EAPOL state machine. If + * the buffer (buf) is not large enough, status information will be truncated + * to fit the buffer. + */ +int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen, + int verbose) +{ + int len, ret; + + if (sm == NULL) + return 0; + + len = os_snprintf(buf, buflen, "EAP state=%s\n", + eap_proxy_sm_state_txt(sm->proxy_state)); + if (len < 0 || (size_t)len >= buflen) + return 0; + + if (sm->eap_type != EAP_TYPE_NONE) { + char name[8] = "Unknown"; + + if (sm->eap_type == EAP_TYPE_SIM) + os_strncpy(name, "SIM", 4); + else if (sm->eap_type == EAP_TYPE_AKA) + os_strncpy(name, "AKA", 4); + + ret = os_snprintf(buf + len, buflen - len, + "selectedMethod=%d (EAP-%s)\n", + sm->eap_type, name); + if (ret < 0 || (size_t)ret >= buflen - len) + return len; + len += ret; + } + + return len; +} + + +static const char *eap_proxy_sm_state_txt(int state) +{ + switch (state) { + case EAP_PROXY_INITIALIZE: + return "INITIALIZE"; + case EAP_PROXY_DISABLED: + return "DISABLED"; + case EAP_PROXY_IDLE: + return "IDLE"; + case EAP_PROXY_RECEIVED: + return "RECEIVED"; + case EAP_PROXY_GET_METHOD: + return "GET_METHOD"; + case EAP_PROXY_METHOD: + return "METHOD"; + case EAP_PROXY_SEND_RESPONSE: + return "SEND_RESPONSE"; + case EAP_PROXY_DISCARD: + return "DISCARD"; + case EAP_PROXY_IDENTITY: + return "IDENTITY"; + case EAP_PROXY_NOTIFICATION: + return "NOTIFICATION"; + case EAP_PROXY_RETRANSMIT: + return "RETRANSMIT"; + case EAP_PROXY_AUTH_SUCCESS: + return "SUCCESS"; + case EAP_PROXY_AUTH_FAILURE: + return "FAILURE"; + default: + return "UNKNOWN"; + } +} +#endif /* CONFIG_CTRL_IFACE */ + + +/** + * eap_proxy_get_mcc_mnc - Get MCC/MNC + * @imsi_buf: Buffer for returning IMSI + * @imsi_len: Buffer for returning IMSI length + * Returns: MNC length (2 or 3) or -1 on error + */ +int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf, + size_t *imsi_len) +{ +#ifdef SIM_AKA_IDENTITY_IMSI + int mnc_len; + int sim_num = eap_proxy->user_selected_sim; + + if (!wpa_qmi_read_card_status(sim_num)) { + wpa_printf(MSG_INFO, "eap_proxy: Card not ready"); + return -1; + } + + if (!wpa_qmi_read_card_imsi(sim_num) || imsi == NULL) { + wpa_printf(MSG_INFO, "eap_proxy: Failed to read card IMSI"); + return -1; + } + + *imsi_len = os_strlen(imsi); + os_memcpy(imsi_buf, imsi, *imsi_len + 1); + + mnc_len = card_mnc_len; + if (mnc_len < 2 || mnc_len > 3) + mnc_len = 3; /* Default to 3 if MNC length is unknown */ + + os_free(imsi); + imsi = NULL; + + return mnc_len; +#else /* SIM_AKA_IDENTITY_IMSI */ + return -1; +#endif /* SIM_AKA_IDENTITY_IMSI */ +} + +int eap_proxy_notify_config(struct eap_proxy_sm *eap_proxy, + struct eap_peer_config *config) +{ + int ret_val; + + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_notify_config\n"); + if (!eap_proxy) { + wpa_printf(MSG_ERROR, "eap_proxy: is NULL"); + return -1; + } + + if ( config && eap_proxy_allowed_method(config, EAP_VENDOR_IETF, + EAP_TYPE_SIM)) { + eap_proxy->eap_type = EAP_TYPE_SIM; + ret_val = TRUE; + } else if ( config && eap_proxy_allowed_method(config, EAP_VENDOR_IETF, + EAP_TYPE_AKA)) { + eap_proxy->eap_type = EAP_TYPE_AKA; + ret_val = TRUE; + } else if ( config && eap_proxy_allowed_method(config, EAP_VENDOR_IETF, + EAP_TYPE_AKA_PRIME)) { + eap_proxy->eap_type = EAP_TYPE_AKA_PRIME; + ret_val = TRUE; + } else + ret_val = FALSE; + + return ret_val; +} + +int eap_proxy_allowed_method (struct eap_peer_config *config, int vendor, + u32 method) +{ + int i; + struct eap_method_type *m; + + wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_allowed_method"); + if (config == NULL || config->eap_methods == NULL) + return -1; + + m = config->eap_methods; + for (i = 0; m[i].vendor != EAP_VENDOR_IETF || + m[i].method != EAP_TYPE_NONE; i++) { + if (m[i].vendor == vendor && m[i].method == method) + return 1; + } + return 0; +} + +#endif /* CONFIG_EAP_PROXY */ diff --git a/src/eap_peer/eap_proxy_qmi.h b/src/eap_peer/eap_proxy_qmi.h new file mode 100644 index 00000000..afe83be9 --- /dev/null +++ b/src/eap_peer/eap_proxy_qmi.h @@ -0,0 +1,112 @@ +/*-------------------------------------------------------------------------- +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------*/ + +#ifndef EAP_PROXY_QMI_H +#define EAP_PROXY_QMI_H + + +#include "eap_i.h" +#include "eap_config.h" +#include "eloop.h" +#include "qmi.h" +#include "qmi_eap_srvc.h" +#include "eapol_supp_sm.h" + +/*msec Response Timeout*/ +#define QMI_RESP_TIME_OUT 650 +#define EAP_PROXY_KEYING_DATA_LEN 64 + +#ifdef CONFIG_EAP_PROXY_DUAL_SIM +#define MAX_NO_OF_SIM_SUPPORTED 2 +#else +#define MAX_NO_OF_SIM_SUPPORTED 1 +#endif /* CONFIG_EAP_PROXY_DUAL_SIM */ + +typedef enum { + QMI_STATE_IDLE = 0x00, + QMI_STATE_RESP_PENDING = 0x01, + QMI_STATE_RESP_RECEIVED = 0x02, + QMI_STATE_RESP_TIME_OUT = 0x03 +} qmi_state_e; + +typedef enum { + EAP_PROXY_QMI_SRVC_NO_RESULT, + EAP_PROXY_QMI_SRVC_SUCCESS, + EAP_PROXY_QMI_SRVC_FAILURE +} eap_proxy_qmi_srv_result; + +/* should match the EAP_state of eap_i.h */ +typedef enum { + EAP_PROXY_INITIALIZE, EAP_PROXY_DISABLED, EAP_PROXY_IDLE, EAP_PROXY_RECEIVED, + EAP_PROXY_GET_METHOD, EAP_PROXY_METHOD, EAP_PROXY_SEND_RESPONSE, + EAP_PROXY_DISCARD, EAP_PROXY_IDENTITY, EAP_PROXY_NOTIFICATION, + EAP_PROXY_RETRANSMIT, + EAP_PROXY_AUTH_SUCCESS, EAP_PROXY_AUTH_FAILURE +} eap_proxy_state; + + +enum eap_proxy_status { + EAP_PROXY_FAILURE = 0x00, + EAP_PROXY_SUCCESS +}; + +typedef enum { + EAP_IDENTITY_ANNONYMOUS = 0x00, + EAP_IDENTITY_IMSI_RAW = 0x02, + EAP_IDENTITY_IMSI_3GPP_REALM = 0x03, + EAP_IDENTITY_IMSI_REALM = 0x04, + EAP_IDENTITY_CFG_RAW = 0x05, + EAP_IDENTITY_CFG_3GPP_REALM = 0x06, + EAP_IDENTITY_CFG_REALM = 0x07, +} eap_identity_format_e; + +struct eap_proxy_sm { + int qmihandle[MAX_NO_OF_SIM_SUPPORTED]; + int qmiTransactionId; + qmi_state_e qmi_state; + eap_proxy_qmi_srv_result srvc_result; + qmi_eap_async_rsp_data_type qmi_resp_data; + eap_proxy_state proxy_state; + Boolean iskey_valid; + u8 *key; + Boolean is_state_changed; + void *ctx; + void *msg_ctx; + struct eapol_callbacks *eapol_cb; + u8 *eapReqData; + size_t eapReqDataLen; + Boolean isEap; + int eap_type; + int user_selected_sim; +}; + +int eap_proxy_allowed_method(struct eap_peer_config *config, int vendor, + u32 method); + +#endif /* EAP_PROXY_QMI_H */ diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 160dfc20..3e5dc8c2 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -70,6 +70,8 @@ int p2p_connection_in_progress(struct p2p_data *p2p) wpa_printf(MSG_DEBUG, "p2p_connection_in_progress state %d", p2p->state); ret = 0; } + if (p2p->pending_action_state == P2P_PENDING_PD) + ret = 1; return ret; } @@ -86,6 +88,15 @@ static void p2p_expire_peers(struct p2p_data *p2p) if (dev->last_seen.sec + P2P_PEER_EXPIRATION_AGE >= now.sec) continue; + if (dev == p2p->go_neg_peer) { + /* + * GO Negotiation is in progress with the peer, so + * don't expire the peer entry until GO Negotiation + * fails or times out. + */ + continue; + } + if (p2p->cfg->go_connected && p2p->cfg->go_connected(p2p->cfg->cb_ctx, dev->info.p2p_device_addr)) { @@ -3239,13 +3250,13 @@ static void p2p_timeout_connect_listen(struct p2p_data *p2p) static void p2p_timeout_wait_peer_connect(struct p2p_data *p2p) { - /* - * TODO: could remain constantly in Listen state for some time if there - * are no other concurrent uses for the radio. For now, go to listen - * state once per second to give other uses a chance to use the radio. - */ p2p_set_state(p2p, P2P_WAIT_PEER_IDLE); - p2p_set_timeout(p2p, 0, 500000); + + if (p2p->cfg->is_concurrent_session_active && + p2p->cfg->is_concurrent_session_active(p2p->cfg->cb_ctx)) + p2p_set_timeout(p2p, 0, 500000); + else + p2p_set_timeout(p2p, 0, 200000); } @@ -3362,7 +3373,7 @@ static void p2p_timeout_invite_listen(struct p2p_data *p2p) p2p->cfg->invitation_result( p2p->cfg->cb_ctx, -1, NULL, NULL, p2p->invite_peer->info.p2p_device_addr, - 0); + 0, 0); } p2p_set_state(p2p, P2P_IDLE); } diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index c6e5c94e..5e729fbd 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -743,6 +743,8 @@ struct p2p_config { * @channels: Available operating channels for the group * @addr: Peer address * @freq: Frequency (in MHz) indicated during invitation or 0 + * @peer_oper_freq: Operating frequency (in MHz) advertized by the peer + * during invitation or 0 * * This callback is used to indicate result of an Invitation procedure * started with a call to p2p_invite(). The indicated status code is @@ -752,7 +754,7 @@ struct p2p_config { */ void (*invitation_result)(void *ctx, int status, const u8 *bssid, const struct p2p_channels *channels, - const u8 *addr, int freq); + const u8 *addr, int freq, int peer_oper_freq); /** * go_connected - Check whether we are connected to a GO @@ -762,6 +764,15 @@ struct p2p_config { * or 0 if not. */ int (*go_connected)(void *ctx, const u8 *dev_addr); + + /** + * is_concurrent_session_active - Check whether concurrent session is + * active on other virtual interfaces + * @ctx: Callback context from cb_ctx + * Returns: 1 if concurrent session is active on other virtual interface + * or 0 if not. + */ + int (*is_concurrent_session_active)(void *ctx); }; diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 17fb3293..1a7c8d76 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -587,8 +587,21 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, if (dev == NULL) dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg); - else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) + else if ((dev->flags & P2P_DEV_PROBE_REQ_ONLY) || + !(dev->flags & P2P_DEV_REPORTED)) p2p_add_dev_info(p2p, sa, dev, &msg); + else if (!dev->listen_freq && !dev->oper_freq) { + /* + * This may happen if the peer entry was added based on PD + * Request and no Probe Request/Response frame has been received + * from this peer (or that information has timed out). + */ + p2p_dbg(p2p, "Update peer " MACSTR + " based on GO Neg Req since listen/oper freq not known", + MAC2STR(dev->info.p2p_device_addr)); + p2p_add_dev_info(p2p, sa, dev, &msg); + } + if (dev && dev->flags & P2P_DEV_USER_REJECTED) { p2p_dbg(p2p, "User has rejected this peer"); status = P2P_SC_FAIL_REJECTED_BY_USER; @@ -1077,6 +1090,7 @@ void p2p_process_go_neg_conf(struct p2p_data *p2p, const u8 *sa, return; } dev->flags &= ~P2P_DEV_WAIT_GO_NEG_CONFIRM; + p2p->cfg->send_action_done(p2p->cfg->cb_ctx); if (msg.dialog_token != dev->dialog_token) { p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)", diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index b5a3058e..870f6bee 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -281,7 +281,9 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, } } - if (!p2p_channels_includes(&intersection, p2p->op_reg_class, + /* Reselect the channel only for the case of the GO */ + if (go && + !p2p_channels_includes(&intersection, p2p->op_reg_class, p2p->op_channel)) { p2p_dbg(p2p, "Initially selected channel (op_class %d channel %d) not in channel intersection - try to reselect", p2p->op_reg_class, p2p->op_channel); @@ -296,7 +298,7 @@ void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, status = P2P_SC_FAIL_NO_COMMON_CHANNELS; goto fail; } - } else if (!(dev->flags & P2P_DEV_FORCE_FREQ) && + } else if (go && !(dev->flags & P2P_DEV_FORCE_FREQ) && !p2p->cfg->cfg_op_channel) { p2p_dbg(p2p, "Try to reselect channel selection with peer information received; previously selected op_class %u channel %u", p2p->op_reg_class, p2p->op_channel); @@ -429,13 +431,23 @@ void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, } if (p2p->cfg->invitation_result) { + int peer_oper_freq = 0; int freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel); if (freq < 0) freq = 0; + + if (msg.operating_channel) { + peer_oper_freq = p2p_channel_to_freq( + msg.operating_channel[3], + msg.operating_channel[4]); + if (peer_oper_freq < 0) + peer_oper_freq = 0; + } + p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status, msg.group_bssid, channels, sa, - freq); + freq, peer_oper_freq); } p2p_parse_free(&msg); diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index e911ad0f..17e8225c 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -118,6 +118,7 @@ struct wpa_tdls_peer { u8 action_code; /* TDLS frame type */ u8 dialog_token; u16 status_code; + u32 peer_capab; int buf_len; /* length of TPK message for retransmission */ u8 *buf; /* buffer for TPK message */ } sm_tmr; @@ -136,6 +137,14 @@ struct wpa_tdls_peer { u8 *ext_capab; size_t ext_capab_len; + + u8 *supp_channels; + size_t supp_channels_len; + + u8 *supp_oper_classes; + size_t supp_oper_classes_len; + + u8 wmm_capable; }; @@ -205,15 +214,16 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, size_t len) + u16 status_code, u32 peer_capab, + const u8 *buf, size_t len) { return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token, - status_code, buf, len); + status_code, peer_capab, buf, len); } static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, - u8 dialog_token, u16 status_code, + u8 dialog_token, u16 status_code, u32 peer_capab, const u8 *msg, size_t msg_len) { struct wpa_tdls_peer *peer; @@ -224,7 +234,7 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, (unsigned int) msg_len); if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, - status_code, msg, msg_len)) { + status_code, peer_capab, msg, msg_len)) { wpa_printf(MSG_INFO, "TDLS: Failed to send message " "(action_code=%u)", action_code); return -1; @@ -262,6 +272,7 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, peer->sm_tmr.action_code = action_code; peer->sm_tmr.dialog_token = dialog_token; peer->sm_tmr.status_code = status_code; + peer->sm_tmr.peer_capab = peer_capab; peer->sm_tmr.buf_len = msg_len; os_free(peer->sm_tmr.buf); peer->sm_tmr.buf = os_malloc(msg_len); @@ -318,6 +329,7 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) peer->sm_tmr.action_code, peer->sm_tmr.dialog_token, peer->sm_tmr.status_code, + peer->sm_tmr.peer_capab, peer->sm_tmr.buf, peer->sm_tmr.buf_len)) { wpa_printf(MSG_INFO, "TDLS: Failed to retry " @@ -633,8 +645,14 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) peer->vht_capabilities = NULL; os_free(peer->ext_capab); peer->ext_capab = NULL; + os_free(peer->supp_channels); + peer->supp_channels = NULL; + os_free(peer->supp_oper_classes); + peer->supp_oper_classes = NULL; peer->rsnie_i_len = peer->rsnie_p_len = 0; peer->cipher = 0; + peer->qos_info = 0; + peer->wmm_capable = 0; peer->tpk_set = peer->tpk_success = 0; os_memset(&peer->tpk, 0, sizeof(peer->tpk)); os_memset(peer->inonce, 0, WPA_NONCE_LEN); @@ -737,7 +755,7 @@ skip_ies: /* request driver to send Teardown using this FTIE */ wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, - reason_code, rbuf, pos - rbuf); + reason_code, 0, rbuf, pos - rbuf); os_free(rbuf); /* clear the Peerkey statemachine */ @@ -886,7 +904,7 @@ static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst, " (action=%u status=%u)", MAC2STR(dst), tdls_action, status); return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status, - NULL, 0); + 0, NULL, 0); } @@ -1092,7 +1110,7 @@ skip_ies: MAC2STR(peer->addr)); status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, - 1, 0, rbuf, pos - rbuf); + 1, 0, 0, rbuf, pos - rbuf); os_free(rbuf); return status; @@ -1176,7 +1194,7 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, skip_ies: status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, - dtoken, 0, rbuf, pos - rbuf); + dtoken, 0, 0, rbuf, pos - rbuf); os_free(rbuf); return status; @@ -1194,6 +1212,7 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, struct wpa_tdls_timeoutie timeoutie; u32 lifetime; int status; + u32 peer_capab = 0; buf_len = 0; if (wpa_tdls_get_privacy(sm)) { @@ -1256,9 +1275,16 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p, (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); + if (peer->vht_capabilities) + peer_capab |= TDLS_PEER_VHT; + else if (peer->ht_capabilities) + peer_capab |= TDLS_PEER_HT; + else if (peer->wmm_capable) + peer_capab |= TDLS_PEER_WMM; + skip_ies: status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, - dtoken, 0, rbuf, pos - rbuf); + dtoken, 0, peer_capab, rbuf, pos - rbuf); os_free(rbuf); return status; @@ -1273,7 +1299,7 @@ static int wpa_tdls_send_discovery_response(struct wpa_sm *sm, "(peer " MACSTR ")", MAC2STR(peer->addr)); return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE, - dialog_token, 0, NULL, 0); + dialog_token, 0, 0, NULL, 0); } @@ -1334,7 +1360,7 @@ int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr) wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer " MACSTR, MAC2STR(addr)); return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST, - 1, 0, NULL, 0); + 1, 0, 0, NULL, 0); } @@ -1434,6 +1460,83 @@ static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde, } +static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde, + struct wpa_tdls_peer *peer) +{ + struct wmm_information_element *wmm; + + if (!kde->wmm) { + wpa_printf(MSG_DEBUG, "TDLS: No supported WMM capabilities received"); + return 0; + } + + if (kde->wmm_len < sizeof(struct wmm_information_element)) { + wpa_printf(MSG_DEBUG, "TDLS: Invalid supported WMM capabilities received"); + return -1; + } + + wmm = (struct wmm_information_element *) kde->wmm; + peer->qos_info = wmm->qos_info; + + peer->wmm_capable = 1; + + wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info); + return 0; +} + + +static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde, + struct wpa_tdls_peer *peer) +{ + if (!kde->supp_channels) { + wpa_printf(MSG_DEBUG, "TDLS: No supported channels received"); + return 0; + } + + if (!peer->supp_channels || + peer->supp_channels_len < kde->supp_channels_len) { + os_free(peer->supp_channels); + peer->supp_channels = os_zalloc(kde->supp_channels_len); + if (peer->supp_channels == NULL) + return -1; + } + + peer->supp_channels_len = kde->supp_channels_len; + + os_memcpy(peer->supp_channels, kde->supp_channels, + peer->supp_channels_len); + wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Channels", + (u8 *) peer->supp_channels, peer->supp_channels_len); + return 0; +} + + +static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde, + struct wpa_tdls_peer *peer) +{ + if (!kde->supp_oper_classes) { + wpa_printf(MSG_DEBUG, "TDLS: No supported operating classes received"); + return 0; + } + + if (!peer->supp_oper_classes || + peer->supp_oper_classes_len < kde->supp_oper_classes_len) { + os_free(peer->supp_oper_classes); + peer->supp_oper_classes = os_zalloc(kde->supp_oper_classes_len); + if (peer->supp_oper_classes == NULL) + return -1; + } + + peer->supp_oper_classes_len = kde->supp_oper_classes_len; + os_memcpy(peer->supp_oper_classes, kde->supp_oper_classes, + peer->supp_oper_classes_len); + wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Operating Classes", + (u8 *) peer->supp_oper_classes, + peer->supp_oper_classes_len); + return 0; +} + + static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len) { @@ -1546,8 +1649,18 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, if (copy_peer_ext_capab(&kde, peer) < 0) goto error; + if (copy_peer_supp_channels(&kde, peer) < 0) + goto error; + + if (copy_peer_supp_oper_classes(&kde, peer) < 0) + goto error; + peer->qos_info = kde.qosinfo; + /* Overwrite with the qos_info obtained in WMM IE */ + if (copy_peer_wmm_capab(&kde, peer) < 0) + goto error; + peer->aid = kde.aid; #ifdef CONFIG_TDLS_TESTING @@ -1739,7 +1852,7 @@ skip_rsn: skip_rsn_check: /* add the peer to the driver as a "setup in progress" peer */ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, - NULL, 0); + NULL, 0, NULL, 0, NULL, 0); peer->tpk_in_progress = 1; wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2"); @@ -1788,7 +1901,11 @@ static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) peer->ht_capabilities, peer->vht_capabilities, peer->qos_info, peer->ext_capab, - peer->ext_capab_len) < 0) + peer->ext_capab_len, + peer->supp_channels, + peer->supp_channels_len, + peer->supp_oper_classes, + peer->supp_oper_classes_len) < 0) return -1; if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) { @@ -1817,7 +1934,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, int ielen; u16 status; const u8 *pos; - int ret; + int ret = 0; wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 " "(Peer " MACSTR ")", MAC2STR(src_addr)); @@ -1916,8 +2033,18 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, if (copy_peer_ext_capab(&kde, peer) < 0) goto error; + if (copy_peer_supp_channels(&kde, peer) < 0) + goto error; + + if (copy_peer_supp_oper_classes(&kde, peer) < 0) + goto error; + peer->qos_info = kde.qosinfo; + /* Overwrite with the qos_info obtained in WMM IE */ + if (copy_peer_wmm_capab(&kde, peer) < 0) + goto error; + peer->aid = kde.aid; if (!wpa_tdls_get_privacy(sm)) { @@ -2034,11 +2161,19 @@ skip_rsn: return -1; } - ret = wpa_tdls_enable_link(sm, peer); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); - wpa_tdls_do_teardown(sm, peer, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); + if (!peer->tpk_success) { + /* + * Enable Link only when tpk_success is 0, signifying that this + * processing of TPK M2 frame is not because of a retransmission + * during TDLS setup handshake. + */ + ret = wpa_tdls_enable_link(sm, peer); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); + wpa_tdls_do_teardown( + sm, peer, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); + } } return ret; @@ -2062,7 +2197,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, u16 status; const u8 *pos; u32 lifetime; - int ret; + int ret = 0; wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 " "(Peer " MACSTR ")", MAC2STR(src_addr)); @@ -2179,11 +2314,19 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, } skip_rsn: - ret = wpa_tdls_enable_link(sm, peer); - if (ret < 0) { - wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); - wpa_tdls_do_teardown(sm, peer, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); + if (!peer->tpk_success) { + /* + * Enable Link only when tpk_success is 0, signifying that this + * processing of TPK M3 frame is not because of a retransmission + * during TDLS setup handshake. + */ + ret = wpa_tdls_enable_link(sm, peer); + if (ret < 0) { + wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); + wpa_tdls_do_teardown( + sm, peer, + WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); + } } return ret; error: @@ -2251,7 +2394,7 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) /* add the peer to the driver as a "setup in progress" peer */ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, - NULL, 0); + NULL, 0, NULL, 0, NULL, 0); peer->tpk_in_progress = 1; @@ -2284,7 +2427,7 @@ void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr) * Disable previous link to allow renegotiation to be completed * on AP path. */ - wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); + wpa_tdls_disable_peer_link(sm, peer); } } diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index 26e9c6ca..50762335 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -54,7 +54,8 @@ struct wpa_sm_ctx { int *tdls_ext_setup); int (*send_tdls_mgmt)(void *ctx, const u8 *dst, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, size_t len); + u16 status_code, u32 peer_capab, + const u8 *buf, size_t len); int (*tdls_oper)(void *ctx, int oper, const u8 *peer); int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid, u16 capability, const u8 *supp_rates, @@ -62,7 +63,10 @@ struct wpa_sm_ctx { const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, u8 qosinfo, const u8 *ext_capab, - size_t ext_capab_len); + size_t ext_capab_len, const u8 *supp_channels, + size_t supp_channels_len, + const u8 *supp_oper_classes, + size_t supp_oper_classes_len); #endif /* CONFIG_TDLS */ void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck, const u8 *replay_ctr); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 0e0d373f..2ee8bc75 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -262,13 +262,13 @@ static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm, static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, - size_t len) + u16 status_code, u32 peer_capab, + const u8 *buf, size_t len) { if (sm->ctx->send_tdls_mgmt) return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code, dialog_token, status_code, - buf, len); + peer_capab, buf, len); return -1; } @@ -286,14 +286,21 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, size_t supp_rates_len, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, - u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len) + u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len, + const u8 *supp_channels, size_t supp_channels_len, + const u8 *supp_oper_classes, + size_t supp_oper_classes_len) { if (sm->ctx->tdls_peer_addset) return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add, aid, capability, supp_rates, supp_rates_len, ht_capab, vht_capab, qosinfo, - ext_capab, ext_capab_len); + ext_capab, ext_capab_len, + supp_channels, + supp_channels_len, + supp_oper_classes, + supp_oper_classes_len); return -1; } #endif /* CONFIG_TDLS */ diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 50b9272b..b890368d 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -246,6 +246,42 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) /** + * wpa_parse_vendor_specific - Parse Vendor Specific IEs + * @pos: Pointer to the IE header + * @end: Pointer to the end of the Key Data buffer + * @ie: Pointer to parsed IE data + * Returns: 0 on success, 1 if end mark is found, -1 on failure + */ +static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end, + struct wpa_eapol_ie_parse *ie) +{ + unsigned int oui; + + if (pos[1] < 4) { + wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)", + pos[1]); + return 1; + } + + oui = WPA_GET_BE24(&pos[2]); + if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) { + if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) { + ie->wmm = &pos[2]; + ie->wmm_len = pos[1]; + wpa_hexdump(MSG_DEBUG, "WPA: WMM IE", + ie->wmm, ie->wmm_len); + } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) { + ie->wmm = &pos[2]; + ie->wmm_len = pos[1]; + wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element", + ie->wmm, ie->wmm_len); + } + } + return 0; +} + + +/** * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs * @pos: Pointer to the IE header * @end: Pointer to the end of the Key Data buffer @@ -434,6 +470,20 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, ie->vht_capabilities_len = pos[1]; } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) { ie->qosinfo = pos[2]; + } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) { + ie->supp_channels = pos + 2; + ie->supp_channels_len = pos[1]; + } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) { + /* + * The value of the Length field of the Supported + * Operating Classes element is between 2 and 253. + * Silently skip invalid elements to avoid interop + * issues when trying to use the value. + */ + if (pos[1] >= 2 && pos[1] <= 253) { + ie->supp_oper_classes = pos + 2; + ie->supp_oper_classes_len = pos[1]; + } } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { ret = wpa_parse_generic(pos, end, ie); if (ret < 0) @@ -442,6 +492,14 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, ret = 0; break; } + + ret = wpa_parse_vendor_specific(pos, end, ie); + if (ret < 0) + break; + if (ret > 0) { + ret = 0; + break; + } } else { wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " "Key Data IE", pos, 2 + pos[1]); diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h index 2c788012..609e5af2 100644 --- a/src/rsn_supp/wpa_ie.h +++ b/src/rsn_supp/wpa_ie.h @@ -53,8 +53,14 @@ struct wpa_eapol_ie_parse { size_t ht_capabilities_len; const u8 *vht_capabilities; size_t vht_capabilities_len; + const u8 *supp_channels; + size_t supp_channels_len; + const u8 *supp_oper_classes; + size_t supp_oper_classes_len; u8 qosinfo; u16 aid; + const u8 *wmm; + size_t wmm_len; }; int wpa_supplicant_parse_ies(const u8 *buf, size_t len, diff --git a/src/tls/pkcs1.c b/src/tls/pkcs1.c index b6fde5ee..ea3e6171 100644 --- a/src/tls/pkcs1.c +++ b/src/tls/pkcs1.c @@ -113,6 +113,11 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, pos++; if (pos == end) return -1; + if (pos - out - 2 < 8) { + /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ + wpa_printf(MSG_INFO, "LibTomCrypt: Too short padding"); + return -1; + } pos++; *outlen -= pos - out; @@ -142,35 +147,26 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, * BT = 00 or 01 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01) * k = length of modulus in octets + * + * Based on 10.1.3, "The block type shall be 01" for a signature. */ if (len < 3 + 8 + 16 /* min hash len */ || - plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) { + plain[0] != 0x00 || plain[1] != 0x01) { wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " "structure"); return -1; } pos = plain + 3; - if (plain[1] == 0x00) { - /* BT = 00 */ - if (plain[2] != 0x00) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " - "PS (BT=00)"); - return -1; - } - while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00) - pos++; - } else { - /* BT = 01 */ - if (plain[2] != 0xff) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " - "PS (BT=01)"); - return -1; - } - while (pos < plain + len && *pos == 0xff) - pos++; + /* BT = 01 */ + if (plain[2] != 0xff) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " + "PS (BT=01)"); + return -1; } + while (pos < plain + len && *pos == 0xff) + pos++; if (pos - plain - 2 < 8) { /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c index 06540bff..9b498292 100644 --- a/src/tls/x509v3.c +++ b/src/tls/x509v3.c @@ -1781,6 +1781,15 @@ skip_digest_oid: return -1; } + if (hdr.payload + hdr.length < data + data_len) { + wpa_hexdump(MSG_INFO, + "X509: Extra data after certificate signature hash", + hdr.payload + hdr.length, + data + data_len - hdr.payload - hdr.length); + os_free(data); + return -1; + } + os_free(data); wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with " diff --git a/src/utils/common.c b/src/utils/common.c index bf326cdb..f0981732 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -622,3 +622,191 @@ char * dup_binstr(const void *src, size_t len) return res; } + + +int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value) +{ + struct wpa_freq_range *freq = NULL, *n; + unsigned int count = 0; + const char *pos, *pos2, *pos3; + + /* + * Comma separated list of frequency ranges. + * For example: 2412-2432,2462,5000-6000 + */ + pos = value; + while (pos && pos[0]) { + n = os_realloc_array(freq, count + 1, + sizeof(struct wpa_freq_range)); + if (n == NULL) { + os_free(freq); + return -1; + } + freq = n; + freq[count].min = atoi(pos); + pos2 = os_strchr(pos, '-'); + pos3 = os_strchr(pos, ','); + if (pos2 && (!pos3 || pos2 < pos3)) { + pos2++; + freq[count].max = atoi(pos2); + } else + freq[count].max = freq[count].min; + pos = pos3; + if (pos) + pos++; + count++; + } + + os_free(res->range); + res->range = freq; + res->num = count; + + return 0; +} + + +int freq_range_list_includes(const struct wpa_freq_range_list *list, + unsigned int freq) +{ + unsigned int i; + + if (list == NULL) + return 0; + + for (i = 0; i < list->num; i++) { + if (freq >= list->range[i].min && freq <= list->range[i].max) + return 1; + } + + return 0; +} + + +char * freq_range_list_str(const struct wpa_freq_range_list *list) +{ + char *buf, *pos, *end; + size_t maxlen; + unsigned int i; + int res; + + if (list->num == 0) + return NULL; + + maxlen = list->num * 30; + buf = os_malloc(maxlen); + if (buf == NULL) + return NULL; + pos = buf; + end = buf + maxlen; + + for (i = 0; i < list->num; i++) { + struct wpa_freq_range *range = &list->range[i]; + + if (range->min == range->max) + res = os_snprintf(pos, end - pos, "%s%u", + i == 0 ? "" : ",", range->min); + else + res = os_snprintf(pos, end - pos, "%s%u-%u", + i == 0 ? "" : ",", + range->min, range->max); + if (res < 0 || res > end - pos) { + os_free(buf); + return NULL; + } + pos += res; + } + + return buf; +} + + +int int_array_len(const int *a) +{ + int i; + for (i = 0; a && a[i]; i++) + ; + return i; +} + + +void int_array_concat(int **res, const int *a) +{ + int reslen, alen, i; + int *n; + + reslen = int_array_len(*res); + alen = int_array_len(a); + + n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); + if (n == NULL) { + os_free(*res); + *res = NULL; + return; + } + for (i = 0; i <= alen; i++) + n[reslen + i] = a[i]; + *res = n; +} + + +static int freq_cmp(const void *a, const void *b) +{ + int _a = *(int *) a; + int _b = *(int *) b; + + if (_a == 0) + return 1; + if (_b == 0) + return -1; + return _a - _b; +} + + +void int_array_sort_unique(int *a) +{ + int alen; + int i, j; + + if (a == NULL) + return; + + alen = int_array_len(a); + qsort(a, alen, sizeof(int), freq_cmp); + + i = 0; + j = 1; + while (a[i] && a[j]) { + if (a[i] == a[j]) { + j++; + continue; + } + a[++i] = a[j++]; + } + if (a[i]) + i++; + a[i] = 0; +} + + +void int_array_add_unique(int **res, int a) +{ + int reslen; + int *n; + + for (reslen = 0; *res && (*res)[reslen]; reslen++) { + if ((*res)[reslen] == a) + return; /* already in the list */ + } + + n = os_realloc_array(*res, reslen + 2, sizeof(int)); + if (n == NULL) { + os_free(*res); + *res = NULL; + return; + } + + n[reslen] = a; + n[reslen + 1] = 0; + + *res = n; +} diff --git a/src/utils/common.h b/src/utils/common.h index 29f0b953..ec3939db 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -505,6 +505,24 @@ static inline int is_broadcast_ether_addr(const u8 *a) #include "wpa_debug.h" +struct wpa_freq_range_list { + struct wpa_freq_range { + unsigned int min; + unsigned int max; + } *range; + unsigned int num; +}; + +int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value); +int freq_range_list_includes(const struct wpa_freq_range_list *list, + unsigned int freq); +char * freq_range_list_str(const struct wpa_freq_range_list *list); + +int int_array_len(const int *a); +void int_array_concat(int **res, const int *a); +void int_array_sort_unique(int *a); +void int_array_add_unique(int **res, int a); + /* * gcc 4.4 ends up generating strict-aliasing warnings about some very common * networking socket uses that do not really result in a real problem and diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index ea81ab25..45a9a13a 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -515,7 +515,7 @@ endif ifdef CONFIG_EAP_PROXY L_CFLAGS += -DCONFIG_EAP_PROXY OBJS += src/eap_peer/eap_proxy_$(CONFIG_EAP_PROXY).c -include eap_proxy_$(CONFIG_EAP_PROXY).mk +include $(LOCAL_PATH)/eap_proxy_$(CONFIG_EAP_PROXY).mk CONFIG_IEEE8021X_EAPOL=y endif @@ -1560,6 +1560,10 @@ ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),) LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB) endif LOCAL_SHARED_LIBRARIES := libc libcutils liblog +ifdef CONFIG_EAP_PROXY +LOCAL_STATIC_LIBRARIES += $(LIB_STATIC_EAP_PROXY) +LOCAL_SHARED_LIBRARIES += $(LIB_SHARED_EAP_PROXY) +endif ifeq ($(CONFIG_TLS), openssl) LOCAL_SHARED_LIBRARIES += libcrypto libssl libkeystore_binder endif diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 index 7a570bdd..ce7554a8 100644 --- a/wpa_supplicant/README-HS20 +++ b/wpa_supplicant/README-HS20 @@ -197,6 +197,8 @@ Credentials can be pre-configured for automatic network selection: # matching with the network. Multiple entries can be used to specify more # than one SSID. # +# sim_num: Identifier for which SIM to use in multi-SIM devices +# # for example: # #cred={ diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 97d59eb4..2b8b667a 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1565,6 +1565,7 @@ static const struct parse_data ssid_fields[] = { { INTe(engine) }, { INTe(engine2) }, { INT(eapol_flags) }, + { INTe(sim_num) }, #endif /* IEEE8021X_EAPOL */ { FUNC_KEY(wep_key0) }, { FUNC_KEY(wep_key1) }, @@ -2033,6 +2034,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) ssid->eapol_flags = DEFAULT_EAPOL_FLAGS; ssid->eap_workaround = DEFAULT_EAP_WORKAROUND; ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE; + ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM; #endif /* IEEE8021X_EAPOL */ #ifdef CONFIG_HT_OVERRIDES ssid->disable_ht = DEFAULT_DISABLE_HT; @@ -2336,6 +2338,11 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "sim_num") == 0) { + cred->sim_num = atoi(value); + return 0; + } + val = wpa_config_parse_string(value, &len); if (val == NULL) { wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " @@ -2511,6 +2518,7 @@ struct wpa_cred * wpa_config_add_cred(struct wpa_config *config) if (cred == NULL) return NULL; cred->id = id; + cred->sim_num = DEFAULT_USER_SELECTED_SIM; if (last) last->next = cred; else diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index bce8d168..112dfa3e 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -210,6 +210,14 @@ struct wpa_cred { size_t ssid_len; } *excluded_ssid; size_t num_excluded_ssid; + + /** + * sim_num - User selected SIM identifier + * + * This variable is used for identifying which SIM is used if the system + * has more than one. + */ + int sim_num; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 20935ce7..b4219581 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -219,6 +219,7 @@ static struct wpa_cred * wpa_config_read_cred(FILE *f, int *line, int id) if (cred == NULL) return NULL; cred->id = id; + cred->sim_num = DEFAULT_USER_SELECTED_SIM; while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) { if (os_strcmp(pos, "}") == 0) { @@ -699,6 +700,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND); STR(pac_file); INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE); + INT_DEFe(sim_num, DEFAULT_USER_SELECTED_SIM); #endif /* IEEE8021X_EAPOL */ INT(mode); INT(frequency); @@ -780,6 +782,9 @@ static void wpa_config_write_cred(FILE *f, struct wpa_cred *cred) fprintf(f, "\n"); } } + + if (cred->sim_num != DEFAULT_USER_SELECTED_SIM) + fprintf(f, "\tsim_num=%d\n", cred->sim_num); } diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index 3a442723..f3da0f17 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -33,6 +33,7 @@ #define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */ #define DEFAULT_AMPDU_FACTOR -1 /* no change */ #define DEFAULT_AMPDU_DENSITY -1 /* no change */ +#define DEFAULT_USER_SELECTED_SIM 1 struct psk_list_entry { struct dl_list list; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 545bef70..d9d2363a 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -4382,48 +4382,21 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s, const char *param) { - struct wpa_freq_range *freq = NULL, *n; - unsigned int count = 0, i; - const char *pos, *pos2, *pos3; + unsigned int i; if (wpa_s->global->p2p == NULL) return -1; - /* - * param includes comma separated frequency range. - * For example: 2412-2432,2462,5000-6000 - */ - pos = param; - while (pos && pos[0]) { - n = os_realloc_array(freq, count + 1, - sizeof(struct wpa_freq_range)); - if (n == NULL) { - os_free(freq); - return -1; - } - freq = n; - freq[count].min = atoi(pos); - pos2 = os_strchr(pos, '-'); - pos3 = os_strchr(pos, ','); - if (pos2 && (!pos3 || pos2 < pos3)) { - pos2++; - freq[count].max = atoi(pos2); - } else - freq[count].max = freq[count].min; - pos = pos3; - if (pos) - pos++; - count++; - } + if (freq_range_list_parse(&wpa_s->global->p2p_disallow_freq, param) < 0) + return -1; - for (i = 0; i < count; i++) { + for (i = 0; i < wpa_s->global->p2p_disallow_freq.num; i++) { + struct wpa_freq_range *freq; + freq = &wpa_s->global->p2p_disallow_freq.range[i]; wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u", - freq[i].min, freq[i].max); + freq->min, freq->max); } - os_free(wpa_s->global->p2p_disallow_freq); - wpa_s->global->p2p_disallow_freq = freq; - wpa_s->global->num_p2p_disallow_freq = count; wpas_p2p_update_channel_list(wpa_s); return 0; } @@ -5226,6 +5199,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_dbg(wpa_s, MSG_DEBUG, "Flush all wpa_supplicant state"); #ifdef CONFIG_P2P + wpas_p2p_cancel(wpa_s); wpas_p2p_stop_find(wpa_s); p2p_ctrl_flush(wpa_s); wpas_p2p_group_remove(wpa_s, "*"); @@ -5273,6 +5247,92 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) } +static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val) +{ + struct wpa_freq_range_list ranges; + int *freqs = NULL; + struct hostapd_hw_modes *mode; + u16 i; + + if (wpa_s->hw.modes == NULL) + return -1; + + os_memset(&ranges, 0, sizeof(ranges)); + if (freq_range_list_parse(&ranges, val) < 0) + return -1; + + for (i = 0; i < wpa_s->hw.num_modes; i++) { + int j; + + mode = &wpa_s->hw.modes[i]; + for (j = 0; j < mode->num_channels; j++) { + unsigned int freq; + + if (mode->channels[j].flag & HOSTAPD_CHAN_DISABLED) + continue; + + freq = mode->channels[j].freq; + if (!freq_range_list_includes(&ranges, freq)) + continue; + + int_array_add_unique(&freqs, freq); + } + } + + os_free(ranges.range); + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = freqs; + + return 0; +} + + +static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, + char *reply, int reply_size, int *reply_len) +{ + char *pos; + + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + *reply_len = -1; + return; + } + + if (params) { + if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0) + wpa_s->scan_res_handler = scan_only_handler; + + pos = os_strstr(params, "freq="); + if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) { + *reply_len = -1; + return; + } + } else { + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = NULL; + if (wpa_s->scan_res_handler == scan_only_handler) + wpa_s->scan_res_handler = NULL; + } + + if (!wpa_s->sched_scanning && !wpa_s->scanning && + ((wpa_s->wpa_state <= WPA_SCANNING) || + (wpa_s->wpa_state == WPA_COMPLETED))) { + wpa_s->normal_scans = 0; + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_s->after_wps = 0; + wpa_s->known_wps_freq = 0; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else if (wpa_s->sched_scanning) { + wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed"); + wpa_supplicant_cancel_sched_scan(wpa_s); + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else { + wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request"); + *reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n"); + } +} + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { @@ -5646,34 +5706,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, wpa_supplicant_cancel_scan(wpa_s); wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING); - } else if (os_strcmp(buf, "SCAN") == 0 || - os_strncmp(buf, "SCAN ", 5) == 0) { - if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) - reply_len = -1; - else { - if (os_strlen(buf) > 4 && - os_strncasecmp(buf + 5, "TYPE=ONLY", 9) == 0) - wpa_s->scan_res_handler = scan_only_handler; - if (!wpa_s->sched_scanning && !wpa_s->scanning && - ((wpa_s->wpa_state <= WPA_SCANNING) || - (wpa_s->wpa_state == WPA_COMPLETED))) { - wpa_s->normal_scans = 0; - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_supplicant_req_scan(wpa_s, 0, 0); - } else if (wpa_s->sched_scanning) { - wpa_printf(MSG_DEBUG, "Stop ongoing " - "sched_scan to allow requested " - "full scan to proceed"); - wpa_supplicant_cancel_sched_scan(wpa_s); - wpa_s->scan_req = MANUAL_SCAN_REQ; - wpa_supplicant_req_scan(wpa_s, 0, 0); - } else { - wpa_printf(MSG_DEBUG, "Ongoing scan action - " - "reject new request"); - reply_len = os_snprintf(reply, reply_size, - "FAIL-BUSY\n"); - } - } + } else if (os_strcmp(buf, "SCAN") == 0) { + wpas_ctrl_scan(wpa_s, NULL, reply, reply_size, &reply_len); + } else if (os_strncmp(buf, "SCAN ", 5) == 0) { + wpas_ctrl_scan(wpa_s, buf + 5, reply, reply_size, &reply_len); } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) { reply_len = wpa_supplicant_ctrl_iface_scan_results( wpa_s, reply, reply_size); diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c index e35d2c39..8016240c 100644 --- a/wpa_supplicant/ctrl_iface_unix.c +++ b/wpa_supplicant/ctrl_iface_unix.c @@ -680,7 +680,7 @@ static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, { struct wpa_global *global = eloop_ctx; struct ctrl_iface_global_priv *priv = sock_ctx; - char buf[256]; + char buf[4096]; int res; struct sockaddr_un from; socklen_t fromlen = sizeof(from); diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 5e7dbf73..d7368e13 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -647,12 +647,14 @@ static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s, static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, - const u8 *buf, size_t len) + u32 peer_capab, const u8 *buf, + size_t len) { if (wpa_s->driver->send_tdls_mgmt) { return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst, action_code, dialog_token, - status_code, buf, len); + status_code, peer_capab, + buf, len); } return -1; } diff --git a/wpa_supplicant/eap_proxy_qmi.mk b/wpa_supplicant/eap_proxy_qmi.mk new file mode 100644 index 00000000..49397ba7 --- /dev/null +++ b/wpa_supplicant/eap_proxy_qmi.mk @@ -0,0 +1,30 @@ + +LOCAL_PATH := $(call my-dir) + +ifeq ($(BOARD_HAS_QCOM_WLAN), true) +L_CFLAGS += -DSIM_AKA_IDENTITY_IMSI +L_CFLAGS += -DSIM_AKA_IMSI_RAW_ENABLED + +ifdef CONFIG_EAP_PROXY_DUAL_SIM +L_CFLAGS += -DCONFIG_EAP_PROXY_DUAL_SIM +endif + +LIB_SHARED_EAP_PROXY := libqmi libqmiservices libidl libqcci_legacy + +INCLUDES += $(TARGET_OUT_HEADERS)/qmi/inc +INCLUDES += $(TARGET_OUT_HEADERS)/qmi/platform +INCLUDES += $(TARGET_OUT_HEADERS)/qmi/src +INCLUDES += $(TARGET_OUT_HEADERS)/qmi/services +INCLUDES += $(TARGET_OUT_HEADERS)/qmi/core/lib/inc + +# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used). +# This requires CONFIG_EAP_AKA to be enabled, too. +# This is supported only in B Family devices. +ifdef CONFIG_EAP_PROXY_AKA_PRIME +L_CFLAGS += -DCONFIG_EAP_PROXY_AKA_PRIME +endif + +#ANDROID_SETGROUPS_OVERRIDE := AID_RADIO AID_WIFI AID_KEYSTORE AID_DIAG AID_INET AID_QCOM_DIAG +L_CFLAGS += -DANDROID_SETGROUPS_OVERRIDE=1001,1010,1017,2002,1003,3009 +endif + diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index e939e36f..cfeb8e8e 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1180,6 +1180,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) { wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation " "stopped scan processing"); + wpa_s->scan_req = wpa_s->last_scan_req; wpa_s->sta_scan_pending = 1; wpa_supplicant_req_scan(wpa_s, 5, 0); return -1; @@ -1219,7 +1220,8 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_NO_RANDOM_POOL */ - if (own_request && wpa_s->scan_res_handler) { + if (own_request && wpa_s->scan_res_handler && + (wpa_s->own_scan_running || !wpa_s->external_scan_running)) { void (*scan_res_handler)(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res); @@ -1241,12 +1243,19 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return 0; } - wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available"); + wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)", + wpa_s->own_scan_running, wpa_s->external_scan_running); wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); wpas_notify_scan_results(wpa_s); wpas_notify_scan_done(wpa_s, 1); + if (!wpa_s->own_scan_running && wpa_s->external_scan_running) { + wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection"); + wpa_scan_results_free(scan_res); + return 0; + } + if (sme_proc_obss_scan(wpa_s) > 0) { wpa_scan_results_free(scan_res); return 0; @@ -1326,7 +1335,8 @@ static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s, return 0; if (wpa_s->p2p_in_provisioning || - wpa_s->show_group_started) { + wpa_s->show_group_started || + wpa_s->p2p_in_invitation) { /* * Use shorter wait during P2P Provisioning * state and during P2P join-a-group operation @@ -2648,6 +2658,58 @@ static void wpas_event_deauth(struct wpa_supplicant *wpa_s, } +static void wpa_supplicant_notify_avoid_freq(struct wpa_supplicant *wpa_s, + union wpa_event_data *event) +{ +#ifdef CONFIG_P2P + struct wpa_supplicant *ifs; +#endif /* CONFIG_P2P */ + struct wpa_freq_range_list *list; + char *str = NULL; + + list = &event->freq_range; + + if (list->num) + str = freq_range_list_str(list); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_AVOID_FREQ "ranges=%s", + str ? str : ""); + +#ifdef CONFIG_P2P + if (freq_range_list_parse(&wpa_s->global->p2p_go_avoid_freq, str)) { + wpa_dbg(wpa_s, MSG_ERROR, "%s: Failed to parse freq range", + __func__); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Update channel list based on frequency avoid event"); + wpas_p2p_update_channel_list(wpa_s); + } + + for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { + int freq; + if (!ifs->current_ssid || + !ifs->current_ssid->p2p_group || + (ifs->current_ssid->mode != WPAS_MODE_P2P_GO && + ifs->current_ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)) + continue; + + freq = ifs->current_ssid->frequency; + if (!freq_range_list_includes(list, freq)) { + wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating frequency %d MHz in safe range", + freq); + continue; + } + + wpa_dbg(ifs, MSG_DEBUG, "P2P GO operating in unsafe frequency %d MHz", + freq); + /* TODO: Consider using CSA or removing the group within + * wpa_supplicant */ + wpa_msg(ifs, MSG_INFO, P2P_EVENT_REMOVE_AND_REFORM_GROUP); + } +#endif /* CONFIG_P2P */ + + os_free(str); +} + + void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { @@ -2701,8 +2763,22 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_supplicant_event_michael_mic_failure(wpa_s, data); break; #ifndef CONFIG_NO_SCAN_PROCESSING + case EVENT_SCAN_STARTED: + if (wpa_s->own_scan_requested) { + wpa_dbg(wpa_s, MSG_DEBUG, "Own scan request started a scan"); + wpa_s->own_scan_requested = 0; + wpa_s->own_scan_running = 1; + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED); + } else { + wpa_dbg(wpa_s, MSG_DEBUG, "External program started a scan"); + wpa_s->external_scan_running = 1; + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_STARTED); + } + break; case EVENT_SCAN_RESULTS: wpa_supplicant_event_scan_results(wpa_s, data); + wpa_s->own_scan_running = 0; + wpa_s->external_scan_running = 0; if (wpa_s->wpa_state != WPA_AUTHENTICATING && wpa_s->wpa_state != WPA_ASSOCIATING) wpas_p2p_continue_after_scan(wpa_s); @@ -3194,6 +3270,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpas_wps_start_pbc(wpa_s, NULL, 0); #endif /* CONFIG_WPS */ break; + case EVENT_AVOID_FREQUENCIES: + wpa_supplicant_notify_avoid_freq(wpa_s, data); + break; case EVENT_CONNECT_FAILED_REASON: #ifdef CONFIG_AP if (!wpa_s->ap_iface || !data) diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 06b08931..68bf6c36 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -859,6 +859,7 @@ static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s, goto fail; os_memcpy(ssid->ssid, ie + 2, ie[1]); ssid->ssid_len = ie[1]; + ssid->eap.sim_num = cred->sim_num; if (interworking_set_hs20_params(wpa_s, ssid) < 0) goto fail; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 88f71bd1..9a4e42f9 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -58,7 +58,8 @@ #ifndef P2P_MAX_INITIAL_CONN_WAIT /* * How many seconds to wait for initial 4-way handshake to get completed after - * WPS provisioning step. + * WPS provisioning step or after the re-invocation of a persistent group on a + * P2P Client. */ #define P2P_MAX_INITIAL_CONN_WAIT 10 #endif /* P2P_MAX_INITIAL_CONN_WAIT */ @@ -319,6 +320,7 @@ static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq, } else { os_get_time(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_handler; + wpa_s->own_scan_requested = 1; } return ret; @@ -456,6 +458,8 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, wpa_s->p2p_in_provisioning = 0; } + wpa_s->p2p_in_invitation = 0; + /* * Make sure wait for the first client does not remain active after the * group has been removed. @@ -487,6 +491,10 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, wpa_s->p2p_in_provisioning = 0; } + wpa_s->show_group_started = 0; + os_free(wpa_s->go_params); + wpa_s->go_params = NULL; + wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network"); if (ssid && (ssid->p2p_group || ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION || @@ -770,6 +778,7 @@ static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s, wpa_s->global->p2p_group_formation = NULL; wpa_s->p2p_in_provisioning = 0; } + wpa_s->p2p_in_invitation = 0; if (!success) { wpa_msg_global(wpa_s->parent, MSG_INFO, @@ -2762,7 +2771,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, if (s) { int go = s->mode == WPAS_MODE_P2P_GO; wpas_p2p_group_add_persistent( - wpa_s, s, go, go ? op_freq : 0, 0, NULL, + wpa_s, s, go, op_freq, 0, NULL, go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0); } else if (bssid) { wpa_s->user_initiated_pd = 0; @@ -2870,7 +2879,8 @@ static void wpas_remove_persistent_client(struct wpa_supplicant *wpa_s, static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, const struct p2p_channels *channels, - const u8 *peer, int neg_freq) + const u8 *peer, int neg_freq, + int peer_oper_freq) { struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *ssid; @@ -2943,6 +2953,14 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, neg_freq); freq = neg_freq; } + else if (peer_oper_freq > 0 && ssid->mode != WPAS_MODE_P2P_GO && + freq_included(channels, peer_oper_freq)) + freq = peer_oper_freq; + else + freq = 0; + + wpa_printf(MSG_DEBUG, "P2P: Persistent group invitation success - op_freq=%d MHz SSID=%s", + freq, wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); wpas_p2p_group_add_persistent(wpa_s, ssid, ssid->mode == WPAS_MODE_P2P_GO, @@ -2957,18 +2975,9 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, static int wpas_p2p_disallowed_freq(struct wpa_global *global, unsigned int freq) { - unsigned int i; - - if (global->p2p_disallow_freq == NULL) - return 0; - - for (i = 0; i < global->num_p2p_disallow_freq; i++) { - if (freq >= global->p2p_disallow_freq[i].min && - freq <= global->p2p_disallow_freq[i].max) - return 1; - } - - return 0; + if (freq_range_list_includes(&global->p2p_go_avoid_freq, freq)) + return 1; + return freq_range_list_includes(&global->p2p_disallow_freq, freq); } @@ -3234,6 +3243,21 @@ static int wpas_go_connected(void *ctx, const u8 *dev_addr) } +static int wpas_is_concurrent_session_active(void *ctx) +{ + struct wpa_supplicant *wpa_s = ctx; + struct wpa_supplicant *ifs; + + for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) { + if (ifs == wpa_s) + continue; + if (ifs->wpa_state > WPA_ASSOCIATED) + return 1; + } + return 0; +} + + static void wpas_p2p_debug_print(void *ctx, int level, const char *msg) { struct wpa_supplicant *wpa_s = ctx; @@ -3344,6 +3368,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.invitation_result = wpas_invitation_result; p2p.get_noa = wpas_get_noa; p2p.go_connected = wpas_go_connected; + p2p.is_concurrent_session_active = wpas_is_concurrent_session_active; os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); @@ -3936,6 +3961,7 @@ static void wpas_p2p_join_scan_req(struct wpa_supplicant *wpa_s, int freq) if (!ret) { os_get_time(&wpa_s->scan_trigger_time); wpa_s->scan_res_handler = wpas_p2p_scan_res_join; + wpa_s->own_scan_requested = 1; } wpabuf_free(ies); @@ -4231,7 +4257,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq); if (res) return res; - wpas_p2p_set_own_freq_preference(wpa_s, force_freq); + wpas_p2p_set_own_freq_preference(wpa_s, + force_freq ? force_freq : pref_freq); wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s); @@ -4661,7 +4688,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, - struct wpa_ssid *params, int addr_allocated) + struct wpa_ssid *params, int addr_allocated, + int freq) { struct wpa_ssid *ssid; @@ -4698,7 +4726,14 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, ssid->passphrase = os_strdup(params->passphrase); wpa_s->show_group_started = 1; + wpa_s->p2p_in_invitation = 1; + wpa_s->p2p_invite_go_freq = freq; + eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent, + NULL); + eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0, + wpas_p2p_group_formation_timeout, + wpa_s->parent, NULL); wpa_supplicant_select_network(wpa_s, ssid); return 0; @@ -4732,16 +4767,16 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, wpa_s->p2p_fallback_to_go_neg = 0; + freq = wpas_p2p_select_go_freq(wpa_s, freq); + if (freq < 0) + return -1; + if (ssid->mode == WPAS_MODE_INFRA) - return wpas_start_p2p_client(wpa_s, ssid, addr_allocated); + return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq); if (ssid->mode != WPAS_MODE_P2P_GO) return -1; - freq = wpas_p2p_select_go_freq(wpa_s, freq); - if (freq < 0) - return -1; - if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40, channels)) return -1; @@ -5929,6 +5964,11 @@ int wpas_p2p_cancel(struct wpa_supplicant *wpa_s) wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED); break; + } else if (wpa_s->p2p_in_invitation) { + wpa_printf(MSG_DEBUG, "P2P: Interface %s in invitation found - cancelling", + wpa_s->ifname); + found = 1; + wpas_p2p_group_formation_failed(wpa_s); } } @@ -6118,6 +6158,7 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s, wpa_s->p2p_go_group_formation_completed = 1; wpa_s->global->p2p_group_formation = NULL; wpa_s->p2p_in_provisioning = 0; + wpa_s->p2p_in_invitation = 0; } wpa_s->global->p2p_go_wait_client.sec = 0; if (addr == NULL) diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 7eec4683..0de6f478 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -141,74 +141,6 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s, } -static int int_array_len(const int *a) -{ - int i; - for (i = 0; a && a[i]; i++) - ; - return i; -} - - -static void int_array_concat(int **res, const int *a) -{ - int reslen, alen, i; - int *n; - - reslen = int_array_len(*res); - alen = int_array_len(a); - - n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); - if (n == NULL) { - os_free(*res); - *res = NULL; - return; - } - for (i = 0; i <= alen; i++) - n[reslen + i] = a[i]; - *res = n; -} - - -static int freq_cmp(const void *a, const void *b) -{ - int _a = *(int *) a; - int _b = *(int *) b; - - if (_a == 0) - return 1; - if (_b == 0) - return -1; - return _a - _b; -} - - -static void int_array_sort_unique(int *a) -{ - int alen; - int i, j; - - if (a == NULL) - return; - - alen = int_array_len(a); - qsort(a, alen, sizeof(int), freq_cmp); - - i = 0; - j = 1; - while (a[i] && a[j]) { - if (a[i] == a[j]) { - j++; - continue; - } - a[++i] = a[j++]; - } - if (a[i]) - i++; - a[i] = 0; -} - - /** * wpa_supplicant_trigger_scan - Request driver to start a scan * @wpa_s: Pointer to wpa_supplicant data @@ -230,6 +162,7 @@ int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s, os_get_time(&wpa_s->scan_trigger_time); wpa_s->scan_runs++; wpa_s->normal_scans++; + wpa_s->own_scan_requested = 1; } return ret; @@ -353,6 +286,33 @@ static void wpa_supplicant_optimize_freqs( } wpa_s->p2p_in_provisioning++; } + + if (params->freqs == NULL && wpa_s->p2p_in_invitation) { + /* + * Optimize scan based on GO information during persistent + * group reinvocation + */ + if (wpa_s->p2p_in_invitation < 5 && + wpa_s->p2p_invite_go_freq > 0) { + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation", + wpa_s->p2p_invite_go_freq); + params->freqs = os_zalloc(2 * sizeof(int)); + if (params->freqs) + params->freqs[0] = wpa_s->p2p_invite_go_freq; + } + wpa_s->p2p_in_invitation++; + if (wpa_s->p2p_in_invitation > 20) { + /* + * This should not really happen since the variable is + * cleared on group removal, but if it does happen, make + * sure we do not get stuck in special invitation scan + * mode. + */ + wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Clear p2p_in_invitation"); + wpa_s->p2p_in_invitation = 0; + } + } + #endif /* CONFIG_P2P */ #ifdef CONFIG_WPS @@ -546,7 +506,6 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; - enum scan_req_type scan_req = NORMAL_SCAN_REQ; int ret; struct wpabuf *extra_ie = NULL; struct wpa_driver_scan_params params; @@ -619,7 +578,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) max_ssids = WPAS_MAX_SCAN_SSIDS; } - scan_req = wpa_s->scan_req; + wpa_s->last_scan_req = wpa_s->scan_req; wpa_s->scan_req = NORMAL_SCAN_REQ; os_memset(¶ms, 0, sizeof(params)); @@ -637,7 +596,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) goto scan; } - if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) { + if (wpa_s->last_scan_req != MANUAL_SCAN_REQ && + wpa_s->connect_without_scan) { for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { if (ssid == wpa_s->connect_without_scan) break; @@ -661,6 +621,18 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) params.num_ssids = 1; goto ssid_list_set; } + if (wpa_s->p2p_in_invitation) { + if (wpa_s->current_ssid) { + wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during invitation"); + params.ssids[0].ssid = wpa_s->current_ssid->ssid; + params.ssids[0].ssid_len = + wpa_s->current_ssid->ssid_len; + params.num_ssids = 1; + } else { + wpa_printf(MSG_DEBUG, "P2P: No specific SSID known for scan during invitation"); + } + goto ssid_list_set; + } #endif /* CONFIG_P2P */ /* Find the starting point from which to continue scanning */ @@ -675,7 +647,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) } } - if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) { + if (wpa_s->last_scan_req != MANUAL_SCAN_REQ && + wpa_s->conf->ap_scan == 2) { wpa_s->connect_without_scan = NULL; wpa_s->prev_scan_wildcard = 0; wpa_supplicant_assoc_try(wpa_s, ssid); @@ -768,6 +741,13 @@ ssid_list_set: wpa_supplicant_optimize_freqs(wpa_s, ¶ms); extra_ie = wpa_supplicant_extra_ies(wpa_s); + if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL && + wpa_s->manual_scan_freqs) { + wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels"); + params.freqs = wpa_s->manual_scan_freqs; + wpa_s->manual_scan_freqs = NULL; + } + if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " "generated frequency list"); @@ -810,7 +790,7 @@ ssid_list_set: } #ifdef CONFIG_P2P - if (wpa_s->p2p_in_provisioning || + if (wpa_s->p2p_in_provisioning || wpa_s->p2p_in_invitation || (wpa_s->show_group_started && wpa_s->go_params)) { /* * The interface may not yet be in P2P mode, so we have to @@ -833,7 +813,8 @@ scan: * station interface when we are not configured to prefer station * connection and a concurrent operation is already in process. */ - if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ && + if (wpa_s->scan_for_connection && + wpa_s->last_scan_req == NORMAL_SCAN_REQ && !scan_params->freqs && !params.freqs && wpas_is_p2p_prioritized(wpa_s) && wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE && @@ -855,6 +836,13 @@ scan: ret = wpa_supplicant_trigger_scan(wpa_s, scan_params); + if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs && + !wpa_s->manual_scan_freqs) { + /* Restore manual_scan_freqs for the next attempt */ + wpa_s->manual_scan_freqs = params.freqs; + params.freqs = NULL; + } + wpabuf_free(extra_ie); os_free(params.freqs); os_free(params.filter_ssids); @@ -864,7 +852,7 @@ scan: if (prev_state != wpa_s->wpa_state) wpa_supplicant_set_state(wpa_s, prev_state); /* Restore scan_req since we will try to scan again */ - wpa_s->scan_req = scan_req; + wpa_s->scan_req = wpa_s->last_scan_req; wpa_supplicant_req_scan(wpa_s, 1, 0); } else { wpa_s->scan_for_connection = 0; diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 4f8d895a..95e2dfff 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -314,6 +314,7 @@ void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); } + wpa_s->wnm_num_neighbor_report = 0; os_free(wpa_s->wnm_neighbor_report_elements); wpa_s->wnm_neighbor_report_elements = NULL; } @@ -328,6 +329,7 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); break; } + os_free(rep->tsf_info); rep->tsf_info = os_zalloc(sizeof(struct tsf_info)); if (rep->tsf_info == NULL) break; @@ -341,6 +343,7 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, "country string"); break; } + os_free(rep->con_coun_str); rep->con_coun_str = os_zalloc(sizeof(struct condensed_country_string)); if (rep->con_coun_str == NULL) @@ -354,6 +357,7 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, "candidate"); break; } + os_free(rep->bss_tran_can); rep->bss_tran_can = os_zalloc(sizeof(struct bss_transition_candidate)); if (rep->bss_tran_can == NULL) @@ -367,6 +371,7 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, "duration"); break; } + os_free(rep->bss_term_dur); rep->bss_term_dur = os_zalloc(sizeof(struct bss_termination_duration)); if (rep->bss_term_dur == NULL) @@ -380,6 +385,7 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, "bearing"); break; } + os_free(rep->bearing); rep->bearing = os_zalloc(sizeof(struct bearing)); if (rep->bearing == NULL) break; @@ -392,6 +398,7 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, "pilot"); break; } + os_free(rep->meas_pilot); rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); if (rep->meas_pilot == NULL) break; @@ -406,6 +413,7 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, "capabilities"); break; } + os_free(rep->rrm_cap); rep->rrm_cap = os_zalloc(sizeof(struct rrm_enabled_capabilities)); if (rep->rrm_cap == NULL) @@ -418,6 +426,7 @@ static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); break; } + os_free(rep->mul_bssid); rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); if (rep->mul_bssid == NULL) break; @@ -455,8 +464,15 @@ static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, id = *pos++; elen = *pos++; + wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); + left -= 2; + if (elen > left) { + wpa_printf(MSG_DEBUG, + "WNM: Truncated neighbor report subelement"); + break; + } wnm_parse_neighbor_report_elem(rep, id, elen, pos); - left -= 2 + elen; + left -= elen; pos += elen; } } @@ -670,10 +686,12 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "WNM: Truncated request"); return; } - wnm_parse_neighbor_report( - wpa_s, pos, len, - &wpa_s->wnm_neighbor_report_elements[ - wpa_s->wnm_num_neighbor_report]); + if (tag == WLAN_EID_NEIGHBOR_REPORT) { + struct neighbor_report *rep; + rep = &wpa_s->wnm_neighbor_report_elements[ + wpa_s->wnm_num_neighbor_report]; + wnm_parse_neighbor_report(wpa_s, pos, len, rep); + } pos += len; wpa_s->wnm_num_neighbor_report++; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index ed08d289..78eccff9 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -459,6 +459,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; + os_free(wpa_s->manual_scan_freqs); + wpa_s->manual_scan_freqs = NULL; + gas_query_deinit(wpa_s->gas); wpa_s->gas = NULL; @@ -3507,7 +3510,8 @@ void wpa_supplicant_deinit(struct wpa_global *global) os_free(global->params.override_driver); os_free(global->params.override_ctrl_interface); - os_free(global->p2p_disallow_freq); + os_free(global->p2p_disallow_freq.range); + os_free(global->p2p_go_avoid_freq.range); os_free(global->add_psk); os_free(global); diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 6414f447..17cb1414 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -430,6 +430,8 @@ fast_reauth=1 # matching with the network. Multiple entries can be used to specify more # than one SSID. # +# sim_num: Identifier for which SIM to use in multi-SIM devices +# # for example: # #cred={ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 353c68e8..643b8750 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -227,12 +227,6 @@ struct p2p_srv_upnp { char *service; }; -struct wpa_freq_range { - unsigned int min; - unsigned int max; -}; - - /** * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces * @@ -257,8 +251,8 @@ struct wpa_global { struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */ int p2p_disabled; int cross_connection; - struct wpa_freq_range *p2p_disallow_freq; - unsigned int num_p2p_disallow_freq; + struct wpa_freq_range_list p2p_disallow_freq; + struct wpa_freq_range_list p2p_go_avoid_freq; enum wpa_conc_pref { WPA_CONC_PREF_NOT_SET, WPA_CONC_PREF_STA, @@ -472,10 +466,14 @@ struct wpa_supplicant { * to be run. */ MANUAL_SCAN_REQ - } scan_req; + } scan_req, last_scan_req; struct os_time scan_trigger_time; int scan_runs; /* number of scan runs since WPS was started */ int *next_scan_freqs; + unsigned int own_scan_requested:1; + unsigned int own_scan_running:1; + unsigned int external_scan_running:1; + int *manual_scan_freqs; int scan_interval; /* time in sec between scans to find suitable AP */ int normal_scans; /* normal scans run before sched_scan */ int scan_for_connection; /* whether the scan request was triggered for @@ -605,6 +603,8 @@ struct wpa_supplicant { u8 p2p_auth_invite[ETH_ALEN]; int p2p_sd_over_ctrl_iface; int p2p_in_provisioning; + int p2p_in_invitation; + int p2p_invite_go_freq; int pending_invite_ssid_id; int show_group_started; u8 go_dev_addr[ETH_ALEN]; diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 61a42bd0..40c7655e 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -539,12 +539,12 @@ static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported, static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst, u8 action_code, u8 dialog_token, - u16 status_code, const u8 *buf, - size_t len) + u16 status_code, u32 peer_capab, + const u8 *buf, size_t len) { struct wpa_supplicant *wpa_s = ctx; return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token, - status_code, buf, len); + status_code, peer_capab, buf, len); } @@ -560,7 +560,9 @@ static int wpa_supplicant_tdls_peer_addset( const u8 *supp_rates, size_t supp_rates_len, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, - u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len) + u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len, + const u8 *supp_channels, size_t supp_channels_len, + const u8 *supp_oper_classes, size_t supp_oper_classes_len) { struct wpa_supplicant *wpa_s = ctx; struct hostapd_sta_add_params params; @@ -588,6 +590,10 @@ static int wpa_supplicant_tdls_peer_addset( params.set = !add; params.ext_capab = ext_capab; params.ext_capab_len = ext_capab_len; + params.supp_channels = supp_channels; + params.supp_channels_len = supp_channels_len; + params.supp_oper_classes = supp_oper_classes; + params.supp_oper_classes_len = supp_oper_classes_len; return wpa_drv_sta_add(wpa_s, ¶ms); } diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index f6c2fcb5..fca69254 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -260,31 +260,6 @@ static void wpas_wps_remove_dup_network(struct wpa_supplicant *wpa_s, ssid->group_cipher != new_ssid->group_cipher) continue; - if (ssid->passphrase && new_ssid->passphrase) { - if (os_strlen(ssid->passphrase) != - os_strlen(new_ssid->passphrase)) - continue; - if (os_strcmp(ssid->passphrase, new_ssid->passphrase) != - 0) - continue; - } else if (ssid->passphrase || new_ssid->passphrase) - continue; - - if ((ssid->psk_set || new_ssid->psk_set) && - os_memcmp(ssid->psk, new_ssid->psk, sizeof(ssid->psk)) != 0) - continue; - - if (ssid->auth_alg == WPA_ALG_WEP) { - if (ssid->wep_tx_keyidx != new_ssid->wep_tx_keyidx) - continue; - if (os_memcmp(ssid->wep_key, new_ssid->wep_key, - sizeof(ssid->wep_key))) - continue; - if (os_memcmp(ssid->wep_key_len, new_ssid->wep_key_len, - sizeof(ssid->wep_key_len))) - continue; - } - /* Remove the duplicated older network entry. */ wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id); wpas_notify_network_removed(wpa_s, ssid); |
