diff --git a/src/drivers/driver.h b/src/drivers/driver.h index d3b285cc4..1ad48dd79 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -683,6 +683,17 @@ struct wpa_bss_params { #define WPA_STA_SHORT_PREAMBLE BIT(2) #define WPA_STA_MFP BIT(3) +/** + * struct p2p_params - P2P parameters for driver-based P2P management + */ +struct p2p_params { + const char *dev_name; + u8 pri_dev_type[8]; +#define DRV_MAX_SEC_DEV_TYPES 5 + u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8]; + size_t num_sec_dev_types; +}; + /** * struct wpa_driver_ops - Driver interface API definition * @@ -1956,6 +1967,222 @@ struct wpa_driver_ops { * to speed up various operations. */ const char * (*get_radio_name)(void *priv); + + /** + * p2p_find - Start P2P Device Discovery + * @priv: Private driver interface data + * @timeout: Timeout for find operation in seconds or 0 for no timeout + * @type: Device Discovery type (enum p2p_discovery_type) + * Returns: 0 on success, -1 on failure + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_find)(void *priv, unsigned int timeout, int type); + + /** + * p2p_stop_find - Stop P2P Device Discovery + * @priv: Private driver interface data + * Returns: 0 on success, -1 on failure + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_stop_find)(void *priv); + + /** + * p2p_listen - Start P2P Listen state for specified duration + * @priv: Private driver interface data + * @timeout: Listen state duration in milliseconds + * Returns: 0 on success, -1 on failure + * + * This function can be used to request the P2P module to keep the + * device discoverable on the listen channel for an extended set of + * time. At least in its current form, this is mainly used for testing + * purposes and may not be of much use for normal P2P operations. + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_listen)(void *priv, unsigned int timeout); + + /** + * p2p_connect - Start P2P group formation (GO negotiation) + * @priv: Private driver interface data + * @peer_addr: MAC address of the peer P2P client + * @wps_method: enum p2p_wps_method value indicating config method + * @go_intent: Local GO intent value (1..15) + * @own_interface_addr: Intended interface address to use with the + * group + * @force_freq: The only allowed channel frequency in MHz or 0 + * @persistent_group: Whether to create persistent group + * Returns: 0 on success, -1 on failure + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_connect)(void *priv, const u8 *peer_addr, int wps_method, + int go_intent, const u8 *own_interface_addr, + unsigned int force_freq, int persistent_group); + + /** + * wps_success_cb - Report successfully completed WPS provisioning + * @priv: Private driver interface data + * @peer_addr: Peer address + * Returns: 0 on success, -1 on failure + * + * This function is used to report successfully completed WPS + * provisioning during group formation in both GO/Registrar and + * client/Enrollee roles. + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*wps_success_cb)(void *priv, const u8 *peer_addr); + + /** + * p2p_group_formation_failed - Report failed WPS provisioning + * @priv: Private driver interface data + * Returns: 0 on success, -1 on failure + * + * This function is used to report failed group formation. This can + * happen either due to failed WPS provisioning or due to 15 second + * timeout during the provisioning phase. + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_group_formation_failed)(void *priv); + + /** + * p2p_set_params - Set P2P parameters + * @priv: Private driver interface data + * @params: P2P parameters + * Returns: 0 on success, -1 on failure + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_set_params)(void *priv, const struct p2p_params *params); + + /** + * p2p_prov_disc_req - Send Provision Discovery Request + * @priv: Private driver interface data + * @peer_addr: MAC address of the peer P2P client + * @config_methods: WPS Config Methods value (only one bit set) + * Returns: 0 on success, -1 on failure + * + * This function can be used to request a discovered P2P peer to + * display a PIN (config_methods = WPS_CONFIG_DISPLAY) or be prepared + * to enter a PIN from us (config_methods = WPS_CONFIG_KEYPAD). The + * Provision Discovery Request frame is transmitted once immediately + * and if no response is received, the frame will be sent again + * whenever the target device is discovered during device dsicovery + * (start with a p2p_find() call). Response from the peer is indicated + * with the EVENT_P2P_PROV_DISC_RESPONSE event. + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr, + u16 config_methods); + + /** + * p2p_sd_request - Schedule a service discovery query + * @priv: Private driver interface data + * @dst: Destination peer or %NULL to apply for all peers + * @tlvs: P2P Service Query TLV(s) + * Returns: Reference to the query or 0 on failure + * + * Response to the query is indicated with the + * EVENT_P2P_SD_RESPONSE driver event. + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + u64 (*p2p_sd_request)(void *priv, const u8 *dst, + const struct wpabuf *tlvs); + + /** + * p2p_sd_cancel_request - Cancel a pending service discovery query + * @priv: Private driver interface data + * @req: Query reference from p2p_sd_request() + * Returns: 0 on success, -1 on failure + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_sd_cancel_request)(void *priv, u64 req); + + /** + * p2p_sd_response - Send response to a service discovery query + * @priv: Private driver interface data + * @freq: Frequency from EVENT_P2P_SD_REQUEST event + * @dst: Destination address from EVENT_P2P_SD_REQUEST event + * @dialog_token: Dialog token from EVENT_P2P_SD_REQUEST event + * @resp_tlvs: P2P Service Response TLV(s) + * Returns: 0 on success, -1 on failure + * + * This function is called as a response to the request indicated with + * the EVENT_P2P_SD_REQUEST driver event. + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_sd_response)(void *priv, int freq, const u8 *dst, + u8 dialog_token, + const struct wpabuf *resp_tlvs); + + /** + * p2p_service_update - Indicate a change in local services + * @priv: Private driver interface data + * Returns: 0 on success, -1 on failure + * + * This function needs to be called whenever there is a change in + * availability of the local services. This will increment the + * Service Update Indicator value which will be used in SD Request and + * Response frames. + * + * This function is only used if the driver implements P2P management, + * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in + * struct wpa_driver_capa. + */ + int (*p2p_service_update)(void *priv); + + /** + * p2p_reject - Reject peer device (explicitly block connections) + * @priv: Private driver interface data + * @addr: MAC address of the peer + * Returns: 0 on success, -1 on failure + */ + int (*p2p_reject)(void *priv, const u8 *addr); + + /** + * p2p_invite - Invite a P2P Device into a group + * @priv: Private driver interface data + * @peer: Device Address of the peer P2P Device + * @role: Local role in the group + * @bssid: Group BSSID or %NULL if not known + * @ssid: Group SSID + * @ssid_len: Length of ssid in octets + * @go_dev_addr: Forced GO Device Address or %NULL if none + * @persistent_group: Whether this is to reinvoke a persistent group + * Returns: 0 on success, -1 on failure + */ + int (*p2p_invite)(void *priv, const u8 *peer, int role, + const u8 *bssid, const u8 *ssid, size_t ssid_len, + const u8 *go_dev_addr, int persistent_group); }; @@ -2314,7 +2541,39 @@ enum wpa_event_type { * station was lost. Detection can be through massive transmission * failures for example. */ - EVENT_STATION_LOW_ACK + EVENT_STATION_LOW_ACK, + + /** + * EVENT_P2P_DEV_FOUND - Report a discovered P2P device + * + * This event is used only if the driver implements P2P management + * internally. Event data is stored in + * union wpa_event_data::p2p_dev_found. + */ + EVENT_P2P_DEV_FOUND, + + /** + * EVENT_P2P_GO_NEG_REQ_RX - Report reception of GO Negotiation Request + * + * This event is used only if the driver implements P2P management + * internally. Event data is stored in + * union wpa_event_data::p2p_go_neg_req_rx. + */ + EVENT_P2P_GO_NEG_REQ_RX, + + /** + * EVENT_P2P_GO_NEG_COMPLETED - Report completion of GO Negotiation + * + * This event is used only if the driver implements P2P management + * internally. Event data is stored in + * union wpa_event_data::p2p_go_neg_completed. + */ + EVENT_P2P_GO_NEG_COMPLETED, + + EVENT_P2P_PROV_DISC_REQUEST, + EVENT_P2P_PROV_DISC_RESPONSE, + EVENT_P2P_SD_REQUEST, + EVENT_P2P_SD_RESPONSE }; @@ -2768,6 +3027,66 @@ union wpa_event_data { struct low_ack { u8 addr[ETH_ALEN]; } low_ack; + + /** + * struct p2p_dev_found - Data for EVENT_P2P_DEV_FOUND + */ + struct p2p_dev_found { + const u8 *addr; + const u8 *dev_addr; + const u8 *pri_dev_type; + const char *dev_name; + u16 config_methods; + u8 dev_capab; + u8 group_capab; + } p2p_dev_found; + + /** + * struct p2p_go_neg_req_rx - Data for EVENT_P2P_GO_NEG_REQ_RX + */ + struct p2p_go_neg_req_rx { + const u8 *src; + u16 dev_passwd_id; + } p2p_go_neg_req_rx; + + /** + * struct p2p_go_neg_completed - Data for EVENT_P2P_GO_NEG_COMPLETED + */ + struct p2p_go_neg_completed { + struct p2p_go_neg_results *res; + } p2p_go_neg_completed; + + struct p2p_prov_disc_req { + const u8 *peer; + u16 config_methods; + const u8 *dev_addr; + const u8 *pri_dev_type; + const char *dev_name; + u16 supp_config_methods; + u8 dev_capab; + u8 group_capab; + } p2p_prov_disc_req; + + struct p2p_prov_disc_resp { + const u8 *peer; + u16 config_methods; + } p2p_prov_disc_resp; + + struct p2p_sd_req { + int freq; + const u8 *sa; + u8 dialog_token; + u16 update_indic; + const u8 *tlvs; + size_t tlvs_len; + } p2p_sd_req; + + struct p2p_sd_resp { + const u8 *sa; + u16 update_indic; + const u8 *tlvs; + size_t tlvs_len; + } p2p_sd_resp; }; /** diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 56359c1ef..4f239128f 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -3311,5 +3311,19 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = { NULL /* set_p2p_powersave */, NULL /* ampdu */, NULL /* set_intra_bss */, - NULL /* get_radio_name */ + NULL /* get_radio_name */, + NULL /* p2p_find */, + NULL /* p2p_stop_find */, + NULL /* p2p_listen */, + NULL /* p2p_connect */, + NULL /* wps_success_cb */, + NULL /* p2p_group_formation_failed */, + NULL /* p2p_set_params */, + NULL /* p2p_prov_disc_req */, + NULL /* p2p_sd_request */, + NULL /* p2p_sd_cancel_request */, + NULL /* p2p_sd_response */, + NULL /* p2p_service_update */, + NULL /* p2p_reject */, + NULL /* p2p_invite */ }; diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 2741182f3..597ab2d51 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -34,6 +34,8 @@ #include "common/ieee802_11_defs.h" #include "crypto/sha1.h" #include "l2_packet/l2_packet.h" +#include "p2p/p2p.h" +#include "wps/wps.h" #include "driver.h" @@ -107,6 +109,19 @@ struct wpa_driver_test_data { unsigned int remain_on_channel_duration; int current_freq; + + struct p2p_data *p2p; + unsigned int off_channel_freq; + struct wpabuf *pending_action_tx; + u8 pending_action_src[ETH_ALEN]; + u8 pending_action_dst[ETH_ALEN]; + u8 pending_action_bssid[ETH_ALEN]; + unsigned int pending_action_freq; + unsigned int pending_listen_freq; + unsigned int pending_listen_duration; + int pending_p2p_scan; + struct sockaddr *probe_from; + socklen_t probe_from_len; }; @@ -116,6 +131,7 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, static void wpa_driver_test_close_test_socket( struct wpa_driver_test_data *drv); static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx); +static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv); static void test_driver_free_bss(struct test_driver_bss *bss) @@ -469,6 +485,34 @@ static int wpa_driver_test_send_mlme(void *priv, const u8 *data, event.tx_status.ack = ret >= 0; wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event); +#ifdef CONFIG_P2P + if (drv->p2p && + WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { + if (drv->pending_action_tx == NULL) { + wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - " + "no pending operation"); + return ret; + } + + if (os_memcmp(hdr->addr1, drv->pending_action_dst, ETH_ALEN) != + 0) { + wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - " + "unknown destination address"); + return ret; + } + + wpabuf_free(drv->pending_action_tx); + drv->pending_action_tx = NULL; + + p2p_send_action_cb(drv->p2p, drv->pending_action_freq, + drv->pending_action_dst, + drv->pending_action_src, + drv->pending_action_bssid, + ret >= 0); + } +#endif /* CONFIG_P2P */ + return ret; } @@ -515,6 +559,10 @@ static void test_driver_scan(struct wpa_driver_test_data *drv, event.rx_probe_req.ie = ie; event.rx_probe_req.ie_len = ielen; wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); +#ifdef CONFIG_P2P + if (drv->p2p) + p2p_probe_req_rx(drv->p2p, sa, ie, ielen); +#endif /* CONFIG_P2P */ } dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) { @@ -1274,7 +1322,23 @@ static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx) static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx) { + struct wpa_driver_test_data *drv = eloop_ctx; wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); + if (drv->pending_p2p_scan && drv->p2p) { +#ifdef CONFIG_P2P + size_t i; + for (i = 0; i < drv->num_scanres; i++) { + struct wpa_scan_res *bss = drv->scanres[i]; + if (p2p_scan_res_handler(drv->p2p, bss->bssid, + bss->freq, bss->level, + (const u8 *) (bss + 1), + bss->ie_len) > 0) + return; + } + p2p_scan_res_handled(drv->p2p); +#endif /* CONFIG_P2P */ + return; + } wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } @@ -1852,6 +1916,8 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, { int freq = 0, own_freq; union wpa_event_data event; + const struct ieee80211_mgmt *mgmt; + u16 fc; struct test_driver_bss *bss; bss = dl_list_first(&drv->bss, struct test_driver_bss, list); @@ -1889,12 +1955,10 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, event.mlme_rx.freq = freq; wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event); - if (drv->probe_req_report && data_len >= 24) { - const struct ieee80211_mgmt *mgmt; - u16 fc; + mgmt = (const struct ieee80211_mgmt *) data; + fc = le_to_host16(mgmt->frame_control); - mgmt = (const struct ieee80211_mgmt *) data; - fc = le_to_host16(mgmt->frame_control); + if (drv->probe_req_report && data_len >= 24) { if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) { os_memset(&event, 0, sizeof(event)); @@ -1904,8 +1968,29 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, data_len - (mgmt->u.probe_req.variable - data); wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event); +#ifdef CONFIG_P2P + if (drv->p2p) + p2p_probe_req_rx(drv->p2p, mgmt->sa, + event.rx_probe_req.ie, + event.rx_probe_req.ie_len); +#endif /* CONFIG_P2P */ } } + +#ifdef CONFIG_P2P + if (drv->p2p && + WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { + size_t hdr_len; + hdr_len = (const u8 *) + &mgmt->u.action.u.vs_public_action.action - data; + p2p_rx_action(drv->p2p, mgmt->da, mgmt->sa, mgmt->bssid, + mgmt->u.action.category, + &mgmt->u.action.u.vs_public_action.action, + data_len - hdr_len, freq); + } +#endif /* CONFIG_P2P */ + } @@ -1921,6 +2006,29 @@ static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv, bss = dl_list_first(&drv->bss, struct test_driver_bss, list); /* data: optional [ STA-addr | ' ' | IEs(hex) ] */ +#ifdef CONFIG_P2P + if (drv->probe_req_report && drv->p2p && data_len) { + const char *d = (const char *) data; + u8 sa[ETH_ALEN]; + u8 ie[512]; + size_t ielen; + + if (hwaddr_aton(d, sa)) + return; + d += 18; + while (*d == ' ') + d++; + ielen = os_strlen(d) / 2; + if (ielen > sizeof(ie)) + ielen = sizeof(ie); + if (hexstr2bin(d, ie, ielen) < 0) + ielen = 0; + drv->probe_from = from; + drv->probe_from_len = fromlen; + p2p_probe_req_rx(drv->p2p, sa, ie, ielen); + drv->probe_from = NULL; + } +#endif /* CONFIG_P2P */ if (!drv->ibss) return; @@ -2077,6 +2185,12 @@ static void wpa_driver_test_deinit(void *priv) struct test_client_socket *cli, *prev; int i; +#ifdef CONFIG_P2P + if (drv->p2p) + p2p_deinit(drv->p2p); + wpabuf_free(drv->pending_action_tx); +#endif /* CONFIG_P2P */ + cli = drv->cli; while (cli) { prev = cli; @@ -2280,6 +2394,13 @@ static int wpa_driver_test_set_param(void *priv, const char *param) } #endif /* CONFIG_CLIENT_MLME */ + if (os_strstr(param, "p2p_mgmt=1")) { + wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P " + "management"); + if (wpa_driver_test_init_p2p(drv) < 0) + return -1; + } + return 0; } @@ -2388,6 +2509,8 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) WPA_DRIVER_AUTH_LEAP; if (drv->use_mlme) capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME; + if (drv->p2p) + capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT; capa->flags |= WPA_DRIVER_FLAGS_AP; capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT; capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE; @@ -2640,6 +2763,33 @@ static int wpa_driver_test_send_action(void *priv, unsigned int freq, } +#ifdef CONFIG_P2P +static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_driver_test_data *drv = eloop_ctx; + int res; + + if (drv->pending_action_tx == NULL) + return; + + if (drv->off_channel_freq != drv->pending_action_freq) { + wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX " + "waiting for another freq=%u", + drv->pending_action_freq); + return; + } + wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to " + MACSTR, MAC2STR(drv->pending_action_dst)); + res = wpa_driver_test_send_action(drv, drv->pending_action_freq, 0, + drv->pending_action_dst, + drv->pending_action_src, + drv->pending_action_bssid, + wpabuf_head(drv->pending_action_tx), + wpabuf_len(drv->pending_action_tx)); +} +#endif /* CONFIG_P2P */ + + static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_driver_test_data *drv = eloop_ctx; @@ -2650,9 +2800,13 @@ static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx) os_memset(&data, 0, sizeof(data)); data.remain_on_channel.freq = drv->remain_on_channel_freq; data.remain_on_channel.duration = drv->remain_on_channel_duration; - wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data); + + if (drv->p2p) + drv->off_channel_freq = 0; drv->remain_on_channel_freq = 0; + + wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data); } @@ -2683,6 +2837,18 @@ static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq, data.remain_on_channel.duration = duration; wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data); +#ifdef CONFIG_P2P + if (drv->p2p) { + drv->off_channel_freq = drv->remain_on_channel_freq; + test_send_action_cb(drv, NULL); + if (drv->off_channel_freq == drv->pending_listen_freq) { + p2p_listen_cb(drv->p2p, drv->pending_listen_freq, + drv->pending_listen_duration); + drv->pending_listen_freq = 0; + } + } +#endif /* CONFIG_P2P */ + return 0; } @@ -2710,6 +2876,455 @@ static int wpa_driver_test_probe_req_report(void *priv, int report) } +#ifdef CONFIG_P2P + +static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type) +{ + struct wpa_driver_test_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout); + if (!drv->p2p) + return -1; + return p2p_find(drv->p2p, timeout, type); +} + + +static int wpa_driver_test_p2p_stop_find(void *priv) +{ + struct wpa_driver_test_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s", __func__); + if (!drv->p2p) + return -1; + p2p_stop_find(drv->p2p); + return 0; +} + + +static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout) +{ + struct wpa_driver_test_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout); + if (!drv->p2p) + return -1; + return p2p_listen(drv->p2p, timeout); +} + + +static int wpa_driver_test_p2p_connect(void *priv, const u8 *peer_addr, + int wps_method, int go_intent, + const u8 *own_interface_addr, + unsigned int force_freq, + int persistent_group) +{ + struct wpa_driver_test_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d " + "go_intent=%d " + "own_interface_addr=" MACSTR " force_freq=%u " + "persistent_group=%d)", + __func__, MAC2STR(peer_addr), wps_method, go_intent, + MAC2STR(own_interface_addr), force_freq, persistent_group); + if (!drv->p2p) + return -1; + return p2p_connect(drv->p2p, peer_addr, wps_method, go_intent, + own_interface_addr, force_freq, persistent_group); +} + + +static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr) +{ + struct wpa_driver_test_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")", + __func__, MAC2STR(peer_addr)); + if (!drv->p2p) + return -1; + p2p_wps_success_cb(drv->p2p, peer_addr); + return 0; +} + + +static int wpa_driver_test_p2p_group_formation_failed(void *priv) +{ + struct wpa_driver_test_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s", __func__); + if (!drv->p2p) + return -1; + p2p_group_formation_failed(drv->p2p); + return 0; +} + + +static int wpa_driver_test_p2p_set_params(void *priv, + const struct p2p_params *params) +{ + struct wpa_driver_test_data *drv = priv; + wpa_printf(MSG_DEBUG, "%s", __func__); + if (!drv->p2p) + return -1; + if (p2p_set_dev_name(drv->p2p, params->dev_name) < 0 || + p2p_set_pri_dev_type(drv->p2p, params->pri_dev_type) < 0 || + p2p_set_sec_dev_types(drv->p2p, params->sec_dev_type, + params->num_sec_dev_types) < 0) + return -1; + return 0; +} + + +static int test_p2p_scan(void *ctx, enum p2p_scan_type type, int freq) +{ + struct wpa_driver_test_data *drv = ctx; + struct wpa_driver_scan_params params; + int ret; + struct wpabuf *wps_ie, *ies; + int social_channels[] = { 2412, 2437, 2462, 0, 0 }; + + wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)", + __func__, type, freq); + + os_memset(¶ms, 0, sizeof(params)); + + /* P2P Wildcard SSID */ + params.num_ssids = 1; + params.ssids[0].ssid = (u8 *) P2P_WILDCARD_SSID; + params.ssids[0].ssid_len = P2P_WILDCARD_SSID_LEN; + +#if 0 /* TODO: WPS IE */ + wpa_s->wps->dev.p2p = 1; + wps_ie = wps_build_probe_req_ie(0, &wpa_s->wps->dev, wpa_s->wps->uuid, + WPS_REQ_ENROLLEE); +#else + wps_ie = wpabuf_alloc(1); +#endif + if (wps_ie == NULL) + return -1; + + ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100); + if (ies == NULL) { + wpabuf_free(wps_ie); + return -1; + } + wpabuf_put_buf(ies, wps_ie); + wpabuf_free(wps_ie); + + p2p_scan_ie(drv->p2p, ies); + + params.extra_ies = wpabuf_head(ies); + params.extra_ies_len = wpabuf_len(ies); + + switch (type) { + case P2P_SCAN_SOCIAL: + params.freqs = social_channels; + break; + case P2P_SCAN_FULL: + break; + case P2P_SCAN_SPECIFIC: + social_channels[0] = freq; + social_channels[1] = 0; + params.freqs = social_channels; + break; + case P2P_SCAN_SOCIAL_PLUS_ONE: + social_channels[3] = freq; + params.freqs = social_channels; + break; + } + + drv->pending_p2p_scan = 1; + ret = wpa_driver_test_scan(drv, ¶ms); + + wpabuf_free(ies); + + return ret; +} + + +static int test_send_action(void *ctx, unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, const u8 *buf, + size_t len, unsigned int wait_time) +{ + struct wpa_driver_test_data *drv = ctx; + + wpa_printf(MSG_DEBUG, "%s(freq=%u dst=" MACSTR " src=" MACSTR + " bssid=" MACSTR " len=%d", + __func__, freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), + (int) len); + if (freq <= 0) { + wpa_printf(MSG_WARNING, "P2P: No frequency specified for " + "action frame TX"); + return -1; + } + + if (drv->pending_action_tx) { + wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX " + "to " MACSTR, MAC2STR(drv->pending_action_dst)); + wpabuf_free(drv->pending_action_tx); + } + drv->pending_action_tx = wpabuf_alloc(len); + if (drv->pending_action_tx == NULL) + return -1; + wpabuf_put_data(drv->pending_action_tx, buf, len); + os_memcpy(drv->pending_action_src, src, ETH_ALEN); + os_memcpy(drv->pending_action_dst, dst, ETH_ALEN); + os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN); + drv->pending_action_freq = freq; + + if (drv->off_channel_freq == freq) { + /* Already on requested channel; send immediately */ + /* TODO: Would there ever be need to extend the current + * duration on the channel? */ + eloop_cancel_timeout(test_send_action_cb, drv, NULL); + eloop_register_timeout(0, 0, test_send_action_cb, drv, NULL); + return 0; + } + + wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted " + "once the driver gets to the requested channel"); + if (wpa_driver_test_remain_on_channel(drv, freq, wait_time) < 0) { + wpa_printf(MSG_DEBUG, "P2P: Failed to request driver " + "to remain on channel (%u MHz) for Action " + "Frame TX", freq); + return -1; + } + + return 0; +} + + +static void test_send_action_done(void *ctx) +{ + wpa_printf(MSG_DEBUG, "%s", __func__); + /* TODO */ +} + + +static void test_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) +{ + struct wpa_driver_test_data *drv = ctx; + union wpa_event_data event; + wpa_printf(MSG_DEBUG, "%s", __func__); + os_memset(&event, 0, sizeof(event)); + event.p2p_go_neg_completed.res = res; + wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_COMPLETED, &event); +} + + +static void test_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id) +{ + struct wpa_driver_test_data *drv = ctx; + union wpa_event_data event; + wpa_printf(MSG_DEBUG, "%s(src=" MACSTR ")", __func__, MAC2STR(src)); + os_memset(&event, 0, sizeof(event)); + event.p2p_go_neg_req_rx.src = src; + event.p2p_go_neg_req_rx.dev_passwd_id = dev_passwd_id; + wpa_supplicant_event(drv->ctx, EVENT_P2P_GO_NEG_REQ_RX, &event); +} + + +static void test_dev_found(void *ctx, const u8 *addr, const u8 *dev_addr, + const u8 *pri_dev_type, const char *dev_name, + u16 config_methods, u8 dev_capab, u8 group_capab) +{ + struct wpa_driver_test_data *drv = ctx; + union wpa_event_data event; + char devtype[WPS_DEV_TYPE_BUFSIZE]; + wpa_printf(MSG_DEBUG, "%s(" MACSTR " p2p_dev_addr=" MACSTR + " pri_dev_type=%s name='%s' config_methods=0x%x " + "dev_capab=0x%x group_capab=0x%x)", + __func__, MAC2STR(addr), MAC2STR(dev_addr), + wps_dev_type_bin2str(pri_dev_type, devtype, + sizeof(devtype)), + dev_name, config_methods, dev_capab, group_capab); + + os_memset(&event, 0, sizeof(event)); + event.p2p_dev_found.addr = addr; + event.p2p_dev_found.dev_addr = dev_addr; + event.p2p_dev_found.pri_dev_type = pri_dev_type; + event.p2p_dev_found.dev_name = dev_name; + event.p2p_dev_found.config_methods = config_methods; + event.p2p_dev_found.dev_capab = dev_capab; + event.p2p_dev_found.group_capab = group_capab; + wpa_supplicant_event(drv->ctx, EVENT_P2P_DEV_FOUND, &event); +} + + +static int test_start_listen(void *ctx, unsigned int freq, + unsigned int duration, + const struct wpabuf *probe_resp_ie) +{ + struct wpa_driver_test_data *drv = ctx; + + wpa_printf(MSG_DEBUG, "%s(freq=%u duration=%u)", + __func__, freq, duration); + + if (wpa_driver_test_probe_req_report(drv, 1) < 0) + return -1; + + drv->pending_listen_freq = freq; + drv->pending_listen_duration = duration; + + if (wpa_driver_test_remain_on_channel(drv, freq, duration) < 0) { + drv->pending_listen_freq = 0; + return -1; + } + + return 0; +} + + +static void test_stop_listen(void *ctx) +{ + wpa_printf(MSG_DEBUG, "%s", __func__); + /* TODO */ +} + + +static int test_send_probe_resp(void *ctx, const struct wpabuf *buf) +{ + struct wpa_driver_test_data *drv = ctx; + char resp[512], *pos, *end; + int ret; + const struct ieee80211_mgmt *mgmt; + const u8 *ie, *ie_end; + + wpa_printf(MSG_DEBUG, "%s", __func__); + wpa_hexdump_buf(MSG_MSGDUMP, "Probe Response", buf); + if (wpabuf_len(buf) < 24) + return -1; + if (!drv->probe_from) { + wpa_printf(MSG_DEBUG, "%s: probe_from not set", __func__); + return -1; + } + + pos = resp; + end = resp + sizeof(resp); + + mgmt = wpabuf_head(buf); + + /* reply: SCANRESP BSSID SSID IEs */ + ret = os_snprintf(pos, end - pos, "SCANRESP " MACSTR " ", + MAC2STR(mgmt->bssid)); + if (ret < 0 || ret >= end - pos) + return -1; + pos += ret; + + ie = mgmt->u.probe_resp.variable; + ie_end = wpabuf_head_u8(buf) + wpabuf_len(buf); + if (ie_end - ie < 2 || ie[0] != WLAN_EID_SSID || + ie + 2 + ie[1] > ie_end) + return -1; + pos += wpa_snprintf_hex(pos, end - pos, ie + 2, ie[1]); + + ret = os_snprintf(pos, end - pos, " "); + if (ret < 0 || ret >= end - pos) + return -1; + pos += ret; + pos += wpa_snprintf_hex(pos, end - pos, ie, ie_end - ie); + + sendto(drv->test_socket, resp, pos - resp, 0, + drv->probe_from, drv->probe_from_len); + + return 0; +} + + +static void test_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token, + u16 update_indic, const u8 *tlvs, size_t tlvs_len) +{ + wpa_printf(MSG_DEBUG, "%s", __func__); + /* TODO */ +} + + +static void test_sd_response(void *ctx, const u8 *sa, u16 update_indic, + const u8 *tlvs, size_t tlvs_len) +{ + wpa_printf(MSG_DEBUG, "%s", __func__); + /* TODO */ +} + + +static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods, + const u8 *dev_addr, const u8 *pri_dev_type, + const char *dev_name, u16 supp_config_methods, + u8 dev_capab, u8 group_capab) +{ + wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", + __func__, MAC2STR(peer), config_methods); + /* TODO */ +} + + +static void test_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods) +{ + wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)", + __func__, MAC2STR(peer), config_methods); + /* TODO */ +} + +#endif /* CONFIG_P2P */ + + +static int wpa_driver_test_init_p2p(struct wpa_driver_test_data *drv) +{ +#ifdef CONFIG_P2P + struct p2p_config p2p; + unsigned int r; + int i; + + os_memset(&p2p, 0, sizeof(p2p)); + p2p.msg_ctx = drv->ctx; + p2p.cb_ctx = drv; + p2p.p2p_scan = test_p2p_scan; + p2p.send_action = test_send_action; + p2p.send_action_done = test_send_action_done; + p2p.go_neg_completed = test_go_neg_completed; + p2p.go_neg_req_rx = test_go_neg_req_rx; + p2p.dev_found = test_dev_found; + p2p.start_listen = test_start_listen; + p2p.stop_listen = test_stop_listen; + p2p.send_probe_resp = test_send_probe_resp; + p2p.sd_request = test_sd_request; + p2p.sd_response = test_sd_response; + p2p.prov_disc_req = test_prov_disc_req; + p2p.prov_disc_resp = test_prov_disc_resp; + + os_memcpy(p2p.dev_addr, drv->own_addr, ETH_ALEN); + + p2p.reg_class = 12; /* TODO: change depending on location */ + /* + * Pick one of the social channels randomly as the listen + * channel. + */ + os_get_random((u8 *) &r, sizeof(r)); + p2p.channel = 1 + (r % 3) * 5; + + /* TODO: change depending on location */ + p2p.op_reg_class = 12; + /* + * For initial tests, pick the operation channel randomly. + * TODO: Use scan results (etc.) to select the best channel. + */ + p2p.op_channel = 1 + r % 11; + + os_memcpy(p2p.country, "US ", 3); + + /* FIX: fetch available channels from the driver */ + p2p.channels.reg_classes = 1; + p2p.channels.reg_class[0].reg_class = 12; /* US/12 = 2.4 GHz band */ + p2p.channels.reg_class[0].channels = 11; + for (i = 0; i < 11; i++) + p2p.channels.reg_class[0].channel[i] = i + 1; + + p2p.max_peers = 100; + + drv->p2p = p2p_init(&p2p); + if (drv->p2p == NULL) + return -1; + return 0; +#else /* CONFIG_P2P */ + wpa_printf(MSG_INFO, "driver_test: P2P support not included"); + return -1; +#endif /* CONFIG_P2P */ +} + + const struct wpa_driver_ops wpa_driver_test_ops = { "test", "wpa_supplicant test driver", @@ -2758,4 +3373,14 @@ const struct wpa_driver_ops wpa_driver_test_ops = { .remain_on_channel = wpa_driver_test_remain_on_channel, .cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel, .probe_req_report = wpa_driver_test_probe_req_report, +#ifdef CONFIG_P2P + .p2p_find = wpa_driver_test_p2p_find, + .p2p_stop_find = wpa_driver_test_p2p_stop_find, + .p2p_listen = wpa_driver_test_p2p_listen, + .p2p_connect = wpa_driver_test_p2p_connect, + .wps_success_cb = wpa_driver_test_wps_success_cb, + .p2p_group_formation_failed = + wpa_driver_test_p2p_group_formation_failed, + .p2p_set_params = wpa_driver_test_p2p_set_params, +#endif /* CONFIG_P2P */ }; diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 34364810f..5331765f3 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -547,4 +547,133 @@ static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu) return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu); } +static inline int wpa_drv_p2p_find(struct wpa_supplicant *wpa_s, + unsigned int timeout, int type) +{ + if (!wpa_s->driver->p2p_find) + return -1; + return wpa_s->driver->p2p_find(wpa_s->drv_priv, timeout, type); +} + +static inline int wpa_drv_p2p_stop_find(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->driver->p2p_stop_find) + return -1; + return wpa_s->driver->p2p_stop_find(wpa_s->drv_priv); +} + +static inline int wpa_drv_p2p_listen(struct wpa_supplicant *wpa_s, + unsigned int timeout) +{ + if (!wpa_s->driver->p2p_listen) + return -1; + return wpa_s->driver->p2p_listen(wpa_s->drv_priv, timeout); +} + +static inline int wpa_drv_p2p_connect(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, int wps_method, + int go_intent, + const u8 *own_interface_addr, + unsigned int force_freq, + int persistent_group) +{ + if (!wpa_s->driver->p2p_connect) + return -1; + return wpa_s->driver->p2p_connect(wpa_s->drv_priv, peer_addr, + wps_method, go_intent, + own_interface_addr, force_freq, + persistent_group); +} + +static inline int wpa_drv_wps_success_cb(struct wpa_supplicant *wpa_s, + const u8 *peer_addr) +{ + if (!wpa_s->driver->wps_success_cb) + return -1; + return wpa_s->driver->wps_success_cb(wpa_s->drv_priv, peer_addr); +} + +static inline int +wpa_drv_p2p_group_formation_failed(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->driver->p2p_group_formation_failed) + return -1; + return wpa_s->driver->p2p_group_formation_failed(wpa_s->drv_priv); +} + +static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s, + const struct p2p_params *params) +{ + if (!wpa_s->driver->p2p_set_params) + return -1; + return wpa_s->driver->p2p_set_params(wpa_s->drv_priv, params); +} + +static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s, + const u8 *peer_addr, + u16 config_methods) +{ + if (!wpa_s->driver->p2p_prov_disc_req) + return -1; + return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr, + config_methods); +} + +static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s, + const u8 *dst, + const struct wpabuf *tlvs) +{ + if (!wpa_s->driver->p2p_sd_request) + return 0; + return wpa_s->driver->p2p_sd_request(wpa_s->drv_priv, dst, tlvs); +} + +static inline int wpa_drv_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, + u64 req) +{ + if (!wpa_s->driver->p2p_sd_cancel_request) + return -1; + return wpa_s->driver->p2p_sd_cancel_request(wpa_s->drv_priv, req); +} + +static inline int wpa_drv_p2p_sd_response(struct wpa_supplicant *wpa_s, + int freq, const u8 *dst, + u8 dialog_token, + const struct wpabuf *resp_tlvs) +{ + if (!wpa_s->driver->p2p_sd_response) + return -1; + return wpa_s->driver->p2p_sd_response(wpa_s->drv_priv, freq, dst, + dialog_token, resp_tlvs); +} + +static inline int wpa_drv_p2p_service_update(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->driver->p2p_service_update) + return -1; + return wpa_s->driver->p2p_service_update(wpa_s->drv_priv); +} + +static inline int wpa_drv_p2p_reject(struct wpa_supplicant *wpa_s, + const u8 *addr) +{ + if (!wpa_s->driver->p2p_reject) + return -1; + return wpa_s->driver->p2p_reject(wpa_s->drv_priv, addr); +} + +static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s, + const u8 *peer, int role, const u8 *bssid, + const u8 *ssid, size_t ssid_len, + const u8 *go_dev_addr, + int persistent_group) +{ + if (!wpa_s->driver->p2p_invite) + return -1; + return wpa_s->driver->p2p_invite(wpa_s->drv_priv, peer, role, bssid, + ssid, ssid_len, go_dev_addr, + persistent_group); +} + + #endif /* DRIVER_I_H */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index bcd59d94e..201c33928 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1950,6 +1950,50 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_probe_req.ie, data->rx_probe_req.ie_len); break; + case EVENT_P2P_DEV_FOUND: + wpas_dev_found(wpa_s, data->p2p_dev_found.addr, + data->p2p_dev_found.dev_addr, + data->p2p_dev_found.pri_dev_type, + data->p2p_dev_found.dev_name, + data->p2p_dev_found.config_methods, + data->p2p_dev_found.dev_capab, + data->p2p_dev_found.group_capab); + break; + case EVENT_P2P_GO_NEG_REQ_RX: + wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src, + data->p2p_go_neg_req_rx.dev_passwd_id); + break; + case EVENT_P2P_GO_NEG_COMPLETED: + wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res); + break; + case EVENT_P2P_PROV_DISC_REQUEST: + wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer, + data->p2p_prov_disc_req.config_methods, + data->p2p_prov_disc_req.dev_addr, + data->p2p_prov_disc_req.pri_dev_type, + data->p2p_prov_disc_req.dev_name, + data->p2p_prov_disc_req.supp_config_methods, + data->p2p_prov_disc_req.dev_capab, + data->p2p_prov_disc_req.group_capab); + break; + case EVENT_P2P_PROV_DISC_RESPONSE: + wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer, + data->p2p_prov_disc_resp.config_methods); + break; + case EVENT_P2P_SD_REQUEST: + wpas_sd_request(wpa_s, data->p2p_sd_req.freq, + data->p2p_sd_req.sa, + data->p2p_sd_req.dialog_token, + data->p2p_sd_req.update_indic, + data->p2p_sd_req.tlvs, + data->p2p_sd_req.tlvs_len); + break; + case EVENT_P2P_SD_RESPONSE: + wpas_sd_response(wpa_s, data->p2p_sd_resp.sa, + data->p2p_sd_resp.update_indic, + data->p2p_sd_resp.tlvs, + data->p2p_sd_resp.tlvs_len); + break; #endif /* CONFIG_P2P */ #ifdef CONFIG_CLIENT_MLME case EVENT_MLME_RX: { diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 37455515f..ca5f01391 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -642,6 +642,8 @@ void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst, { if (wpa_s->global->p2p_disabled) return; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return; if (wpa_s->pending_action_tx == NULL) { wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - no " @@ -1050,6 +1052,8 @@ static void wpas_p2p_group_formation_timeout(void *eloop_ctx, wpa_printf(MSG_DEBUG, "P2P: Group Formation timed out"); if (wpa_s->global->p2p) p2p_group_formation_failed(wpa_s->global->p2p); + else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + wpa_drv_p2p_group_formation_failed(wpa_s); wpas_group_formation_completed(wpa_s, 0); } @@ -1623,6 +1627,8 @@ void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic, void * wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst, const struct wpabuf *tlvs) { + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return (void *) wpa_drv_p2p_sd_request(wpa_s, dst, tlvs); return p2p_sd_request(wpa_s->global->p2p, dst, tlvs); } @@ -1649,6 +1655,8 @@ void * wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst, int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, void *req) { + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return wpa_drv_p2p_sd_cancel_request(wpa_s, (u64) req); return p2p_sd_cancel_request(wpa_s->global->p2p, req); } @@ -1657,6 +1665,11 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, const u8 *dst, u8 dialog_token, const struct wpabuf *resp_tlvs) { + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { + wpa_drv_p2p_sd_response(wpa_s, freq, dst, dialog_token, + resp_tlvs); + return; + } p2p_sd_response(wpa_s->global->p2p, freq, dst, dialog_token, resp_tlvs); } @@ -1664,6 +1677,10 @@ void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq, void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s) { + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { + wpa_drv_p2p_service_update(wpa_s); + return; + } p2p_sd_service_update(wpa_s->global->p2p); } @@ -2247,6 +2264,39 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) if (global->p2p) return 0; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { + struct p2p_params params; + + wpa_printf(MSG_DEBUG, "P2P: Use driver-based P2P management"); + os_memset(¶ms, 0, sizeof(params)); + params.dev_name = wpa_s->conf->device_name; + if (wpa_s->conf->device_type && + wps_dev_type_str2bin(wpa_s->conf->device_type, + params.pri_dev_type) < 0) { + wpa_printf(MSG_ERROR, "P2P: Invalid device_type"); + return -1; + } + for (i = 0; i < MAX_SEC_DEVICE_TYPES; i++) { + if (wpa_s->conf->sec_device_type[i] == NULL) + continue; + if (wps_dev_type_str2bin( + wpa_s->conf->sec_device_type[i], + params.sec_dev_type[ + params.num_sec_dev_types]) < 0) { + wpa_printf(MSG_ERROR, "P2P: Invalid " + "sec_device_type"); + return -1; + } + params.num_sec_dev_types++; + if (params.num_sec_dev_types == DRV_MAX_SEC_DEV_TYPES) + break; + } + if (wpa_drv_p2p_set_params(wpa_s, ¶ms) < 0) + return -1; + + return 0; + } + os_memset(&p2p, 0, sizeof(p2p)); p2p.msg_ctx = wpa_s; p2p.cb_ctx = wpa_s; @@ -2466,6 +2516,12 @@ static int wpas_p2p_start_go_neg(struct wpa_supplicant *wpa_s, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group) { + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { + return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method, + go_intent, own_interface_addr, + force_freq, persistent_group); + } + return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, persistent_group); @@ -2478,6 +2534,9 @@ static int wpas_p2p_auth_go_neg(struct wpa_supplicant *wpa_s, int go_intent, const u8 *own_interface_addr, unsigned int force_freq, int persistent_group) { + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return -1; + return p2p_authorize(wpa_s->global->p2p, peer_addr, wps_method, go_intent, own_interface_addr, force_freq, persistent_group); @@ -2907,6 +2966,9 @@ static int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, if (timeout > wpa_s->max_remain_on_chan) timeout = wpa_s->max_remain_on_chan; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return wpa_drv_p2p_listen(wpa_s, timeout); + return p2p_listen(wpa_s->global->p2p, timeout); } @@ -3284,6 +3346,9 @@ struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct p2p_group *group; struct p2p_group_config *cfg; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return NULL; + cfg = os_zalloc(sizeof(*cfg)); if (cfg == NULL) return NULL; @@ -3322,6 +3387,8 @@ void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr, NULL); if (wpa_s->global->p2p) p2p_wps_success_cb(wpa_s->global->p2p, peer_addr); + else if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + wpa_drv_wps_success_cb(wpa_s, peer_addr); wpas_group_formation_completed(wpa_s, 1); } @@ -3341,6 +3408,11 @@ int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr, else return -1; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { + return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr, + config_methods); + } + if (wpa_s->global->p2p == NULL) return -1; @@ -3374,6 +3446,9 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, wpas_p2p_clear_pending_action_tx(wpa_s); wpa_s->p2p_long_listen = 0; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return wpa_drv_p2p_find(wpa_s, timeout, type); + return p2p_find(wpa_s->global->p2p, timeout, type); } @@ -3385,6 +3460,11 @@ void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) { + wpa_drv_p2p_stop_find(wpa_s); + return; + } + p2p_stop_find(wpa_s->global->p2p); wpas_p2p_remove_pending_group_interface(wpa_s); @@ -3497,6 +3577,9 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr) { wpa_s->p2p_long_listen = 0; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return wpa_drv_p2p_reject(wpa_s, addr); + return p2p_reject(wpa_s->global->p2p, addr); } @@ -3532,6 +3615,11 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr, } wpa_s->pending_invite_ssid_id = ssid->id; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid, + ssid->ssid, ssid->ssid_len, + go_dev_addr, 1); + return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, 0, go_dev_addr, 1); } @@ -3581,6 +3669,11 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname, } wpa_s->parent->pending_invite_ssid_id = -1; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return wpa_drv_p2p_invite(wpa_s, peer_addr, role, bssid, + ssid->ssid, ssid->ssid_len, + go_dev_addr, 0); + return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid, ssid->ssid, ssid->ssid_len, wpa_s->assoc_freq, go_dev_addr, 0); @@ -3638,6 +3731,9 @@ void wpas_p2p_completed(struct wpa_supplicant *wpa_s) int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, u32 interval1, u32 duration2, u32 interval2) { + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return -1; + if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL || wpa_s->current_ssid->mode != WPAS_MODE_INFRA) @@ -3652,6 +3748,9 @@ int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1, int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period, unsigned int interval) { + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return -1; + return p2p_ext_listen(wpa_s->global->p2p, period, interval); } @@ -3694,6 +3793,8 @@ void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, { if (wpa_s->global->p2p_disabled) return; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return; p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len); } @@ -3704,6 +3805,8 @@ void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid, { if (wpa_s->global->p2p_disabled) return; + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) + return; p2p_disassoc_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len); }