diff options
Diffstat (limited to 'freebsd/contrib/wpa/src/wps/wps_upnp_web.c')
-rw-r--r-- | freebsd/contrib/wpa/src/wps/wps_upnp_web.c | 88 |
1 files changed, 79 insertions, 9 deletions
diff --git a/freebsd/contrib/wpa/src/wps/wps_upnp_web.c b/freebsd/contrib/wpa/src/wps/wps_upnp_web.c index 8c3bbd1b..09f36d37 100644 --- a/freebsd/contrib/wpa/src/wps/wps_upnp_web.c +++ b/freebsd/contrib/wpa/src/wps/wps_upnp_web.c @@ -302,7 +302,8 @@ static void http_put_empty(struct wpabuf *buf, enum http_reply_code code) * would appear to be required (given that we will be closing it!). */ static void web_connection_parse_get(struct upnp_wps_device_sm *sm, - struct http_request *hreq, char *filename) + struct http_request *hreq, + const char *filename) { struct wpabuf *buf; /* output buffer, allocated */ char *put_length_here; @@ -411,6 +412,15 @@ send_buf: } +static void wps_upnp_peer_del(struct upnp_wps_peer *peer) +{ + dl_list_del(&peer->list); + if (peer->wps) + wps_deinit(peer->wps); + os_free(peer); +} + + static enum http_reply_code web_process_get_device_info(struct upnp_wps_device_sm *sm, struct wpabuf **reply, const char **replyname) @@ -428,7 +438,9 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm, if (!iface || iface->ctx->ap_pin == NULL) return HTTP_INTERNAL_SERVER_ERROR; - peer = &iface->peer; + peer = os_zalloc(sizeof(*peer)); + if (!peer) + return HTTP_INTERNAL_SERVER_ERROR; /* * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS @@ -438,9 +450,6 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm, * registration. */ - if (peer->wps) - wps_deinit(peer->wps); - os_memset(&cfg, 0, sizeof(cfg)); cfg.wps = iface->wps; cfg.pin = (u8 *) iface->ctx->ap_pin; @@ -457,8 +466,22 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm, *reply = NULL; if (*reply == NULL) { wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo"); + os_free(peer); return HTTP_INTERNAL_SERVER_ERROR; } + + if (dl_list_len(&iface->peers) > 3) { + struct upnp_wps_peer *old; + + old = dl_list_first(&iface->peers, struct upnp_wps_peer, list); + if (old) { + wpa_printf(MSG_DEBUG, "WPS UPnP: Drop oldest active session"); + wps_upnp_peer_del(old); + } + } + dl_list_add_tail(&iface->peers, &peer->list); + /* TODO: Could schedule a timeout to free the entry */ + *replyname = name; return HTTP_OK; } @@ -474,6 +497,8 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data, enum wps_process_res res; enum wsc_op_code op_code; struct upnp_wps_device_interface *iface; + struct wps_parse_attr attr; + struct upnp_wps_peer *tmp, *peer; iface = dl_list_first(&sm->interfaces, struct upnp_wps_device_interface, list); @@ -489,11 +514,56 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data, msg = xml_get_base64_item(data, "NewInMessage", &ret); if (msg == NULL) return ret; - res = wps_process_msg(iface->peer.wps, WSC_UPnP, msg); - if (res == WPS_FAILURE) + + if (wps_parse_msg(msg, &attr)) { + wpa_printf(MSG_DEBUG, + "WPS UPnP: Could not parse PutMessage - NewInMessage"); + wpabuf_free(msg); + return HTTP_BAD_REQUEST; + } + + /* Find a matching active peer session */ + peer = NULL; + dl_list_for_each(tmp, &iface->peers, struct upnp_wps_peer, list) { + if (!tmp->wps) + continue; + if (attr.enrollee_nonce && + os_memcmp(tmp->wps->nonce_e, attr.enrollee_nonce, + WPS_NONCE_LEN) != 0) + continue; /* Enrollee nonce mismatch */ + if (attr.msg_type && + *attr.msg_type != WPS_M2 && + *attr.msg_type != WPS_M2D && + attr.registrar_nonce && + os_memcmp(tmp->wps->nonce_r, attr.registrar_nonce, + WPS_NONCE_LEN) != 0) + continue; /* Registrar nonce mismatch */ + peer = tmp; + break; + } + if (!peer) { + /* + Try to use the first entry in case message could work with + * it. The actual handler function will reject this, if needed. + * This maintains older behavior where only a single peer entry + * was supported. + */ + peer = dl_list_first(&iface->peers, struct upnp_wps_peer, list); + } + if (!peer || !peer->wps) { + wpa_printf(MSG_DEBUG, "WPS UPnP: No active peer entry found"); + wpabuf_free(msg); + return HTTP_BAD_REQUEST; + } + + res = wps_process_msg(peer->wps, WSC_UPnP, msg); + if (res == WPS_FAILURE) { *reply = NULL; - else - *reply = wps_get_msg(iface->peer.wps, &op_code); + wpa_printf(MSG_DEBUG, "WPS UPnP: Drop active peer session"); + wps_upnp_peer_del(peer); + } else { + *reply = wps_get_msg(peer->wps, &op_code); + } wpabuf_free(msg); if (*reply == NULL) return HTTP_INTERNAL_SERVER_ERROR; |