Message ID | 20181205102401.17810-11-arnout@mind.be |
---|---|
State | Changes Requested |
Headers | show |
Series | [v3,01/12] hostapd: Add Multi-AP protocol support | expand |
On Wed, Dec 05, 2018 at 11:24:00AM +0100, Arnout Vandecappelle (Essensium/Mind) wrote: > Introduce a new, global configuration option multi_ap_backhaul_sta to > enable this feature. It has to be separate from the per-SSID > multi_ap_backhaul_sta option since no SSID exists yet when WPS is > performed. multi_ap_backhaul_sta is set to 1 in the automatically > created SSID. Thus, if the AP does not support Multi-AP, association > will fail and WPS will be terminated. Why would this configuration parameter be needed? I thought I already suggested that it would be better to indicate this as a parameter specific to each instance of WPS provisioning, i.e., as a new optional argument to the WPS_PBC control interface command. In other words, wpas_wps_start_pbc() should get this from the caller and wpa_supplicant_wps_cred() should get this from a new field added into struct wps_credential.
On 20/12/2018 11:19, Jouni Malinen wrote: > On Wed, Dec 05, 2018 at 11:24:00AM +0100, Arnout Vandecappelle (Essensium/Mind) wrote: >> Introduce a new, global configuration option multi_ap_backhaul_sta to >> enable this feature. It has to be separate from the per-SSID >> multi_ap_backhaul_sta option since no SSID exists yet when WPS is >> performed. multi_ap_backhaul_sta is set to 1 in the automatically >> created SSID. Thus, if the AP does not support Multi-AP, association >> will fail and WPS will be terminated. > > Why would this configuration parameter be needed? I thought I already > suggested I either missed that or misinterpreted it. > that it would be better to indicate this as a parameter > specific to each instance of WPS provisioning, i.e., as a new optional > argument to the WPS_PBC control interface command. That makes sense. > In other words, > wpas_wps_start_pbc() should get this from the caller So an extra argument to wpas_wps_start_pbc, right? I guess then it should be added also to: * wpa_cli; * new D-Bus interface; * (for OpenWrt only: ubus interface); but not to: * old D-Bus interfae; * p2p enrollment. And I'm not sure what to do with EVENT_WPS_BUTTON_PUSHED. But the only caller of that is apparently some atheros driver. > and > wpa_supplicant_wps_cred() should get this from a new field added into > struct wps_credential. Wouldn't struct wps_data be more appropriate? It's not very clear to me where that gets initialized though... But actually, the same goes for wps_credential. Is it possible that both of these only get initialized after wpas_wps_start_pbc() has already returned? Maybe the best way to pass it on would be through the phase1 config string? Although it feels like a bit of a hack to me, it looks like that is the way to pass down context information into EAP, right? Regards, Arnout
Hi Jouni, I forgot to ask in my earlier reply... On 05/12/2018 11:24, Arnout Vandecappelle (Essensium/Mind) wrote: > diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c > index 2882c6ad0..63eb2e84c 100644 > --- a/src/p2p/p2p_build.c > +++ b/src/p2p/p2p_build.c > @@ -802,7 +802,7 @@ int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, > wpabuf_put_be16(buf, p2p->cfg->config_methods); > } > > - if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0) > + if (wps_build_wfa_ext(buf, 0, NULL, 0, 0) < 0) These small changes make the patch very big and perhaps hard to review. Would you like me to split off the additional argument to wps_build_wfa_ext as a separate patch? Regards, Arnout > return -1; > > if (all_attr && p2p->cfg->num_sec_dev_types) {
On Tue, Jan 08, 2019 at 11:04:42AM +0100, Arnout Vandecappelle wrote: > On 05/12/2018 11:24, Arnout Vandecappelle (Essensium/Mind) wrote: > > diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c > > - if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0) > > + if (wps_build_wfa_ext(buf, 0, NULL, 0, 0) < 0) > > These small changes make the patch very big and perhaps hard to review. Would > you like me to split off the additional argument to wps_build_wfa_ext as a > separate patch? That would certainly make it easier to review the real functional changes, so yes, that's the preferred approach for this type of refactoring cases needed for new functionality.
On Mon, Jan 07, 2019 at 03:56:24PM +0100, Arnout Vandecappelle wrote: > On 20/12/2018 11:19, Jouni Malinen wrote: > > that it would be better to indicate this as a parameter > > specific to each instance of WPS provisioning, i.e., as a new optional > > argument to the WPS_PBC control interface command. > > That makes sense. > > > In other words, > > wpas_wps_start_pbc() should get this from the caller > > So an extra argument to wpas_wps_start_pbc, right? Yes. > I guess then it should be added also to: > > * wpa_cli; wpa_cli is already accepting arbitrary number of arguments to WPS_PBC. > * new D-Bus interface; If we expect this functionality to be used over D-Bus, sure. > * (for OpenWrt only: ubus interface); Sounds reasonable. > but not to: > > * old D-Bus interfae; > * p2p enrollment. Agreed. > And I'm not sure what to do with EVENT_WPS_BUTTON_PUSHED. But the only caller > of that is apparently some atheros driver. I'd ignore that for this, i.e., that wpas_wps_start_pbc() call should just note that there was no request for Multi-AP. > > and > > wpa_supplicant_wps_cred() should get this from a new field added into > > struct wps_credential. > > Wouldn't struct wps_data be more appropriate? It's not very clear to me where > that gets initialized though... But actually, the same goes for wps_credential. wpa_supplicant_wps_cred() gets called with information parsed from M8, so this should be filled based on what the Registrar told us. I don't see why struct wps_data would be involved in that part (i.e., processing of a received Credential). > Is it possible that both of these only get initialized after > wpas_wps_start_pbc() has already returned? Yes and not only possible, but that will happen in practice every time. > Maybe the best way to pass it on would be through the phase1 config string? > Although it feels like a bit of a hack to me, it looks like that is the way to > pass down context information into EAP, right? So this is a bit different direction, i.e., configuration of the local WPS Enrollee behavior for the request information while the comment about wpa_supplicant_wps_cred() was on how to process the response information. Anyway, yes, this is a bit complex due to the way the EAP peer implementation is kept as a separate module between core wpa_supplicant and WPS module. I did not consider details for that part, but yes, a new parameter within the phase1 config string seems to make most sense for getting information about the new optional WPS_PBC argument to the actual WPS Enrollee implementation which needs to generate the WSC messages with some additional information.
On 08/01/2019 12:04, Jouni Malinen wrote: > On Mon, Jan 07, 2019 at 03:56:24PM +0100, Arnout Vandecappelle wrote: >> On 20/12/2018 11:19, Jouni Malinen wrote: [snip] >>> wpa_supplicant_wps_cred() should get this from a new field added into >>> struct wps_credential. >> >> Wouldn't struct wps_data be more appropriate? It's not very clear to me where >> that gets initialized though... But actually, the same goes for wps_credential. > > wpa_supplicant_wps_cred() gets called with information parsed from M8, > so this should be filled based on what the Registrar told us. Unfortunately, the registrar doesn't tell us anything. The M8 does NOT contain the Multi-AP IE. However, wpa_supplicant_wps_cred has access to the current_ssid which has the multi_ap setting. In fact, this bit of the patch: + if (wpa_s->conf->multi_ap_backhaul_sta) + ssid->multi_ap_backhaul_sta = 1; + else + ssid->multi_ap_backhaul_sta = 0; is probably (I should check) redundant because the multi_ap_backhaul_sta bit is already set in wpas_wps_start_pbc(). I notice now, however, that the multi_ap_backhaul_sta option is missing from wpa_config_write_network(). > I don't > see why struct wps_data would be involved in that part (i.e., processing > of a received Credential). > >> Is it possible that both of these only get initialized after >> wpas_wps_start_pbc() has already returned? > > Yes and not only possible, but that will happen in practice every time. > >> Maybe the best way to pass it on would be through the phase1 config string? >> Although it feels like a bit of a hack to me, it looks like that is the way to >> pass down context information into EAP, right? > > So this is a bit different direction, i.e., configuration of the local > WPS Enrollee behavior for the request information while the comment > about wpa_supplicant_wps_cred() was on how to process the response > information. Indeed I was mixing those two. > Anyway, yes, this is a bit complex due to the way the EAP > peer implementation is kept as a separate module between core > wpa_supplicant and WPS module. I did not consider details for that part, > but yes, a new parameter within the phase1 config string seems to make > most sense for getting information about the new optional WPS_PBC > argument to the actual WPS Enrollee implementation which needs to > generate the WSC messages with some additional information. OK, thanks. Regards, Arnout
On Tue, Jan 08, 2019 at 04:05:35PM +0100, Arnout Vandecappelle wrote: > On 08/01/2019 12:04, Jouni Malinen wrote: > > wpa_supplicant_wps_cred() gets called with information parsed from M8, > > so this should be filled based on what the Registrar told us. > > Unfortunately, the registrar doesn't tell us anything. The M8 does NOT contain > the Multi-AP IE. That sounds like a bad protocol design to me.. > However, wpa_supplicant_wps_cred has access to the current_ssid which has the > multi_ap setting. I'd be a bit careful with wpa_s->current_ssid there.. It does not actually have to be set in some WPS use cases. Anyway, for the Multi-AP PBC case, I think this will in practice always be pointing to the network profile where the extra parameter from WPS_PBC would be present. Anyway, I would also be fine in adding a new flag in struct wpa_supplicant for tracking this type of pending state for WPS, if required.
Hi Jouni, On Tue, Jan 08, 2019 at 01:04:37PM +0200, Jouni Malinen wrote: > On Mon, Jan 07, 2019 at 03:56:24PM +0100, Arnout Vandecappelle wrote: > > On 20/12/2018 11:19, Jouni Malinen wrote: > > > that it would be better to indicate this as a parameter > > > specific to each instance of WPS provisioning, i.e., as a new optional > > > argument to the WPS_PBC control interface command. > > > > That makes sense. I'm sure you have good reasons for requesting it do be done in that way. It'd be great if you can elaborate on those reasons, see below for the cause of my confusion with that. > > > > > In other words, > > > wpas_wps_start_pbc() should get this from the caller > > > > So an extra argument to wpas_wps_start_pbc, right? > > Yes. I've been going that road for a bit now and more and more come to the conclusion that setting a global variable (just like other WPS- related global configurations) would be much less complex. Also note that a station is most likely really either a regular station or multi-ap backhaul station, also considering the context: multi-ap interface in 4-addr-mode sitting in a bridge while regular station being a whole different use-case. Coming from OpenWrt, whether the interface is a multiap backhaul sta or a regular sta is known at the time of wpa_supplicant.conf being generated. Sure, at this point we could store that somewhere next to wpa_supplicant_$ifname.conf and when pushing the WPS butten checking that file to decide whether multi_ap=1 is being passed along the call of wps_start_pbc or not. A more dynamic decission doesn't make much sense, because higher layers are also already set according to whether the STA interface is part of a bridge or not. > > > I guess then it should be added also to: > > > > * wpa_cli; > > wpa_cli is already accepting arbitrary number of arguments to WPS_PBC. > > > * new D-Bus interface; > > If we expect this functionality to be used over D-Bus, sure. > > > * (for OpenWrt only: ubus interface); > > Sounds reasonable. > > > but not to: > > > > * old D-Bus interfae; > > * p2p enrollment. > > Agreed. > > > And I'm not sure what to do with EVENT_WPS_BUTTON_PUSHED. But the only caller > > of that is apparently some atheros driver. > > I'd ignore that for this, i.e., that wpas_wps_start_pbc() call should > just note that there was no request for Multi-AP. > > > > and > > > wpa_supplicant_wps_cred() should get this from a new field added into > > > struct wps_credential. > > > > Wouldn't struct wps_data be more appropriate? It's not very clear to me where > > that gets initialized though... But actually, the same goes for wps_credential. > > wpa_supplicant_wps_cred() gets called with information parsed from M8, > so this should be filled based on what the Registrar told us. I don't > see why struct wps_data would be involved in that part (i.e., processing > of a received Credential). > > > Is it possible that both of these only get initialized after > > wpas_wps_start_pbc() has already returned? > > Yes and not only possible, but that will happen in practice every time. > > > Maybe the best way to pass it on would be through the phase1 config string? > > Although it feels like a bit of a hack to me, it looks like that is the way to > > pass down context information into EAP, right? > > So this is a bit different direction, i.e., configuration of the local > WPS Enrollee behavior for the request information while the comment > about wpa_supplicant_wps_cred() was on how to process the response > information. Anyway, yes, this is a bit complex due to the way the EAP > peer implementation is kept as a separate module between core > wpa_supplicant and WPS module. I did not consider details for that part, > but yes, a new parameter within the phase1 config string seems to make > most sense for getting information about the new optional WPS_PBC > argument to the actual WPS Enrollee implementation which needs to > generate the WSC messages with some additional information. That kinda adds to it complexity wise... Cheers Daniel > > -- > Jouni Malinen PGP id EFC895FA > > _______________________________________________ > Hostap mailing list > Hostap@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/hostap
On Fri, Jan 18, 2019 at 01:28:43AM +0100, Daniel Golle wrote: > Hi Jouni, > > On Tue, Jan 08, 2019 at 01:04:37PM +0200, Jouni Malinen wrote: > > On Mon, Jan 07, 2019 at 03:56:24PM +0100, Arnout Vandecappelle wrote: > > > On 20/12/2018 11:19, Jouni Malinen wrote: > > > > that it would be better to indicate this as a parameter > > > > specific to each instance of WPS provisioning, i.e., as a new optional > > > > argument to the WPS_PBC control interface command. > > > > > > That makes sense. > > I'm sure you have good reasons for requesting it do be done in that > way. It'd be great if you can elaborate on those reasons, see below > for the cause of my confusion with that. This information (whether to request credentials for Multi-AP use case or for something else) is associated with a specific instance of WPS protocol exchange; not to global state of a WPS Enrollee device. > > > > In other words, > > > > wpas_wps_start_pbc() should get this from the caller > > > > > > So an extra argument to wpas_wps_start_pbc, right? > > > > Yes. > > I've been going that road for a bit now and more and more come to > the conclusion that setting a global variable (just like other WPS- > related global configurations) would be much less complex. Sure, it might be less complex, but it would be less correct as well. It should also not be assumed that there is only a single WPS exchange in process at any point in time. The most common example of this is the use of WPS ER in wpa_supplicant, but that would obviously be Registrar instead of two Enrollees, so that might not hit this specific case. Anyway, using a global variable for setting a parameter for a single WPS protocol instance does not sound correct. > Also note that a station is most likely really either a regular station > or multi-ap backhaul station, also considering the context: multi-ap > interface in 4-addr-mode sitting in a bridge while regular station > being a whole different use-case. Probably true as well, but still, this is just trying to justify taking a shortcut over a cleaner design. > Coming from OpenWrt, whether the interface is a multiap backhaul sta or > a regular sta is known at the time of wpa_supplicant.conf being > generated. Sure, at this point we could store that somewhere next to > wpa_supplicant_$ifname.conf and when pushing the WPS butten checking > that file to decide whether multi_ap=1 is being passed along the call > of wps_start_pbc or not. A more dynamic decission doesn't make much > sense, because higher layers are also already set according to whether > the STA interface is part of a bridge or not. I don't think wpa_supplicant implementation design should be based on assumptions that OpenWrt or some other user of wpa_supplicant has such knowledge of the device using WPS Enrollee functionality only for a specific purpose.
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index 2882c6ad0..63eb2e84c 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -802,7 +802,7 @@ int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id, wpabuf_put_be16(buf, p2p->cfg->config_methods); } - if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0) + if (wps_build_wfa_ext(buf, 0, NULL, 0, 0) < 0) return -1; if (all_attr && p2p->cfg->num_sec_dev_types) { diff --git a/src/wps/wps.c b/src/wps/wps.c index 8d228270f..c162e793d 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -430,7 +430,7 @@ struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) if (wps_build_version(ie) || wps_build_req_type(ie, req_type) || - wps_build_wfa_ext(ie, 0, NULL, 0)) { + wps_build_wfa_ext(ie, 0, NULL, 0, 0)) { wpabuf_free(ie); return NULL; } @@ -464,7 +464,7 @@ struct wpabuf * wps_build_assoc_resp_ie(void) if (wps_build_version(ie) || wps_build_resp_type(ie, WPS_RESP_AP) || - wps_build_wfa_ext(ie, 0, NULL, 0)) { + wps_build_wfa_ext(ie, 0, NULL, 0, 0)) { wpabuf_free(ie); return NULL; } @@ -516,7 +516,7 @@ struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev, wps_build_model_name(dev, ie) || wps_build_model_number(dev, ie) || wps_build_dev_name(dev, ie) || - wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) || + wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0, 0) || wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types) || wps_build_secondary_dev_type(dev, ie) diff --git a/src/wps/wps.h b/src/wps/wps.h index 2505d2d9f..129f27ab4 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -612,6 +612,12 @@ struct wps_context { */ int ap_setup_locked; + /** + * multi_ap_backhaul_sta - Whether this is a Multi-AP backhaul STA + * enrollee + */ + int multi_ap_backhaul_sta; + /** * uuid - Own UUID */ diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c index 770f5e90c..22b33e8c3 100644 --- a/src/wps/wps_attr_build.c +++ b/src/wps/wps_attr_build.c @@ -203,7 +203,8 @@ int wps_build_version(struct wpabuf *msg) int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, - const u8 *auth_macs, size_t auth_macs_count) + const u8 *auth_macs, size_t auth_macs_count, + u8 multi_ap_subelem) { u8 *len; @@ -244,6 +245,13 @@ int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, MAC2STR(&auth_macs[i * ETH_ALEN])); } + if (multi_ap_subelem) { + wpa_printf(MSG_DEBUG, "WPS: * Multi-AP (0x%x)", multi_ap_subelem); + wpabuf_put_u8(msg, WFA_ELEM_MULTI_AP); + wpabuf_put_u8(msg, 1); /* length */ + wpabuf_put_u8(msg, multi_ap_subelem); + } + WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2); #ifdef CONFIG_WPS_TESTING diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c index bcae1ba58..747dc4710 100644 --- a/src/wps/wps_common.c +++ b/src/wps/wps_common.c @@ -374,7 +374,7 @@ struct wpabuf * wps_get_oob_cred(struct wps_context *wps, int rf_band, (rf_band && wps_build_rf_bands_attr(plain, rf_band)) || (channel && wps_build_ap_channel(plain, channel)) || wps_build_mac_addr(plain, wps->dev.mac_addr) || - wps_build_wfa_ext(plain, 0, NULL, 0)) { + wps_build_wfa_ext(plain, 0, NULL, 0, 0)) { os_free(data.new_psk); wpabuf_clear_free(plain); return NULL; @@ -421,7 +421,7 @@ struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id, if (wps_build_oob_dev_pw(data, dev_pw_id, pubkey, wpabuf_head(dev_pw), wpabuf_len(dev_pw)) || - wps_build_wfa_ext(data, 0, NULL, 0)) { + wps_build_wfa_ext(data, 0, NULL, 0, 0)) { wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password " "token"); wpabuf_clear_free(data); @@ -586,7 +586,7 @@ struct wpabuf * wps_build_wsc_ack(struct wps_data *wps) wps_build_msg_type(msg, WPS_WSC_ACK) || wps_build_enrollee_nonce(wps, msg) || wps_build_registrar_nonce(wps, msg) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } @@ -610,7 +610,7 @@ struct wpabuf * wps_build_wsc_nack(struct wps_data *wps) wps_build_enrollee_nonce(wps, msg) || wps_build_registrar_nonce(wps, msg) || wps_build_config_error(msg, wps->config_error) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } @@ -726,7 +726,7 @@ struct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx, if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER, nfc_dh_pubkey, NULL, 0) || wps_build_uuid_e(msg, ctx->uuid) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } @@ -809,7 +809,7 @@ struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx, wps_build_ssid(msg, ctx) || wps_build_ap_freq(msg, freq) || (bssid && wps_build_mac_addr(msg, bssid)) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } @@ -848,7 +848,7 @@ struct wpabuf * wps_build_nfc_handover_req_p2p(struct wps_context *ctx, wps_build_rf_bands(&ctx->dev, msg, 0) || wps_build_serial_number(&ctx->dev, msg) || wps_build_uuid_e(msg, ctx->uuid) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } @@ -900,7 +900,7 @@ struct wpabuf * wps_build_nfc_handover_sel_p2p(struct wps_context *ctx, wps_build_rf_bands(&ctx->dev, msg, 0) || wps_build_serial_number(&ctx->dev, msg) || wps_build_uuid_e(msg, ctx->uuid) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h index 301864da4..9fccb4eeb 100644 --- a/src/wps/wps_defs.h +++ b/src/wps/wps_defs.h @@ -152,7 +152,8 @@ enum { WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02, WFA_ELEM_REQUEST_TO_ENROLL = 0x03, WFA_ELEM_SETTINGS_DELAY_TIME = 0x04, - WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05 + WFA_ELEM_REGISTRAR_CONFIGURATION_METHODS = 0x05, + WFA_ELEM_MULTI_AP = 0x06 }; /* Device Password ID */ diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index 417507740..e175770f1 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -105,6 +105,7 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps) { struct wpabuf *msg; u16 config_methods; + u8 multi_ap_backhaul_sta = 0; if (random_get_bytes(wps->nonce_e, WPS_NONCE_LEN) < 0) return NULL; @@ -134,6 +135,9 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps) WPS_CONFIG_PHY_PUSHBUTTON); } + if (wps->wps->multi_ap_backhaul_sta) + multi_ap_backhaul_sta = MULTI_AP_BACKHAUL_STA; + if (wps_build_version(msg) || wps_build_msg_type(msg, WPS_M1) || wps_build_uuid_e(msg, wps->uuid_e) || @@ -152,7 +156,7 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps) wps_build_dev_password_id(msg, wps->dev_pw_id) || wps_build_config_error(msg, WPS_CFG_NO_ERROR) || wps_build_os_version(&wps->wps->dev, msg) || - wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_wfa_ext(msg, 0, NULL, 0, multi_ap_backhaul_sta) || wps_build_vendor_ext_m1(&wps->wps->dev, msg)) { wpabuf_free(msg); return NULL; @@ -190,7 +194,7 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps) wps_build_msg_type(msg, WPS_M3) || wps_build_registrar_nonce(wps, msg) || wps_build_e_hash(wps, msg) || - wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_wfa_ext(msg, 0, NULL, 0, 0) || wps_build_authenticator(wps, msg)) { wpabuf_free(msg); return NULL; @@ -223,7 +227,7 @@ static struct wpabuf * wps_build_m5(struct wps_data *wps) wps_build_e_snonce1(wps, plain) || wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain) || - wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_wfa_ext(msg, 0, NULL, 0, 0) || wps_build_authenticator(wps, msg)) { wpabuf_clear_free(plain); wpabuf_free(msg); @@ -393,7 +397,7 @@ static struct wpabuf * wps_build_m7(struct wps_data *wps) (wps->wps->ap && wps_build_ap_settings(wps, plain)) || wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain) || - wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_wfa_ext(msg, 0, NULL, 0, 0) || wps_build_authenticator(wps, msg)) { wpabuf_clear_free(plain); wpabuf_free(msg); @@ -430,7 +434,7 @@ static struct wpabuf * wps_build_wsc_done(struct wps_data *wps) wps_build_msg_type(msg, WPS_WSC_DONE) || wps_build_enrollee_nonce(wps, msg) || wps_build_registrar_nonce(wps, msg) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index affd6a4af..06a8fdaf3 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -1530,7 +1530,7 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id, wps_er_build_selected_registrar(msg, sel_reg) || wps_er_build_dev_password_id(msg, dev_passwd_id) || wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) || - wps_build_wfa_ext(msg, 0, auth_macs, count) || + wps_build_wfa_ext(msg, 0, auth_macs, count, 0) || wps_er_build_uuid_r(msg, er->wps->uuid)) { wpabuf_free(msg); return; @@ -2048,7 +2048,7 @@ struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps, data.wps = wps; data.use_cred = cred; if (wps_build_cred(&data, ret) || - wps_build_wfa_ext(ret, 0, NULL, 0)) { + wps_build_wfa_ext(ret, 0, NULL, 0, 0)) { wpabuf_free(ret); return NULL; } diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index fe0c60bd1..7972fc225 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -163,7 +163,8 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, struct wpabuf *plain); int wps_build_version(struct wpabuf *msg); int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll, - const u8 *auth_macs, size_t auth_macs_count); + const u8 *auth_macs, size_t auth_macs_count, + u8 multi_ap_subelem); int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type); int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg); int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 379925e3f..b5ac29bea 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -1281,7 +1281,7 @@ static int wps_set_ie(struct wps_registrar *reg) wps_build_sel_reg_config_methods(reg, beacon) || wps_build_sel_pbc_reg_uuid_e(reg, beacon) || (reg->dualband && wps_build_rf_bands(®->wps->dev, beacon, 0)) || - wps_build_wfa_ext(beacon, 0, auth_macs, count) || + wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) || wps_build_vendor_ext(®->wps->dev, beacon)) { wpabuf_free(beacon); wpabuf_free(probe); @@ -1311,7 +1311,7 @@ static int wps_set_ie(struct wps_registrar *reg) wps_build_device_attrs(®->wps->dev, probe) || wps_build_probe_config_methods(reg, probe) || (reg->dualband && wps_build_rf_bands(®->wps->dev, probe, 0)) || - wps_build_wfa_ext(probe, 0, auth_macs, count) || + wps_build_wfa_ext(probe, 0, auth_macs, count, 0) || wps_build_vendor_ext(®->wps->dev, probe)) { wpabuf_free(beacon); wpabuf_free(probe); @@ -1845,7 +1845,7 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps) wps_build_config_error(msg, WPS_CFG_NO_ERROR) || wps_build_dev_password_id(msg, wps->dev_pw_id) || wps_build_os_version(&wps->wps->dev, msg) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } @@ -1913,7 +1913,7 @@ static struct wpabuf * wps_build_m2d(struct wps_data *wps) wps_build_assoc_state(wps, msg) || wps_build_config_error(msg, err) || wps_build_os_version(&wps->wps->dev, msg) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } @@ -1949,7 +1949,7 @@ static struct wpabuf * wps_build_m4(struct wps_data *wps) wps_build_r_snonce1(wps, plain) || wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain) || - wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_wfa_ext(msg, 0, NULL, 0, 0) || wps_build_authenticator(wps, msg)) { wpabuf_clear_free(plain); wpabuf_free(msg); @@ -1984,7 +1984,7 @@ static struct wpabuf * wps_build_m6(struct wps_data *wps) wps_build_r_snonce2(wps, plain) || wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain) || - wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_wfa_ext(msg, 0, NULL, 0, 0) || wps_build_authenticator(wps, msg)) { wpabuf_clear_free(plain); wpabuf_free(msg); @@ -2021,7 +2021,7 @@ static struct wpabuf * wps_build_m8(struct wps_data *wps) (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) || wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain) || - wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_wfa_ext(msg, 0, NULL, 0, 0) || wps_build_authenticator(wps, msg)) { wpabuf_clear_free(plain); wpabuf_clear_free(msg); diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c index 0c458c6ad..ca893a43c 100644 --- a/src/wps/wps_upnp.c +++ b/src/wps/wps_upnp.c @@ -599,7 +599,7 @@ static struct wpabuf * build_fake_wsc_ack(void) wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); wpabuf_put_be16(msg, WPS_NONCE_LEN); wpabuf_put(msg, WPS_NONCE_LEN); - if (wps_build_wfa_ext(msg, 0, NULL, 0)) { + if (wps_build_wfa_ext(msg, 0, NULL, 0, 0)) { wpabuf_free(msg); return NULL; } diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 4ff93f62f..6cbc21fd8 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -4652,6 +4652,7 @@ static const struct global_parse_data global_fields[] = { { STR(config_methods), CFG_CHANGED_CONFIG_METHODS }, { INT_RANGE(wps_cred_processing, 0, 2), 0 }, { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION }, + { INT_RANGE(multi_ap_backhaul_sta, 0, 1), CFG_CHANGED_MULTI_AP_BACKHAUL_STA }, #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE }, diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index cd7571f59..c8857016f 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -374,6 +374,7 @@ struct wpa_cred { #define CFG_CHANGED_P2P_PASSPHRASE_LEN BIT(16) #define CFG_CHANGED_SCHED_SCAN_PLANS BIT(17) #define CFG_CHANGED_WOWLAN_TRIGGERS BIT(18) +#define CFG_CHANGED_MULTI_AP_BACKHAUL_STA BIT(19) /** * struct wpa_config - wpa_supplicant configuration data @@ -768,6 +769,7 @@ struct wpa_config { int p2p_optimize_listen_chan; struct wpabuf *wps_vendor_ext_m1; + int multi_ap_backhaul_sta; #define MAX_WPS_VENDOR_EXT 10 /** diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 09115e19d..e78f273b1 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1183,6 +1183,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "\n"); } } + + if (config->multi_ap_backhaul_sta) + fprintf(f, "multi_ap_backhaul_sta=%d\n", config->multi_ap_backhaul_sta); + #endif /* CONFIG_WPS */ #ifdef CONFIG_P2P { diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index e5dee2236..d22f76664 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -286,6 +286,11 @@ fast_reauth=1 # The vendor attribute contents to be added in M1 (hex string) #wps_vendor_ext_m1=000137100100020001 +# Multi-AP STA config +# When set to 1, the Multi-AP vendor extension is added to WPS M1 and the +# Multi-AP IE is sent to the driver for inclusion in association request frames. +#multi_ap_backhaul_sta=1 + # NFC password token for WPS # These parameters can be used to configure a fixed NFC password token for the # station. This can be generated, e.g., with nfc_pw_token. When these diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 1a2677b8e..de3943912 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -473,6 +473,11 @@ static int wpa_supplicant_wps_cred(void *ctx, wpa_config_set_network_defaults(ssid); ssid->wps_run = wpa_s->wps_run; + if (wpa_s->conf->multi_ap_backhaul_sta) + ssid->multi_ap_backhaul_sta = 1; + else + ssid->multi_ap_backhaul_sta = 0; + os_free(ssid->ssid); ssid->ssid = os_malloc(cred->ssid_len); if (ssid->ssid) { @@ -1181,6 +1186,8 @@ int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid, return -1; if (wpa_s->wps_fragment_size) ssid->eap.fragment_size = wpa_s->wps_fragment_size; + if (wpa_s->conf->multi_ap_backhaul_sta) + ssid->multi_ap_backhaul_sta = 1; wpa_supplicant_wps_event(wpa_s, WPS_EV_PBC_ACTIVE, NULL); eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout, wpa_s, NULL); @@ -1527,7 +1534,6 @@ static void wpas_wps_set_vendor_ext_m1(struct wpa_supplicant *wpa_s, } } - int wpas_wps_init(struct wpa_supplicant *wpa_s) { struct wps_context *wps; @@ -1569,6 +1575,8 @@ int wpas_wps_init(struct wpa_supplicant *wpa_s) wpas_wps_set_vendor_ext_m1(wpa_s, wps); + wps->multi_ap_backhaul_sta = wpa_s->conf->multi_ap_backhaul_sta; + wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version); modes = wpa_s->hw.modes; if (modes) { @@ -2205,6 +2213,9 @@ void wpas_wps_update_config(struct wpa_supplicant *wpa_s) if (wpa_s->conf->changed_parameters & CFG_CHANGED_VENDOR_EXTENSION) wpas_wps_set_vendor_ext_m1(wpa_s, wps); + if (wpa_s->conf->changed_parameters & CFG_CHANGED_MULTI_AP_BACKHAUL_STA) + wps->multi_ap_backhaul_sta = wpa_s->conf->multi_ap_backhaul_sta; + if (wpa_s->conf->changed_parameters & CFG_CHANGED_OS_VERSION) wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);