WPS: Change concurrent radio AP to use only one WPS UPnP instance

WPS external Registrars can get confused about multiple UPnP
instances (one per radio) on a dual-concurrent APs. Simplify the
design by sharing a single UPnP state machine for all wireless
interfaces controlled by hostapd. This matches with the previous
changes that made a single command enable WPS functionality on
all interfaces.

This is relatively minimal change to address the sharing of the
state among multiple struct hostapd_data instances. More cleanup
can be done separately to remove unnecessary copies of information.
This commit is contained in:
Jouni Malinen 2010-11-11 14:50:13 +02:00 committed by Jouni Malinen
parent d318c534da
commit fd806bac5f
6 changed files with 203 additions and 92 deletions

View file

@ -1148,26 +1148,19 @@ static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
if (hapd->conf->ap_pin) if (hapd->conf->ap_pin)
ctx->ap_pin = os_strdup(hapd->conf->ap_pin); ctx->ap_pin = os_strdup(hapd->conf->ap_pin);
hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd); hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd,
if (hapd->wps_upnp == NULL) { hapd->conf->upnp_iface);
os_free(ctx); if (hapd->wps_upnp == NULL)
return -1; return -1;
}
wps->wps_upnp = hapd->wps_upnp; wps->wps_upnp = hapd->wps_upnp;
if (upnp_wps_device_start(hapd->wps_upnp, hapd->conf->upnp_iface)) {
upnp_wps_device_deinit(hapd->wps_upnp);
hapd->wps_upnp = NULL;
return -1;
}
return 0; return 0;
} }
static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd) static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
{ {
upnp_wps_device_deinit(hapd->wps_upnp); upnp_wps_device_deinit(hapd->wps_upnp, hapd);
} }
#endif /* CONFIG_WPS_UPNP */ #endif /* CONFIG_WPS_UPNP */

View file

