aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrint E. Kriebel <bekit@cyngn.com>2014-06-30 19:11:53 -0700
committerBrint E. Kriebel <bekit@cyngn.com>2014-06-30 19:11:53 -0700
commitd00e77faedf730376b0ef1fbf13993c73eff146b (patch)
treedf8bf02fdf600bb8cc09087a7775e7e7f59c5398
parente2d64c3ae308a10f6010c7cb162190b104604c7d (diff)
parent7b4ceed0292e1faa84549e5630be193573d1561b (diff)
downloadandroid_external_wpa_supplicant_8-d00e77faedf730376b0ef1fbf13993c73eff146b.tar.gz
android_external_wpa_supplicant_8-d00e77faedf730376b0ef1fbf13993c73eff146b.tar.bz2
android_external_wpa_supplicant_8-d00e77faedf730376b0ef1fbf13993c73eff146b.zip
-rw-r--r--hostapd/Makefile9
-rw-r--r--src/ap/hostapd.c1
-rw-r--r--src/common/ieee802_11_defs.h2
-rw-r--r--src/common/qca-vendor.h51
-rw-r--r--src/common/wpa_ctrl.h5
-rw-r--r--src/drivers/driver.h42
-rw-r--r--src/drivers/driver_common.c2
-rw-r--r--src/drivers/driver_nl80211.c299
-rw-r--r--src/drivers/nl80211_copy.h466
-rw-r--r--src/eap_peer/eap_config.h8
-rw-r--r--src/eap_peer/eap_proxy_qmi.c1944
-rw-r--r--src/eap_peer/eap_proxy_qmi.h112
-rw-r--r--src/p2p/p2p.c25
-rw-r--r--src/p2p/p2p.h13
-rw-r--r--src/p2p/p2p_go_neg.c16
-rw-r--r--src/p2p/p2p_invitation.c18
-rw-r--r--src/rsn_supp/tdls.c197
-rw-r--r--src/rsn_supp/wpa.h8
-rw-r--r--src/rsn_supp/wpa_i.h17
-rw-r--r--src/rsn_supp/wpa_ie.c58
-rw-r--r--src/rsn_supp/wpa_ie.h6
-rw-r--r--src/tls/pkcs1.c34
-rw-r--r--src/tls/x509v3.c9
-rw-r--r--src/utils/common.c188
-rw-r--r--src/utils/common.h18
-rw-r--r--wpa_supplicant/Android.mk6
-rw-r--r--wpa_supplicant/README-HS202
-rw-r--r--wpa_supplicant/config.c8
-rw-r--r--wpa_supplicant/config.h8
-rw-r--r--wpa_supplicant/config_file.c5
-rw-r--r--wpa_supplicant/config_ssid.h1
-rw-r--r--wpa_supplicant/ctrl_iface.c160
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c2
-rw-r--r--wpa_supplicant/driver_i.h6
-rw-r--r--wpa_supplicant/eap_proxy_qmi.mk30
-rw-r--r--wpa_supplicant/events.c85
-rw-r--r--wpa_supplicant/interworking.c1
-rw-r--r--wpa_supplicant/p2p_supplicant.c85
-rw-r--r--wpa_supplicant/scan.c138
-rw-r--r--wpa_supplicant/wnm_sta.c28
-rw-r--r--wpa_supplicant/wpa_supplicant.c6
-rw-r--r--wpa_supplicant/wpa_supplicant.conf2
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h18
-rw-r--r--wpa_supplicant/wpas_glue.c14
-rw-r--r--wpa_supplicant/wps_supplicant.c25
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, &params, 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(&params, 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, &params);
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, &params);
}
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);