LCOV - code coverage report
Current view: top level - src/wps - wps_er.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 835 1114 75.0 %
Date: 2014-05-28 Functions: 66 72 91.7 %

          Line data    Source code
       1             : /*
       2             :  * Wi-Fi Protected Setup - External Registrar
       3             :  * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "base64.h"
      13             : #include "uuid.h"
      14             : #include "eloop.h"
      15             : #include "httpread.h"
      16             : #include "http_client.h"
      17             : #include "http_server.h"
      18             : #include "upnp_xml.h"
      19             : #include "wps_i.h"
      20             : #include "wps_upnp.h"
      21             : #include "wps_upnp_i.h"
      22             : #include "wps_er.h"
      23             : 
      24             : 
      25             : static void wps_er_deinit_finish(void *eloop_data, void *user_ctx);
      26             : static void wps_er_ap_timeout(void *eloop_data, void *user_ctx);
      27             : static void wps_er_sta_timeout(void *eloop_data, void *user_ctx);
      28             : static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg);
      29             : static int wps_er_send_get_device_info(struct wps_er_ap *ap,
      30             :                                        void (*m1_handler)(struct wps_er_ap *ap,
      31             :                                                           struct wpabuf *m1));
      32             : 
      33             : 
      34          44 : static void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta,
      35             :                              enum wps_event event)
      36             : {
      37             :         union wps_event_data data;
      38          44 :         struct wps_event_er_enrollee *ev = &data.enrollee;
      39             : 
      40          44 :         if (wps->event_cb == NULL)
      41          44 :                 return;
      42             : 
      43          44 :         os_memset(&data, 0, sizeof(data));
      44          44 :         ev->uuid = sta->uuid;
      45          44 :         ev->mac_addr = sta->addr;
      46          44 :         ev->m1_received = sta->m1_received;
      47          44 :         ev->config_methods = sta->config_methods;
      48          44 :         ev->dev_passwd_id = sta->dev_passwd_id;
      49          44 :         ev->pri_dev_type = sta->pri_dev_type;
      50          44 :         ev->dev_name = sta->dev_name;
      51          44 :         ev->manufacturer = sta->manufacturer;
      52          44 :         ev->model_name = sta->model_name;
      53          44 :         ev->model_number = sta->model_number;
      54          44 :         ev->serial_number = sta->serial_number;
      55          44 :         wps->event_cb(wps->cb_ctx, event, &data);
      56             : }
      57             : 
      58             : 
      59          56 : static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr,
      60             :                                           const u8 *uuid)
      61             : {
      62             :         struct wps_er_sta *sta;
      63          66 :         dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) {
      64          96 :                 if ((addr == NULL ||
      65          86 :                      os_memcmp(sta->addr, addr, ETH_ALEN) == 0) &&
      66           0 :                     (uuid == NULL ||
      67           0 :                      os_memcmp(uuid, sta->uuid, WPS_UUID_LEN) == 0))
      68          38 :                         return sta;
      69             :         }
      70          18 :         return NULL;
      71             : }
      72             : 
      73             : 
      74          18 : static void wps_er_sta_free(struct wps_er_sta *sta)
      75             : {
      76          18 :         wps_er_sta_event(sta->ap->er->wps, sta, WPS_EV_ER_ENROLLEE_REMOVE);
      77          18 :         if (sta->wps)
      78           1 :                 wps_deinit(sta->wps);
      79          18 :         os_free(sta->manufacturer);
      80          18 :         os_free(sta->model_name);
      81          18 :         os_free(sta->model_number);
      82          18 :         os_free(sta->serial_number);
      83          18 :         os_free(sta->dev_name);
      84          18 :         http_client_free(sta->http);
      85          18 :         eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
      86          18 :         os_free(sta->cred);
      87          18 :         os_free(sta);
      88          18 : }
      89             : 
      90             : 
      91           9 : static void wps_er_sta_remove_all(struct wps_er_ap *ap)
      92             : {
      93             :         struct wps_er_sta *prev, *sta;
      94          27 :         dl_list_for_each_safe(sta, prev, &ap->sta, struct wps_er_sta, list)
      95          18 :                 wps_er_sta_free(sta);
      96           9 : }
      97             : 
      98             : 
      99          50 : static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
     100             :                                         struct in_addr *addr, const u8 *uuid,
     101             :                                         const u8 *mac_addr)
     102             : {
     103             :         struct wps_er_ap *ap;
     104          50 :         dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
     105          41 :                 if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
     106          35 :                     (uuid == NULL ||
     107          76 :                      os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0) &&
     108           6 :                     (mac_addr == NULL ||
     109           6 :                      os_memcmp(mac_addr, ap->mac_addr, ETH_ALEN) == 0))
     110          41 :                         return ap;
     111             :         }
     112           9 :         return NULL;
     113             : }
     114             : 
     115             : 
     116          54 : static struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id)
     117             : {
     118             :         struct wps_er_ap *ap;
     119          54 :         dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
     120          54 :                 if (ap->id == id)
     121          54 :                         return ap;
     122             :         }
     123           0 :         return NULL;
     124             : }
     125             : 
     126             : 
     127          18 : static void wps_er_ap_event(struct wps_context *wps, struct wps_er_ap *ap,
     128             :                             enum wps_event event)
     129             : {
     130             :         union wps_event_data data;
     131          18 :         struct wps_event_er_ap *evap = &data.ap;
     132             : 
     133          18 :         if (wps->event_cb == NULL)
     134          18 :                 return;
     135             : 
     136          18 :         os_memset(&data, 0, sizeof(data));
     137          18 :         evap->uuid = ap->uuid;
     138          18 :         evap->friendly_name = ap->friendly_name;
     139          18 :         evap->manufacturer = ap->manufacturer;
     140          18 :         evap->manufacturer_url = ap->manufacturer_url;
     141          18 :         evap->model_description = ap->model_description;
     142          18 :         evap->model_name = ap->model_name;
     143          18 :         evap->model_number = ap->model_number;
     144          18 :         evap->model_url = ap->model_url;
     145          18 :         evap->serial_number = ap->serial_number;
     146          18 :         evap->upc = ap->upc;
     147          18 :         evap->pri_dev_type = ap->pri_dev_type;
     148          18 :         evap->wps_state = ap->wps_state;
     149          18 :         evap->mac_addr = ap->mac_addr;
     150          18 :         wps->event_cb(wps->cb_ctx, event, &data);
     151             : }
     152             : 
     153             : 
     154           9 : static void wps_er_ap_free(struct wps_er_ap *ap)
     155             : {
     156           9 :         http_client_free(ap->http);
     157           9 :         ap->http = NULL;
     158             : 
     159           9 :         os_free(ap->location);
     160           9 :         os_free(ap->friendly_name);
     161           9 :         os_free(ap->manufacturer);
     162           9 :         os_free(ap->manufacturer_url);
     163           9 :         os_free(ap->model_description);
     164           9 :         os_free(ap->model_name);
     165           9 :         os_free(ap->model_number);
     166           9 :         os_free(ap->model_url);
     167           9 :         os_free(ap->serial_number);
     168           9 :         os_free(ap->udn);
     169           9 :         os_free(ap->upc);
     170             : 
     171           9 :         os_free(ap->scpd_url);
     172           9 :         os_free(ap->control_url);
     173           9 :         os_free(ap->event_sub_url);
     174             : 
     175           9 :         os_free(ap->ap_settings);
     176             : 
     177           9 :         os_free(ap);
     178           9 : }
     179             : 
     180             : 
     181           9 : static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap)
     182             : {
     183           9 :         wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)",
     184             :                    inet_ntoa(ap->addr), ap->location);
     185           9 :         dl_list_del(&ap->list);
     186           9 :         wps_er_ap_free(ap);
     187             : 
     188           9 :         if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing))
     189           9 :                 wps_er_deinit_finish(er, NULL);
     190           9 : }
     191             : 
     192             : 
     193           9 : static void wps_er_http_unsubscribe_cb(void *ctx, struct http_client *c,
     194             :                                        enum http_client_event event)
     195             : {
     196           9 :         struct wps_er_ap *ap = ctx;
     197             : 
     198           9 :         switch (event) {
     199             :         case HTTP_CLIENT_OK:
     200           9 :                 wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from events");
     201           9 :                 ap->subscribed = 0;
     202           9 :                 break;
     203             :         case HTTP_CLIENT_FAILED:
     204             :         case HTTP_CLIENT_INVALID_REPLY:
     205             :         case HTTP_CLIENT_TIMEOUT:
     206           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to unsubscribe from "
     207             :                            "events");
     208           0 :                 break;
     209             :         }
     210           9 :         http_client_free(ap->http);
     211           9 :         ap->http = NULL;
     212             : 
     213             :         /*
     214             :          * Need to get rid of the AP entry regardless of whether we managed to
     215             :          * unsubscribe cleanly or not.
     216             :          */
     217           9 :         wps_er_ap_unsubscribed(ap->er, ap);
     218           9 : }
     219             : 
     220             : 
     221           9 : static void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap)
     222             : {
     223             :         struct wpabuf *req;
     224             :         struct sockaddr_in dst;
     225             :         char *url, *path;
     226             :         char sid[100];
     227             : 
     228           9 :         if (ap->event_sub_url == NULL) {
     229           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
     230             :                            "subscribe");
     231           0 :                 goto fail;
     232             :         }
     233           9 :         if (ap->http) {
     234           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
     235             :                            "send subscribe request");
     236           0 :                 goto fail;
     237             :         }
     238             : 
     239           9 :         url = http_client_url_parse(ap->event_sub_url, &dst, &path);
     240           9 :         if (url == NULL) {
     241           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
     242           0 :                 goto fail;
     243             :         }
     244             : 
     245           9 :         req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
     246           9 :         if (req == NULL) {
     247           0 :                 os_free(url);
     248           0 :                 goto fail;
     249             :         }
     250           9 :         uuid_bin2str(ap->sid, sid, sizeof(sid));
     251           9 :         wpabuf_printf(req,
     252             :                       "UNSUBSCRIBE %s HTTP/1.1\r\n"
     253             :                       "HOST: %s:%d\r\n"
     254             :                       "SID: uuid:%s\r\n"
     255             :                       "\r\n",
     256           9 :                       path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid);
     257           9 :         os_free(url);
     258           9 :         wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request",
     259             :                           wpabuf_head(req), wpabuf_len(req));
     260             : 
     261           9 :         ap->http = http_client_addr(&dst, req, 1000,
     262             :                                     wps_er_http_unsubscribe_cb, ap);
     263           9 :         if (ap->http == NULL) {
     264           0 :                 wpabuf_free(req);
     265           0 :                 goto fail;
     266             :         }
     267          18 :         return;
     268             : 
     269             : fail:
     270             :         /*
     271             :          * Need to get rid of the AP entry even when we fail to unsubscribe
     272             :          * cleanly.
     273             :          */
     274           0 :         wps_er_ap_unsubscribed(ap->er, ap);
     275             : }
     276             : 
     277             : 
     278           9 : static struct wps_er_ap_settings * wps_er_ap_get_settings(struct wps_er *er,
     279             :                                                           const u8 *uuid)
     280             : {
     281             :         struct wps_er_ap_settings *s;
     282           9 :         dl_list_for_each(s, &er->ap_settings, struct wps_er_ap_settings, list)
     283           0 :                 if (os_memcmp(uuid, s->uuid, WPS_UUID_LEN) == 0)
     284           0 :                         return s;
     285           9 :         return NULL;
     286             : }
     287             : 
     288             : 
     289           0 : int wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr)
     290             : {
     291             :         struct wps_er_ap *ap;
     292             :         struct wps_er_ap_settings *settings;
     293             : 
     294           0 :         ap = wps_er_ap_get(er, addr, NULL, NULL);
     295           0 :         if (ap == NULL || ap->ap_settings == NULL)
     296           0 :                 return -1;
     297             : 
     298           0 :         settings = wps_er_ap_get_settings(er, ap->uuid);
     299           0 :         if (!settings) {
     300           0 :                 settings = os_zalloc(sizeof(*settings));
     301           0 :                 if (settings == NULL)
     302           0 :                         return -1;
     303           0 :                 os_memcpy(settings->uuid, ap->uuid, WPS_UUID_LEN);
     304           0 :                 dl_list_add(&er->ap_settings, &settings->list);
     305             :         }
     306           0 :         os_memcpy(&settings->ap_settings, ap->ap_settings,
     307             :                   sizeof(struct wps_credential));
     308             : 
     309           0 :         return 0;
     310             : }
     311             : 
     312             : 
     313           9 : static int wps_er_ap_use_cached_settings(struct wps_er *er,
     314             :                                          struct wps_er_ap *ap)
     315             : {
     316             :         struct wps_er_ap_settings *s;
     317             : 
     318           9 :         if (ap->ap_settings)
     319           0 :                 return 0;
     320             : 
     321           9 :         s = wps_er_ap_get_settings(ap->er, ap->uuid);
     322           9 :         if (!s)
     323           9 :                 return -1;
     324             : 
     325           0 :         ap->ap_settings = os_malloc(sizeof(*ap->ap_settings));
     326           0 :         if (ap->ap_settings == NULL)
     327           0 :                 return -1;
     328             : 
     329           0 :         os_memcpy(ap->ap_settings, &s->ap_settings, sizeof(*ap->ap_settings));
     330           0 :         wpa_printf(MSG_DEBUG, "WPS ER: Use cached AP settings");
     331           0 :         return 0;
     332             : }
     333             : 
     334             : 
     335           9 : static void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap)
     336             : {
     337           9 :         wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
     338             :                    inet_ntoa(ap->addr), ap->location);
     339           9 :         eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
     340           9 :         wps_er_sta_remove_all(ap);
     341           9 :         wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE);
     342           9 :         http_client_free(ap->http);
     343           9 :         ap->http = NULL;
     344           9 :         if (ap->wps) {
     345           0 :                 wps_deinit(ap->wps);
     346           0 :                 ap->wps = NULL;
     347             :         }
     348             : 
     349           9 :         dl_list_del(&ap->list);
     350           9 :         if (ap->subscribed) {
     351           9 :                 dl_list_add(&er->ap_unsubscribing, &ap->list);
     352           9 :                 wps_er_ap_unsubscribe(er, ap);
     353             :         } else
     354           0 :                 wps_er_ap_free(ap);
     355           9 : }
     356             : 
     357             : 
     358           0 : static void wps_er_ap_timeout(void *eloop_data, void *user_ctx)
     359             : {
     360           0 :         struct wps_er *er = eloop_data;
     361           0 :         struct wps_er_ap *ap = user_ctx;
     362           0 :         wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out");
     363           0 :         wps_er_ap_remove_entry(er, ap);
     364           0 : }
     365             : 
     366             : 
     367           9 : static int wps_er_get_sid(struct wps_er_ap *ap, char *sid)
     368             : {
     369             :         char *pos;
     370             :         char txt[100];
     371             : 
     372           9 :         if (!sid) {
     373           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: No SID received from %s (%s)",
     374             :                            inet_ntoa(ap->addr), ap->location);
     375           0 :                 return -1;
     376             :         }
     377             : 
     378           9 :         pos = os_strstr(sid, "uuid:");
     379           9 :         if (!pos) {
     380           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
     381             :                            "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
     382             :                            sid);
     383           0 :                 return -1;
     384             :         }
     385             : 
     386           9 :         pos += 5;
     387           9 :         if (uuid_str2bin(pos, ap->sid) < 0) {
     388           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
     389             :                            "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
     390             :                            sid);
     391           0 :                 return -1;
     392             :         }
     393             : 
     394           9 :         uuid_bin2str(ap->sid, txt, sizeof(txt));
     395           9 :         wpa_printf(MSG_DEBUG, "WPS ER: SID for subscription with %s (%s): %s",
     396             :                    inet_ntoa(ap->addr), ap->location, txt);
     397             : 
     398           9 :         return 0;
     399             : }
     400             : 
     401             : 
     402           9 : static void wps_er_http_subscribe_cb(void *ctx, struct http_client *c,
     403             :                                      enum http_client_event event)
     404             : {
     405           9 :         struct wps_er_ap *ap = ctx;
     406             : 
     407           9 :         switch (event) {
     408             :         case HTTP_CLIENT_OK:
     409           9 :                 wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events");
     410           9 :                 ap->subscribed = 1;
     411           9 :                 wps_er_get_sid(ap, http_client_get_hdr_line(c, "SID"));
     412           9 :                 wps_er_ap_use_cached_settings(ap->er, ap);
     413           9 :                 wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD);
     414           9 :                 break;
     415             :         case HTTP_CLIENT_FAILED:
     416             :         case HTTP_CLIENT_INVALID_REPLY:
     417             :         case HTTP_CLIENT_TIMEOUT:
     418           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events");
     419           0 :                 break;
     420             :         }
     421           9 :         http_client_free(ap->http);
     422           9 :         ap->http = NULL;
     423           9 : }
     424             : 
     425             : 
     426           9 : static void wps_er_subscribe(struct wps_er_ap *ap)
     427             : {
     428             :         struct wpabuf *req;
     429             :         struct sockaddr_in dst;
     430             :         char *url, *path;
     431             : 
     432           9 :         if (ap->event_sub_url == NULL) {
     433           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
     434             :                            "subscribe");
     435           0 :                 return;
     436             :         }
     437           9 :         if (ap->http) {
     438           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
     439             :                            "send subscribe request");
     440           0 :                 return;
     441             :         }
     442             : 
     443           9 :         url = http_client_url_parse(ap->event_sub_url, &dst, &path);
     444           9 :         if (url == NULL) {
     445           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
     446           0 :                 return;
     447             :         }
     448             : 
     449           9 :         req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
     450           9 :         if (req == NULL) {
     451           0 :                 os_free(url);
     452           0 :                 return;
     453             :         }
     454          45 :         wpabuf_printf(req,
     455             :                       "SUBSCRIBE %s HTTP/1.1\r\n"
     456             :                       "HOST: %s:%d\r\n"
     457             :                       "CALLBACK: <http://%s:%d/event/%u/%u>\r\n"
     458             :                       "NT: upnp:event\r\n"
     459             :                       "TIMEOUT: Second-%d\r\n"
     460             :                       "\r\n",
     461           9 :                       path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port),
     462          18 :                       ap->er->ip_addr_text, ap->er->http_port,
     463           9 :                       ap->er->event_id, ap->id, 1800);
     464           9 :         os_free(url);
     465           9 :         wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request",
     466             :                           wpabuf_head(req), wpabuf_len(req));
     467             : 
     468           9 :         ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb,
     469             :                                     ap);
     470           9 :         if (ap->http == NULL)
     471           0 :                 wpabuf_free(req);
     472             : }
     473             : 
     474             : 
     475           9 : static void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1)
     476             : {
     477             :         struct wps_parse_attr attr;
     478             : 
     479           9 :         if (wps_parse_msg(m1, &attr) < 0) {
     480           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1");
     481           9 :                 return;
     482             :         }
     483           9 :         if (attr.primary_dev_type)
     484           9 :                 os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8);
     485           9 :         if (attr.wps_state)
     486           9 :                 ap->wps_state = *attr.wps_state;
     487           9 :         if (attr.mac_addr)
     488           9 :                 os_memcpy(ap->mac_addr, attr.mac_addr, ETH_ALEN);
     489             : 
     490           9 :         wps_er_subscribe(ap);
     491             : }
     492             : 
     493             : 
     494           9 : static void wps_er_get_device_info(struct wps_er_ap *ap)
     495             : {
     496           9 :         wps_er_send_get_device_info(ap, wps_er_ap_get_m1);
     497           9 : }
     498             : 
     499             : 
     500           9 : static const char * wps_er_find_wfadevice(const char *data)
     501             : {
     502             :         const char *tag, *tagname, *end;
     503             :         char *val;
     504           9 :         int found = 0;
     505             : 
     506          27 :         while (!found) {
     507             :                 /* Find next <device> */
     508             :                 for (;;) {
     509          81 :                         if (xml_next_tag(data, &tag, &tagname, &end))
     510           0 :                                 return NULL;
     511          81 :                         data = end;
     512          90 :                         if (!os_strncasecmp(tagname, "device", 6) &&
     513          18 :                             *tag != '/' &&
     514           9 :                             (tagname[6] == '>' || !isgraph(tagname[6]))) {
     515             :                                 break;
     516             :                         }
     517          72 :                 }
     518             : 
     519             :                 /* Check whether deviceType is WFADevice */
     520           9 :                 val = xml_get_first_item(data, "deviceType");
     521           9 :                 if (val == NULL)
     522           0 :                         return NULL;
     523           9 :                 wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val);
     524          18 :                 found = os_strcasecmp(val, "urn:schemas-wifialliance-org:"
     525           9 :                                       "device:WFADevice:1") == 0;
     526           9 :                 os_free(val);
     527             :         }
     528             : 
     529           9 :         return data;
     530             : }
     531             : 
     532             : 
     533           9 : static void wps_er_parse_device_description(struct wps_er_ap *ap,
     534             :                                             struct wpabuf *reply)
     535             : {
     536             :         /* Note: reply includes null termination after the buffer data */
     537           9 :         const char *tmp, *data = wpabuf_head(reply);
     538             :         char *pos;
     539             : 
     540           9 :         wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
     541             :                           wpabuf_head(reply), wpabuf_len(reply));
     542             : 
     543             :         /*
     544             :          * The root device description may include multiple devices, so first
     545             :          * find the beginning of the WFADevice description to allow the
     546             :          * simplistic parser to pick the correct entries.
     547             :          */
     548           9 :         tmp = wps_er_find_wfadevice(data);
     549           9 :         if (tmp == NULL) {
     550           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - "
     551             :                            "trying to parse invalid data");
     552             :         } else
     553           9 :                 data = tmp;
     554             : 
     555           9 :         ap->friendly_name = xml_get_first_item(data, "friendlyName");
     556           9 :         wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
     557             : 
     558           9 :         ap->manufacturer = xml_get_first_item(data, "manufacturer");
     559           9 :         wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer);
     560             : 
     561           9 :         ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL");
     562           9 :         wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'",
     563             :                    ap->manufacturer_url);
     564             : 
     565           9 :         ap->model_description = xml_get_first_item(data, "modelDescription");
     566           9 :         wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'",
     567             :                    ap->model_description);
     568             : 
     569           9 :         ap->model_name = xml_get_first_item(data, "modelName");
     570           9 :         wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name);
     571             : 
     572           9 :         ap->model_number = xml_get_first_item(data, "modelNumber");
     573           9 :         wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number);
     574             : 
     575           9 :         ap->model_url = xml_get_first_item(data, "modelURL");
     576           9 :         wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url);
     577             : 
     578           9 :         ap->serial_number = xml_get_first_item(data, "serialNumber");
     579           9 :         wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
     580             : 
     581           9 :         ap->udn = xml_get_first_item(data, "UDN");
     582           9 :         wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
     583           9 :         pos = os_strstr(ap->udn, "uuid:");
     584           9 :         if (pos) {
     585           9 :                 pos += 5;
     586           9 :                 if (uuid_str2bin(pos, ap->uuid) < 0)
     587           0 :                         wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN");
     588             :         }
     589             : 
     590           9 :         ap->upc = xml_get_first_item(data, "UPC");
     591           9 :         wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc);
     592             : 
     593           9 :         ap->scpd_url = http_link_update(
     594           9 :                 xml_get_first_item(data, "SCPDURL"), ap->location);
     595           9 :         wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url);
     596             : 
     597           9 :         ap->control_url = http_link_update(
     598           9 :                 xml_get_first_item(data, "controlURL"), ap->location);
     599           9 :         wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url);
     600             : 
     601           9 :         ap->event_sub_url = http_link_update(
     602           9 :                 xml_get_first_item(data, "eventSubURL"), ap->location);
     603           9 :         wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url);
     604           9 : }
     605             : 
     606             : 
     607           9 : static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
     608             :                                     enum http_client_event event)
     609             : {
     610           9 :         struct wps_er_ap *ap = ctx;
     611             :         struct wpabuf *reply;
     612           9 :         int ok = 0;
     613             : 
     614           9 :         switch (event) {
     615             :         case HTTP_CLIENT_OK:
     616           9 :                 reply = http_client_get_body(c);
     617           9 :                 if (reply == NULL)
     618           0 :                         break;
     619           9 :                 wps_er_parse_device_description(ap, reply);
     620           9 :                 ok = 1;
     621           9 :                 break;
     622             :         case HTTP_CLIENT_FAILED:
     623             :         case HTTP_CLIENT_INVALID_REPLY:
     624             :         case HTTP_CLIENT_TIMEOUT:
     625           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info");
     626           0 :                 break;
     627             :         }
     628           9 :         http_client_free(ap->http);
     629           9 :         ap->http = NULL;
     630           9 :         if (ok)
     631           9 :                 wps_er_get_device_info(ap);
     632           9 : }
     633             : 
     634             : 
     635          36 : void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
     636             :                    const char *location, int max_age)
     637             : {
     638             :         struct wps_er_ap *ap;
     639             : 
     640          36 :         ap = wps_er_ap_get(er, addr, uuid, NULL);
     641          36 :         if (ap) {
     642             :                 /* Update advertisement timeout */
     643          27 :                 eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
     644          27 :                 eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
     645          27 :                 return;
     646             :         }
     647             : 
     648           9 :         ap = os_zalloc(sizeof(*ap));
     649           9 :         if (ap == NULL)
     650           0 :                 return;
     651           9 :         dl_list_init(&ap->sta);
     652           9 :         ap->er = er;
     653           9 :         ap->id = ++er->next_ap_id;
     654           9 :         ap->location = os_strdup(location);
     655           9 :         if (ap->location == NULL) {
     656           0 :                 os_free(ap);
     657           0 :                 return;
     658             :         }
     659           9 :         dl_list_add(&er->ap, &ap->list);
     660             : 
     661           9 :         ap->addr.s_addr = addr->s_addr;
     662           9 :         os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
     663           9 :         eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
     664             : 
     665           9 :         wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)",
     666             :                    inet_ntoa(ap->addr), ap->location);
     667             : 
     668             :         /* Fetch device description */
     669           9 :         ap->http = http_client_url(ap->location, NULL, 10000,
     670             :                                    wps_er_http_dev_desc_cb, ap);
     671             : }
     672             : 
     673             : 
     674           0 : void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
     675             : {
     676             :         struct wps_er_ap *ap;
     677           0 :         dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
     678           0 :                 if (ap->addr.s_addr == addr->s_addr) {
     679           0 :                         wps_er_ap_remove_entry(er, ap);
     680           0 :                         return;
     681             :                 }
     682             :         }
     683             : }
     684             : 
     685             : 
     686           9 : static void wps_er_ap_remove_all(struct wps_er *er)
     687             : {
     688             :         struct wps_er_ap *prev, *ap;
     689             :         struct wps_er_ap_settings *prev_s, *s;
     690          18 :         dl_list_for_each_safe(ap, prev, &er->ap, struct wps_er_ap, list)
     691           9 :                 wps_er_ap_remove_entry(er, ap);
     692           9 :         dl_list_for_each_safe(s, prev_s, &er->ap_settings,
     693             :                               struct wps_er_ap_settings, list)
     694           0 :                 os_free(s);
     695           9 : }
     696             : 
     697             : 
     698          54 : static void http_put_date(struct wpabuf *buf)
     699             : {
     700          54 :         wpabuf_put_str(buf, "Date: ");
     701          54 :         format_date(buf);
     702          54 :         wpabuf_put_str(buf, "\r\n");
     703          54 : }
     704             : 
     705             : 
     706           0 : static void wps_er_http_resp_not_found(struct http_request *req)
     707             : {
     708             :         struct wpabuf *buf;
     709           0 :         buf = wpabuf_alloc(200);
     710           0 :         if (buf == NULL) {
     711           0 :                 http_request_deinit(req);
     712           0 :                 return;
     713             :         }
     714             : 
     715           0 :         wpabuf_put_str(buf,
     716             :                        "HTTP/1.1 404 Not Found\r\n"
     717             :                        "Server: unspecified, UPnP/1.0, unspecified\r\n"
     718             :                        "Connection: close\r\n");
     719           0 :         http_put_date(buf);
     720           0 :         wpabuf_put_str(buf, "\r\n");
     721           0 :         http_request_send_and_deinit(req, buf);
     722             : }
     723             : 
     724             : 
     725          54 : static void wps_er_http_resp_ok(struct http_request *req)
     726             : {
     727             :         struct wpabuf *buf;
     728          54 :         buf = wpabuf_alloc(200);
     729          54 :         if (buf == NULL) {
     730           0 :                 http_request_deinit(req);
     731          54 :                 return;
     732             :         }
     733             : 
     734          54 :         wpabuf_put_str(buf,
     735             :                        "HTTP/1.1 200 OK\r\n"
     736             :                        "Server: unspecified, UPnP/1.0, unspecified\r\n"
     737             :                        "Connection: close\r\n"
     738             :                        "Content-Length: 0\r\n");
     739          54 :         http_put_date(buf);
     740          54 :         wpabuf_put_str(buf, "\r\n");
     741          54 :         http_request_send_and_deinit(req, buf);
     742             : }
     743             : 
     744             : 
     745           0 : static void wps_er_sta_timeout(void *eloop_data, void *user_ctx)
     746             : {
     747           0 :         struct wps_er_sta *sta = eloop_data;
     748           0 :         wpa_printf(MSG_DEBUG, "WPS ER: STA entry timed out");
     749           0 :         dl_list_del(&sta->list);
     750           0 :         wps_er_sta_free(sta);
     751           0 : }
     752             : 
     753             : 
     754          54 : static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
     755             :                                                const u8 *addr,
     756             :                                                struct wps_parse_attr *attr,
     757             :                                                int probe_req)
     758             : {
     759          54 :         struct wps_er_sta *sta = wps_er_sta_get(ap, addr, NULL);
     760          54 :         int new_sta = 0;
     761             :         int m1;
     762             : 
     763          54 :         m1 = !probe_req && attr->msg_type && *attr->msg_type == WPS_M1;
     764             : 
     765          54 :         if (sta == NULL) {
     766             :                 /*
     767             :                  * Only allow new STA entry to be added based on Probe Request
     768             :                  * or M1. This will filter out bogus events and anything that
     769             :                  * may have been ongoing at the time ER subscribed for events.
     770             :                  */
     771          18 :                 if (!probe_req && !m1)
     772           0 :                         return NULL;
     773             : 
     774          18 :                 sta = os_zalloc(sizeof(*sta));
     775          18 :                 if (sta == NULL)
     776           0 :                         return NULL;
     777          18 :                 os_memcpy(sta->addr, addr, ETH_ALEN);
     778          18 :                 sta->ap = ap;
     779          18 :                 dl_list_add(&ap->sta, &sta->list);
     780          18 :                 new_sta = 1;
     781             :         }
     782             : 
     783          54 :         if (m1)
     784           8 :                 sta->m1_received = 1;
     785             : 
     786          54 :         if (attr->config_methods && (!probe_req || !sta->m1_received))
     787          32 :                 sta->config_methods = WPA_GET_BE16(attr->config_methods);
     788          54 :         if (attr->uuid_e && (!probe_req || !sta->m1_received))
     789          32 :                 os_memcpy(sta->uuid, attr->uuid_e, WPS_UUID_LEN);
     790          54 :         if (attr->primary_dev_type && (!probe_req || !sta->m1_received))
     791          32 :                 os_memcpy(sta->pri_dev_type, attr->primary_dev_type, 8);
     792          54 :         if (attr->dev_password_id && (!probe_req || !sta->m1_received))
     793          32 :                 sta->dev_passwd_id = WPA_GET_BE16(attr->dev_password_id);
     794             : 
     795          54 :         if (attr->manufacturer) {
     796          32 :                 os_free(sta->manufacturer);
     797          32 :                 sta->manufacturer = dup_binstr(attr->manufacturer,
     798             :                                                attr->manufacturer_len);
     799             :         }
     800             : 
     801          54 :         if (attr->model_name) {
     802          32 :                 os_free(sta->model_name);
     803          32 :                 sta->model_name = dup_binstr(attr->model_name,
     804             :                                              attr->model_name_len);
     805             :         }
     806             : 
     807          54 :         if (attr->model_number) {
     808          32 :                 os_free(sta->model_number);
     809          32 :                 sta->model_number = dup_binstr(attr->model_number,
     810             :                                                attr->model_number_len);
     811             :         }
     812             : 
     813          54 :         if (attr->serial_number) {
     814           8 :                 os_free(sta->serial_number);
     815           8 :                 sta->serial_number = dup_binstr(attr->serial_number,
     816             :                                                 attr->serial_number_len);
     817             :         }
     818             : 
     819          54 :         if (attr->dev_name) {
     820          32 :                 os_free(sta->dev_name);
     821          32 :                 sta->dev_name = dup_binstr(attr->dev_name, attr->dev_name_len);
     822             :         }
     823             : 
     824          54 :         eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
     825          54 :         eloop_register_timeout(300, 0, wps_er_sta_timeout, sta, NULL);
     826             : 
     827          54 :         if (m1 || new_sta)
     828          26 :                 wps_er_sta_event(ap->er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
     829             : 
     830          54 :         return sta;
     831             : }
     832             : 
     833             : 
     834          24 : static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
     835             :                                                const u8 *addr,
     836             :                                                struct wpabuf *msg)
     837             : {
     838             :         struct wps_parse_attr attr;
     839             : 
     840         144 :         wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from "
     841         144 :                    MACSTR, MAC2STR(addr));
     842          24 :         wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
     843             :                         "(TLVs from Probe Request)", msg);
     844             : 
     845          24 :         if (wps_validate_probe_req(msg, addr) < 0) {
     846           0 :                 wpa_printf(MSG_INFO, "WPS-STRICT: ER: Ignore invalid proxied "
     847           0 :                            "Probe Request frame from " MACSTR, MAC2STR(addr));
     848           0 :                 return;
     849             :         }
     850             : 
     851          24 :         if (wps_parse_msg(msg, &attr) < 0) {
     852           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
     853             :                            "WLANEvent message");
     854           0 :                 return;
     855             :         }
     856             : 
     857          24 :         wps_er_add_sta_data(ap, addr, &attr, 1);
     858          24 :         wps_registrar_probe_req_rx(ap->er->wps->registrar, addr, msg, 0);
     859             : }
     860             : 
     861             : 
     862          23 : static void wps_er_http_put_wlan_response_cb(void *ctx, struct http_client *c,
     863             :                                              enum http_client_event event)
     864             : {
     865          23 :         struct wps_er_sta *sta = ctx;
     866             : 
     867          23 :         switch (event) {
     868             :         case HTTP_CLIENT_OK:
     869          23 :                 wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse OK");
     870          23 :                 break;
     871             :         case HTTP_CLIENT_FAILED:
     872             :         case HTTP_CLIENT_INVALID_REPLY:
     873             :         case HTTP_CLIENT_TIMEOUT:
     874           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse failed");
     875           0 :                 break;
     876             :         }
     877          23 :         http_client_free(sta->http);
     878          23 :         sta->http = NULL;
     879          23 : }
     880             : 
     881             : 
     882             : static const char *soap_prefix =
     883             :         "<?xml version=\"1.0\"?>\n"
     884             :         "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
     885             :         "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
     886             :         "<s:Body>\n";
     887             : static const char *soap_postfix =
     888             :         "</s:Body>\n</s:Envelope>\n";
     889             : static const char *urn_wfawlanconfig =
     890             :         "urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
     891             : 
     892          61 : static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg,
     893             :                                        const char *name, const char *arg_name,
     894             :                                        const char *path,
     895             :                                        const struct sockaddr_in *dst,
     896             :                                        char **len_ptr, char **body_ptr)
     897             : {
     898             :         unsigned char *encoded;
     899             :         size_t encoded_len;
     900             :         struct wpabuf *buf;
     901             : 
     902          61 :         if (msg) {
     903          50 :                 encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg),
     904             :                                         &encoded_len);
     905          50 :                 if (encoded == NULL)
     906           0 :                         return NULL;
     907             :         } else {
     908          11 :                 encoded = NULL;
     909          11 :                 encoded_len = 0;
     910             :         }
     911             : 
     912          61 :         buf = wpabuf_alloc(1000 + encoded_len);
     913          61 :         if (buf == NULL) {
     914           0 :                 os_free(encoded);
     915           0 :                 return NULL;
     916             :         }
     917             : 
     918          61 :         wpabuf_printf(buf,
     919             :                       "POST %s HTTP/1.1\r\n"
     920             :                       "Host: %s:%d\r\n"
     921             :                       "Content-Type: text/xml; charset=\"utf-8\"\r\n"
     922             :                       "Content-Length: ",
     923          61 :                       path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port));
     924             : 
     925          61 :         *len_ptr = wpabuf_put(buf, 0);
     926          61 :         wpabuf_printf(buf,
     927             :                       "        \r\n"
     928             :                       "SOAPACTION: \"%s#%s\"\r\n"
     929             :                       "\r\n",
     930             :                       urn_wfawlanconfig, name);
     931             : 
     932          61 :         *body_ptr = wpabuf_put(buf, 0);
     933             : 
     934          61 :         wpabuf_put_str(buf, soap_prefix);
     935          61 :         wpabuf_printf(buf, "<u:%s xmlns:u=\"", name);
     936          61 :         wpabuf_put_str(buf, urn_wfawlanconfig);
     937          61 :         wpabuf_put_str(buf, "\">\n");
     938          61 :         if (encoded) {
     939          50 :                 wpabuf_printf(buf, "<%s>%s</%s>\n",
     940             :                               arg_name, (char *) encoded, arg_name);
     941          50 :                 os_free(encoded);
     942             :         }
     943             : 
     944          61 :         return buf;
     945             : }
     946             : 
     947             : 
     948          61 : static void wps_er_soap_end(struct wpabuf *buf, const char *name,
     949             :                             char *len_ptr, char *body_ptr)
     950             : {
     951             :         char len_buf[10];
     952          61 :         wpabuf_printf(buf, "</u:%s>\n", name);
     953          61 :         wpabuf_put_str(buf, soap_postfix);
     954          61 :         os_snprintf(len_buf, sizeof(len_buf), "%d",
     955          61 :                     (int) ((char *) wpabuf_put(buf, 0) - body_ptr));
     956          61 :         os_memcpy(len_ptr, len_buf, os_strlen(len_buf));
     957          61 : }
     958             : 
     959             : 
     960          23 : static void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg)
     961             : {
     962             :         struct wpabuf *buf;
     963             :         char *len_ptr, *body_ptr;
     964             :         struct sockaddr_in dst;
     965             :         char *url, *path;
     966             : 
     967          23 :         if (sta->http) {
     968           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - "
     969             :                            "ignore new request");
     970           0 :                 wpabuf_free(msg);
     971           0 :                 return;
     972             :         }
     973             : 
     974          23 :         if (sta->ap->control_url == NULL) {
     975           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
     976           0 :                 wpabuf_free(msg);
     977           0 :                 return;
     978             :         }
     979             : 
     980          23 :         url = http_client_url_parse(sta->ap->control_url, &dst, &path);
     981          23 :         if (url == NULL) {
     982           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
     983           0 :                 wpabuf_free(msg);
     984           0 :                 return;
     985             :         }
     986             : 
     987          23 :         buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst,
     988             :                               &len_ptr, &body_ptr);
     989          23 :         wpabuf_free(msg);
     990          23 :         os_free(url);
     991          23 :         if (buf == NULL)
     992           0 :                 return;
     993          23 :         wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n",
     994             :                       UPNP_WPS_WLANEVENT_TYPE_EAP);
     995         138 :         wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n",
     996         138 :                       MAC2STR(sta->addr));
     997             : 
     998          23 :         wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr);
     999             : 
    1000          23 :         sta->http = http_client_addr(&dst, buf, 1000,
    1001             :                                      wps_er_http_put_wlan_response_cb, sta);
    1002          23 :         if (sta->http == NULL)
    1003           0 :                 wpabuf_free(buf);
    1004             : }
    1005             : 
    1006             : 
    1007          30 : static void wps_er_sta_process(struct wps_er_sta *sta, struct wpabuf *msg,
    1008             :                                enum wsc_op_code op_code)
    1009             : {
    1010             :         enum wps_process_res res;
    1011             : 
    1012          30 :         res = wps_process_msg(sta->wps, op_code, msg);
    1013          30 :         if (res == WPS_CONTINUE) {
    1014          23 :                 struct wpabuf *next = wps_get_msg(sta->wps, &op_code);
    1015          23 :                 if (next)
    1016          23 :                         wps_er_sta_send_msg(sta, next);
    1017             :         } else {
    1018           7 :                 wpa_printf(MSG_DEBUG, "WPS ER: Protocol run %s with the "
    1019             :                            "enrollee (res=%d)",
    1020             :                            res == WPS_DONE ? "succeeded" : "failed", res);
    1021           7 :                 wps_deinit(sta->wps);
    1022           7 :                 sta->wps = NULL;
    1023           7 :                 if (res == WPS_DONE) {
    1024             :                         /* Remove the STA entry after short timeout */
    1025           6 :                         eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
    1026           6 :                         eloop_register_timeout(10, 0, wps_er_sta_timeout, sta,
    1027             :                                                NULL);
    1028             :                 }
    1029             :         }
    1030          30 : }
    1031             : 
    1032             : 
    1033           8 : static void wps_er_sta_start(struct wps_er_sta *sta, struct wpabuf *msg)
    1034             : {
    1035             :         struct wps_config cfg;
    1036             : 
    1037           8 :         if (sta->wps)
    1038           0 :                 wps_deinit(sta->wps);
    1039             : 
    1040           8 :         os_memset(&cfg, 0, sizeof(cfg));
    1041           8 :         cfg.wps = sta->ap->er->wps;
    1042           8 :         cfg.registrar = 1;
    1043           8 :         cfg.peer_addr = sta->addr;
    1044             : 
    1045           8 :         sta->wps = wps_init(&cfg);
    1046           8 :         if (sta->wps == NULL)
    1047           8 :                 return;
    1048           8 :         sta->wps->er = 1;
    1049           8 :         sta->wps->use_cred = sta->ap->ap_settings;
    1050           8 :         if (sta->ap->ap_settings) {
    1051           8 :                 os_free(sta->cred);
    1052           8 :                 sta->cred = os_malloc(sizeof(*sta->cred));
    1053           8 :                 if (sta->cred) {
    1054           8 :                         os_memcpy(sta->cred, sta->ap->ap_settings,
    1055             :                                   sizeof(*sta->cred));
    1056           8 :                         sta->cred->cred_attr = NULL;
    1057           8 :                         os_memcpy(sta->cred->mac_addr, sta->addr, ETH_ALEN);
    1058           8 :                         sta->wps->use_cred = sta->cred;
    1059             :                 }
    1060             :         }
    1061             : 
    1062           8 :         wps_er_sta_process(sta, msg, WSC_MSG);
    1063             : }
    1064             : 
    1065             : 
    1066          30 : static void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr,
    1067             :                                          struct wpabuf *msg)
    1068             : {
    1069             :         struct wps_parse_attr attr;
    1070             :         struct wps_er_sta *sta;
    1071             : 
    1072         180 :         wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR,
    1073         180 :                    MAC2STR(addr));
    1074          30 :         wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
    1075             :                         "(TLVs from EAP-WSC)", msg);
    1076             : 
    1077          30 :         if (wps_parse_msg(msg, &attr) < 0) {
    1078           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
    1079             :                            "WLANEvent message");
    1080           0 :                 return;
    1081             :         }
    1082             : 
    1083          30 :         sta = wps_er_add_sta_data(ap, addr, &attr, 0);
    1084          30 :         if (sta == NULL)
    1085           0 :                 return;
    1086             : 
    1087          30 :         if (attr.msg_type && *attr.msg_type == WPS_M1)
    1088           8 :                 wps_er_sta_start(sta, msg);
    1089          22 :         else if (sta->wps) {
    1090          22 :                 enum wsc_op_code op_code = WSC_MSG;
    1091          22 :                 if (attr.msg_type) {
    1092          22 :                         switch (*attr.msg_type) {
    1093             :                         case WPS_WSC_ACK:
    1094           0 :                                 op_code = WSC_ACK;
    1095           0 :                                 break;
    1096             :                         case WPS_WSC_NACK:
    1097           1 :                                 op_code = WSC_NACK;
    1098           1 :                                 break;
    1099             :                         case WPS_WSC_DONE:
    1100           6 :                                 op_code = WSC_Done;
    1101           6 :                                 break;
    1102             :                         }
    1103             :                 }
    1104          22 :                 wps_er_sta_process(sta, msg, op_code);
    1105             :         }
    1106             : }
    1107             : 
    1108             : 
    1109          54 : static void wps_er_process_wlanevent(struct wps_er_ap *ap,
    1110             :                                      struct wpabuf *event)
    1111             : {
    1112             :         u8 *data;
    1113             :         u8 wlan_event_type;
    1114             :         u8 wlan_event_mac[ETH_ALEN];
    1115             :         struct wpabuf msg;
    1116             : 
    1117          54 :         wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
    1118             :                     wpabuf_head(event), wpabuf_len(event));
    1119          54 :         if (wpabuf_len(event) < 1 + 17) {
    1120           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
    1121           0 :                 return;
    1122             :         }
    1123             : 
    1124          54 :         data = wpabuf_mhead(event);
    1125          54 :         wlan_event_type = data[0];
    1126          54 :         if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
    1127           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
    1128             :                            "WLANEvent");
    1129           0 :                 return;
    1130             :         }
    1131             : 
    1132          54 :         wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));
    1133             : 
    1134          54 :         switch (wlan_event_type) {
    1135             :         case 1:
    1136          24 :                 wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
    1137          24 :                 break;
    1138             :         case 2:
    1139          30 :                 wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
    1140          30 :                 break;
    1141             :         default:
    1142           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
    1143             :                            wlan_event_type);
    1144           0 :                 break;
    1145             :         }
    1146             : }
    1147             : 
    1148             : 
    1149          54 : static void wps_er_http_event(struct wps_er *er, struct http_request *req,
    1150             :                               unsigned int ap_id)
    1151             : {
    1152          54 :         struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id);
    1153             :         struct wpabuf *event;
    1154             :         enum http_reply_code ret;
    1155             : 
    1156          54 :         if (ap == NULL) {
    1157           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id "
    1158             :                            "%u", ap_id);
    1159           0 :                 wps_er_http_resp_not_found(req);
    1160           0 :                 return;
    1161             :         }
    1162          54 :         wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s",
    1163             :                    ap_id, http_request_get_data(req));
    1164             : 
    1165          54 :         event = xml_get_base64_item(http_request_get_data(req), "WLANEvent",
    1166             :                                     &ret);
    1167          54 :         if (event == NULL) {
    1168           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent "
    1169             :                            "from the event notification");
    1170             :                 /*
    1171             :                  * Reply with OK anyway to avoid getting unregistered from
    1172             :                  * events.
    1173             :                  */
    1174           0 :                 wps_er_http_resp_ok(req);
    1175           0 :                 return;
    1176             :         }
    1177             : 
    1178          54 :         wps_er_process_wlanevent(ap, event);
    1179             : 
    1180          54 :         wpabuf_free(event);
    1181          54 :         wps_er_http_resp_ok(req);
    1182             : }
    1183             : 
    1184             : 
    1185          54 : static void wps_er_http_notify(struct wps_er *er, struct http_request *req)
    1186             : {
    1187          54 :         char *uri = http_request_get_uri(req);
    1188             : 
    1189          54 :         if (os_strncmp(uri, "/event/", 7) == 0) {
    1190             :                 unsigned int event_id;
    1191             :                 char *pos;
    1192          54 :                 event_id = atoi(uri + 7);
    1193          54 :                 if (event_id != er->event_id) {
    1194           0 :                         wpa_printf(MSG_DEBUG, "WPS ER: HTTP event for an "
    1195             :                                    "unknown event id %u", event_id);
    1196           0 :                         return;
    1197             :                 }
    1198          54 :                 pos = os_strchr(uri + 7, '/');
    1199          54 :                 if (pos == NULL)
    1200           0 :                         return;
    1201          54 :                 pos++;
    1202          54 :                 wps_er_http_event(er, req, atoi(pos));
    1203             :         } else {
    1204           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'",
    1205             :                            uri);
    1206           0 :                 wps_er_http_resp_not_found(req);
    1207             :         }
    1208             : }
    1209             : 
    1210             : 
    1211          54 : static void wps_er_http_req(void *ctx, struct http_request *req)
    1212             : {
    1213          54 :         struct wps_er *er = ctx;
    1214          54 :         struct sockaddr_in *cli = http_request_get_cli_addr(req);
    1215          54 :         enum httpread_hdr_type type = http_request_get_type(req);
    1216             :         struct wpabuf *buf;
    1217             : 
    1218          54 :         wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from "
    1219             :                    "%s:%d",
    1220             :                    http_request_get_uri(req), type,
    1221          54 :                    inet_ntoa(cli->sin_addr), ntohs(cli->sin_port));
    1222             : 
    1223          54 :         switch (type) {
    1224             :         case HTTPREAD_HDR_TYPE_NOTIFY:
    1225          54 :                 wps_er_http_notify(er, req);
    1226          54 :                 break;
    1227             :         default:
    1228           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type "
    1229             :                            "%d", type);
    1230           0 :                 buf = wpabuf_alloc(200);
    1231           0 :                 if (buf == NULL) {
    1232           0 :                         http_request_deinit(req);
    1233          54 :                         return;
    1234             :                 }
    1235           0 :                 wpabuf_put_str(buf,
    1236             :                                "HTTP/1.1 501 Unimplemented\r\n"
    1237             :                                "Connection: close\r\n");
    1238           0 :                 http_put_date(buf);
    1239           0 :                 wpabuf_put_str(buf, "\r\n");
    1240           0 :                 http_request_send_and_deinit(req, buf);
    1241           0 :                 break;
    1242             :         }
    1243             : }
    1244             : 
    1245             : 
    1246             : struct wps_er *
    1247           9 : wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
    1248             : {
    1249             :         struct wps_er *er;
    1250             :         struct in_addr addr;
    1251             : 
    1252           9 :         er = os_zalloc(sizeof(*er));
    1253           9 :         if (er == NULL)
    1254           0 :                 return NULL;
    1255           9 :         dl_list_init(&er->ap);
    1256           9 :         dl_list_init(&er->ap_unsubscribing);
    1257           9 :         dl_list_init(&er->ap_settings);
    1258             : 
    1259           9 :         er->multicast_sd = -1;
    1260           9 :         er->ssdp_sd = -1;
    1261             : 
    1262           9 :         os_strlcpy(er->ifname, ifname, sizeof(er->ifname));
    1263           9 :         er->wps = wps;
    1264           9 :         if (os_get_random((unsigned char *) &er->event_id,
    1265             :                           sizeof(er->event_id)) < 0) {
    1266           0 :                 wps_er_deinit(er, NULL, NULL);
    1267           0 :                 return NULL;
    1268             :         }
    1269             :         /* Limit event_id to < 32 bits to avoid issues with atoi() */
    1270           9 :         er->event_id &= 0x0fffffff;
    1271             : 
    1272           9 :         if (filter && os_strncmp(filter, "ifname=", 7) == 0) {
    1273             :                 const char *pos, *end;
    1274           9 :                 pos = filter + 7;
    1275           9 :                 end = os_strchr(pos, ' ');
    1276           9 :                 if (end) {
    1277           0 :                         size_t len = end - pos;
    1278           0 :                         os_strlcpy(er->ifname, pos, len < sizeof(er->ifname) ?
    1279             :                                    len + 1 : sizeof(er->ifname));
    1280           0 :                         filter = end + 1;
    1281             :                 } else {
    1282           9 :                         os_strlcpy(er->ifname, pos, sizeof(er->ifname));
    1283           9 :                         filter = NULL;
    1284             :                 }
    1285           9 :                 er->forced_ifname = 1;
    1286             :         }
    1287             : 
    1288           9 :         if (filter) {
    1289           0 :                 if (inet_aton(filter, &er->filter_addr) == 0) {
    1290           0 :                         wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
    1291             :                                    "address %s", filter);
    1292           0 :                         wps_er_deinit(er, NULL, NULL);
    1293           0 :                         return NULL;
    1294             :                 }
    1295           0 :                 wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
    1296             :                            "with %s", filter);
    1297             :         }
    1298           9 :         if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
    1299           9 :                            er->mac_addr)) {
    1300           0 :                 wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
    1301           0 :                            "for %s. Does it have IP address?", er->ifname);
    1302           0 :                 wps_er_deinit(er, NULL, NULL);
    1303           0 :                 return NULL;
    1304             :         }
    1305             : 
    1306           9 :         if (wps_er_ssdp_init(er) < 0) {
    1307           0 :                 wpa_printf(MSG_INFO, "WPS UPnP: SSDP initialization failed");
    1308           0 :                 wps_er_deinit(er, NULL, NULL);
    1309           0 :                 return NULL;
    1310             :         }
    1311             : 
    1312           9 :         addr.s_addr = er->ip_addr;
    1313           9 :         er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er);
    1314           9 :         if (er->http_srv == NULL) {
    1315           0 :                 wpa_printf(MSG_INFO, "WPS UPnP: HTTP initialization failed");
    1316           0 :                 wps_er_deinit(er, NULL, NULL);
    1317           0 :                 return NULL;
    1318             :         }
    1319           9 :         er->http_port = http_server_get_port(er->http_srv);
    1320             : 
    1321          18 :         wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s)",
    1322           9 :                    er->ifname, er->ip_addr_text);
    1323             : 
    1324           9 :         return er;
    1325             : }
    1326             : 
    1327             : 
    1328           0 : void wps_er_refresh(struct wps_er *er)
    1329             : {
    1330             :         struct wps_er_ap *ap;
    1331             :         struct wps_er_sta *sta;
    1332             : 
    1333           0 :         dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
    1334           0 :                 wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_ADD);
    1335           0 :                 dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list)
    1336           0 :                         wps_er_sta_event(er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
    1337             :         }
    1338             : 
    1339           0 :         wps_er_send_ssdp_msearch(er);
    1340           0 : }
    1341             : 
    1342             : 
    1343           9 : static void wps_er_deinit_finish(void *eloop_data, void *user_ctx)
    1344             : {
    1345           9 :         struct wps_er *er = eloop_data;
    1346             :         void (*deinit_done_cb)(void *ctx);
    1347             :         void *deinit_done_ctx;
    1348             :         struct wps_er_ap *ap, *tmp;
    1349             : 
    1350           9 :         wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit");
    1351             : 
    1352           9 :         dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap,
    1353             :                               list) {
    1354           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it",
    1355             :                            inet_ntoa(ap->addr), ap->location);
    1356           0 :                 dl_list_del(&ap->list);
    1357           0 :                 wps_er_ap_free(ap);
    1358             :         }
    1359             : 
    1360           9 :         eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
    1361           9 :         deinit_done_cb = er->deinit_done_cb;
    1362           9 :         deinit_done_ctx = er->deinit_done_ctx;
    1363           9 :         os_free(er->ip_addr_text);
    1364           9 :         os_free(er);
    1365             : 
    1366           9 :         if (deinit_done_cb)
    1367           0 :                 deinit_done_cb(deinit_done_ctx);
    1368           9 : }
    1369             : 
    1370             : 
    1371        1968 : void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx)
    1372             : {
    1373        1968 :         if (er == NULL)
    1374        3927 :                 return;
    1375           9 :         http_server_deinit(er->http_srv);
    1376           9 :         wps_er_ap_remove_all(er);
    1377           9 :         wps_er_ssdp_deinit(er);
    1378           9 :         eloop_register_timeout(dl_list_empty(&er->ap_unsubscribing) ? 0 : 5, 0,
    1379             :                                wps_er_deinit_finish, er, NULL);
    1380           9 :         wpa_printf(MSG_DEBUG, "WPS ER: Finish deinit from timeout");
    1381           9 :         er->deinitializing = 1;
    1382           9 :         er->deinit_done_cb = cb;
    1383           9 :         er->deinit_done_ctx = ctx;
    1384             : }
    1385             : 
    1386             : 
    1387          18 : static void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c,
    1388             :                                        enum http_client_event event)
    1389             : {
    1390          18 :         struct wps_er_ap *ap = ctx;
    1391             :         union wps_event_data data;
    1392             : 
    1393          18 :         os_memset(&data, 0, sizeof(data));
    1394             : 
    1395          18 :         switch (event) {
    1396             :         case HTTP_CLIENT_OK:
    1397          18 :                 wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK");
    1398          18 :                 data.set_sel_reg.state = WPS_ER_SET_SEL_REG_DONE;
    1399          18 :                 data.set_sel_reg.uuid = ap->uuid;
    1400          18 :                 break;
    1401             :         case HTTP_CLIENT_FAILED:
    1402             :         case HTTP_CLIENT_INVALID_REPLY:
    1403             :         case HTTP_CLIENT_TIMEOUT:
    1404           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed");
    1405           0 :                 data.set_sel_reg.state = WPS_ER_SET_SEL_REG_FAILED;
    1406           0 :                 data.set_sel_reg.uuid = ap->uuid;
    1407           0 :                 break;
    1408             :         }
    1409          18 :         http_client_free(ap->http);
    1410          18 :         ap->http = NULL;
    1411             : 
    1412          18 :         if (data.set_sel_reg.uuid)
    1413          18 :                 ap->er->wps->event_cb(ap->er->wps->cb_ctx,
    1414             :                                       WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
    1415          18 : }
    1416             : 
    1417             : 
    1418          26 : static void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg)
    1419             : {
    1420             :         struct wpabuf *buf;
    1421             :         char *len_ptr, *body_ptr;
    1422             :         struct sockaddr_in dst;
    1423             :         char *url, *path;
    1424             : 
    1425          26 :         if (ap->control_url == NULL) {
    1426           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
    1427           0 :                 return;
    1428             :         }
    1429             : 
    1430          26 :         if (ap->http) {
    1431           3 :                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for AP - "
    1432             :                            "ignore new request");
    1433           3 :                 return;
    1434             :         }
    1435             : 
    1436          23 :         if (ap->wps) {
    1437           4 :                 wpa_printf(MSG_DEBUG, "WPS ER: Pending WPS operation for AP - "
    1438             :                            "skip SetSelectedRegistrar");
    1439           4 :                 return;
    1440             :         }
    1441             : 
    1442          19 :         url = http_client_url_parse(ap->control_url, &dst, &path);
    1443          19 :         if (url == NULL) {
    1444           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
    1445           0 :                 return;
    1446             :         }
    1447             : 
    1448          19 :         buf = wps_er_soap_hdr(msg, "SetSelectedRegistrar", "NewMessage", path,
    1449             :                               &dst, &len_ptr, &body_ptr);
    1450          19 :         os_free(url);
    1451          19 :         if (buf == NULL)
    1452           0 :                 return;
    1453             : 
    1454          19 :         wps_er_soap_end(buf, "SetSelectedRegistrar", len_ptr, body_ptr);
    1455             : 
    1456          19 :         ap->http = http_client_addr(&dst, buf, 1000,
    1457             :                                     wps_er_http_set_sel_reg_cb, ap);
    1458          19 :         if (ap->http == NULL)
    1459           0 :                 wpabuf_free(buf);
    1460             : }
    1461             : 
    1462             : 
    1463          26 : static int wps_er_build_selected_registrar(struct wpabuf *msg, int sel_reg)
    1464             : {
    1465          26 :         wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
    1466          26 :         wpabuf_put_be16(msg, 1);
    1467          26 :         wpabuf_put_u8(msg, !!sel_reg);
    1468          26 :         return 0;
    1469             : }
    1470             : 
    1471             : 
    1472          26 : static int wps_er_build_dev_password_id(struct wpabuf *msg, u16 dev_passwd_id)
    1473             : {
    1474          26 :         wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
    1475          26 :         wpabuf_put_be16(msg, 2);
    1476          26 :         wpabuf_put_be16(msg, dev_passwd_id);
    1477          26 :         return 0;
    1478             : }
    1479             : 
    1480             : 
    1481          26 : static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
    1482             :                                                u16 sel_reg_config_methods)
    1483             : {
    1484          26 :         wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
    1485          26 :         wpabuf_put_be16(msg, 2);
    1486          26 :         wpabuf_put_be16(msg, sel_reg_config_methods);
    1487          26 :         return 0;
    1488             : }
    1489             : 
    1490             : 
    1491          26 : static int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r)
    1492             : {
    1493          26 :         wpabuf_put_be16(msg, ATTR_UUID_R);
    1494          26 :         wpabuf_put_be16(msg, WPS_UUID_LEN);
    1495          26 :         wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN);
    1496          26 :         return 0;
    1497             : }
    1498             : 
    1499             : 
    1500          28 : void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
    1501             :                         u16 sel_reg_config_methods)
    1502             : {
    1503             :         struct wpabuf *msg;
    1504             :         struct wps_er_ap *ap;
    1505          28 :         struct wps_registrar *reg = er->wps->registrar;
    1506             :         const u8 *auth_macs;
    1507             :         u8 bcast[ETH_ALEN];
    1508             :         size_t count;
    1509             :         union wps_event_data data;
    1510             : 
    1511          28 :         if (er->skip_set_sel_reg) {
    1512           2 :                 wpa_printf(MSG_DEBUG, "WPS ER: Skip SetSelectedRegistrar");
    1513           2 :                 return;
    1514             :         }
    1515             : 
    1516          26 :         msg = wpabuf_alloc(500);
    1517          26 :         if (msg == NULL)
    1518           0 :                 return;
    1519             : 
    1520          26 :         auth_macs = wps_authorized_macs(reg, &count);
    1521          26 :         if (count == 0) {
    1522          15 :                 os_memset(bcast, 0xff, ETH_ALEN);
    1523          15 :                 auth_macs = bcast;
    1524          15 :                 count = 1;
    1525             :         }
    1526             : 
    1527          52 :         if (wps_build_version(msg) ||
    1528          52 :             wps_er_build_selected_registrar(msg, sel_reg) ||
    1529          52 :             wps_er_build_dev_password_id(msg, dev_passwd_id) ||
    1530          52 :             wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
    1531          52 :             wps_build_wfa_ext(msg, 0, auth_macs, count) ||
    1532          26 :             wps_er_build_uuid_r(msg, er->wps->uuid)) {
    1533           0 :                 wpabuf_free(msg);
    1534           0 :                 return;
    1535             :         }
    1536             : 
    1537          26 :         os_memset(&data, 0, sizeof(data));
    1538          26 :         data.set_sel_reg.sel_reg = sel_reg;
    1539          26 :         data.set_sel_reg.dev_passwd_id = dev_passwd_id;
    1540          26 :         data.set_sel_reg.sel_reg_config_methods = sel_reg_config_methods;
    1541          26 :         data.set_sel_reg.state = WPS_ER_SET_SEL_REG_START;
    1542             : 
    1543          52 :         dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
    1544          27 :                 if (er->set_sel_reg_uuid_filter &&
    1545           1 :                     os_memcmp(ap->uuid, er->set_sel_reg_uuid_filter,
    1546             :                               WPS_UUID_LEN) != 0)
    1547           0 :                         continue;
    1548          26 :                 data.set_sel_reg.uuid = ap->uuid;
    1549          26 :                 er->wps->event_cb(er->wps->cb_ctx,
    1550             :                                   WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
    1551          26 :                 wps_er_send_set_sel_reg(ap, msg);
    1552             :         }
    1553             : 
    1554          26 :         wpabuf_free(msg);
    1555             : }
    1556             : 
    1557             : 
    1558           1 : int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr)
    1559             : {
    1560             :         int res;
    1561             :         struct wps_er_ap *ap;
    1562             : 
    1563           1 :         if (er == NULL || er->wps == NULL)
    1564           0 :                 return -1;
    1565             : 
    1566           1 :         if (wps_registrar_pbc_overlap(er->wps->registrar, NULL, NULL)) {
    1567           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: PBC overlap - do not start PBC "
    1568             :                            "mode");
    1569           0 :                 return -2;
    1570             :         }
    1571             : 
    1572           1 :         if (uuid)
    1573           0 :                 ap = wps_er_ap_get(er, NULL, uuid, NULL);
    1574             :         else
    1575           1 :                 ap = NULL;
    1576           1 :         if (ap == NULL) {
    1577           1 :                 struct wps_er_sta *sta = NULL;
    1578           1 :                 dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
    1579           1 :                         sta = wps_er_sta_get(ap, addr, uuid);
    1580           1 :                         if (sta) {
    1581           1 :                                 uuid = ap->uuid;
    1582           1 :                                 break;
    1583             :                         }
    1584             :                 }
    1585           1 :                 if (sta == NULL)
    1586           0 :                         return -3; /* Unknown UUID */
    1587             :         }
    1588             : 
    1589           1 :         if (ap->ap_settings == NULL) {
    1590           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: AP settings not known");
    1591           0 :                 return -4;
    1592             :         }
    1593             : 
    1594           1 :         er->set_sel_reg_uuid_filter = uuid;
    1595           1 :         res = wps_registrar_button_pushed(er->wps->registrar, NULL);
    1596           1 :         er->set_sel_reg_uuid_filter = NULL;
    1597           1 :         if (res)
    1598           0 :                 return -1;
    1599             : 
    1600           1 :         return 0;
    1601             : }
    1602             : 
    1603             : 
    1604           1 : static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
    1605             : {
    1606           1 :         struct wps_er_ap *ap = ctx;
    1607             :         union wps_event_data data;
    1608             : 
    1609           1 :         wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received");
    1610           1 :         os_free(ap->ap_settings);
    1611           1 :         ap->ap_settings = os_malloc(sizeof(*cred));
    1612           1 :         if (ap->ap_settings) {
    1613           1 :                 os_memcpy(ap->ap_settings, cred, sizeof(*cred));
    1614           1 :                 ap->ap_settings->cred_attr = NULL;
    1615             :         }
    1616             : 
    1617           1 :         os_memset(&data, 0, sizeof(data));
    1618           1 :         data.ap_settings.uuid = ap->uuid;
    1619           1 :         data.ap_settings.cred = cred;
    1620           1 :         ap->er->wps->event_cb(ap->er->wps->cb_ctx, WPS_EV_ER_AP_SETTINGS,
    1621             :                               &data);
    1622           1 : }
    1623             : 
    1624             : 
    1625           1 : const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr)
    1626             : {
    1627             :         struct wps_er_ap *ap;
    1628           1 :         dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
    1629             :                 struct wps_er_sta *sta;
    1630           1 :                 sta = wps_er_sta_get(ap, addr, NULL);
    1631           1 :                 if (sta)
    1632           1 :                         return sta->uuid;
    1633             :         }
    1634           0 :         return NULL;
    1635             : }
    1636             : 
    1637             : 
    1638           8 : static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
    1639             :                                        enum http_client_event event)
    1640             : {
    1641           8 :         struct wps_er_ap *ap = ctx;
    1642             :         struct wpabuf *reply;
    1643           8 :         char *msg = NULL;
    1644             : 
    1645           8 :         switch (event) {
    1646             :         case HTTP_CLIENT_OK:
    1647           7 :                 wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK");
    1648           7 :                 reply = http_client_get_body(c);
    1649           7 :                 if (reply == NULL)
    1650           0 :                         break;
    1651           7 :                 msg = os_zalloc(wpabuf_len(reply) + 1);
    1652           7 :                 if (msg == NULL)
    1653           0 :                         break;
    1654           7 :                 os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply));
    1655           7 :                 break;
    1656             :         case HTTP_CLIENT_FAILED:
    1657             :         case HTTP_CLIENT_INVALID_REPLY:
    1658             :         case HTTP_CLIENT_TIMEOUT:
    1659           1 :                 wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed");
    1660           1 :                 if (ap->wps) {
    1661           1 :                         wps_deinit(ap->wps);
    1662           1 :                         ap->wps = NULL;
    1663             :                 }
    1664           1 :                 break;
    1665             :         }
    1666           8 :         http_client_free(ap->http);
    1667           8 :         ap->http = NULL;
    1668             : 
    1669           8 :         if (msg) {
    1670             :                 struct wpabuf *buf;
    1671             :                 enum http_reply_code ret;
    1672           7 :                 buf = xml_get_base64_item(msg, "NewOutMessage", &ret);
    1673           7 :                 os_free(msg);
    1674           7 :                 if (buf == NULL) {
    1675           0 :                         wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
    1676             :                                    "NewOutMessage from PutMessage response");
    1677           0 :                         wps_deinit(ap->wps);
    1678           0 :                         ap->wps = NULL;
    1679           8 :                         return;
    1680             :                 }
    1681           7 :                 wps_er_ap_process(ap, buf);
    1682           7 :                 wpabuf_free(buf);
    1683             :         }
    1684             : }
    1685             : 
    1686             : 
    1687           8 : static void wps_er_ap_put_message(struct wps_er_ap *ap,
    1688             :                                   const struct wpabuf *msg)
    1689             : {
    1690             :         struct wpabuf *buf;
    1691             :         char *len_ptr, *body_ptr;
    1692             :         struct sockaddr_in dst;
    1693             :         char *url, *path;
    1694             : 
    1695           8 :         if (ap->http) {
    1696           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
    1697             :                            "with the AP - cannot continue learn");
    1698           0 :                 return;
    1699             :         }
    1700             : 
    1701           8 :         if (ap->control_url == NULL) {
    1702           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
    1703           0 :                 return;
    1704             :         }
    1705             : 
    1706           8 :         url = http_client_url_parse(ap->control_url, &dst, &path);
    1707           8 :         if (url == NULL) {
    1708           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
    1709           0 :                 return;
    1710             :         }
    1711             : 
    1712           8 :         buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst,
    1713             :                               &len_ptr, &body_ptr);
    1714           8 :         os_free(url);
    1715           8 :         if (buf == NULL)
    1716           0 :                 return;
    1717             : 
    1718           8 :         wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr);
    1719             : 
    1720           8 :         ap->http = http_client_addr(&dst, buf, 10000,
    1721             :                                     wps_er_http_put_message_cb, ap);
    1722           8 :         if (ap->http == NULL)
    1723           0 :                 wpabuf_free(buf);
    1724             : }
    1725             : 
    1726             : 
    1727           9 : static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
    1728             : {
    1729             :         enum wps_process_res res;
    1730             :         struct wps_parse_attr attr;
    1731             :         enum wsc_op_code op_code;
    1732             : 
    1733           9 :         op_code = WSC_MSG;
    1734           9 :         if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
    1735           9 :                 switch (*attr.msg_type) {
    1736             :                 case WPS_WSC_ACK:
    1737           0 :                         op_code = WSC_ACK;
    1738           0 :                         break;
    1739             :                 case WPS_WSC_NACK:
    1740           0 :                         op_code = WSC_NACK;
    1741           0 :                         break;
    1742             :                 case WPS_WSC_DONE:
    1743           1 :                         op_code = WSC_Done;
    1744           1 :                         break;
    1745             :                 }
    1746             :         }
    1747             : 
    1748           9 :         res = wps_process_msg(ap->wps, op_code, msg);
    1749           9 :         if (res == WPS_CONTINUE) {
    1750           8 :                 struct wpabuf *next = wps_get_msg(ap->wps, &op_code);
    1751           8 :                 if (next) {
    1752           8 :                         wps_er_ap_put_message(ap, next);
    1753           8 :                         wpabuf_free(next);
    1754             :                 } else {
    1755           0 :                         wpa_printf(MSG_DEBUG, "WPS ER: Failed to build "
    1756             :                                    "message");
    1757           0 :                         wps_deinit(ap->wps);
    1758           0 :                         ap->wps = NULL;
    1759             :                 }
    1760           1 :         } else if (res == WPS_DONE) {
    1761           1 :                 wpa_printf(MSG_DEBUG, "WPS ER: Protocol run done");
    1762           1 :                 wps_deinit(ap->wps);
    1763           1 :                 ap->wps = NULL;
    1764             :         } else {
    1765           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from "
    1766             :                            "AP (res=%d)", res);
    1767           0 :                 wps_deinit(ap->wps);
    1768           0 :                 ap->wps = NULL;
    1769             :         }
    1770           9 : }
    1771             : 
    1772             : 
    1773           1 : static void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1)
    1774             : {
    1775             :         struct wps_config cfg;
    1776             : 
    1777           1 :         if (ap->wps) {
    1778           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
    1779             :                            "progress with this AP");
    1780           0 :                 return;
    1781             :         }
    1782             : 
    1783           1 :         os_memset(&cfg, 0, sizeof(cfg));
    1784           1 :         cfg.wps = ap->er->wps;
    1785           1 :         cfg.registrar = 1;
    1786           1 :         ap->wps = wps_init(&cfg);
    1787           1 :         if (ap->wps == NULL)
    1788           0 :                 return;
    1789           1 :         ap->wps->ap_settings_cb = wps_er_ap_settings_cb;
    1790           1 :         ap->wps->ap_settings_cb_ctx = ap;
    1791             : 
    1792           1 :         wps_er_ap_process(ap, m1);
    1793             : }
    1794             : 
    1795             : 
    1796          11 : static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
    1797             : {
    1798             :         struct wpabuf *info;
    1799             :         enum http_reply_code ret;
    1800             : 
    1801          11 :         wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
    1802             :                    "from the AP");
    1803          11 :         info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
    1804          11 :         if (info == NULL) {
    1805           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
    1806             :                            "NewDeviceInfo from GetDeviceInfo response");
    1807          11 :                 return;
    1808             :         }
    1809             : 
    1810          11 :         ap->m1_handler(ap, info);
    1811          11 :         wpabuf_free(info);
    1812             : }
    1813             : 
    1814             : 
    1815          11 : static void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c,
    1816             :                                         enum http_client_event event)
    1817             : {
    1818          11 :         struct wps_er_ap *ap = ctx;
    1819             :         struct wpabuf *reply;
    1820          11 :         char *dev_info = NULL;
    1821             : 
    1822          11 :         switch (event) {
    1823             :         case HTTP_CLIENT_OK:
    1824          11 :                 wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK");
    1825          11 :                 reply = http_client_get_body(c);
    1826          11 :                 if (reply == NULL)
    1827           0 :                         break;
    1828          11 :                 dev_info = os_zalloc(wpabuf_len(reply) + 1);
    1829          11 :                 if (dev_info == NULL)
    1830           0 :                         break;
    1831          11 :                 os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply));
    1832          11 :                 break;
    1833             :         case HTTP_CLIENT_FAILED:
    1834             :         case HTTP_CLIENT_INVALID_REPLY:
    1835             :         case HTTP_CLIENT_TIMEOUT:
    1836           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed");
    1837           0 :                 break;
    1838             :         }
    1839          11 :         http_client_free(ap->http);
    1840          11 :         ap->http = NULL;
    1841             : 
    1842          11 :         if (dev_info) {
    1843          11 :                 wps_er_ap_learn(ap, dev_info);
    1844          11 :                 os_free(dev_info);
    1845             :         }
    1846          11 : }
    1847             : 
    1848             : 
    1849          11 : static int wps_er_send_get_device_info(struct wps_er_ap *ap,
    1850             :                                        void (*m1_handler)(struct wps_er_ap *ap,
    1851             :                                                           struct wpabuf *m1))
    1852             : {
    1853             :         struct wpabuf *buf;
    1854             :         char *len_ptr, *body_ptr;
    1855             :         struct sockaddr_in dst;
    1856             :         char *url, *path;
    1857             : 
    1858          11 :         if (ap->http) {
    1859           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
    1860             :                            "with the AP - cannot get device info");
    1861           0 :                 return -1;
    1862             :         }
    1863             : 
    1864          11 :         if (ap->control_url == NULL) {
    1865           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
    1866           0 :                 return -1;
    1867             :         }
    1868             : 
    1869          11 :         url = http_client_url_parse(ap->control_url, &dst, &path);
    1870          11 :         if (url == NULL) {
    1871           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
    1872           0 :                 return -1;
    1873             :         }
    1874             : 
    1875          11 :         buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst,
    1876             :                               &len_ptr, &body_ptr);
    1877          11 :         os_free(url);
    1878          11 :         if (buf == NULL)
    1879           0 :                 return -1;
    1880             : 
    1881          11 :         wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr);
    1882             : 
    1883          11 :         ap->http = http_client_addr(&dst, buf, 10000,
    1884             :                                     wps_er_http_get_dev_info_cb, ap);
    1885          11 :         if (ap->http == NULL) {
    1886           0 :                 wpabuf_free(buf);
    1887           0 :                 return -1;
    1888             :         }
    1889             : 
    1890          11 :         ap->m1_handler = m1_handler;
    1891             : 
    1892          11 :         return 0;
    1893             : }
    1894             : 
    1895             : 
    1896           1 : int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
    1897             :                  const u8 *pin, size_t pin_len)
    1898             : {
    1899             :         struct wps_er_ap *ap;
    1900             : 
    1901           1 :         if (er == NULL)
    1902           0 :                 return -1;
    1903             : 
    1904           1 :         ap = wps_er_ap_get(er, NULL, uuid, addr);
    1905           1 :         if (ap == NULL) {
    1906           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
    1907             :                            "request");
    1908           0 :                 return -1;
    1909             :         }
    1910           1 :         if (uuid == NULL)
    1911           0 :                 uuid = ap->uuid;
    1912           1 :         if (ap->wps) {
    1913           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
    1914             :                            "with the AP - cannot start learn");
    1915           0 :                 return -1;
    1916             :         }
    1917             : 
    1918           1 :         if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0)
    1919           0 :                 return -1;
    1920             : 
    1921           1 :         er->skip_set_sel_reg = 1;
    1922           1 :         wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
    1923           1 :         er->skip_set_sel_reg = 0;
    1924             : 
    1925           1 :         return 0;
    1926             : }
    1927             : 
    1928             : 
    1929           8 : int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
    1930             :                       const struct wps_credential *cred)
    1931             : {
    1932             :         struct wps_er_ap *ap;
    1933             : 
    1934           8 :         if (er == NULL)
    1935           0 :                 return -1;
    1936             : 
    1937           8 :         ap = wps_er_ap_get(er, NULL, uuid, addr);
    1938           8 :         if (ap == NULL) {
    1939           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
    1940             :                            "request");
    1941           0 :                 return -1;
    1942             :         }
    1943             : 
    1944           8 :         os_free(ap->ap_settings);
    1945           8 :         ap->ap_settings = os_malloc(sizeof(*cred));
    1946           8 :         if (ap->ap_settings == NULL)
    1947           0 :                 return -1;
    1948           8 :         os_memcpy(ap->ap_settings, cred, sizeof(*cred));
    1949           8 :         ap->ap_settings->cred_attr = NULL;
    1950           8 :         wpa_printf(MSG_DEBUG, "WPS ER: Updated local AP settings based set "
    1951             :                    "config request");
    1952             : 
    1953           8 :         return 0;
    1954             : }
    1955             : 
    1956             : 
    1957           1 : static void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1)
    1958             : {
    1959             :         struct wps_config cfg;
    1960             : 
    1961           1 :         if (ap->wps) {
    1962           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
    1963             :                            "progress with this AP");
    1964           0 :                 return;
    1965             :         }
    1966             : 
    1967           1 :         os_memset(&cfg, 0, sizeof(cfg));
    1968           1 :         cfg.wps = ap->er->wps;
    1969           1 :         cfg.registrar = 1;
    1970           1 :         cfg.new_ap_settings = ap->ap_settings;
    1971           1 :         ap->wps = wps_init(&cfg);
    1972           1 :         if (ap->wps == NULL)
    1973           0 :                 return;
    1974           1 :         ap->wps->ap_settings_cb = NULL;
    1975           1 :         ap->wps->ap_settings_cb_ctx = NULL;
    1976             : 
    1977           1 :         wps_er_ap_process(ap, m1);
    1978             : }
    1979             : 
    1980             : 
    1981           1 : int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
    1982             :                   const u8 *pin, size_t pin_len,
    1983             :                   const struct wps_credential *cred)
    1984             : {
    1985             :         struct wps_er_ap *ap;
    1986             : 
    1987           1 :         if (er == NULL)
    1988           0 :                 return -1;
    1989             : 
    1990           1 :         ap = wps_er_ap_get(er, NULL, uuid, addr);
    1991           1 :         if (ap == NULL) {
    1992           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
    1993             :                            "request");
    1994           0 :                 return -1;
    1995             :         }
    1996           1 :         if (uuid == NULL)
    1997           1 :                 uuid = ap->uuid;
    1998           1 :         if (ap->wps) {
    1999           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
    2000             :                            "with the AP - cannot start config");
    2001           0 :                 return -1;
    2002             :         }
    2003             : 
    2004           1 :         os_free(ap->ap_settings);
    2005           1 :         ap->ap_settings = os_malloc(sizeof(*cred));
    2006           1 :         if (ap->ap_settings == NULL)
    2007           0 :                 return -1;
    2008           1 :         os_memcpy(ap->ap_settings, cred, sizeof(*cred));
    2009           1 :         ap->ap_settings->cred_attr = NULL;
    2010             : 
    2011           1 :         if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0)
    2012           0 :                 return -1;
    2013             : 
    2014           1 :         er->skip_set_sel_reg = 1;
    2015           1 :         wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
    2016           1 :         er->skip_set_sel_reg = 0;
    2017             : 
    2018           1 :         return 0;
    2019             : }
    2020             : 
    2021             : 
    2022             : #ifdef CONFIG_WPS_NFC
    2023             : 
    2024           1 : struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
    2025             :                                               struct wps_credential *cred)
    2026             : {
    2027             :         struct wpabuf *ret;
    2028             :         struct wps_data data;
    2029             : 
    2030           1 :         ret = wpabuf_alloc(500);
    2031           1 :         if (ret == NULL)
    2032           0 :                 return NULL;
    2033             : 
    2034           1 :         os_memset(&data, 0, sizeof(data));
    2035           1 :         data.wps = wps;
    2036           1 :         data.use_cred = cred;
    2037           2 :         if (wps_build_cred(&data, ret) ||
    2038           1 :             wps_build_wfa_ext(ret, 0, NULL, 0)) {
    2039           0 :                 wpabuf_free(ret);
    2040           0 :                 return NULL;
    2041             :         }
    2042             : 
    2043           1 :         return ret;
    2044             : }
    2045             : 
    2046             : 
    2047           1 : struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
    2048             :                                         const u8 *addr)
    2049             : {
    2050             :         struct wps_er_ap *ap;
    2051             : 
    2052           1 :         if (er == NULL)
    2053           0 :                 return NULL;
    2054             : 
    2055           1 :         ap = wps_er_ap_get(er, NULL, uuid, addr);
    2056           1 :         if (ap == NULL)
    2057           0 :                 return NULL;
    2058           1 :         if (ap->ap_settings == NULL) {
    2059           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
    2060             :                            "selected AP");
    2061           0 :                 return NULL;
    2062             :         }
    2063             : 
    2064           1 :         return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
    2065             : }
    2066             : 
    2067             : 
    2068           3 : struct wpabuf * wps_er_nfc_handover_sel(struct wps_er *er,
    2069             :                                         struct wps_context *wps, const u8 *uuid,
    2070             :                                         const u8 *addr, struct wpabuf *pubkey)
    2071             : {
    2072             :         struct wps_er_ap *ap;
    2073             : 
    2074           3 :         if (er == NULL)
    2075           0 :                 return NULL;
    2076             : 
    2077           3 :         ap = wps_er_ap_get(er, NULL, uuid, addr);
    2078           3 :         if (ap == NULL)
    2079           0 :                 return NULL;
    2080           3 :         if (ap->ap_settings == NULL) {
    2081           0 :                 wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
    2082             :                            "selected AP");
    2083           0 :                 return NULL;
    2084             :         }
    2085             : 
    2086           3 :         os_memcpy(wps->ssid, ap->ap_settings->ssid, ap->ap_settings->ssid_len);
    2087           3 :         wps->ssid_len = ap->ap_settings->ssid_len;
    2088             : 
    2089           3 :         return wps_build_nfc_handover_sel(wps, pubkey, addr, 0);
    2090             : }
    2091             : 
    2092             : #endif /* CONFIG_WPS_NFC */

Generated by: LCOV version 1.10