@ -212,6 +212,10 @@
/* Maximum number of Probe Request events per second */ /* Maximum number of Probe Request events per second */
#define MAX_EVENTS_PER_SEC 5 #define MAX_EVENTS_PER_SEC 5
static struct upnp_wps_device_sm *shared_upnp_device = NULL;
/* Write the current date/time per RFC */ /* Write the current date/time per RFC */
void format_date(struct wpabuf *buf) void format_date(struct wpabuf *buf)
{ {
@ -965,7 +969,7 @@ static void upnp_wps_free_subscriptions(struct dl_list *head)
* upnp_wps_device_stop - Stop WPS UPnP operations on an interface * upnp_wps_device_stop - Stop WPS UPnP operations on an interface
* @sm: WPS UPnP state machine from upnp_wps_device_init() * @sm: WPS UPnP state machine from upnp_wps_device_init()
*/ */
void upnp_wps_device_stop(struct upnp_wps_device_sm *sm) static void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
{ {
if (!sm || !sm->started) if (!sm || !sm->started)
return; return;
@ -997,7 +1001,7 @@ void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
* @net_if: Selected network interface name * @net_if: Selected network interface name
* Returns: 0 on success, -1 on failure * Returns: 0 on success, -1 on failure
*/ */
int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if) static int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if)
{ {
if (!sm || !net_if) if (!sm || !net_if)
return -1; return -1;
@ -1052,24 +1056,56 @@ fail:
} }
static struct upnp_wps_device_interface *
upnp_wps_get_iface(struct upnp_wps_device_sm *sm, void *priv)
{
struct upnp_wps_device_interface *iface;
dl_list_for_each(iface, &sm->interfaces,
struct upnp_wps_device_interface, list) {
if (iface->priv == priv)
return iface;
}
return NULL;
}
/** /**
* upnp_wps_device_deinit - Deinitialize WPS UPnP * upnp_wps_device_deinit - Deinitialize WPS UPnP
* @sm: WPS UPnP state machine from upnp_wps_device_init() * @sm: WPS UPnP state machine from upnp_wps_device_init()
* @priv: External context data that was used in upnp_wps_device_init() call
*/ */
void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm) void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv)
{ {
struct upnp_wps_device_interface *iface;
if (!sm) if (!sm)
return; return;
upnp_wps_device_stop(sm); iface = upnp_wps_get_iface(sm, priv);
if (iface == NULL) {
wpa_printf(MSG_ERROR, "WPS UPnP: Could not find the interface "
"instance to deinit");
return;
}
wpa_printf(MSG_DEBUG, "WPS UPnP: Deinit interface instance %p", iface);
if (dl_list_len(&sm->interfaces) == 1) {
wpa_printf(MSG_DEBUG, "WPS UPnP: Deinitializing last instance "
"- free global device instance");
upnp_wps_device_stop(sm);
}
dl_list_del(&iface->list);
if (sm->peer.wps) if (iface->peer.wps)
wps_deinit(sm->peer.wps); wps_deinit(iface->peer.wps);
os_free(sm->root_dir); os_free(iface->ctx->ap_pin);
os_free(sm->desc_url); os_free(iface->ctx);
os_free(sm->ctx->ap_pin);
os_free(sm->ctx); if (dl_list_empty(&sm->interfaces)) {
os_free(sm); os_free(sm->root_dir);
os_free(sm->desc_url);
os_free(sm);
shared_upnp_device = NULL;
}
} }
@ -1078,25 +1114,59 @@ void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm)
* @ctx: callback table; we must eventually free it * @ctx: callback table; we must eventually free it
* @wps: Pointer to longterm WPS context * @wps: Pointer to longterm WPS context
* @priv: External context data that will be used in callbacks * @priv: External context data that will be used in callbacks
* @net_if: Selected network interface name
* Returns: WPS UPnP state or %NULL on failure * Returns: WPS UPnP state or %NULL on failure
*/ */
struct upnp_wps_device_sm * struct upnp_wps_device_sm *
upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps, upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
void *priv) void *priv, char *net_if)
{ {
struct upnp_wps_device_sm *sm; struct upnp_wps_device_sm *sm;
struct upnp_wps_device_interface *iface;
int start = 0;
sm = os_zalloc(sizeof(*sm)); iface = os_zalloc(sizeof(*iface));
if (!sm) { if (iface == NULL) {
wpa_printf(MSG_ERROR, "WPS UPnP: upnp_wps_device_init failed"); os_free(ctx->ap_pin);
os_free(ctx);
return NULL;
}
wpa_printf(MSG_DEBUG, "WPS UPnP: Init interface instance %p", iface);
iface->ctx = ctx;
iface->wps = wps;
iface->priv = priv;
if (shared_upnp_device) {
wpa_printf(MSG_DEBUG, "WPS UPnP: Share existing device "
"context");
sm = shared_upnp_device;
} else {
wpa_printf(MSG_DEBUG, "WPS UPnP: Initialize device context");
sm = os_zalloc(sizeof(*sm));
if (!sm) {
wpa_printf(MSG_ERROR, "WPS UPnP: upnp_wps_device_init "
"failed");
os_free(iface);
os_free(ctx->ap_pin);
os_free(ctx);
return NULL;
}
shared_upnp_device = sm;
dl_list_init(&sm->msearch_replies);
dl_list_init(&sm->subscriptions);
dl_list_init(&sm->interfaces);
start = 1;
}
dl_list_add(&sm->interfaces, &iface->list);
if (start && upnp_wps_device_start(sm, net_if)) {
upnp_wps_device_deinit(sm, priv);
return NULL; return NULL;
} }
sm->ctx = ctx;
sm->wps = wps;
sm->priv = priv;
dl_list_init(&sm->msearch_replies);
dl_list_init(&sm->subscriptions);
return sm; return sm;
} }
@ -1115,16 +1185,20 @@ int upnp_wps_subscribers(struct upnp_wps_device_sm *sm)
int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin) int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin)
{ {
struct upnp_wps_device_interface *iface;
if (sm == NULL) if (sm == NULL)
return 0; return 0;
os_free(sm->ctx->ap_pin); dl_list_for_each(iface, &sm->interfaces,
if (ap_pin) { struct upnp_wps_device_interface, list) {
sm->ctx->ap_pin = os_strdup(ap_pin); os_free(iface->ctx->ap_pin);
if (sm->ctx->ap_pin == NULL) if (ap_pin) {
return -1; iface->ctx->ap_pin = os_strdup(ap_pin);
} else if (iface->ctx->ap_pin == NULL)
sm->ctx->ap_pin = NULL; return -1;
} else
iface->ctx->ap_pin = NULL;
}
return 0; return 0;
} }

View file

