diff options
| -rw-r--r-- | src/common/ieee802_11_defs.h | 1 | ||||
| -rw-r--r-- | src/common/wpa_ctrl.h | 19 | ||||
| -rw-r--r-- | src/drivers/driver_nl80211.c | 2 | ||||
| -rw-r--r-- | src/p2p/p2p.c | 72 | ||||
| -rw-r--r-- | src/p2p/p2p.h | 10 | ||||
| -rw-r--r-- | src/p2p/p2p_go_neg.c | 18 | ||||
| -rw-r--r-- | src/p2p/p2p_group.c | 26 | ||||
| -rw-r--r-- | src/p2p/p2p_i.h | 2 | ||||
| -rw-r--r-- | src/p2p/p2p_invitation.c | 7 | ||||
| -rw-r--r-- | src/p2p/p2p_pd.c | 13 | ||||
| -rw-r--r-- | wpa_supplicant/ctrl_iface.c | 229 | ||||
| -rw-r--r-- | wpa_supplicant/p2p_supplicant.c | 5 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant.c | 7 | ||||
| -rw-r--r-- | wpa_supplicant/wpa_supplicant_i.h | 3 |
14 files changed, 411 insertions, 3 deletions
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index b8e9254f..6de71e9e 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -809,6 +809,7 @@ struct ieee80211_vht_operation { #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) * 00:50:F2 */ #define WPA_IE_VENDOR_TYPE 0x0050f201 +#define WMM_IE_VENDOR_TYPE 0x0050f202 #define WPS_IE_VENDOR_TYPE 0x0050f204 #define OUI_WFA 0x506f9a #define P2P_IE_VENDOR_TYPE 0x506f9a09 diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 534bc997..d91594e3 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -239,6 +239,25 @@ extern "C" { #define WPA_BSS_MASK_DELIM BIT(17) +/* VENDOR_ELEM_* frame id values */ +enum wpa_vendor_elem_frame { + VENDOR_ELEM_PROBE_REQ_P2P = 0, + VENDOR_ELEM_PROBE_RESP_P2P = 1, + VENDOR_ELEM_PROBE_RESP_P2P_GO = 2, + VENDOR_ELEM_BEACON_P2P_GO = 3, + VENDOR_ELEM_P2P_PD_REQ = 4, + VENDOR_ELEM_P2P_PD_RESP = 5, + VENDOR_ELEM_P2P_GO_NEG_REQ = 6, + VENDOR_ELEM_P2P_GO_NEG_RESP = 7, + VENDOR_ELEM_P2P_GO_NEG_CONF = 8, + VENDOR_ELEM_P2P_INV_REQ = 9, + VENDOR_ELEM_P2P_INV_RESP = 10, + VENDOR_ELEM_P2P_ASSOC_REQ = 11, + VENDOR_ELEM_P2P_ASSOC_RESP = 12, + NUM_VENDOR_ELEM_FRAMES +}; + + /* wpa_supplicant/hostapd control interface access */ /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 4d5da949..683123b1 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -10566,7 +10566,7 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report) if (!report) { if (bss->nl_preq && drv->device_ap_sme && - is_ap_interface(drv->nlmode)) { + is_ap_interface(drv->nlmode) && !bss->in_deinit) { /* * Do not disable Probe Request reporting that was * enabled in nl80211_setup_ap(). diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 48f3aa65..565cbdbd 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -12,6 +12,7 @@ #include "eloop.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/wpa_ctrl.h" #include "wps/wps_i.h" #include "p2p_i.h" #include "p2p.h" @@ -608,6 +609,46 @@ static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev, } +static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies, + size_t ies_len) +{ + const u8 *pos, *end; + u8 id, len; + + wpabuf_free(dev->info.vendor_elems); + dev->info.vendor_elems = NULL; + + end = ies + ies_len; + + for (pos = ies; pos + 1 < end; pos += len) { + id = *pos++; + len = *pos++; + + if (pos + len > end) + break; + + if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3) + continue; + + if (len >= 4) { + u32 type = WPA_GET_BE32(pos); + + if (type == WPA_IE_VENDOR_TYPE || + type == WMM_IE_VENDOR_TYPE || + type == WPS_IE_VENDOR_TYPE || + type == P2P_IE_VENDOR_TYPE || + type == WFD_IE_VENDOR_TYPE) + continue; + } + + /* Unknown vendor element - make raw IE data available */ + if (wpabuf_resize(&dev->info.vendor_elems, 2 + len) < 0) + break; + wpabuf_put_data(dev->info.vendor_elems, pos - 2, 2 + len); + } +} + + /** * p2p_add_device - Add peer entries based on scan results or P2P frames * @p2p: P2P module context from p2p_init() @@ -756,6 +797,8 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, p2p_parse_free(&msg); + p2p_update_peer_vendor_elems(dev, ies, ies_len); + if (dev->flags & P2P_DEV_REPORTED) return 0; @@ -825,6 +868,7 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev) } wpabuf_free(dev->info.wfd_subelems); + wpabuf_free(dev->info.vendor_elems); wpabuf_free(dev->go_neg_conf); os_free(dev); @@ -1957,6 +2001,9 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p) extra = wpabuf_len(p2p->wfd_ie_probe_resp); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -1977,6 +2024,10 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p) wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]) + wpabuf_put_buf(buf, + p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]); + /* P2P IE */ len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_capability(buf, p2p->dev_capab & @@ -2252,6 +2303,9 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, extra = wpabuf_len(p2p->wfd_ie_assoc_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]); + /* * (Re)Association Request - P2P IE * P2P Capability attribute (shall be present) @@ -2267,6 +2321,10 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]) + wpabuf_put_buf(tmp, + p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]); + peer = bssid ? p2p_get_device(p2p, bssid) : NULL; lpos = p2p_buf_add_ie_hdr(tmp); @@ -2854,6 +2912,10 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id) wpabuf_put_buf(ies, p2p->wfd_ie_probe_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]) + wpabuf_put_buf(ies, + p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]); + len = p2p_buf_add_ie_hdr(ies); p2p_buf_add_capability(ies, p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0); @@ -2880,6 +2942,10 @@ size_t p2p_scan_ie_buf_len(struct p2p_data *p2p) len += wpabuf_len(p2p->wfd_ie_probe_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p && p2p->vendor_elem && + p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]) + len += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]); + return len; } @@ -4742,3 +4808,9 @@ int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len) p2p->cfg->passphrase_len = len; return 0; } + + +void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem) +{ + p2p->vendor_elem = vendor_elem; +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 16500a80..dee79dfb 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -230,6 +230,14 @@ struct p2p_peer_info { * wfd_subelems - Wi-Fi Display subelements from WFD IE(s) */ struct wpabuf *wfd_subelems; + + /** + * vendor_elems - Unrecognized vendor elements + * + * This buffer includes any other vendor element than P2P, WPS, and WFD + * IE(s) from the frame that was used to discover the peer. + */ + struct wpabuf *vendor_elems; }; enum p2p_prov_disc_status { @@ -1995,4 +2003,6 @@ void p2p_loop_on_known_peers(struct p2p_data *p2p, void *user_data), void *user_data); +void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem); + #endif /* P2P_H */ diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index f24fe236..bd7a2cf5 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -10,6 +10,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "p2p_i.h" #include "p2p.h" @@ -142,6 +143,9 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, extra = wpabuf_len(p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -191,6 +195,9 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]); + return buf; } @@ -268,6 +275,9 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, extra = wpabuf_len(p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -336,6 +346,8 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]); return buf; } @@ -844,6 +856,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, extra = wpabuf_len(p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -888,6 +903,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]); + return buf; } diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index aa075bdb..da8588aa 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -11,6 +11,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "wps/wps_i.h" #include "p2p_i.h" @@ -214,6 +215,10 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) extra = wpabuf_len(group->p2p->wfd_ie_beacon); #endif /* CONFIG_WIFI_DISPLAY */ + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]) + extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]); + ie = wpabuf_alloc(257 + extra); if (ie == NULL) return NULL; @@ -223,6 +228,11 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon); #endif /* CONFIG_WIFI_DISPLAY */ + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]) + wpabuf_put_buf(ie, + group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]); + len = p2p_buf_add_ie_hdr(ie); p2p_group_add_common_ies(group, ie); p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); @@ -448,6 +458,13 @@ static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) ie = p2p_group_encaps_probe_resp(p2p_subelems); wpabuf_free(p2p_subelems); + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]) { + struct wpabuf *extra; + extra = wpabuf_dup(group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]); + ie = wpabuf_concat(extra, ie); + } + #ifdef CONFIG_WIFI_DISPLAY if (group->wfd_ie) { struct wpabuf *wfd = wpabuf_dup(group->wfd_ie); @@ -634,6 +651,10 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) extra = wpabuf_len(group->wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]) + extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]); + /* * (Re)Association Response - P2P IE * Status attribute (shall be present when association request is @@ -649,6 +670,11 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) wpabuf_put_buf(resp, group->wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]) + wpabuf_put_buf(resp, + group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]); + rlen = p2p_buf_add_ie_hdr(resp); if (status != P2P_SC_SUCCESS) p2p_buf_add_status(resp, status); diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 39a927a3..3b60582b 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -499,6 +499,8 @@ struct p2p_data { #endif /* CONFIG_WIFI_DISPLAY */ u16 authorized_oob_dev_pw_id; + + struct wpabuf **vendor_elem; }; /** diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index a36898e9..ef01a668 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -10,6 +10,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.h" #include "p2p_i.h" #include "p2p.h" @@ -45,6 +46,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, extra = wpabuf_len(wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -86,6 +90,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, wpabuf_put_buf(buf, wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]); + if (dev_pw_id >= 0) { /* WSC IE in Invitation Request for NFC static handover */ p2p_build_wps_ie(p2p, buf, dev_pw_id, 0); diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index 68d79d23..e1013672 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -10,6 +10,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "p2p_i.h" #include "p2p.h" @@ -53,6 +54,9 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, extra = wpabuf_len(p2p->wfd_ie_prov_disc_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -77,6 +81,9 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); + return buf; } @@ -111,6 +118,9 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, extra = wpabuf_len(wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]); + buf = wpabuf_alloc(100 + extra); if (buf == NULL) return NULL; @@ -125,6 +135,9 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, wpabuf_put_buf(buf, wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]); + return buf; } diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 244fd2d0..f612b494 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -4715,6 +4715,22 @@ static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd, return pos - buf; pos += res; + if (info->vendor_elems) { + res = os_snprintf(pos, end - pos, "vendor_elems="); + if (res < 0 || res >= end - pos) + return pos - buf; + pos += res; + + pos += wpa_snprintf_hex(pos, end - pos, + wpabuf_head(info->vendor_elems), + wpabuf_len(info->vendor_elems)); + + res = os_snprintf(pos, end - pos, "\n"); + if (res < 0 || res >= end - pos) + return pos - buf; + pos += res; + } + return pos - buf; } @@ -6227,6 +6243,210 @@ static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) #endif /* CONFIG_TESTING_OPTIONS */ +static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s) +{ + unsigned int i; + char buf[30]; + + wpa_printf(MSG_DEBUG, "Update vendor elements"); + + for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) { + if (wpa_s->vendor_elem[i]) { + os_snprintf(buf, sizeof(buf), "frame[%u]", i); + wpa_hexdump_buf(MSG_DEBUG, buf, wpa_s->vendor_elem[i]); + } + } + +#ifdef CONFIG_P2P + if (wpa_s->parent == wpa_s && + wpa_s->global->p2p && + !wpa_s->global->p2p_disabled) + p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem); +#endif /* CONFIG_P2P */ +} + + +static struct wpa_supplicant * +wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s, + enum wpa_vendor_elem_frame frame) +{ + switch (frame) { +#ifdef CONFIG_P2P + case VENDOR_ELEM_PROBE_REQ_P2P: + case VENDOR_ELEM_PROBE_RESP_P2P: + case VENDOR_ELEM_PROBE_RESP_P2P_GO: + case VENDOR_ELEM_BEACON_P2P_GO: + case VENDOR_ELEM_P2P_PD_REQ: + case VENDOR_ELEM_P2P_PD_RESP: + case VENDOR_ELEM_P2P_GO_NEG_REQ: + case VENDOR_ELEM_P2P_GO_NEG_RESP: + case VENDOR_ELEM_P2P_GO_NEG_CONF: + case VENDOR_ELEM_P2P_INV_REQ: + case VENDOR_ELEM_P2P_INV_RESP: + case VENDOR_ELEM_P2P_ASSOC_REQ: + return wpa_s->parent; +#endif /* CONFIG_P2P */ + default: + return wpa_s; + } +} + + +static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos = cmd; + int frame; + size_t len; + struct wpabuf *buf; + struct ieee802_11_elems elems; + + frame = atoi(pos); + if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) + return -1; + wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + + pos = os_strchr(pos, ' '); + if (pos == NULL) + return -1; + pos++; + + len = os_strlen(pos); + if (len == 0) + return 0; + if (len & 1) + return -1; + len /= 2; + + buf = wpabuf_alloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) { + wpabuf_free(buf); + return -1; + } + + if (ieee802_11_parse_elems(wpabuf_head_u8(buf), len, &elems, 0) == + ParseFailed) { + wpabuf_free(buf); + return -1; + } + + if (wpa_s->vendor_elem[frame] == NULL) { + wpa_s->vendor_elem[frame] = buf; + wpas_ctrl_vendor_elem_update(wpa_s); + return 0; + } + + if (wpabuf_resize(&wpa_s->vendor_elem[frame], len) < 0) { + wpabuf_free(buf); + return -1; + } + + wpabuf_put_buf(wpa_s->vendor_elem[frame], buf); + wpabuf_free(buf); + wpas_ctrl_vendor_elem_update(wpa_s); + + return 0; +} + + +static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd, + char *buf, size_t buflen) +{ + int frame = atoi(cmd); + + if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) + return -1; + wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + + if (wpa_s->vendor_elem[frame] == NULL) + return 0; + + return wpa_snprintf_hex(buf, buflen, + wpabuf_head_u8(wpa_s->vendor_elem[frame]), + wpabuf_len(wpa_s->vendor_elem[frame])); +} + + +static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos = cmd; + int frame; + size_t len; + u8 *buf; + struct ieee802_11_elems elems; + u8 *ie, *end; + + frame = atoi(pos); + if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES) + return -1; + wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame); + + pos = os_strchr(pos, ' '); + if (pos == NULL) + return -1; + pos++; + + if (*pos == '*') { + wpabuf_free(wpa_s->vendor_elem[frame]); + wpa_s->vendor_elem[frame] = NULL; + wpas_ctrl_vendor_elem_update(wpa_s); + return 0; + } + + if (wpa_s->vendor_elem[frame] == NULL) + return -1; + + len = os_strlen(pos); + if (len == 0) + return 0; + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(pos, buf, len) < 0) { + os_free(buf); + return -1; + } + + if (ieee802_11_parse_elems(buf, len, &elems, 0) == ParseFailed) { + os_free(buf); + return -1; + } + + ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]); + end = ie + wpabuf_len(wpa_s->vendor_elem[frame]); + + for (; ie + 1 < end; ie += 2 + ie[1]) { + if (ie + len > end) + break; + if (os_memcmp(ie, buf, len) != 0) + continue; + + if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) { + wpabuf_free(wpa_s->vendor_elem[frame]); + wpa_s->vendor_elem[frame] = NULL; + } else { + os_memmove(ie, ie + len, + wpabuf_len(wpa_s->vendor_elem[frame]) - len); + wpa_s->vendor_elem[frame]->used -= len; + } + os_free(buf); + wpas_ctrl_vendor_elem_update(wpa_s); + return 0; + } + + os_free(buf); + + return -1; +} + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { @@ -6792,6 +7012,15 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0) reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ + } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) { + if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0) + reply_len = -1; + } else if (os_strncmp(buf, "VENDOR_ELEM_GET ", 16) == 0) { + reply_len = wpas_ctrl_vendor_elem_get(wpa_s, buf + 16, reply, + reply_size); + } else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) { + if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0) + reply_len = -1; } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 0af5e326..bcad4caa 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -1693,14 +1693,15 @@ static void wpas_dev_found(void *ctx, const u8 *addr, wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR " p2p_dev_addr=" MACSTR " pri_dev_type=%s name='%s' config_methods=0x%x " - "dev_capab=0x%x group_capab=0x%x%s%s", + "dev_capab=0x%x group_capab=0x%x%s%s%s", MAC2STR(addr), MAC2STR(info->p2p_device_addr), wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype)), info->device_name, info->config_methods, info->dev_capab, info->group_capab, wfd_dev_info_hex ? " wfd_dev_info=0x" : "", - wfd_dev_info_hex ? wfd_dev_info_hex : ""); + wfd_dev_info_hex ? wfd_dev_info_hex : "", + info->vendor_elems ? " vendor_elems=1" : ""); os_free(wfd_dev_info_hex); #endif /* CONFIG_NO_STDOUT_DEBUG */ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 55570de6..9414e8f3 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -375,6 +375,8 @@ void free_hw_features(struct wpa_supplicant *wpa_s) static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) { + int i; + bgscan_deinit(wpa_s); autoscan_deinit(wpa_s); scard_deinit(wpa_s->scard); @@ -498,6 +500,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) #ifdef CONFIG_HS20 hs20_deinit(wpa_s); #endif /* CONFIG_HS20 */ + + for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) { + wpabuf_free(wpa_s->vendor_elem[i]); + wpa_s->vendor_elem[i] = NULL; + } } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 8a9ca979..bf3d19df 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -12,6 +12,7 @@ #include "utils/list.h" #include "common/defs.h" #include "common/sae.h" +#include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "config_ssid.h" @@ -860,6 +861,8 @@ struct wpa_supplicant { struct wpa_radio_work *connect_work; unsigned int ext_work_id; + + struct wpabuf *vendor_elem[NUM_VENDOR_ELEM_FRAMES]; }; |
