int cckm_process_response (struct wpa_sm *sm, u8 *bssid) { struct wpa_ptk lptk; struct wpa_ptk *ptk = &lptk; u32 cckm_rn; struct cckm_ie_rsp *cie = (struct cckm_ie_rsp *)sm->cckm_resp_ie; u8 data[8]; /* Reject Non-CCKM IEs */ if ((cie->elem_id != WLAN_EID_CCKM) || (os_memcmp(cie->oui, "\x00\x40\x96\x00", sizeof(cie->oui)) != 0)) { return -1; } /* Derive PTK from BTK and RN */ cckm_rn = WPA_GET_LE32(cie->rn); wpa_btk_to_ptk(sm->cgk.btk, sizeof(sm->cgk.btk), bssid, cckm_rn, (u8 *)ptk, sizeof(struct wpa_ptk)); if (cckm_verify_mic(sm, cie, ptk->kck)) { wpa_printf(MSG_WARNING, "CCKM Reassociation Response - " "MIC Failure\n"); return -1; } if (sm->pairwise_cipher == WPA_CIPHER_TKIP) { /* Supplicant: swap tx/rx Mic keys */ os_memcpy(data, ptk->u.auth.tx_mic_key, 8); os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8); os_memcpy(ptk->u.auth.rx_mic_key, data, 8); } /* MIC verification successful, store and install PTK */ os_memcpy (&sm->ptk, ptk, sizeof(struct wpa_ptk)); cckm_install_ptk(sm); /* Install GTK */ cckm_install_gtk(sm, cckm_rn, cie->gtk, WPA_GET_LE16(cie->gtk_len), cie->mcast_keyid, cie->rsc, 6); wpa_printf(MSG_INFO, "CCKM-FAST-ROAMING Connection to " MACSTR " Completed", MAC2STR(bssid)); return 0; }
static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, const u8 *pos, u8 len, struct neighbor_report *rep) { u8 left = len; if (left < 13) { wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); return; } os_memcpy(rep->bssid, pos, ETH_ALEN); rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN); rep->regulatory_class = *(pos + 10); rep->channel_number = *(pos + 11); rep->phy_type = *(pos + 12); pos += 13; left -= 13; while (left >= 2) { u8 id, elen; 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 -= elen; pos += elen; } rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class, rep->channel_number); }
static int try_wep(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *plain) { u32 icv, rx_icv; u8 k[16]; int i, j; for (i = 0, j = 0; i < sizeof(k); i++) { k[i] = key[j]; j++; if (j >= key_len) j = 0; } os_memcpy(plain, data, data_len); wep_crypt(k, plain, data_len); icv = crc32(plain, data_len - 4); rx_icv = WPA_GET_LE32(plain + data_len - 4); if (icv != rx_icv) return -1; return 0; }
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { struct p2p_message msg; struct p2p_device *dev; int freq; enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; struct wpabuf *resp; u32 adv_id = 0; struct p2ps_advertisement *p2ps_adv = NULL; u8 conncap = P2PS_SETUP_NEW; u8 auto_accept = 0; u32 session_id = 0; u8 session_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; u8 adv_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; const u8 *group_mac; int passwd_id = DEV_PW_DEFAULT; u16 config_methods; u16 allowed_config_methods = WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; struct p2ps_feature_capab resp_fcap = { 0, 0 }; struct p2ps_feature_capab *req_fcap = NULL; u8 remote_conncap; u16 method; if (p2p_parse(data, len, &msg)) return; p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR " with config methods 0x%x (freq=%d)", MAC2STR(sa), msg.wps_config_methods, rx_freq); group_mac = msg.intended_addr; dev = p2p_get_device(p2p, sa); if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { p2p_dbg(p2p, "Provision Discovery Request from unknown peer " MACSTR, MAC2STR(sa)); if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1, 0)) { p2p_dbg(p2p, "Provision Discovery Request add device failed " MACSTR, MAC2STR(sa)); goto out; } if (!dev) { dev = p2p_get_device(p2p, sa); if (!dev) { p2p_dbg(p2p, "Provision Discovery device not found " MACSTR, MAC2STR(sa)); goto out; } } } else if (msg.wfd_subelems) { wpabuf_free(dev->info.wfd_subelems); dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); } if (!msg.adv_id) { allowed_config_methods |= WPS_CONFIG_PUSHBUTTON; if (!(msg.wps_config_methods & allowed_config_methods)) { p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request"); goto out; } /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */ if (msg.group_id) { size_t i; for (i = 0; i < p2p->num_groups; i++) { if (p2p_group_is_group_id_match( p2p->groups[i], msg.group_id, msg.group_id_len)) break; } if (i == p2p->num_groups) { p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject"); goto out; } } } else { allowed_config_methods |= WPS_CONFIG_P2PS; /* * Set adv_id here, so in case of an error, a P2PS PD Response * will be sent. */ adv_id = WPA_GET_LE32(msg.adv_id); if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) { reject = P2P_SC_FAIL_INVALID_PARAMS; goto out; } req_fcap = (struct p2ps_feature_capab *) msg.feature_cap; os_memcpy(session_mac, msg.session_mac, ETH_ALEN); os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); session_id = WPA_GET_LE32(msg.session_id); if (msg.conn_cap) conncap = *msg.conn_cap; /* * We need to verify a P2PS config methog in an initial PD * request or in a follow-on PD request with the status * SUCCESS_DEFERRED. */ if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) && !(msg.wps_config_methods & allowed_config_methods)) { p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request"); goto out; } /* * TODO: since we don't support multiple PD, reject PD request * if we are in the middle of P2PS PD with some other peer */ } dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | P2P_DEV_PD_PEER_KEYPAD | P2P_DEV_PD_PEER_P2PS); if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) { p2p_dbg(p2p, "Peer " MACSTR " requested us to show a PIN on display", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_KEYPAD; passwd_id = DEV_PW_USER_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Peer " MACSTR " requested us to write its PIN using keypad", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_DISPLAY; passwd_id = DEV_PW_REGISTRAR_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_P2PS; passwd_id = DEV_PW_P2PS_DEFAULT; } /* Remove stale persistent groups */ if (p2p->cfg->remove_stale_groups) { p2p->cfg->remove_stale_groups( p2p->cfg->cb_ctx, dev->info.p2p_device_addr, msg.persistent_dev, msg.persistent_ssid, msg.persistent_ssid_len); } reject = P2P_SC_SUCCESS; /* * End of a legacy P2P PD Request processing, from this point continue * with P2PS one. */ if (!msg.adv_id) goto out; remote_conncap = conncap; if (!msg.status) { unsigned int forced_freq, pref_freq; if (os_memcmp(p2p->cfg->dev_addr, msg.adv_mac, ETH_ALEN)) { p2p_dbg(p2p, "P2PS PD adv mac does not match the local one"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; goto out; } p2ps_adv = p2p_service_p2ps_id(p2p, adv_id); if (!p2ps_adv) { p2p_dbg(p2p, "P2PS PD invalid adv_id=0x%X", adv_id); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; goto out; } p2p_dbg(p2p, "adv_id: 0x%X, p2ps_adv: %p", adv_id, p2ps_adv); auto_accept = p2ps_adv->auto_accept; conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx, conncap, auto_accept, &forced_freq, &pref_freq); p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d", auto_accept, remote_conncap, conncap); p2p_prepare_channel(p2p, dev, forced_freq, pref_freq, 0); resp_fcap.cpt = p2ps_own_preferred_cpt(p2ps_adv->cpt_priority, req_fcap->cpt); p2p_dbg(p2p, "cpt: service:0x%x remote:0x%x result:0x%x", p2ps_adv->cpt_mask, req_fcap->cpt, resp_fcap.cpt); if (!resp_fcap.cpt) { p2p_dbg(p2p, "Incompatible P2PS feature capability CPT bitmask"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if (p2ps_adv->config_methods && !(msg.wps_config_methods & p2ps_adv->config_methods)) { p2p_dbg(p2p, "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)", p2ps_adv->config_methods, msg.wps_config_methods); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if (!p2ps_adv->state) { p2p_dbg(p2p, "P2PS state unavailable"); reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; } else if (!conncap) { p2p_dbg(p2p, "Conncap resolution failed"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Keypad - always defer"); auto_accept = 0; } if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) || msg.persistent_dev) && conncap != P2PS_SETUP_NEW && msg.channel_list && msg.channel_list_len && p2p_peer_channels_check(p2p, &p2p->channels, dev, msg.channel_list, msg.channel_list_len) < 0) { p2p_dbg(p2p, "No common channels - force deferred flow"); auto_accept = 0; } if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) || msg.persistent_dev) && msg.operating_channel) { struct p2p_channels intersect; /* * There are cases where only the operating channel is * provided. This requires saving the channel as the * supported channel list, and verifying that it is * supported. */ if (dev->channels.reg_classes == 0 || !p2p_channels_includes(&dev->channels, msg.operating_channel[3], msg.operating_channel[4])) { struct p2p_channels *ch = &dev->channels; os_memset(ch, 0, sizeof(*ch)); ch->reg_class[0].reg_class = msg.operating_channel[3]; ch->reg_class[0].channel[0] = msg.operating_channel[4]; ch->reg_class[0].channels = 1; ch->reg_classes = 1; } p2p_channels_intersect(&p2p->channels, &dev->channels, &intersect); if (intersect.reg_classes == 0) { p2p_dbg(p2p, "No common channels - force deferred flow"); auto_accept = 0; } } if (auto_accept || reject != P2P_SC_SUCCESS) { struct p2ps_provision *tmp; if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, msg.wps_config_methods, session_mac, adv_mac) < 0) { reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; goto out; } tmp = p2p->p2ps_prov; tmp->force_freq = forced_freq; tmp->pref_freq = pref_freq; if (conncap) { tmp->conncap = conncap; tmp->status = P2P_SC_SUCCESS; } else { tmp->conncap = auto_accept; tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } if (reject != P2P_SC_SUCCESS) goto out; } } if (!msg.status && !auto_accept && (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) { struct p2ps_provision *tmp; if (!conncap) { reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; goto out; } if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, msg.wps_config_methods, session_mac, adv_mac) < 0) { reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; goto out; } tmp = p2p->p2ps_prov; reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; tmp->status = reject; } /* Not a P2PS Follow-on PD */ if (!msg.status) goto out; if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) { reject = *msg.status; goto out; } if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov) goto out; if (p2p->p2ps_prov->adv_id != adv_id || os_memcmp(p2p->p2ps_prov->adv_mac, msg.adv_mac, ETH_ALEN)) { p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Advertisement ID/MAC"); goto out; } if (p2p->p2ps_prov->session_id != session_id || os_memcmp(p2p->p2ps_prov->session_mac, msg.session_mac, ETH_ALEN)) { p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC"); goto out; } method = p2p->p2ps_prov->method; conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx, remote_conncap, p2p->p2ps_prov->conncap, &p2p->p2ps_prov->force_freq, &p2p->p2ps_prov->pref_freq); resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority, req_fcap->cpt); p2p_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x", p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt); p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq, p2p->p2ps_prov->pref_freq, 0); /* * Ensure that if we asked for PIN originally, our method is consistent * with original request. */ if (method & WPS_CONFIG_DISPLAY) method = WPS_CONFIG_KEYPAD; else if (method & WPS_CONFIG_KEYPAD) method = WPS_CONFIG_DISPLAY; if (!conncap || !(msg.wps_config_methods & method)) { /* * Reject this "Deferred Accept* * if incompatible conncap or method */ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if (!resp_fcap.cpt) { p2p_dbg(p2p, "Incompatible P2PS feature capability CPT bitmask"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) || msg.persistent_dev) && conncap != P2PS_SETUP_NEW && msg.channel_list && msg.channel_list_len && p2p_peer_channels_check(p2p, &p2p->channels, dev, msg.channel_list, msg.channel_list_len) < 0) { p2p_dbg(p2p, "No common channels in Follow-On Provision Discovery Request"); reject = P2P_SC_FAIL_NO_COMMON_CHANNELS; } else { reject = P2P_SC_SUCCESS; } dev->oper_freq = 0; if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) { u8 tmp; if (msg.operating_channel) dev->oper_freq = p2p_channel_to_freq(msg.operating_channel[3], msg.operating_channel[4]); if ((conncap & P2PS_SETUP_GROUP_OWNER) && p2p_go_select_channel(p2p, dev, &tmp) < 0) reject = P2P_SC_FAIL_NO_COMMON_CHANNELS; } p2p->p2ps_prov->status = reject; p2p->p2ps_prov->conncap = conncap; out: if (reject == P2P_SC_SUCCESS || reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) config_methods = msg.wps_config_methods; else config_methods = 0; /* * Send PD Response for an initial PD Request or for follow-on * PD Request with P2P_SC_SUCCESS_DEFERRED status. */ if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) { resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, reject, config_methods, adv_id, msg.group_id, msg.group_id_len, msg.persistent_ssid, msg.persistent_ssid_len, (const u8 *) &resp_fcap, sizeof(resp_fcap)); if (!resp) { p2p_parse_free(&msg); return; } p2p_dbg(p2p, "Sending Provision Discovery Response"); if (rx_freq > 0) freq = rx_freq; else freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel); if (freq < 0) { p2p_dbg(p2p, "Unknown regulatory class/channel"); wpabuf_free(resp); p2p_parse_free(&msg); return; } p2p->pending_action_state = P2P_PENDING_PD_RESPONSE; if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, p2p->cfg->dev_addr, wpabuf_head(resp), wpabuf_len(resp), 200) < 0) p2p_dbg(p2p, "Failed to send Action frame"); else p2p->send_action_in_progress = 1; wpabuf_free(resp); } if (!dev) { p2p_parse_free(&msg); return; } freq = 0; if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) { freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel); if (freq < 0) freq = 0; } if (!p2p->cfg->p2ps_prov_complete) { /* Don't emit anything */ } else if (msg.status && *msg.status != P2P_SC_SUCCESS && *msg.status != P2P_SC_SUCCESS_DEFERRED) { reject = *msg.status; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, sa, adv_mac, session_mac, NULL, adv_id, session_id, 0, 0, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, NULL, 0, freq); } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { p2p->p2ps_prov->status = reject; p2p->p2ps_prov->conncap = conncap; if (reject != P2P_SC_SUCCESS) p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, sa, adv_mac, session_mac, NULL, adv_id, session_id, conncap, 0, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, NULL, 0, freq); else p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq); } else if (msg.status && p2p->p2ps_prov) { p2p->p2ps_prov->status = P2P_SC_SUCCESS; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq); } else if (msg.status) { } else if (auto_accept && reject == P2P_SC_SUCCESS) { p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq); } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && (!msg.session_info || !msg.session_info_len)) { p2p->p2ps_prov->method = msg.wps_config_methods; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 1, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq); } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { size_t buf_len = msg.session_info_len; char *buf = os_malloc(2 * buf_len + 1); if (buf) { p2p->p2ps_prov->method = msg.wps_config_methods; utf8_escape((char *) msg.session_info, buf_len, buf, 2 * buf_len + 1); p2p->cfg->p2ps_prov_complete( p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 1, buf, (const u8 *) &resp_fcap, sizeof(resp_fcap), freq); os_free(buf); } } /* * prov_disc_req callback is used to generate P2P-PROV-DISC-ENTER-PIN, * P2P-PROV-DISC-SHOW-PIN, and P2P-PROV-DISC-PBC-REQ events. * Call it either on legacy P2P PD or on P2PS PD only if we need to * enter/show PIN. * * The callback is called in the following cases: * 1. Legacy P2P PD request, response status SUCCESS * 2. P2PS advertiser, method: DISPLAY, autoaccept: TRUE, * response status: SUCCESS * 3. P2PS advertiser, method DISPLAY, autoaccept: FALSE, * response status: INFO_CURRENTLY_UNAVAILABLE * 4. P2PS advertiser, method: KEYPAD, autoaccept==any, * response status: INFO_CURRENTLY_UNAVAILABLE * 5. P2PS follow-on with SUCCESS_DEFERRED, * advertiser role: DISPLAY, autoaccept: FALSE, * seeker: KEYPAD, response status: SUCCESS */ if (p2p->cfg->prov_disc_req && ((reject == P2P_SC_SUCCESS && !msg.adv_id) || (!msg.status && (reject == P2P_SC_SUCCESS || reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) && passwd_id == DEV_PW_USER_SPECIFIED) || (!msg.status && reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && passwd_id == DEV_PW_REGISTRAR_SPECIFIED) || (reject == P2P_SC_SUCCESS && msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) { const u8 *dev_addr = sa; if (msg.p2p_device_addr) dev_addr = msg.p2p_device_addr; p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa, msg.wps_config_methods, dev_addr, msg.pri_dev_type, msg.device_name, msg.config_methods, msg.capability ? msg.capability[0] : 0, msg.capability ? msg.capability[1] : 0, msg.group_id, msg.group_id_len); } if (reject == P2P_SC_SUCCESS) { switch (config_methods) { case WPS_CONFIG_DISPLAY: dev->wps_prov_info = WPS_CONFIG_KEYPAD; break; case WPS_CONFIG_KEYPAD: dev->wps_prov_info = WPS_CONFIG_DISPLAY; break; case WPS_CONFIG_PUSHBUTTON: dev->wps_prov_info = WPS_CONFIG_PUSHBUTTON; break; case WPS_CONFIG_P2PS: dev->wps_prov_info = WPS_CONFIG_P2PS; break; default: dev->wps_prov_info = 0; break; } if (msg.intended_addr) os_memcpy(dev->interface_addr, msg.intended_addr, ETH_ALEN); } p2p_parse_free(&msg); }
void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len) { struct p2p_message msg; struct p2p_device *dev; u16 report_config_methods = 0, req_config_methods; u8 status = P2P_SC_SUCCESS; u32 adv_id = 0; u8 conncap = P2PS_SETUP_NEW; u8 adv_mac[ETH_ALEN]; const u8 *group_mac; int passwd_id = DEV_PW_DEFAULT; int p2ps_seeker; if (p2p_parse(data, len, &msg)) return; if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) { p2p_parse_free(&msg); return; } /* Parse the P2PS members present */ if (msg.status) status = *msg.status; group_mac = msg.intended_addr; if (msg.adv_mac) os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); else os_memset(adv_mac, 0, ETH_ALEN); if (msg.adv_id) adv_id = WPA_GET_LE32(msg.adv_id); if (msg.conn_cap) { conncap = *msg.conn_cap; /* Switch bits to local relative */ switch (conncap) { case P2PS_SETUP_GROUP_OWNER: conncap = P2PS_SETUP_CLIENT; break; case P2PS_SETUP_CLIENT: conncap = P2PS_SETUP_GROUP_OWNER; break; } } p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR " with config methods 0x%x", MAC2STR(sa), msg.wps_config_methods); dev = p2p_get_device(p2p, sa); if (dev == NULL || !dev->req_config_methods) { p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR " with no pending request", MAC2STR(sa)); p2p_parse_free(&msg); return; } if (dev->dialog_token != msg.dialog_token) { p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)", msg.dialog_token, dev->dialog_token); p2p_parse_free(&msg); return; } if (p2p->pending_action_state == P2P_PENDING_PD) { os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN); p2p->pending_action_state = P2P_NO_PENDING_ACTION; } p2ps_seeker = p2p->p2ps_prov && p2p->p2ps_prov->pd_seeker; /* * Use a local copy of the requested config methods since * p2p_reset_pending_pd() can clear this in the peer entry. */ req_config_methods = dev->req_config_methods; /* * If the response is from the peer to whom a user initiated request * was sent earlier, we reset that state info here. */ if (p2p->user_initiated_pd && os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0) p2p_reset_pending_pd(p2p); if (msg.wps_config_methods != req_config_methods) { p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x", msg.wps_config_methods, req_config_methods); if (p2p->cfg->prov_disc_fail) p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_REJECTED, adv_id, adv_mac, NULL); p2p_parse_free(&msg); p2ps_prov_free(p2p); goto out; } report_config_methods = req_config_methods; dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | P2P_DEV_PD_PEER_KEYPAD | P2P_DEV_PD_PEER_P2PS); if (req_config_methods & WPS_CONFIG_DISPLAY) { p2p_dbg(p2p, "Peer " MACSTR " accepted to show a PIN on display", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_DISPLAY; passwd_id = DEV_PW_REGISTRAR_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Peer " MACSTR " accepted to write our PIN using keypad", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_KEYPAD; passwd_id = DEV_PW_USER_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_P2PS; passwd_id = DEV_PW_P2PS_DEFAULT; } if ((status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) && p2p->p2ps_prov) { dev->oper_freq = 0; /* * Save the reported channel list and operating frequency. * Note that the specification mandates that the responder * should include in the channel list only channels reported by * the initiator, so this is only a sanity check, and if this * fails the flow would continue, although it would probably * fail. Same is true for the operating channel. */ if (msg.channel_list && msg.channel_list_len && p2p_peer_channels_check(p2p, &p2p->channels, dev, msg.channel_list, msg.channel_list_len) < 0) p2p_dbg(p2p, "P2PS PD Response - no common channels"); if (msg.operating_channel) { if (p2p_channels_includes(&p2p->channels, msg.operating_channel[3], msg.operating_channel[4]) && p2p_channels_includes(&dev->channels, msg.operating_channel[3], msg.operating_channel[4])) { dev->oper_freq = p2p_channel_to_freq( msg.operating_channel[3], msg.operating_channel[4]); } else { p2p_dbg(p2p, "P2PS PD Response - invalid operating channel"); } } if (p2p->cfg->p2ps_prov_complete) { int freq = 0; if (conncap == P2PS_SETUP_GROUP_OWNER) { u8 tmp; /* * Re-select the operating channel as it is * possible that original channel is no longer * valid. This should not really fail. */ if (p2p_go_select_channel(p2p, dev, &tmp) < 0) p2p_dbg(p2p, "P2PS PD channel selection failed"); freq = p2p_channel_to_freq(p2p->op_reg_class, p2p->op_channel); if (freq < 0) freq = 0; } p2p->cfg->p2ps_prov_complete( p2p->cfg->cb_ctx, status, sa, adv_mac, p2p->p2ps_prov->session_mac, group_mac, adv_id, p2p->p2ps_prov->session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 1, 0, NULL, msg.feature_cap, msg.feature_cap_len, freq); } p2ps_prov_free(p2p); } else if (status != P2P_SC_SUCCESS && status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && status != P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { if (p2p->cfg->p2ps_prov_complete) p2p->cfg->p2ps_prov_complete( p2p->cfg->cb_ctx, status, sa, adv_mac, p2p->p2ps_prov->session_mac, group_mac, adv_id, p2p->p2ps_prov->session_id, 0, 0, NULL, 0, 1, 0, NULL, NULL, 0, 0); p2ps_prov_free(p2p); } if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { if (p2p->cfg->remove_stale_groups) { p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx, dev->info.p2p_device_addr, NULL, NULL, 0); } if (msg.session_info && msg.session_info_len) { size_t info_len = msg.session_info_len; char *deferred_sess_resp = os_malloc(2 * info_len + 1); if (!deferred_sess_resp) { p2p_parse_free(&msg); p2ps_prov_free(p2p); goto out; } utf8_escape((char *) msg.session_info, info_len, deferred_sess_resp, 2 * info_len + 1); if (p2p->cfg->prov_disc_fail) p2p->cfg->prov_disc_fail( p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_INFO_UNAVAILABLE, adv_id, adv_mac, deferred_sess_resp); os_free(deferred_sess_resp); } else if (p2p->cfg->prov_disc_fail) p2p->cfg->prov_disc_fail( p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_INFO_UNAVAILABLE, adv_id, adv_mac, NULL); } else if (status != P2P_SC_SUCCESS) { p2p_dbg(p2p, "Peer rejected our Provision Discovery Request"); if (p2p->cfg->prov_disc_fail) p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_REJECTED, adv_id, adv_mac, NULL); p2p_parse_free(&msg); p2ps_prov_free(p2p); goto out; } /* Store the provisioning info */ dev->wps_prov_info = msg.wps_config_methods; if (msg.intended_addr) os_memcpy(dev->interface_addr, msg.intended_addr, ETH_ALEN); p2p_parse_free(&msg); out: dev->req_config_methods = 0; p2p->cfg->send_action_done(p2p->cfg->cb_ctx); if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) { p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with " MACSTR, MAC2STR(dev->info.p2p_device_addr)); dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG; p2p_connect_send(p2p, dev); return; } /* * prov_disc_resp callback is used to generate P2P-PROV-DISC-ENTER-PIN, * P2P-PROV-DISC-SHOW-PIN, and P2P-PROV-DISC-PBC-REQ events. * Call it only for a legacy P2P PD or for P2PS PD scenarios where * show/enter PIN events are needed. * * The callback is called in the following cases: * 1. Legacy P2P PD response with a status SUCCESS * 2. P2PS, advertiser method: DISPLAY, autoaccept: true, * response status: SUCCESS, local method KEYPAD * 3. P2PS, advertiser method: KEYPAD,Seeker side, * response status: INFO_CURRENTLY_UNAVAILABLE, * local method: DISPLAY */ if (p2p->cfg->prov_disc_resp && ((status == P2P_SC_SUCCESS && !adv_id) || (p2ps_seeker && status == P2P_SC_SUCCESS && passwd_id == DEV_PW_REGISTRAR_SPECIFIED) || (p2ps_seeker && status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && passwd_id == DEV_PW_USER_SPECIFIED))) p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa, report_config_methods); if (p2p->state == P2P_PD_DURING_FIND) { p2p_clear_timeout(p2p); p2p_continue_find(p2p); } }
static int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p, struct p2p_message *msg) { u8 conn_cap_go = 0; u8 conn_cap_cli = 0; u32 session_id; u32 adv_id; #define P2PS_PD_RESP_CHECK(_val, _attr) \ do { \ if ((_val) && !msg->_attr) { \ p2p_dbg(p2p, "P2PS PD Response missing " #_attr); \ return -1; \ } \ } while (0) P2PS_PD_RESP_CHECK(1, status); P2PS_PD_RESP_CHECK(1, adv_id); P2PS_PD_RESP_CHECK(1, adv_mac); P2PS_PD_RESP_CHECK(1, capability); P2PS_PD_RESP_CHECK(1, p2p_device_info); P2PS_PD_RESP_CHECK(1, session_id); P2PS_PD_RESP_CHECK(1, session_mac); P2PS_PD_RESP_CHECK(1, feature_cap); session_id = WPA_GET_LE32(msg->session_id); adv_id = WPA_GET_LE32(msg->adv_id); if (p2p->p2ps_prov->session_id != session_id) { p2p_dbg(p2p, "Ignore PD Response with unexpected Session ID"); return -1; } if (os_memcmp(p2p->p2ps_prov->session_mac, msg->session_mac, ETH_ALEN)) { p2p_dbg(p2p, "Ignore PD Response with unexpected Session MAC"); return -1; } if (p2p->p2ps_prov->adv_id != adv_id) { p2p_dbg(p2p, "Ignore PD Response with unexpected Advertisement ID"); return -1; } if (os_memcmp(p2p->p2ps_prov->adv_mac, msg->adv_mac, ETH_ALEN) != 0) { p2p_dbg(p2p, "Ignore PD Response with unexpected Advertisement MAC"); return -1; } if (msg->listen_channel) { p2p_dbg(p2p, "Ignore malformed PD Response - unexpected Listen Channel"); return -1; } if (*msg->status == P2P_SC_SUCCESS && !(!!msg->conn_cap ^ !!msg->persistent_dev)) { p2p_dbg(p2p, "Ignore malformed PD Response - either conn_cap or persistent group should be present"); return -1; } if (msg->persistent_dev && *msg->status != P2P_SC_SUCCESS) { p2p_dbg(p2p, "Ignore malformed PD Response - persistent group is present, but the status isn't success"); return -1; } if (msg->conn_cap) { conn_cap_go = *msg->conn_cap == P2PS_SETUP_GROUP_OWNER; conn_cap_cli = *msg->conn_cap == P2PS_SETUP_CLIENT; } P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli, channel_list); P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli, config_timeout); P2PS_PD_RESP_CHECK(conn_cap_go, group_id); P2PS_PD_RESP_CHECK(conn_cap_go, intended_addr); P2PS_PD_RESP_CHECK(conn_cap_go, operating_channel); /* * TODO: Also validate that operating channel is present if the device * is a GO in a persistent group. We can't do it here since we don't * know what is the role of the peer. It should be probably done in * p2ps_prov_complete callback, but currently operating channel isn't * passed to it. */ #undef P2PS_PD_RESP_CHECK return 0; }
void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len) { struct p2p_message msg; struct p2p_device *dev; u16 report_config_methods = 0, req_config_methods; u8 status = P2P_SC_SUCCESS; int success = 0; u32 adv_id = 0; u8 conncap = P2PS_SETUP_NEW; u8 adv_mac[ETH_ALEN]; u8 group_mac[ETH_ALEN]; int passwd_id = DEV_PW_DEFAULT; if (p2p_parse(data, len, &msg)) { return; } /* Parse the P2PS members present */ if (msg.status) { status = *msg.status; } if (msg.intended_addr) { os_memcpy(group_mac, msg.intended_addr, ETH_ALEN); } else { os_memset(group_mac, 0, ETH_ALEN); } if (msg.adv_mac) { os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); } else { os_memset(adv_mac, 0, ETH_ALEN); } if (msg.adv_id) { adv_id = WPA_GET_LE32(msg.adv_id); } if (msg.conn_cap) { conncap = *msg.conn_cap; /* Switch bits to local relative */ switch (conncap) { case P2PS_SETUP_GROUP_OWNER: conncap = P2PS_SETUP_CLIENT; break; case P2PS_SETUP_CLIENT: conncap = P2PS_SETUP_GROUP_OWNER; break; } } p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR " with config methods 0x%x", MAC2STR(sa), msg.wps_config_methods); dev = p2p_get_device(p2p, sa); if (dev == NULL || !dev->req_config_methods) { p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR " with no pending request", MAC2STR(sa)); p2p_parse_free(&msg); return; } if (dev->dialog_token != msg.dialog_token) { p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)", msg.dialog_token, dev->dialog_token); p2p_parse_free(&msg); return; } if (p2p->pending_action_state == P2P_PENDING_PD) { os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN); p2p->pending_action_state = P2P_NO_PENDING_ACTION; } /* * Use a local copy of the requested config methods since * p2p_reset_pending_pd() can clear this in the peer entry. */ req_config_methods = dev->req_config_methods; /* * If the response is from the peer to whom a user initiated request * was sent earlier, we reset that state info here. */ if (p2p->user_initiated_pd && os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0) { p2p_reset_pending_pd(p2p); } if (msg.wps_config_methods != req_config_methods) { p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x", msg.wps_config_methods, req_config_methods); if (p2p->cfg->prov_disc_fail) { p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_REJECTED, adv_id, adv_mac, NULL); } p2p_parse_free(&msg); p2ps_prov_free(p2p); goto out; } report_config_methods = req_config_methods; dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | P2P_DEV_PD_PEER_KEYPAD | P2P_DEV_PD_PEER_P2PS); if (req_config_methods & WPS_CONFIG_DISPLAY) { p2p_dbg(p2p, "Peer " MACSTR " accepted to show a PIN on display", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_DISPLAY; passwd_id = DEV_PW_REGISTRAR_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Peer " MACSTR " accepted to write our PIN using keypad", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_KEYPAD; passwd_id = DEV_PW_USER_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN", MAC2STR(sa)); dev->flags |= P2P_DEV_PD_PEER_P2PS; passwd_id = DEV_PW_P2PS_DEFAULT; } if ((msg.conn_cap || msg.persistent_dev) && msg.adv_id && (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) && p2p->p2ps_prov) { if (p2p->cfg->p2ps_prov_complete) { p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, status, sa, adv_mac, p2p->p2ps_prov->session_mac, group_mac, adv_id, p2p->p2ps_prov->session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 1, 0, NULL); } p2ps_prov_free(p2p); } if (status != P2P_SC_SUCCESS && status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && status != P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { if (p2p->cfg->p2ps_prov_complete) { p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, status, sa, adv_mac, p2p->p2ps_prov->session_mac, group_mac, adv_id, p2p->p2ps_prov->session_id, 0, 0, NULL, 0, 1, 0, NULL); } p2ps_prov_free(p2p); } if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { if (p2p->cfg->remove_stale_groups) { p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx, dev->info.p2p_device_addr, NULL, NULL, 0); } if (msg.session_info && msg.session_info_len) { size_t info_len = msg.session_info_len; char *deferred_sess_resp = os_malloc(2 * info_len + 1); if (!deferred_sess_resp) { p2p_parse_free(&msg); p2ps_prov_free(p2p); goto out; } utf8_escape((char *)msg.session_info, info_len, deferred_sess_resp, 2 * info_len + 1); if (p2p->cfg->prov_disc_fail) { p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_INFO_UNAVAILABLE, adv_id, adv_mac, deferred_sess_resp); } os_free(deferred_sess_resp); } else if (p2p->cfg->prov_disc_fail) { p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_INFO_UNAVAILABLE, adv_id, adv_mac, NULL); } } else if (msg.wps_config_methods != dev->req_config_methods || status != P2P_SC_SUCCESS) { p2p_dbg(p2p, "Peer rejected our Provision Discovery Request"); if (p2p->cfg->prov_disc_fail) { p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, P2P_PROV_DISC_REJECTED, 0, NULL, NULL); } p2p_parse_free(&msg); p2ps_prov_free(p2p); goto out; } /* Store the provisioning info */ dev->wps_prov_info = msg.wps_config_methods; p2p_parse_free(&msg); success = 1; out: dev->req_config_methods = 0; p2p->cfg->send_action_done(p2p->cfg->cb_ctx); if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) { p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with " MACSTR, MAC2STR(dev->info.p2p_device_addr)); dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG; p2p_connect_send(p2p, dev); return; } if (success && p2p->cfg->prov_disc_resp) { p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa, report_config_methods); } if (p2p->state == P2P_PD_DURING_FIND) { p2p_clear_timeout(p2p); p2p_continue_find(p2p); } }
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { struct p2p_message msg; struct p2p_device *dev; int freq; enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; struct wpabuf *resp; u32 adv_id = 0; struct p2ps_advertisement *p2ps_adv = NULL; u8 conncap = P2PS_SETUP_NEW; u8 auto_accept = 0; u32 session_id = 0; u8 session_mac[ETH_ALEN]; u8 adv_mac[ETH_ALEN]; u8 group_mac[ETH_ALEN]; int passwd_id = DEV_PW_DEFAULT; u16 config_methods; if (p2p_parse(data, len, &msg)) { return; } p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR " with config methods 0x%x (freq=%d)", MAC2STR(sa), msg.wps_config_methods, rx_freq); dev = p2p_get_device(p2p, sa); if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { p2p_dbg(p2p, "Provision Discovery Request from unknown peer " MACSTR, MAC2STR(sa)); if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1, 0)) { p2p_dbg(p2p, "Provision Discovery Request add device failed " MACSTR, MAC2STR(sa)); } } else if (msg.wfd_subelems) { wpabuf_free(dev->info.wfd_subelems); dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); } if (!(msg.wps_config_methods & (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_P2PS))) { p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request"); goto out; } /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */ if (!msg.adv_id && msg.group_id) { size_t i; for (i = 0; i < p2p->num_groups; i++) { if (p2p_group_is_group_id_match(p2p->groups[i], msg.group_id, msg.group_id_len)) { break; } } if (i == p2p->num_groups) { p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject"); goto out; } } if (dev) { dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | P2P_DEV_PD_PEER_KEYPAD | P2P_DEV_PD_PEER_P2PS); /* Remove stale persistent groups */ if (p2p->cfg->remove_stale_groups) { p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx, dev->info.p2p_device_addr, msg.persistent_dev, msg.persistent_ssid, msg.persistent_ssid_len); } } if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) { p2p_dbg(p2p, "Peer " MACSTR " requested us to show a PIN on display", MAC2STR(sa)); if (dev) { dev->flags |= P2P_DEV_PD_PEER_KEYPAD; } passwd_id = DEV_PW_USER_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Peer " MACSTR " requested us to write its PIN using keypad", MAC2STR(sa)); if (dev) { dev->flags |= P2P_DEV_PD_PEER_DISPLAY; } passwd_id = DEV_PW_REGISTRAR_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN", MAC2STR(sa)); if (dev) { dev->flags |= P2P_DEV_PD_PEER_P2PS; } passwd_id = DEV_PW_P2PS_DEFAULT; } reject = P2P_SC_SUCCESS; os_memset(session_mac, 0, ETH_ALEN); os_memset(adv_mac, 0, ETH_ALEN); os_memset(group_mac, 0, ETH_ALEN); if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac && (msg.status || msg.conn_cap)) { u8 remote_conncap; if (msg.intended_addr) { os_memcpy(group_mac, msg.intended_addr, ETH_ALEN); } os_memcpy(session_mac, msg.session_mac, ETH_ALEN); os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); session_id = WPA_GET_LE32(msg.session_id); adv_id = WPA_GET_LE32(msg.adv_id); if (!msg.status) { p2ps_adv = p2p_service_p2ps_id(p2p, adv_id); } p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv); if (msg.conn_cap) { conncap = *msg.conn_cap; } remote_conncap = conncap; if (p2ps_adv) { auto_accept = p2ps_adv->auto_accept; conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx, conncap, auto_accept); p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d", auto_accept, remote_conncap, conncap); if (p2ps_adv->config_methods && !(msg.wps_config_methods & p2ps_adv->config_methods)) { p2p_dbg(p2p, "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)", p2ps_adv->config_methods, msg.wps_config_methods); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if (!p2ps_adv->state) { p2p_dbg(p2p, "P2PS state unavailable"); reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; } else if (!conncap) { p2p_dbg(p2p, "Conncap resolution failed"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Keypad - always defer"); auto_accept = 0; } if (auto_accept || reject != P2P_SC_SUCCESS) { struct p2ps_provision *tmp; if (reject == P2P_SC_SUCCESS && !conncap) { reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, msg.wps_config_methods, session_mac, adv_mac) < 0) { reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; goto out; } tmp = p2p->p2ps_prov; if (conncap) { tmp->conncap = conncap; tmp->status = P2P_SC_SUCCESS; } else { tmp->conncap = auto_accept; tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } if (reject != P2P_SC_SUCCESS) { goto out; } } } else if (!msg.status) { reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; goto out; } if (!msg.status && !auto_accept && (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) { struct p2ps_provision *tmp; if (!conncap) { reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; goto out; } if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, msg.wps_config_methods, session_mac, adv_mac) < 0) { reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; goto out; } tmp = p2p->p2ps_prov; reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; tmp->status = reject; } if (msg.status) { if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) { reject = *msg.status; } else if (*msg.status == P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { u16 method = p2p->p2ps_prov->method; conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx, remote_conncap, p2p->p2ps_prov->conncap); p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d", p2p->p2ps_prov->conncap, remote_conncap, conncap); /* * Ensure that if we asked for PIN originally, * our method is consistent with original * request. */ if (method & WPS_CONFIG_DISPLAY) { method = WPS_CONFIG_KEYPAD; } else if (method & WPS_CONFIG_KEYPAD) { method = WPS_CONFIG_DISPLAY; } /* Reject this "Deferred Accept* if incompatible * conncap or method */ if (!conncap || !(msg.wps_config_methods & method)) { reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else { reject = P2P_SC_SUCCESS; } p2p->p2ps_prov->status = reject; p2p->p2ps_prov->conncap = conncap; } } } out: if (reject == P2P_SC_SUCCESS || reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { config_methods = msg.wps_config_methods; } else { config_methods = 0; } resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, reject, config_methods, adv_id, msg.group_id, msg.group_id_len, msg.persistent_ssid, msg.persistent_ssid_len); if (resp == NULL) { p2p_parse_free(&msg); return; } p2p_dbg(p2p, "Sending Provision Discovery Response"); if (rx_freq > 0) { freq = rx_freq; } else { freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel); } if (freq < 0) { p2p_dbg(p2p, "Unknown regulatory class/channel"); wpabuf_free(resp); p2p_parse_free(&msg); return; } p2p->pending_action_state = P2P_PENDING_PD_RESPONSE; if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, p2p->cfg->dev_addr, wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { p2p_dbg(p2p, "Failed to send Action frame"); } else { p2p->send_action_in_progress = 1; } wpabuf_free(resp); if (!p2p->cfg->p2ps_prov_complete) { /* Don't emit anything */ } else if (msg.status && *msg.status != P2P_SC_SUCCESS && *msg.status != P2P_SC_SUCCESS_DEFERRED) { reject = *msg.status; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, sa, adv_mac, session_mac, NULL, adv_id, session_id, 0, 0, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL); } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { p2p->p2ps_prov->status = reject; p2p->p2ps_prov->conncap = conncap; if (reject != P2P_SC_SUCCESS) { p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, sa, adv_mac, session_mac, NULL, adv_id, session_id, conncap, 0, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL); } else { p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL); } } else if (msg.status && p2p->p2ps_prov) { p2p->p2ps_prov->status = P2P_SC_SUCCESS; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL); } else if (msg.status) { } else if (auto_accept && reject == P2P_SC_SUCCESS) { p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL); } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && (!msg.session_info || !msg.session_info_len)) { p2p->p2ps_prov->method = msg.wps_config_methods; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 1, NULL); } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { size_t buf_len = msg.session_info_len; char *buf = os_malloc(2 * buf_len + 1); if (buf) { p2p->p2ps_prov->method = msg.wps_config_methods; utf8_escape((char *)msg.session_info, buf_len, buf, 2 * buf_len + 1); p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 1, buf); os_free(buf); } } if (reject == P2P_SC_SUCCESS && p2p->cfg->prov_disc_req) { const u8 *dev_addr = sa; if (msg.p2p_device_addr) { dev_addr = msg.p2p_device_addr; } p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa, msg.wps_config_methods, dev_addr, msg.pri_dev_type, msg.device_name, msg.config_methods, msg.capability ? msg.capability[0] : 0, msg.capability ? msg.capability[1] : 0, msg.group_id, msg.group_id_len); } p2p_parse_free(&msg); }
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, const u8 *data, size_t slen, u8 dialog_token) { const u8 *pos = data; u8 subtype; struct wpa_bss_anqp *anqp = NULL; int ret; if (slen < 2) return; if (bss) anqp = bss->anqp; subtype = *pos++; slen--; pos++; /* Reserved */ slen--; switch (subtype) { case HS20_STYPE_CAPABILITY_LIST: wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " HS Capability List", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_capability_list); anqp->hs20_capability_list = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_OPERATOR_FRIENDLY_NAME: wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Operator Friendly Name", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_operator_friendly_name); anqp->hs20_operator_friendly_name = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_WAN_METRICS: wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen); if (slen < 13) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN " "Metrics value from " MACSTR, MAC2STR(sa)); break; } wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa), pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5), pos[9], pos[10], WPA_GET_LE16(pos + 11)); if (anqp) { wpabuf_free(anqp->hs20_wan_metrics); anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_CONNECTION_CAPABILITY: wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Connection Capability", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_connection_capability); anqp->hs20_connection_capability = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_OPERATING_CLASS: wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Operating Class", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_operating_class); anqp->hs20_operating_class = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_OSU_PROVIDERS_LIST: wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " OSU Providers list", MAC2STR(sa)); wpa_s->num_prov_found++; if (anqp) { wpabuf_free(anqp->hs20_osu_providers_list); anqp->hs20_osu_providers_list = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_ICON_BINARY_FILE: ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen, dialog_token); if (wpa_s->fetch_osu_icon_in_progress) { hs20_osu_icon_fetch_result(wpa_s, ret); eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL); eloop_register_timeout(0, 0, hs20_continue_icon_fetch, wpa_s, NULL); } break; default: wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype); break; } }
void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { struct p2p_message msg; struct p2p_device *dev; int freq; enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; struct wpabuf *resp; u32 adv_id = 0; struct p2ps_advertisement *p2ps_adv = NULL; u8 conncap = P2PS_SETUP_NEW; u8 auto_accept = 0; u32 session_id = 0; u8 session_mac[ETH_ALEN]; u8 adv_mac[ETH_ALEN]; const u8 *group_mac; int passwd_id = DEV_PW_DEFAULT; u16 config_methods; u16 allowed_config_methods = WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; struct p2ps_feature_capab resp_fcap = { 0, 0 }; struct p2ps_feature_capab *req_fcap; if (p2p_parse(data, len, &msg)) return; p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR " with config methods 0x%x (freq=%d)", MAC2STR(sa), msg.wps_config_methods, rx_freq); group_mac = msg.intended_addr; dev = p2p_get_device(p2p, sa); if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { p2p_dbg(p2p, "Provision Discovery Request from unknown peer " MACSTR, MAC2STR(sa)); if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1, 0)) { p2p_dbg(p2p, "Provision Discovery Request add device failed " MACSTR, MAC2STR(sa)); } } else if (msg.wfd_subelems) { wpabuf_free(dev->info.wfd_subelems); dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); } if (msg.adv_id) allowed_config_methods |= WPS_CONFIG_P2PS; else allowed_config_methods |= WPS_CONFIG_PUSHBUTTON; if (!(msg.wps_config_methods & allowed_config_methods)) { p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request"); goto out; } /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */ if (!msg.adv_id && msg.group_id) { size_t i; for (i = 0; i < p2p->num_groups; i++) { if (p2p_group_is_group_id_match(p2p->groups[i], msg.group_id, msg.group_id_len)) break; } if (i == p2p->num_groups) { p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject"); goto out; } } if (dev) { dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | P2P_DEV_PD_PEER_KEYPAD | P2P_DEV_PD_PEER_P2PS); /* Remove stale persistent groups */ if (p2p->cfg->remove_stale_groups) { p2p->cfg->remove_stale_groups( p2p->cfg->cb_ctx, dev->info.p2p_device_addr, msg.persistent_dev, msg.persistent_ssid, msg.persistent_ssid_len); } } if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) { p2p_dbg(p2p, "Peer " MACSTR " requested us to show a PIN on display", MAC2STR(sa)); if (dev) dev->flags |= P2P_DEV_PD_PEER_KEYPAD; passwd_id = DEV_PW_USER_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Peer " MACSTR " requested us to write its PIN using keypad", MAC2STR(sa)); if (dev) dev->flags |= P2P_DEV_PD_PEER_DISPLAY; passwd_id = DEV_PW_REGISTRAR_SPECIFIED; } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN", MAC2STR(sa)); if (dev) dev->flags |= P2P_DEV_PD_PEER_P2PS; passwd_id = DEV_PW_P2PS_DEFAULT; } reject = P2P_SC_SUCCESS; os_memset(session_mac, 0, ETH_ALEN); os_memset(adv_mac, 0, ETH_ALEN); /* Note 1: A feature capability attribute structure can be changed * in the future. The assumption is that such modifications are * backwards compatible, therefore we allow processing of * msg.feature_cap exceeding the size of the p2ps_feature_capab * structure. * Note 2: Vverification of msg.feature_cap_len below has to be changed * to allow 2 byte feature capability processing if struct * p2ps_feature_capab is extended to include additional fields and it * affects the structure size. */ if (msg.adv_id && msg.session_id && msg.session_mac && msg.adv_mac && msg.feature_cap && msg.feature_cap_len >= sizeof(*req_fcap) && (msg.status || msg.conn_cap)) { u8 remote_conncap; req_fcap = (struct p2ps_feature_capab *) msg.feature_cap; os_memcpy(session_mac, msg.session_mac, ETH_ALEN); os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); session_id = WPA_GET_LE32(msg.session_id); adv_id = WPA_GET_LE32(msg.adv_id); if (!msg.status) p2ps_adv = p2p_service_p2ps_id(p2p, adv_id); p2p_dbg(p2p, "adv_id: %x - p2ps_adv - %p", adv_id, p2ps_adv); if (msg.conn_cap) conncap = *msg.conn_cap; remote_conncap = conncap; if (p2ps_adv) { auto_accept = p2ps_adv->auto_accept; conncap = p2p->cfg->p2ps_group_capability( p2p->cfg->cb_ctx, conncap, auto_accept); p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d", auto_accept, remote_conncap, conncap); resp_fcap.cpt = p2ps_own_preferred_cpt(p2ps_adv->cpt_priority, req_fcap->cpt); p2p_dbg(p2p, "cpt: service:0x%x remote:0x%x result:0x%x", p2ps_adv->cpt_mask, req_fcap->cpt, resp_fcap.cpt); if (!resp_fcap.cpt) { p2p_dbg(p2p, "Incompatible P2PS feature capability CPT bitmask"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if (p2ps_adv->config_methods && !(msg.wps_config_methods & p2ps_adv->config_methods)) { p2p_dbg(p2p, "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)", p2ps_adv->config_methods, msg.wps_config_methods); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if (!p2ps_adv->state) { p2p_dbg(p2p, "P2PS state unavailable"); reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; } else if (!conncap) { p2p_dbg(p2p, "Conncap resolution failed"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { p2p_dbg(p2p, "Keypad - always defer"); auto_accept = 0; } if (auto_accept || reject != P2P_SC_SUCCESS) { struct p2ps_provision *tmp; if (reject == P2P_SC_SUCCESS && !conncap) { reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } if (p2ps_setup_p2ps_prov( p2p, adv_id, session_id, msg.wps_config_methods, session_mac, adv_mac) < 0) { reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; goto out; } tmp = p2p->p2ps_prov; if (conncap) { tmp->conncap = conncap; tmp->status = P2P_SC_SUCCESS; } else { tmp->conncap = auto_accept; tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } if (reject != P2P_SC_SUCCESS) goto out; } } else if (!msg.status) { reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; goto out; } if (!msg.status && !auto_accept && (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) { struct p2ps_provision *tmp; if (!conncap) { reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; goto out; } if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, msg.wps_config_methods, session_mac, adv_mac) < 0) { reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; goto out; } tmp = p2p->p2ps_prov; reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; tmp->status = reject; } if (msg.status) { if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) { reject = *msg.status; } else if (*msg.status == P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { u16 method = p2p->p2ps_prov->method; conncap = p2p->cfg->p2ps_group_capability( p2p->cfg->cb_ctx, remote_conncap, p2p->p2ps_prov->conncap); p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d", p2p->p2ps_prov->conncap, remote_conncap, conncap); resp_fcap.cpt = p2ps_own_preferred_cpt( p2p->p2ps_prov->cpt_priority, req_fcap->cpt); p2p_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x", p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt); /* * Ensure that if we asked for PIN originally, * our method is consistent with original * request. */ if (method & WPS_CONFIG_DISPLAY) method = WPS_CONFIG_KEYPAD; else if (method & WPS_CONFIG_KEYPAD) method = WPS_CONFIG_DISPLAY; if (!conncap || !(msg.wps_config_methods & method)) { /* * Reject this "Deferred Accept* * if incompatible conncap or method */ reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else if (!resp_fcap.cpt) { p2p_dbg(p2p, "Incompatible P2PS feature capability CPT bitmask"); reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; } else { reject = P2P_SC_SUCCESS; } p2p->p2ps_prov->status = reject; p2p->p2ps_prov->conncap = conncap; } } } out: if (reject == P2P_SC_SUCCESS || reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) config_methods = msg.wps_config_methods; else config_methods = 0; resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, reject, config_methods, adv_id, msg.group_id, msg.group_id_len, msg.persistent_ssid, msg.persistent_ssid_len, (const u8 *) &resp_fcap, sizeof(resp_fcap)); if (resp == NULL) { p2p_parse_free(&msg); return; } p2p_dbg(p2p, "Sending Provision Discovery Response"); if (rx_freq > 0) freq = rx_freq; else freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel); if (freq < 0) { p2p_dbg(p2p, "Unknown regulatory class/channel"); wpabuf_free(resp); p2p_parse_free(&msg); return; } p2p->pending_action_state = P2P_PENDING_PD_RESPONSE; if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, p2p->cfg->dev_addr, wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { p2p_dbg(p2p, "Failed to send Action frame"); } else p2p->send_action_in_progress = 1; wpabuf_free(resp); if (!p2p->cfg->p2ps_prov_complete) { /* Don't emit anything */ } else if (msg.status && *msg.status != P2P_SC_SUCCESS && *msg.status != P2P_SC_SUCCESS_DEFERRED) { reject = *msg.status; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, sa, adv_mac, session_mac, NULL, adv_id, session_id, 0, 0, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, NULL, 0); } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { p2p->p2ps_prov->status = reject; p2p->p2ps_prov->conncap = conncap; if (reject != P2P_SC_SUCCESS) p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, sa, adv_mac, session_mac, NULL, adv_id, session_id, conncap, 0, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, NULL, 0); else p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap)); } else if (msg.status && p2p->p2ps_prov) { p2p->p2ps_prov->status = P2P_SC_SUCCESS; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap)); } else if (msg.status) { } else if (auto_accept && reject == P2P_SC_SUCCESS) { p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 0, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap)); } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && (!msg.session_info || !msg.session_info_len)) { p2p->p2ps_prov->method = msg.wps_config_methods; p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 1, NULL, (const u8 *) &resp_fcap, sizeof(resp_fcap)); } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { size_t buf_len = msg.session_info_len; char *buf = os_malloc(2 * buf_len + 1); if (buf) { p2p->p2ps_prov->method = msg.wps_config_methods; utf8_escape((char *) msg.session_info, buf_len, buf, 2 * buf_len + 1); p2p->cfg->p2ps_prov_complete( p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, adv_mac, session_mac, group_mac, adv_id, session_id, conncap, passwd_id, msg.persistent_ssid, msg.persistent_ssid_len, 0, 1, buf, (const u8 *) &resp_fcap, sizeof(resp_fcap)); os_free(buf); } } /* * prov_disc_req callback is used to generate P2P-PROV-DISC-ENTER-PIN, * P2P-PROV-DISC-SHOW-PIN, and P2P-PROV-DISC-PBC-REQ events. * Call it either on legacy P2P PD or on P2PS PD only if we need to * enter/show PIN. * * The callback is called in the following cases: * 1. Legacy P2P PD request, response status SUCCESS * 2. P2PS advertiser, method: DISPLAY, autoaccept: TRUE, * response status: SUCCESS * 3. P2PS advertiser, method DISPLAY, autoaccept: FALSE, * response status: INFO_CURRENTLY_UNAVAILABLE * 4. P2PS advertiser, method: KEYPAD, autoaccept==any, * response status: INFO_CURRENTLY_UNAVAILABLE * 5. P2PS follow-on with SUCCESS_DEFERRED, * advertiser role: DISPLAY, autoaccept: FALSE, * seeker: KEYPAD, response status: SUCCESS */ if (p2p->cfg->prov_disc_req && ((reject == P2P_SC_SUCCESS && !msg.adv_id) || (!msg.status && (reject == P2P_SC_SUCCESS || reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) && passwd_id == DEV_PW_USER_SPECIFIED) || (!msg.status && reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && passwd_id == DEV_PW_REGISTRAR_SPECIFIED) || (reject == P2P_SC_SUCCESS && msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) { const u8 *dev_addr = sa; if (msg.p2p_device_addr) dev_addr = msg.p2p_device_addr; p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa, msg.wps_config_methods, dev_addr, msg.pri_dev_type, msg.device_name, msg.config_methods, msg.capability ? msg.capability[0] : 0, msg.capability ? msg.capability[1] : 0, msg.group_id, msg.group_id_len); } if (dev && reject == P2P_SC_SUCCESS) { switch (config_methods) { case WPS_CONFIG_DISPLAY: dev->wps_prov_info = WPS_CONFIG_KEYPAD; break; case WPS_CONFIG_KEYPAD: dev->wps_prov_info = WPS_CONFIG_DISPLAY; break; case WPS_CONFIG_PUSHBUTTON: dev->wps_prov_info = WPS_CONFIG_PUSHBUTTON; break; case WPS_CONFIG_P2PS: dev->wps_prov_info = WPS_CONFIG_P2PS; break; default: dev->wps_prov_info = 0; break; } if (msg.intended_addr) os_memcpy(dev->interface_addr, msg.intended_addr, ETH_ALEN); } p2p_parse_free(&msg); }
static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, u8 id, u8 elen, const u8 *pos) { switch (id) { case WNM_NEIGHBOR_TSF: if (elen < 2 + 2) { wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); break; } rep->tsf_offset = WPA_GET_LE16(pos); rep->beacon_int = WPA_GET_LE16(pos + 2); rep->tsf_present = 1; break; case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: if (elen < 2) { wpa_printf(MSG_DEBUG, "WNM: Too short condensed " "country string"); break; } os_memcpy(rep->country, pos, 2); rep->country_present = 1; break; case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: if (elen < 1) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " "candidate"); break; } rep->preference = pos[0]; rep->preference_present = 1; break; case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: rep->bss_term_tsf = WPA_GET_LE64(pos); rep->bss_term_dur = WPA_GET_LE16(pos + 8); rep->bss_term_present = 1; break; case WNM_NEIGHBOR_BEARING: if (elen < 8) { wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " "bearing"); break; } rep->bearing = WPA_GET_LE16(pos); rep->distance = WPA_GET_LE32(pos + 2); rep->rel_height = WPA_GET_LE16(pos + 2 + 4); rep->bearing_present = 1; break; case WNM_NEIGHBOR_MEASUREMENT_PILOT: if (elen < 1) { wpa_printf(MSG_DEBUG, "WNM: Too short measurement " "pilot"); break; } os_free(rep->meas_pilot); rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); if (rep->meas_pilot == NULL) break; rep->meas_pilot->measurement_pilot = pos[0]; rep->meas_pilot->subelem_len = elen - 1; os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); break; case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: if (elen < 5) { wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " "capabilities"); break; } os_memcpy(rep->rm_capab, pos, 5); rep->rm_capab_present = 1; break; case WNM_NEIGHBOR_MULTIPLE_BSSID: if (elen < 1) { 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; rep->mul_bssid->max_bssid_indicator = pos[0]; rep->mul_bssid->subelem_len = elen - 1; os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); break; } }
static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth, const u8 *src_addr, const u8 *data, size_t data_len) { struct ft_r0kh_r1kh_push_frame *frame, f; struct ft_remote_r0kh *r0kh; struct os_time now; os_time_t tsend; int pairwise; wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push"); if (data_len < sizeof(*frame)) return -1; r0kh = wpa_auth->conf.r0kh_list; while (r0kh) { if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0) break; r0kh = r0kh->next; } if (r0kh == NULL) { wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for " "PMK-R0 push source address " MACSTR, MAC2STR(src_addr)); return -1; } frame = (struct ft_r0kh_r1kh_push_frame *) data; /* aes_unwrap() does not support inplace decryption, so use a temporary * buffer for the data. */ if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, frame->timestamp, f.timestamp) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from " MACSTR, MAC2STR(src_addr)); return -1; } os_get_time(&now); tsend = WPA_GET_LE32(f.timestamp); if ((now.sec > tsend && now.sec - tsend > 60) || (now.sec < tsend && tsend - now.sec > 60)) { wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid " "timestamp: sender time %d own time %d\n", (int) tsend, (int) now.sec); return -1; } if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching " "R1KH-ID (received " MACSTR " own " MACSTR ")", MAC2STR(f.r1kh_id), MAC2STR(wpa_auth->conf.r1_key_holder)); return -1; } pairwise = le_to_host16(f.pairwise); wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID=" MACSTR " pairwise=0x%x", MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise); wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1", f.pmk_r1, PMK_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name", f.pmk_r1_name, WPA_PMK_NAME_LEN); wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name, pairwise); os_memset(f.pmk_r1, 0, PMK_LEN); return 0; }
void write_pcapng_write_read(struct wlantest *wt, int dlt, struct pcap_pkthdr *hdr, const u8 *data) { struct pcapng_enhanced_packet *pkt; u8 *pos; u32 *block_len; u64 timestamp; size_t len, datalen = hdr->caplen; u8 rtap[] = { 0x00 /* rev */, 0x00 /* pad */, 0x0a, 0x00, /* header len */ 0x02, 0x00, 0x00, 0x00, /* present flags */ 0x00, /* flags */ 0x00 /* pad */ }; if (wt->assume_fcs) rtap[8] |= 0x10; if (!wt->pcapng) return; len = sizeof(*pkt) + hdr->len + 100 + notes_len(wt, 32) + sizeof(rtap); pkt = os_zalloc(len); if (pkt == NULL) return; pkt->block_type = PCAPNG_BLOCK_ENHANCED_PACKET; pkt->interface_id = 0; timestamp = 1000000 * hdr->ts.tv_sec + hdr->ts.tv_usec; pkt->timestamp_high = timestamp >> 32; pkt->timestamp_low = timestamp & 0xffffffff; wt->write_pcapng_time_high = pkt->timestamp_high; wt->write_pcapng_time_low = pkt->timestamp_low; pkt->captured_len = hdr->caplen; pkt->packet_len = hdr->len; pos = (u8 *) (pkt + 1); switch (dlt) { case DLT_IEEE802_11_RADIO: break; case DLT_PRISM_HEADER: /* remove prism header (could be kept ... lazy) */ pkt->captured_len -= WPA_GET_LE32(data + 4); pkt->packet_len -= WPA_GET_LE32(data + 4); datalen -= WPA_GET_LE32(data + 4); data += WPA_GET_LE32(data + 4); /* fall through */ case DLT_IEEE802_11: pkt->captured_len += sizeof(rtap); pkt->packet_len += sizeof(rtap); os_memcpy(pos, &rtap, sizeof(rtap)); pos += sizeof(rtap); break; default: return; } os_memcpy(pos, data, datalen); pos += datalen + PAD32(pkt->captured_len); pos = pcapng_add_comments(wt, pos); block_len = (u32 *) pos; pos += 4; *block_len = pkt->block_total_len = pos - (u8 *) pkt; fwrite(pkt, pos - (u8 *) pkt, 1, wt->pcapng); os_free(pkt); write_pcapng_decrypted(wt); }
static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, struct p2p_message *msg) { const u8 *pos; u16 nlen; char devtype[WPS_DEV_TYPE_BUFSIZE]; switch (id) { case P2P_ATTR_CAPABILITY: if (len < 2) { wpa_printf(MSG_DEBUG, "P2P: Too short Capability " "attribute (length %d)", len); return -1; } msg->capability = data; wpa_printf(MSG_DEBUG, "P2P: * Device Capability %02x " "Group Capability %02x", data[0], data[1]); break; case P2P_ATTR_DEVICE_ID: if (len < ETH_ALEN) { wpa_printf(MSG_DEBUG, "P2P: Too short Device ID " "attribute (length %d)", len); return -1; } msg->device_id = data; wpa_printf(MSG_DEBUG, "P2P: * Device ID " MACSTR, MAC2STR(msg->device_id)); break; case P2P_ATTR_GROUP_OWNER_INTENT: if (len < 1) { wpa_printf(MSG_DEBUG, "P2P: Too short GO Intent " "attribute (length %d)", len); return -1; } msg->go_intent = data; wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u " "Tie breaker %u", data[0] >> 1, data[0] & 0x01); break; case P2P_ATTR_STATUS: if (len < 1) { wpa_printf(MSG_DEBUG, "P2P: Too short Status " "attribute (length %d)", len); return -1; } msg->status = data; wpa_printf(MSG_DEBUG, "P2P: * Status: %d", data[0]); break; case P2P_ATTR_LISTEN_CHANNEL: if (len == 0) { wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Ignore " "null channel"); break; } if (len < 5) { wpa_printf(MSG_DEBUG, "P2P: Too short Listen Channel " "attribute (length %d)", len); return -1; } msg->listen_channel = data; wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: " "Country %c%c(0x%02x) Regulatory " "Class %d Channel Number %d", data[0], data[1], data[2], data[3], data[4]); break; case P2P_ATTR_OPERATING_CHANNEL: if (len == 0) { wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " "Ignore null channel"); break; } if (len < 5) { wpa_printf(MSG_DEBUG, "P2P: Too short Operating " "Channel attribute (length %d)", len); return -1; } msg->operating_channel = data; wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: " "Country %c%c(0x%02x) Regulatory " "Class %d Channel Number %d", data[0], data[1], data[2], data[3], data[4]); break; case P2P_ATTR_CHANNEL_LIST: if (len < 3) { wpa_printf(MSG_DEBUG, "P2P: Too short Channel List " "attribute (length %d)", len); return -1; } msg->channel_list = data; msg->channel_list_len = len; wpa_printf(MSG_DEBUG, "P2P: * Channel List: Country String " "'%c%c(0x%02x)'", data[0], data[1], data[2]); wpa_hexdump(MSG_MSGDUMP, "P2P: Channel List", msg->channel_list, msg->channel_list_len); break; case P2P_ATTR_GROUP_INFO: msg->group_info = data; msg->group_info_len = len; wpa_printf(MSG_DEBUG, "P2P: * Group Info"); break; case P2P_ATTR_DEVICE_INFO: if (len < ETH_ALEN + 2 + 8 + 1) { wpa_printf(MSG_DEBUG, "P2P: Too short Device Info " "attribute (length %d)", len); return -1; } msg->p2p_device_info = data; msg->p2p_device_info_len = len; pos = data; msg->p2p_device_addr = pos; pos += ETH_ALEN; msg->config_methods = WPA_GET_BE16(pos); pos += 2; msg->pri_dev_type = pos; pos += 8; msg->num_sec_dev_types = *pos++; if (msg->num_sec_dev_types * 8 > data + len - pos) { wpa_printf(MSG_DEBUG, "P2P: Device Info underflow"); return -1; } pos += msg->num_sec_dev_types * 8; if (data + len - pos < 4) { wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " "length %d", (int) (data + len - pos)); return -1; } if (WPA_GET_BE16(pos) != ATTR_DEV_NAME) { wpa_hexdump(MSG_DEBUG, "P2P: Unexpected Device Name " "header", pos, 4); return -1; } pos += 2; nlen = WPA_GET_BE16(pos); pos += 2; if (nlen > data + len - pos || nlen > WPS_DEV_NAME_MAX_LEN) { wpa_printf(MSG_DEBUG, "P2P: Invalid Device Name " "length %u (buf len %d)", nlen, (int) (data + len - pos)); return -1; } p2p_copy_filter_devname(msg->device_name, sizeof(msg->device_name), pos, nlen); wpa_printf(MSG_DEBUG, "P2P: * Device Info: addr " MACSTR " primary device type %s device name '%s' " "config methods 0x%x", MAC2STR(msg->p2p_device_addr), wps_dev_type_bin2str(msg->pri_dev_type, devtype, sizeof(devtype)), msg->device_name, msg->config_methods); break; case P2P_ATTR_CONFIGURATION_TIMEOUT: if (len < 2) { wpa_printf(MSG_DEBUG, "P2P: Too short Configuration " "Timeout attribute (length %d)", len); return -1; } msg->config_timeout = data; wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout"); break; case P2P_ATTR_INTENDED_INTERFACE_ADDR: if (len < ETH_ALEN) { wpa_printf(MSG_DEBUG, "P2P: Too short Intended P2P " "Interface Address attribute (length %d)", len); return -1; } msg->intended_addr = data; wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address: " MACSTR, MAC2STR(msg->intended_addr)); break; case P2P_ATTR_GROUP_BSSID: if (len < ETH_ALEN) { wpa_printf(MSG_DEBUG, "P2P: Too short P2P Group BSSID " "attribute (length %d)", len); return -1; } msg->group_bssid = data; wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID: " MACSTR, MAC2STR(msg->group_bssid)); break; case P2P_ATTR_GROUP_ID: if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) { wpa_printf(MSG_DEBUG, "P2P: Invalid P2P Group ID " "attribute length %d", len); return -1; } msg->group_id = data; msg->group_id_len = len; wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID: Device Address " MACSTR, MAC2STR(msg->group_id)); wpa_hexdump_ascii(MSG_DEBUG, "P2P: * P2P Group ID: SSID", msg->group_id + ETH_ALEN, msg->group_id_len - ETH_ALEN); break; case P2P_ATTR_INVITATION_FLAGS: if (len < 1) { wpa_printf(MSG_DEBUG, "P2P: Too short Invitation " "Flag attribute (length %d)", len); return -1; } msg->invitation_flags = data; wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", data[0]); break; case P2P_ATTR_MANAGEABILITY: if (len < 1) { wpa_printf(MSG_DEBUG, "P2P: Too short Manageability " "attribute (length %d)", len); return -1; } msg->manageability = data; wpa_printf(MSG_DEBUG, "P2P: * Manageability: bitmap 0x%x", data[0]); break; case P2P_ATTR_NOTICE_OF_ABSENCE: if (len < 2) { wpa_printf(MSG_DEBUG, "P2P: Too short Notice of " "Absence attribute (length %d)", len); return -1; } msg->noa = data; msg->noa_len = len; wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence"); break; case P2P_ATTR_EXT_LISTEN_TIMING: if (len < 4) { wpa_printf(MSG_DEBUG, "P2P: Too short Extended Listen " "Timing attribute (length %d)", len); return -1; } msg->ext_listen_timing = data; wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing " "(period %u msec interval %u msec)", WPA_GET_LE16(msg->ext_listen_timing), WPA_GET_LE16(msg->ext_listen_timing + 2)); break; case P2P_ATTR_MINOR_REASON_CODE: if (len < 1) { wpa_printf(MSG_DEBUG, "P2P: Too short Minor Reason " "Code attribute (length %d)", len); return -1; } msg->minor_reason_code = data; wpa_printf(MSG_DEBUG, "P2P: * Minor Reason Code: %u", *msg->minor_reason_code); break; case P2P_ATTR_OOB_GO_NEG_CHANNEL: if (len < 6) { wpa_printf(MSG_DEBUG, "P2P: Too short OOB GO Neg " "Channel attribute (length %d)", len); return -1; } msg->oob_go_neg_channel = data; wpa_printf(MSG_DEBUG, "P2P: * OOB GO Neg Channel: " "Country %c%c(0x%02x) Operating Class %d " "Channel Number %d Role %d", data[0], data[1], data[2], data[3], data[4], data[5]); break; case P2P_ATTR_SERVICE_HASH: if (len < P2PS_HASH_LEN) { wpa_printf(MSG_DEBUG, "P2P: Too short Service Hash (length %u)", len); return -1; } msg->service_hash_count = len / P2PS_HASH_LEN; msg->service_hash = data; wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash(s)", data, len); break; case P2P_ATTR_SESSION_INFORMATION_DATA: msg->session_info = data; msg->session_info_len = len; wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %u bytes - %p", len, data); break; case P2P_ATTR_CONNECTION_CAPABILITY: if (len < 1) { wpa_printf(MSG_DEBUG, "P2P: Too short Connection Capability (length %u)", len); return -1; } msg->conn_cap = data; wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x", *msg->conn_cap); break; case P2P_ATTR_ADVERTISEMENT_ID: if (len < 10) { wpa_printf(MSG_DEBUG, "P2P: Too short Advertisement ID (length %u)", len); return -1; } msg->adv_id = data; msg->adv_mac = &data[sizeof(u32)]; wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID %x", WPA_GET_LE32(data)); break; case P2P_ATTR_ADVERTISED_SERVICE: if (len < 8) { wpa_printf(MSG_DEBUG, "P2P: Too short Service Instance (length %u)", len); return -1; } msg->adv_service_instance = data; msg->adv_service_instance_len = len; if (len <= 255 + 8) { char str[256]; u8 namelen; namelen = data[6]; if (namelen > len - 7) break; os_memcpy(str, &data[7], namelen); str[namelen] = '\0'; wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %x-%s", WPA_GET_LE32(data), str); } else { wpa_printf(MSG_DEBUG, "P2P: * Service Instance: %p", data); } break; case P2P_ATTR_SESSION_ID: if (len < sizeof(u32) + ETH_ALEN) { wpa_printf(MSG_DEBUG, "P2P: Too short Session ID Info (length %u)", len); return -1; } msg->session_id = data; msg->session_mac = &data[sizeof(u32)]; wpa_printf(MSG_DEBUG, "P2P: * Session ID: %x " MACSTR, WPA_GET_LE32(data), MAC2STR(msg->session_mac)); break; case P2P_ATTR_FEATURE_CAPABILITY: if (!len) { wpa_printf(MSG_DEBUG, "P2P: Too short Feature Capability (length %u)", len); return -1; } msg->feature_cap = data; msg->feature_cap_len = len; wpa_printf(MSG_DEBUG, "P2P: * Feature Cap (length=%u)", len); break; case P2P_ATTR_PERSISTENT_GROUP: { if (len < ETH_ALEN || len > ETH_ALEN + SSID_MAX_LEN) { wpa_printf(MSG_DEBUG, "P2P: Invalid Persistent Group Info (length %u)", len); return -1; } msg->persistent_dev = data; msg->persistent_ssid_len = len - ETH_ALEN; msg->persistent_ssid = &data[ETH_ALEN]; wpa_printf(MSG_DEBUG, "P2P: * Persistent Group: " MACSTR " %s", MAC2STR(msg->persistent_dev), wpa_ssid_txt(msg->persistent_ssid, msg->persistent_ssid_len)); break; } default: wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d " "(length %d)", id, len); break; } return 0; }