@ -35,11 +35,8 @@ struct upnp_wps_device_ctx {
struct upnp_wps_device_sm * struct upnp_wps_device_sm *
upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps, upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
void *priv); void *priv, char *net_if);
void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm); void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm, void *priv);
int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if);
void upnp_wps_device_stop(struct upnp_wps_device_sm *sm);
int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm, int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
const u8 from_mac_addr[ETH_ALEN], const u8 from_mac_addr[ETH_ALEN],

View file

@ -103,16 +103,26 @@ struct subscription {
}; };
struct upnp_wps_device_interface {
struct dl_list list;
struct upnp_wps_device_ctx *ctx; /* callback table */
struct wps_context *wps;
void *priv;
/* FIX: maintain separate structures for each UPnP peer */
struct upnp_wps_peer peer;
};
/* /*
* Our instance data corresponding to one WiFi network interface * Our instance data corresponding to the AP device. Note that there may be
* (multiple might share the same wired network interface!). * multiple wireless interfaces sharing the same UPnP device instance. Each
* such interface is stored in the list of struct upnp_wps_device_interface
* instances.
* *
* This is known as an opaque struct declaration to users of the WPS UPnP code. * This is known as an opaque struct declaration to users of the WPS UPnP code.
*/ */
struct upnp_wps_device_sm { struct upnp_wps_device_sm {
struct upnp_wps_device_ctx *ctx; /* callback table */ struct dl_list interfaces; /* struct upnp_wps_device_interface */
struct wps_context *wps;
void *priv;
char *root_dir; char *root_dir;
char *desc_url; char *desc_url;
int started; /* nonzero if we are active */ int started; /* nonzero if we are active */
@ -136,9 +146,6 @@ struct upnp_wps_device_sm {
enum upnp_wps_wlanevent_type wlanevent_type; enum upnp_wps_wlanevent_type wlanevent_type;
os_time_t last_event_sec; os_time_t last_event_sec;
unsigned int num_events_in_sec; unsigned int num_events_in_sec;
/* FIX: maintain separate structures for each UPnP peer */
struct upnp_wps_peer peer;
}; };
/* wps_upnp.c */ /* wps_upnp.c */

View file

@ -136,9 +136,12 @@ next_advertisement(struct upnp_wps_device_sm *sm,
struct wpabuf *msg; struct wpabuf *msg;
char *NTString = ""; char *NTString = "";
char uuid_string[80]; char uuid_string[80];
struct upnp_wps_device_interface *iface;
*islast = 0; *islast = 0;
uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string)); iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
msg = wpabuf_alloc(800); /* more than big enough */ msg = wpabuf_alloc(800); /* more than big enough */
if (msg == NULL) if (msg == NULL)
goto fail; goto fail;
@ -588,8 +591,13 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
} }
if (str_starts(data, "uuid:")) { if (str_starts(data, "uuid:")) {
char uuid_string[80]; char uuid_string[80];
struct upnp_wps_device_interface *iface;
iface = dl_list_first(
&sm->interfaces,
struct upnp_wps_device_interface,
list);
data += os_strlen("uuid:"); data += os_strlen("uuid:");
uuid_bin2str(sm->wps->uuid, uuid_string, uuid_bin2str(iface->wps->uuid, uuid_string,
sizeof(uuid_string)); sizeof(uuid_string));
if (str_starts(data, uuid_string)) if (str_starts(data, uuid_string))
st_match = 1; st_match = 1;

View file

@ -184,6 +184,10 @@ static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
{ {
const char *s; const char *s;
char uuid_string[80]; char uuid_string[80];
struct upnp_wps_device_interface *iface;
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
wpabuf_put_str(buf, wps_device_xml_prefix); wpabuf_put_str(buf, wps_device_xml_prefix);
@ -191,38 +195,38 @@ static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
* Add required fields with default values if not configured. Add * Add required fields with default values if not configured. Add
* optional and recommended fields only if configured. * optional and recommended fields only if configured.
*/ */
s = sm->wps->friendly_name; s = iface->wps->friendly_name;
s = ((s && *s) ? s : "WPS Access Point"); s = ((s && *s) ? s : "WPS Access Point");
xml_add_tagged_data(buf, "friendlyName", s); xml_add_tagged_data(buf, "friendlyName", s);
s = sm->wps->dev.manufacturer; s = iface->wps->dev.manufacturer;
s = ((s && *s) ? s : ""); s = ((s && *s) ? s : "");
xml_add_tagged_data(buf, "manufacturer", s); xml_add_tagged_data(buf, "manufacturer", s);
if (sm->wps->manufacturer_url) if (iface->wps->manufacturer_url)
xml_add_tagged_data(buf, "manufacturerURL", xml_add_tagged_data(buf, "manufacturerURL",
sm->wps->manufacturer_url); iface->wps->manufacturer_url);
if (sm->wps->model_description) if (iface->wps->model_description)
xml_add_tagged_data(buf, "modelDescription", xml_add_tagged_data(buf, "modelDescription",
sm->wps->model_description); iface->wps->model_description);
s = sm->wps->dev.model_name; s = iface->wps->dev.model_name;
s = ((s && *s) ? s : ""); s = ((s && *s) ? s : "");
xml_add_tagged_data(buf, "modelName", s); xml_add_tagged_data(buf, "modelName", s);
if (sm->wps->dev.model_number) if (iface->wps->dev.model_number)
xml_add_tagged_data(buf, "modelNumber", xml_add_tagged_data(buf, "modelNumber",
sm->wps->dev.model_number); iface->wps->dev.model_number);
if (sm->wps->model_url) if (iface->wps->model_url)
xml_add_tagged_data(buf, "modelURL", sm->wps->model_url); xml_add_tagged_data(buf, "modelURL", iface->wps->model_url);
if (sm->wps->dev.serial_number) if (iface->wps->dev.serial_number)
xml_add_tagged_data(buf, "serialNumber", xml_add_tagged_data(buf, "serialNumber",
sm->wps->dev.serial_number); iface->wps->dev.serial_number);
uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string)); uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
s = uuid_string; s = uuid_string;
/* Need "uuid:" prefix, thus we can't use xml_add_tagged_data() /* Need "uuid:" prefix, thus we can't use xml_add_tagged_data()
* easily... * easily...
@ -231,8 +235,8 @@ static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
xml_data_encode(buf, s, os_strlen(s)); xml_data_encode(buf, s, os_strlen(s));
wpabuf_put_str(buf, "</UDN>\n"); wpabuf_put_str(buf, "</UDN>\n");
if (sm->wps->upc) if (iface->wps->upc)
xml_add_tagged_data(buf, "UPC", sm->wps->upc); xml_add_tagged_data(buf, "UPC", iface->wps->upc);
wpabuf_put_str(buf, wps_device_xml_postfix); wpabuf_put_str(buf, wps_device_xml_postfix);
} }
@ -311,6 +315,10 @@ static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
size_t extra_len = 0; size_t extra_len = 0;
int body_length; int body_length;
char len_buf[10]; char len_buf[10];
struct upnp_wps_device_interface *iface;
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
/* /*
* It is not required that filenames be case insensitive but it is * It is not required that filenames be case insensitive but it is
@ -322,16 +330,16 @@ static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML"); wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
req = GET_DEVICE_XML_FILE; req = GET_DEVICE_XML_FILE;
extra_len = 3000; extra_len = 3000;
if (sm->wps->friendly_name) if (iface->wps->friendly_name)
extra_len += os_strlen(sm->wps->friendly_name); extra_len += os_strlen(iface->wps->friendly_name);
if (sm->wps->manufacturer_url) if (iface->wps->manufacturer_url)
extra_len += os_strlen(sm->wps->manufacturer_url); extra_len += os_strlen(iface->wps->manufacturer_url);
if (sm->wps->model_description) if (iface->wps->model_description)
extra_len += os_strlen(sm->wps->model_description); extra_len += os_strlen(iface->wps->model_description);
if (sm->wps->model_url) if (iface->wps->model_url)
extra_len += os_strlen(sm->wps->model_url); extra_len += os_strlen(iface->wps->model_url);
if (sm->wps->upc) if (iface->wps->upc)
extra_len += os_strlen(sm->wps->upc); extra_len += os_strlen(iface->wps->upc);
} else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) { } else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML"); wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
req = GET_SCPD_XML_FILE; req = GET_SCPD_XML_FILE;
@ -408,11 +416,16 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
{ {
static const char *name = "NewDeviceInfo"; static const char *name = "NewDeviceInfo";
struct wps_config cfg; struct wps_config cfg;
struct upnp_wps_peer *peer = &sm->peer; struct upnp_wps_device_interface *iface;
struct upnp_wps_peer *peer;
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
peer = &iface->peer;
wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo"); wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
if (sm->ctx->ap_pin == NULL) if (iface->ctx->ap_pin == NULL)
return HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR;
/* /*
@ -427,9 +440,9 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
wps_deinit(peer->wps); wps_deinit(peer->wps);
os_memset(&cfg, 0, sizeof(cfg)); os_memset(&cfg, 0, sizeof(cfg));
cfg.wps = sm->wps; cfg.wps = iface->wps;
cfg.pin = (u8 *) sm->ctx->ap_pin; cfg.pin = (u8 *) iface->ctx->ap_pin;
cfg.pin_len = os_strlen(sm->ctx->ap_pin); cfg.pin_len = os_strlen(iface->ctx->ap_pin);
peer->wps = wps_init(&cfg); peer->wps = wps_init(&cfg);
if (peer->wps) { if (peer->wps) {
enum wsc_op_code op_code; enum wsc_op_code op_code;
@ -458,6 +471,10 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
enum http_reply_code ret; enum http_reply_code ret;
enum wps_process_res res; enum wps_process_res res;
enum wsc_op_code op_code; enum wsc_op_code op_code;
struct upnp_wps_device_interface *iface;
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
/* /*
* PutMessage is used by external UPnP-based Registrar to perform WPS * PutMessage is used by external UPnP-based Registrar to perform WPS
@ -468,11 +485,11 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
msg = xml_get_base64_item(data, "NewInMessage", &ret); msg = xml_get_base64_item(data, "NewInMessage", &ret);
if (msg == NULL) if (msg == NULL)
return ret; return ret;
res = wps_process_msg(sm->peer.wps, WSC_UPnP, msg); res = wps_process_msg(iface->peer.wps, WSC_UPnP, msg);
if (res == WPS_FAILURE) if (res == WPS_FAILURE)
*reply = NULL; *reply = NULL;
else else
*reply = wps_get_msg(sm->peer.wps, &op_code); *reply = wps_get_msg(iface->peer.wps, &op_code);
wpabuf_free(msg); wpabuf_free(msg);
if (*reply == NULL) if (*reply == NULL)
return HTTP_INTERNAL_SERVER_ERROR; return HTTP_INTERNAL_SERVER_ERROR;
@ -491,6 +508,8 @@ web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
int ev_type; int ev_type;
int type; int type;
char *val; char *val;
struct upnp_wps_device_interface *iface;
int ok = 0;
/* /*
* External UPnP-based Registrar is passing us a message to be proxied * External UPnP-based Registrar is passing us a message to be proxied
@ -559,9 +578,16 @@ web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type); wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
} else } else
type = -1; type = -1;
if (!sm->ctx->rx_req_put_wlan_response || dl_list_for_each(iface, &sm->interfaces,
sm->ctx->rx_req_put_wlan_response(sm->priv, ev_type, macaddr, msg, struct upnp_wps_device_interface, list) {
type)) { if (iface->ctx->rx_req_put_wlan_response &&
iface->ctx->rx_req_put_wlan_response(iface->priv, ev_type,
macaddr, msg, type)
== 0)
ok = 1;
}
if (!ok) {
wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->" wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
"rx_req_put_wlan_response"); "rx_req_put_wlan_response");
wpabuf_free(msg); wpabuf_free(msg);
@ -606,6 +632,8 @@ web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
struct wpabuf *msg; struct wpabuf *msg;
enum http_reply_code ret; enum http_reply_code ret;
struct subscription *s; struct subscription *s;
struct upnp_wps_device_interface *iface;
int err = 0;
wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar"); wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
s = find_er(sm, cli); s = find_er(sm, cli);
@ -617,11 +645,15 @@ web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
msg = xml_get_base64_item(data, "NewMessage", &ret); msg = xml_get_base64_item(data, "NewMessage", &ret);
if (msg == NULL) if (msg == NULL)
return ret; return ret;
if (upnp_er_set_selected_registrar(sm->wps->registrar, s, msg)) { dl_list_for_each(iface, &sm->interfaces,
wpabuf_free(msg); struct upnp_wps_device_interface, list) {
return HTTP_INTERNAL_SERVER_ERROR; if (upnp_er_set_selected_registrar(iface->wps->registrar, s,
msg))
err = 1;
} }
wpabuf_free(msg); wpabuf_free(msg);
if (err)
return HTTP_INTERNAL_SERVER_ERROR;
*replyname = NULL; *replyname = NULL;
*reply = NULL; *reply = NULL;
return HTTP_OK; return HTTP_OK;