wps_upnp_web.c
Go to the documentation of this file.
00001 /*
00002  * UPnP WPS Device - Web connections
00003  * Copyright (c) 2000-2003 Intel Corporation
00004  * Copyright (c) 2006-2007 Sony Corporation
00005  * Copyright (c) 2008-2009 Atheros Communications
00006  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
00007  *
00008  * See wps_upnp.c for more details on licensing and code history.
00009  */
00010 
00011 #include "includes.h"
00012 
00013 #include "common.h"
00014 #include "base64.h"
00015 #include "uuid.h"
00016 #include "httpread.h"
00017 #include "http_server.h"
00018 #include "wps_i.h"
00019 #include "wps_upnp.h"
00020 #include "wps_upnp_i.h"
00021 #include "upnp_xml.h"
00022 
00023 /***************************************************************************
00024  * Web connections (we serve pages of info about ourselves, handle
00025  * requests, etc. etc.).
00026  **************************************************************************/
00027 
00028 #define WEB_CONNECTION_TIMEOUT_SEC 30   /* Drop web connection after t.o. */
00029 #define WEB_CONNECTION_MAX_READ 8000    /* Max we'll read for TCP request */
00030 #define MAX_WEB_CONNECTIONS 10          /* max simultaneous web connects */
00031 
00032 
00033 static const char *urn_wfawlanconfig =
00034         "urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
00035 static const char *http_server_hdr =
00036         "Server: unspecified, UPnP/1.0, unspecified\r\n";
00037 static const char *http_connection_close =
00038         "Connection: close\r\n";
00039 
00040 /*
00041  * "Files" that we serve via HTTP. The format of these files is given by
00042  * WFA WPS specifications. Extra white space has been removed to save space.
00043  */
00044 
00045 static const char wps_scpd_xml[] =
00046 "<?xml version=\"1.0\"?>\n"
00047 "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">\n"
00048 "<specVersion><major>1</major><minor>0</minor></specVersion>\n"
00049 "<actionList>\n"
00050 "<action>\n"
00051 "<name>GetDeviceInfo</name>\n"
00052 "<argumentList>\n"
00053 "<argument>\n"
00054 "<name>NewDeviceInfo</name>\n"
00055 "<direction>out</direction>\n"
00056 "<relatedStateVariable>DeviceInfo</relatedStateVariable>\n"
00057 "</argument>\n"
00058 "</argumentList>\n"
00059 "</action>\n"
00060 "<action>\n"
00061 "<name>PutMessage</name>\n"
00062 "<argumentList>\n"
00063 "<argument>\n"
00064 "<name>NewInMessage</name>\n"
00065 "<direction>in</direction>\n"
00066 "<relatedStateVariable>InMessage</relatedStateVariable>\n"
00067 "</argument>\n"
00068 "<argument>\n"
00069 "<name>NewOutMessage</name>\n"
00070 "<direction>out</direction>\n"
00071 "<relatedStateVariable>OutMessage</relatedStateVariable>\n"
00072 "</argument>\n"
00073 "</argumentList>\n"
00074 "</action>\n"
00075 "<action>\n"
00076 "<name>PutWLANResponse</name>\n"
00077 "<argumentList>\n"
00078 "<argument>\n"
00079 "<name>NewMessage</name>\n"
00080 "<direction>in</direction>\n"
00081 "<relatedStateVariable>Message</relatedStateVariable>\n"
00082 "</argument>\n"
00083 "<argument>\n"
00084 "<name>NewWLANEventType</name>\n"
00085 "<direction>in</direction>\n"
00086 "<relatedStateVariable>WLANEventType</relatedStateVariable>\n"
00087 "</argument>\n"
00088 "<argument>\n"
00089 "<name>NewWLANEventMAC</name>\n"
00090 "<direction>in</direction>\n"
00091 "<relatedStateVariable>WLANEventMAC</relatedStateVariable>\n"
00092 "</argument>\n"
00093 "</argumentList>\n"
00094 "</action>\n"
00095 "<action>\n"
00096 "<name>SetSelectedRegistrar</name>\n"
00097 "<argumentList>\n"
00098 "<argument>\n"
00099 "<name>NewMessage</name>\n"
00100 "<direction>in</direction>\n"
00101 "<relatedStateVariable>Message</relatedStateVariable>\n"
00102 "</argument>\n"
00103 "</argumentList>\n"
00104 "</action>\n"
00105 "</actionList>\n"
00106 "<serviceStateTable>\n"
00107 "<stateVariable sendEvents=\"no\">\n"
00108 "<name>Message</name>\n"
00109 "<dataType>bin.base64</dataType>\n"
00110 "</stateVariable>\n"
00111 "<stateVariable sendEvents=\"no\">\n"
00112 "<name>InMessage</name>\n"
00113 "<dataType>bin.base64</dataType>\n"
00114 "</stateVariable>\n"
00115 "<stateVariable sendEvents=\"no\">\n"
00116 "<name>OutMessage</name>\n"
00117 "<dataType>bin.base64</dataType>\n"
00118 "</stateVariable>\n"
00119 "<stateVariable sendEvents=\"no\">\n"
00120 "<name>DeviceInfo</name>\n"
00121 "<dataType>bin.base64</dataType>\n"
00122 "</stateVariable>\n"
00123 "<stateVariable sendEvents=\"yes\">\n"
00124 "<name>APStatus</name>\n"
00125 "<dataType>ui1</dataType>\n"
00126 "</stateVariable>\n"
00127 "<stateVariable sendEvents=\"yes\">\n"
00128 "<name>STAStatus</name>\n"
00129 "<dataType>ui1</dataType>\n"
00130 "</stateVariable>\n"
00131 "<stateVariable sendEvents=\"yes\">\n"
00132 "<name>WLANEvent</name>\n"
00133 "<dataType>bin.base64</dataType>\n"
00134 "</stateVariable>\n"
00135 "<stateVariable sendEvents=\"no\">\n"
00136 "<name>WLANEventType</name>\n"
00137 "<dataType>ui1</dataType>\n"
00138 "</stateVariable>\n"
00139 "<stateVariable sendEvents=\"no\">\n"
00140 "<name>WLANEventMAC</name>\n"
00141 "<dataType>string</dataType>\n"
00142 "</stateVariable>\n"
00143 "<stateVariable sendEvents=\"no\">\n"
00144 "<name>WLANResponse</name>\n"
00145 "<dataType>bin.base64</dataType>\n"
00146 "</stateVariable>\n"
00147 "</serviceStateTable>\n"
00148 "</scpd>\n"
00149 ;
00150 
00151 
00152 static const char *wps_device_xml_prefix =
00153         "<?xml version=\"1.0\"?>\n"
00154         "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
00155         "<specVersion>\n"
00156         "<major>1</major>\n"
00157         "<minor>0</minor>\n"
00158         "</specVersion>\n"
00159         "<device>\n"
00160         "<deviceType>urn:schemas-wifialliance-org:device:WFADevice:1"
00161         "</deviceType>\n";
00162 
00163 static const char *wps_device_xml_postfix =
00164         "<serviceList>\n"
00165         "<service>\n"
00166         "<serviceType>urn:schemas-wifialliance-org:service:WFAWLANConfig:1"
00167         "</serviceType>\n"
00168         "<serviceId>urn:wifialliance-org:serviceId:WFAWLANConfig1</serviceId>"
00169         "\n"
00170         "<SCPDURL>" UPNP_WPS_SCPD_XML_FILE "</SCPDURL>\n"
00171         "<controlURL>" UPNP_WPS_DEVICE_CONTROL_FILE "</controlURL>\n"
00172         "<eventSubURL>" UPNP_WPS_DEVICE_EVENT_FILE "</eventSubURL>\n"
00173         "</service>\n"
00174         "</serviceList>\n"
00175         "</device>\n"
00176         "</root>\n";
00177 
00178 
00179 /* format_wps_device_xml -- produce content of "file" wps_device.xml
00180  * (UPNP_WPS_DEVICE_XML_FILE)
00181  */
00182 static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
00183                                   struct wpabuf *buf)
00184 {
00185         const char *s;
00186         char uuid_string[80];
00187 
00188         wpabuf_put_str(buf, wps_device_xml_prefix);
00189 
00190         /*
00191          * Add required fields with default values if not configured. Add
00192          * optional and recommended fields only if configured.
00193          */
00194         s = sm->wps->friendly_name;
00195         s = ((s && *s) ? s : "WPS Access Point");
00196         xml_add_tagged_data(buf, "friendlyName", s);
00197 
00198         s = sm->wps->dev.manufacturer;
00199         s = ((s && *s) ? s : "");
00200         xml_add_tagged_data(buf, "manufacturer", s);
00201 
00202         if (sm->wps->manufacturer_url)
00203                 xml_add_tagged_data(buf, "manufacturerURL",
00204                                     sm->wps->manufacturer_url);
00205 
00206         if (sm->wps->model_description)
00207                 xml_add_tagged_data(buf, "modelDescription",
00208                                     sm->wps->model_description);
00209 
00210         s = sm->wps->dev.model_name;
00211         s = ((s && *s) ? s : "");
00212         xml_add_tagged_data(buf, "modelName", s);
00213 
00214         if (sm->wps->dev.model_number)
00215                 xml_add_tagged_data(buf, "modelNumber",
00216                                     sm->wps->dev.model_number);
00217 
00218         if (sm->wps->model_url)
00219                 xml_add_tagged_data(buf, "modelURL", sm->wps->model_url);
00220 
00221         if (sm->wps->dev.serial_number)
00222                 xml_add_tagged_data(buf, "serialNumber",
00223                                     sm->wps->dev.serial_number);
00224 
00225         uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string));
00226         s = uuid_string;
00227         /* Need "uuid:" prefix, thus we can't use xml_add_tagged_data()
00228          * easily...
00229          */
00230         wpabuf_put_str(buf, "<UDN>uuid:");
00231         xml_data_encode(buf, s, os_strlen(s));
00232         wpabuf_put_str(buf, "</UDN>\n");
00233 
00234         if (sm->wps->upc)
00235                 xml_add_tagged_data(buf, "UPC", sm->wps->upc);
00236 
00237         wpabuf_put_str(buf, wps_device_xml_postfix);
00238 }
00239 
00240 
00241 static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code)
00242 {
00243         wpabuf_put_str(buf, "HTTP/1.1 ");
00244         switch (code) {
00245         case HTTP_OK:
00246                 wpabuf_put_str(buf, "200 OK\r\n");
00247                 break;
00248         case HTTP_BAD_REQUEST:
00249                 wpabuf_put_str(buf, "400 Bad request\r\n");
00250                 break;
00251         case HTTP_PRECONDITION_FAILED:
00252                 wpabuf_put_str(buf, "412 Precondition failed\r\n");
00253                 break;
00254         case HTTP_UNIMPLEMENTED:
00255                 wpabuf_put_str(buf, "501 Unimplemented\r\n");
00256                 break;
00257         case HTTP_INTERNAL_SERVER_ERROR:
00258         default:
00259                 wpabuf_put_str(buf, "500 Internal server error\r\n");
00260                 break;
00261         }
00262 }
00263 
00264 
00265 static void http_put_date(struct wpabuf *buf)
00266 {
00267         wpabuf_put_str(buf, "Date: ");
00268         format_date(buf);
00269         wpabuf_put_str(buf, "\r\n");
00270 }
00271 
00272 
00273 static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
00274 {
00275         http_put_reply_code(buf, code);
00276         wpabuf_put_str(buf, http_server_hdr);
00277         wpabuf_put_str(buf, http_connection_close);
00278         wpabuf_put_str(buf, "Content-Length: 0\r\n"
00279                        "\r\n");
00280 }
00281 
00282 
00283 /* Given that we have received a header w/ GET, act upon it
00284  *
00285  * Format of GET (case-insensitive):
00286  *
00287  * First line must be:
00288  *      GET /<file> HTTP/1.1
00289  * Since we don't do anything fancy we just ignore other lines.
00290  *
00291  * Our response (if no error) which includes only required lines is:
00292  * HTTP/1.1 200 OK
00293  * Connection: close
00294  * Content-Type: text/xml
00295  * Date: <rfc1123-date>
00296  *
00297  * Header lines must end with \r\n
00298  * Per RFC 2616, content-length: is not required but connection:close
00299  * would appear to be required (given that we will be closing it!).
00300  */
00301 static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
00302                                      struct http_request *hreq, char *filename)
00303 {
00304         struct wpabuf *buf; /* output buffer, allocated */
00305         char *put_length_here;
00306         char *body_start;
00307         enum {
00308                 GET_DEVICE_XML_FILE,
00309                 GET_SCPD_XML_FILE
00310         } req;
00311         size_t extra_len = 0;
00312         int body_length;
00313         char len_buf[10];
00314 
00315         /*
00316          * It is not required that filenames be case insensitive but it is
00317          * allowed and cannot hurt here.
00318          */
00319         if (filename == NULL)
00320                 filename = "(null)"; /* just in case */
00321         if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) {
00322                 wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
00323                 req = GET_DEVICE_XML_FILE;
00324                 extra_len = 3000;
00325                 if (sm->wps->friendly_name)
00326                         extra_len += os_strlen(sm->wps->friendly_name);
00327                 if (sm->wps->manufacturer_url)
00328                         extra_len += os_strlen(sm->wps->manufacturer_url);
00329                 if (sm->wps->model_description)
00330                         extra_len += os_strlen(sm->wps->model_description);
00331                 if (sm->wps->model_url)
00332                         extra_len += os_strlen(sm->wps->model_url);
00333                 if (sm->wps->upc)
00334                         extra_len += os_strlen(sm->wps->upc);
00335         } else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
00336                 wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
00337                 req = GET_SCPD_XML_FILE;
00338                 extra_len = os_strlen(wps_scpd_xml);
00339         } else {
00340                 /* File not found */
00341                 wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
00342                            filename);
00343                 buf = wpabuf_alloc(200);
00344                 if (buf == NULL) {
00345                         http_request_deinit(hreq);
00346                         return;
00347                 }
00348                 wpabuf_put_str(buf,
00349                                "HTTP/1.1 404 Not Found\r\n"
00350                                "Connection: close\r\n");
00351 
00352                 http_put_date(buf);
00353 
00354                 /* terminating empty line */
00355                 wpabuf_put_str(buf, "\r\n");
00356 
00357                 goto send_buf;
00358         }
00359 
00360         buf = wpabuf_alloc(1000 + extra_len);
00361         if (buf == NULL) {
00362                 http_request_deinit(hreq);
00363                 return;
00364         }
00365 
00366         wpabuf_put_str(buf,
00367                        "HTTP/1.1 200 OK\r\n"
00368                        "Content-Type: text/xml; charset=\"utf-8\"\r\n");
00369         wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n");
00370         wpabuf_put_str(buf, "Connection: close\r\n");
00371         wpabuf_put_str(buf, "Content-Length: ");
00372         /*
00373          * We will paste the length in later, leaving some extra whitespace.
00374          * HTTP code is supposed to be tolerant of extra whitespace.
00375          */
00376         put_length_here = wpabuf_put(buf, 0);
00377         wpabuf_put_str(buf, "        \r\n");
00378 
00379         http_put_date(buf);
00380 
00381         /* terminating empty line */
00382         wpabuf_put_str(buf, "\r\n");
00383 
00384         body_start = wpabuf_put(buf, 0);
00385 
00386         switch (req) {
00387         case GET_DEVICE_XML_FILE:
00388                 format_wps_device_xml(sm, buf);
00389                 break;
00390         case GET_SCPD_XML_FILE:
00391                 wpabuf_put_str(buf, wps_scpd_xml);
00392                 break;
00393         }
00394 
00395         /* Now patch in the content length at the end */
00396         body_length = (char *) wpabuf_put(buf, 0) - body_start;
00397         os_snprintf(len_buf, 10, "%d", body_length);
00398         os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
00399 
00400 send_buf:
00401         http_request_send_and_deinit(hreq, buf);
00402 }
00403 
00404 
00405 static enum http_reply_code
00406 web_process_get_device_info(struct upnp_wps_device_sm *sm,
00407                             struct wpabuf **reply, const char **replyname)
00408 {
00409         static const char *name = "NewDeviceInfo";
00410         struct wps_config cfg;
00411         struct upnp_wps_peer *peer = &sm->peer;
00412 
00413         wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
00414 
00415         /*
00416          * Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
00417          * registration over UPnP with the AP acting as an Enrollee. It should
00418          * be noted that this is frequently used just to get the device data,
00419          * i.e., there may not be any intent to actually complete the
00420          * registration.
00421          */
00422 
00423         if (peer->wps)
00424                 wps_deinit(peer->wps);
00425 
00426         os_memset(&cfg, 0, sizeof(cfg));
00427         cfg.wps = sm->wps;
00428         cfg.pin = (u8 *) sm->ctx->ap_pin;
00429         cfg.pin_len = os_strlen(sm->ctx->ap_pin);
00430         peer->wps = wps_init(&cfg);
00431         if (peer->wps) {
00432                 enum wsc_op_code op_code;
00433                 *reply = wps_get_msg(peer->wps, &op_code);
00434                 if (*reply == NULL) {
00435                         wps_deinit(peer->wps);
00436                         peer->wps = NULL;
00437                 }
00438         } else
00439                 *reply = NULL;
00440         if (*reply == NULL) {
00441                 wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
00442                 return HTTP_INTERNAL_SERVER_ERROR;
00443         }
00444         *replyname = name;
00445         return HTTP_OK;
00446 }
00447 
00448 
00449 static enum http_reply_code
00450 web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
00451                         struct wpabuf **reply, const char **replyname)
00452 {
00453         struct wpabuf *msg;
00454         static const char *name = "NewOutMessage";
00455         enum http_reply_code ret;
00456         enum wps_process_res res;
00457         enum wsc_op_code op_code;
00458 
00459         /*
00460          * PutMessage is used by external UPnP-based Registrar to perform WPS
00461          * operation with the access point itself; as compared with
00462          * PutWLANResponse which is for proxying.
00463          */
00464         wpa_printf(MSG_DEBUG, "WPS UPnP: PutMessage");
00465         msg = xml_get_base64_item(data, "NewInMessage", &ret);
00466         if (msg == NULL)
00467                 return ret;
00468         res = wps_process_msg(sm->peer.wps, WSC_UPnP, msg);
00469         if (res == WPS_FAILURE)
00470                 *reply = NULL;
00471         else
00472                 *reply = wps_get_msg(sm->peer.wps, &op_code);
00473         wpabuf_free(msg);
00474         if (*reply == NULL)
00475                 return HTTP_INTERNAL_SERVER_ERROR;
00476         *replyname = name;
00477         return HTTP_OK;
00478 }
00479 
00480 
00481 static enum http_reply_code
00482 web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
00483                               struct wpabuf **reply, const char **replyname)
00484 {
00485         struct wpabuf *msg;
00486         enum http_reply_code ret;
00487         u8 macaddr[ETH_ALEN];
00488         int ev_type;
00489         int type;
00490         char *val;
00491 
00492         /*
00493          * External UPnP-based Registrar is passing us a message to be proxied
00494          * over to a Wi-Fi -based client of ours.
00495          */
00496 
00497         wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse");
00498         msg = xml_get_base64_item(data, "NewMessage", &ret);
00499         if (msg == NULL) {
00500                 wpa_printf(MSG_DEBUG, "WPS UPnP: Could not extract NewMessage "
00501                            "from PutWLANResponse");
00502                 return ret;
00503         }
00504         val = xml_get_first_item(data, "NewWLANEventType");
00505         if (val == NULL) {
00506                 wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventType in "
00507                            "PutWLANResponse");
00508                 wpabuf_free(msg);
00509                 return UPNP_ARG_VALUE_INVALID;
00510         }
00511         ev_type = atol(val);
00512         os_free(val);
00513         val = xml_get_first_item(data, "NewWLANEventMAC");
00514         if (val == NULL) {
00515                 wpa_printf(MSG_DEBUG, "WPS UPnP: No NewWLANEventMAC in "
00516                            "PutWLANResponse");
00517                 wpabuf_free(msg);
00518                 return UPNP_ARG_VALUE_INVALID;
00519         }
00520         if (hwaddr_aton(val, macaddr)) {
00521                 wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid NewWLANEventMAC in "
00522                            "PutWLANResponse: '%s'", val);
00523                 if (hwaddr_aton2(val, macaddr) > 0) {
00524                         /*
00525                          * At least some versions of Intel PROset seem to be
00526                          * using dot-deliminated MAC address format here.
00527                          */
00528                         wpa_printf(MSG_DEBUG, "WPS UPnP: Workaround - allow "
00529                                    "incorrect MAC address format in "
00530                                    "NewWLANEventMAC");
00531                 } else {
00532                         wpabuf_free(msg);
00533                         os_free(val);
00534                         return UPNP_ARG_VALUE_INVALID;
00535                 }
00536         }
00537         os_free(val);
00538         if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
00539                 struct wps_parse_attr attr;
00540                 if (wps_parse_msg(msg, &attr) < 0 ||
00541                     attr.msg_type == NULL)
00542                         type = -1;
00543                 else
00544                         type = *attr.msg_type;
00545                 wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
00546         } else
00547                 type = -1;
00548         if (!sm->ctx->rx_req_put_wlan_response ||
00549             sm->ctx->rx_req_put_wlan_response(sm->priv, ev_type, macaddr, msg,
00550                                               type)) {
00551                 wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
00552                            "rx_req_put_wlan_response");
00553                 wpabuf_free(msg);
00554                 return HTTP_INTERNAL_SERVER_ERROR;
00555         }
00556         wpabuf_free(msg);
00557         *replyname = NULL;
00558         *reply = NULL;
00559         return HTTP_OK;
00560 }
00561 
00562 
00563 static int find_er_addr(struct subscription *s, struct sockaddr_in *cli)
00564 {
00565         struct subscr_addr *a;
00566 
00567         dl_list_for_each(a, &s->addr_list, struct subscr_addr, list) {
00568                 if (cli->sin_addr.s_addr == a->saddr.sin_addr.s_addr)
00569                         return 1;
00570         }
00571         return 0;
00572 }
00573 
00574 
00575 static struct subscription * find_er(struct upnp_wps_device_sm *sm,
00576                                      struct sockaddr_in *cli)
00577 {
00578         struct subscription *s;
00579         dl_list_for_each(s, &sm->subscriptions, struct subscription, list)
00580                 if (find_er_addr(s, cli))
00581                         return s;
00582         return NULL;
00583 }
00584 
00585 
00586 static enum http_reply_code
00587 web_process_set_selected_registrar(struct upnp_wps_device_sm *sm,
00588                                    struct sockaddr_in *cli, char *data,
00589                                    struct wpabuf **reply,
00590                                    const char **replyname)
00591 {
00592         struct wpabuf *msg;
00593         enum http_reply_code ret;
00594         struct subscription *s;
00595 
00596         wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
00597         s = find_er(sm, cli);
00598         if (s == NULL) {
00599                 wpa_printf(MSG_DEBUG, "WPS UPnP: Ignore SetSelectedRegistrar "
00600                            "from unknown ER");
00601                 return UPNP_ACTION_FAILED;
00602         }
00603         msg = xml_get_base64_item(data, "NewMessage", &ret);
00604         if (msg == NULL)
00605                 return ret;
00606         if (upnp_er_set_selected_registrar(sm->wps->registrar, s, msg)) {
00607                 wpabuf_free(msg);
00608                 return HTTP_INTERNAL_SERVER_ERROR;
00609         }
00610         wpabuf_free(msg);
00611         *replyname = NULL;
00612         *reply = NULL;
00613         return HTTP_OK;
00614 }
00615 
00616 
00617 static const char *soap_prefix =
00618         "<?xml version=\"1.0\"?>\n"
00619         "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
00620         "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
00621         "<s:Body>\n";
00622 static const char *soap_postfix =
00623         "</s:Body>\n</s:Envelope>\n";
00624 
00625 static const char *soap_error_prefix =
00626         "<s:Fault>\n"
00627         "<faultcode>s:Client</faultcode>\n"
00628         "<faultstring>UPnPError</faultstring>\n"
00629         "<detail>\n"
00630         "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n";
00631 static const char *soap_error_postfix =
00632         "<errorDescription>Error</errorDescription>\n"
00633         "</UPnPError>\n"
00634         "</detail>\n"
00635         "</s:Fault>\n";
00636 
00637 static void web_connection_send_reply(struct http_request *req,
00638                                       enum http_reply_code ret,
00639                                       const char *action, int action_len,
00640                                       const struct wpabuf *reply,
00641                                       const char *replyname)
00642 {
00643         struct wpabuf *buf;
00644         char *replydata;
00645         char *put_length_here = NULL;
00646         char *body_start = NULL;
00647 
00648         if (reply) {
00649                 size_t len;
00650                 replydata = (char *) base64_encode(wpabuf_head(reply),
00651                                                    wpabuf_len(reply), &len);
00652         } else
00653                 replydata = NULL;
00654 
00655         /* Parameters of the response:
00656          *      action(action_len) -- action we are responding to
00657          *      replyname -- a name we need for the reply
00658          *      replydata -- NULL or null-terminated string
00659          */
00660         buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) +
00661                            (action_len > 0 ? action_len * 2 : 0));
00662         if (buf == NULL) {
00663                 wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
00664                            "POST");
00665                 os_free(replydata);
00666                 http_request_deinit(req);
00667                 return;
00668         }
00669 
00670         /*
00671          * Assuming we will be successful, put in the output header first.
00672          * Note: we do not keep connections alive (and httpread does
00673          * not support it)... therefore we must have Connection: close.
00674          */
00675         if (ret == HTTP_OK) {
00676                 wpabuf_put_str(buf,
00677                                "HTTP/1.1 200 OK\r\n"
00678                                "Content-Type: text/xml; "
00679                                "charset=\"utf-8\"\r\n");
00680         } else {
00681                 wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret);
00682         }
00683         wpabuf_put_str(buf, http_connection_close);
00684 
00685         wpabuf_put_str(buf, "Content-Length: ");
00686         /*
00687          * We will paste the length in later, leaving some extra whitespace.
00688          * HTTP code is supposed to be tolerant of extra whitespace.
00689          */
00690         put_length_here = wpabuf_put(buf, 0);
00691         wpabuf_put_str(buf, "        \r\n");
00692 
00693         http_put_date(buf);
00694 
00695         /* terminating empty line */
00696         wpabuf_put_str(buf, "\r\n");
00697 
00698         body_start = wpabuf_put(buf, 0);
00699 
00700         if (ret == HTTP_OK) {
00701                 wpabuf_put_str(buf, soap_prefix);
00702                 wpabuf_put_str(buf, "<u:");
00703                 wpabuf_put_data(buf, action, action_len);
00704                 wpabuf_put_str(buf, "Response xmlns:u=\"");
00705                 wpabuf_put_str(buf, urn_wfawlanconfig);
00706                 wpabuf_put_str(buf, "\">\n");
00707                 if (replydata && replyname) {
00708                         /* TODO: might possibly need to escape part of reply
00709                          * data? ...
00710                          * probably not, unlikely to have ampersand(&) or left
00711                          * angle bracket (<) in it...
00712                          */
00713                         wpabuf_printf(buf, "<%s>", replyname);
00714                         wpabuf_put_str(buf, replydata);
00715                         wpabuf_printf(buf, "</%s>\n", replyname);
00716                 }
00717                 wpabuf_put_str(buf, "</u:");
00718                 wpabuf_put_data(buf, action, action_len);
00719                 wpabuf_put_str(buf, "Response>\n");
00720                 wpabuf_put_str(buf, soap_postfix);
00721         } else {
00722                 /* Error case */
00723                 wpabuf_put_str(buf, soap_prefix);
00724                 wpabuf_put_str(buf, soap_error_prefix);
00725                 wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret);
00726                 wpabuf_put_str(buf, soap_error_postfix);
00727                 wpabuf_put_str(buf, soap_postfix);
00728         }
00729         os_free(replydata);
00730 
00731         /* Now patch in the content length at the end */
00732         if (body_start && put_length_here) {
00733                 int body_length = (char *) wpabuf_put(buf, 0) - body_start;
00734                 char len_buf[10];
00735                 os_snprintf(len_buf, sizeof(len_buf), "%d", body_length);
00736                 os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
00737         }
00738 
00739         http_request_send_and_deinit(req, buf);
00740 }
00741 
00742 
00743 static const char * web_get_action(struct http_request *req,
00744                                    size_t *action_len)
00745 {
00746         const char *match;
00747         int match_len;
00748         char *b;
00749         char *action;
00750 
00751         *action_len = 0;
00752         /* The SOAPAction line of the header tells us what we want to do */
00753         b = http_request_get_hdr_line(req, "SOAPAction:");
00754         if (b == NULL)
00755                 return NULL;
00756         if (*b == '"')
00757                 b++;
00758         else
00759                 return NULL;
00760         match = urn_wfawlanconfig;
00761         match_len = os_strlen(urn_wfawlanconfig) - 1;
00762         if (os_strncasecmp(b, match, match_len))
00763                 return NULL;
00764         b += match_len;
00765         /* skip over version */
00766         while (isgraph(*b) && *b != '#')
00767                 b++;
00768         if (*b != '#')
00769                 return NULL;
00770         b++;
00771         /* Following the sharp(#) should be the action and a double quote */
00772         action = b;
00773         while (isgraph(*b) && *b != '"')
00774                 b++;
00775         if (*b != '"')
00776                 return NULL;
00777         *action_len = b - action;
00778         return action;
00779 }
00780 
00781 
00782 /* Given that we have received a header w/ POST, act upon it
00783  *
00784  * Format of POST (case-insensitive):
00785  *
00786  * First line must be:
00787  *      POST /<file> HTTP/1.1
00788  * Since we don't do anything fancy we just ignore other lines.
00789  *
00790  * Our response (if no error) which includes only required lines is:
00791  * HTTP/1.1 200 OK
00792  * Connection: close
00793  * Content-Type: text/xml
00794  * Date: <rfc1123-date>
00795  *
00796  * Header lines must end with \r\n
00797  * Per RFC 2616, content-length: is not required but connection:close
00798  * would appear to be required (given that we will be closing it!).
00799  */
00800 static void web_connection_parse_post(struct upnp_wps_device_sm *sm,
00801                                       struct sockaddr_in *cli,
00802                                       struct http_request *req,
00803                                       const char *filename)
00804 {
00805         enum http_reply_code ret;
00806         char *data = http_request_get_data(req); /* body of http msg */
00807         const char *action = NULL;
00808         size_t action_len = 0;
00809         const char *replyname = NULL; /* argument name for the reply */
00810         struct wpabuf *reply = NULL; /* data for the reply */
00811 
00812         if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) {
00813                 wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s",
00814                            filename);
00815                 ret = HTTP_NOT_FOUND;
00816                 goto bad;
00817         }
00818 
00819         ret = UPNP_INVALID_ACTION;
00820         action = web_get_action(req, &action_len);
00821         if (action == NULL)
00822                 goto bad;
00823 
00824         if (!os_strncasecmp("GetDeviceInfo", action, action_len))
00825                 ret = web_process_get_device_info(sm, &reply, &replyname);
00826         else if (!os_strncasecmp("PutMessage", action, action_len))
00827                 ret = web_process_put_message(sm, data, &reply, &replyname);
00828         else if (!os_strncasecmp("PutWLANResponse", action, action_len))
00829                 ret = web_process_put_wlan_response(sm, data, &reply,
00830                                                     &replyname);
00831         else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
00832                 ret = web_process_set_selected_registrar(sm, cli, data, &reply,
00833                                                          &replyname);
00834         else
00835                 wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
00836 
00837 bad:
00838         if (ret != HTTP_OK)
00839                 wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
00840         web_connection_send_reply(req, ret, action, action_len, reply,
00841                                   replyname);
00842         wpabuf_free(reply);
00843 }
00844 
00845 
00846 /* Given that we have received a header w/ SUBSCRIBE, act upon it
00847  *
00848  * Format of SUBSCRIBE (case-insensitive):
00849  *
00850  * First line must be:
00851  *      SUBSCRIBE /wps_event HTTP/1.1
00852  *
00853  * Our response (if no error) which includes only required lines is:
00854  * HTTP/1.1 200 OK
00855  * Server: xx, UPnP/1.0, xx
00856  * SID: uuid:xxxxxxxxx
00857  * Timeout: Second-<n>
00858  * Content-Length: 0
00859  * Date: xxxx
00860  *
00861  * Header lines must end with \r\n
00862  * Per RFC 2616, content-length: is not required but connection:close
00863  * would appear to be required (given that we will be closing it!).
00864  */
00865 static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm,
00866                                            struct http_request *req,
00867                                            const char *filename)
00868 {
00869         struct wpabuf *buf;
00870         char *b;
00871         char *hdr = http_request_get_hdr(req);
00872         char *h;
00873         char *match;
00874         int match_len;
00875         char *end;
00876         int len;
00877         int got_nt = 0;
00878         u8 uuid[UUID_LEN];
00879         int got_uuid = 0;
00880         char *callback_urls = NULL;
00881         struct subscription *s = NULL;
00882         enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
00883 
00884         buf = wpabuf_alloc(1000);
00885         if (buf == NULL) {
00886                 http_request_deinit(req);
00887                 return;
00888         }
00889 
00890         /* Parse/validate headers */
00891         h = hdr;
00892         /* First line: SUBSCRIBE /wps_event HTTP/1.1
00893          * has already been parsed.
00894          */
00895         if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
00896                 ret = HTTP_PRECONDITION_FAILED;
00897                 goto error;
00898         }
00899         wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event");
00900         end = os_strchr(h, '\n');
00901 
00902         for (; end != NULL; h = end + 1) {
00903                 /* Option line by option line */
00904                 h = end + 1;
00905                 end = os_strchr(h, '\n');
00906                 if (end == NULL)
00907                         break; /* no unterminated lines allowed */
00908 
00909                 /* NT assures that it is our type of subscription;
00910                  * not used for a renewl.
00911                  **/
00912                 match = "NT:";
00913                 match_len = os_strlen(match);
00914                 if (os_strncasecmp(h, match, match_len) == 0) {
00915                         h += match_len;
00916                         while (*h == ' ' || *h == '\t')
00917                                 h++;
00918                         match = "upnp:event";
00919                         match_len = os_strlen(match);
00920                         if (os_strncasecmp(h, match, match_len) != 0) {
00921                                 ret = HTTP_BAD_REQUEST;
00922                                 goto error;
00923                         }
00924                         got_nt = 1;
00925                         continue;
00926                 }
00927                 /* HOST should refer to us */
00928 #if 0
00929                 match = "HOST:";
00930                 match_len = os_strlen(match);
00931                 if (os_strncasecmp(h, match, match_len) == 0) {
00932                         h += match_len;
00933                         while (*h == ' ' || *h == '\t')
00934                                 h++;
00935                         .....
00936                 }
00937 #endif
00938                 /* CALLBACK gives one or more URLs for NOTIFYs
00939                  * to be sent as a result of the subscription.
00940                  * Each URL is enclosed in angle brackets.
00941                  */
00942                 match = "CALLBACK:";
00943                 match_len = os_strlen(match);
00944                 if (os_strncasecmp(h, match, match_len) == 0) {
00945                         h += match_len;
00946                         while (*h == ' ' || *h == '\t')
00947                                 h++;
00948                         len = end - h;
00949                         os_free(callback_urls);
00950                         callback_urls = os_malloc(len + 1);
00951                         if (callback_urls == NULL) {
00952                                 ret = HTTP_INTERNAL_SERVER_ERROR;
00953                                 goto error;
00954                         }
00955                         os_memcpy(callback_urls, h, len);
00956                         callback_urls[len] = 0;
00957                         continue;
00958                 }
00959                 /* SID is only for renewal */
00960                 match = "SID:";
00961                 match_len = os_strlen(match);
00962                 if (os_strncasecmp(h, match, match_len) == 0) {
00963                         h += match_len;
00964                         while (*h == ' ' || *h == '\t')
00965                                 h++;
00966                         match = "uuid:";
00967                         match_len = os_strlen(match);
00968                         if (os_strncasecmp(h, match, match_len) != 0) {
00969                                 ret = HTTP_BAD_REQUEST;
00970                                 goto error;
00971                         }
00972                         h += match_len;
00973                         while (*h == ' ' || *h == '\t')
00974                                 h++;
00975                         if (uuid_str2bin(h, uuid)) {
00976                                 ret = HTTP_BAD_REQUEST;
00977                                 goto error;
00978                         }
00979                         got_uuid = 1;
00980                         continue;
00981                 }
00982                 /* TIMEOUT is requested timeout, but apparently we can
00983                  * just ignore this.
00984                  */
00985         }
00986 
00987         if (got_uuid) {
00988                 /* renewal */
00989                 if (callback_urls) {
00990                         ret = HTTP_BAD_REQUEST;
00991                         goto error;
00992                 }
00993                 s = subscription_renew(sm, uuid);
00994                 if (s == NULL) {
00995                         ret = HTTP_PRECONDITION_FAILED;
00996                         goto error;
00997                 }
00998         } else if (callback_urls) {
00999                 if (!got_nt) {
01000                         ret = HTTP_PRECONDITION_FAILED;
01001                         goto error;
01002                 }
01003                 s = subscription_start(sm, callback_urls);
01004                 if (s == NULL) {
01005                         ret = HTTP_INTERNAL_SERVER_ERROR;
01006                         goto error;
01007                 }
01008         } else {
01009                 ret = HTTP_PRECONDITION_FAILED;
01010                 goto error;
01011         }
01012 
01013         /* success */
01014         http_put_reply_code(buf, HTTP_OK);
01015         wpabuf_put_str(buf, http_server_hdr);
01016         wpabuf_put_str(buf, http_connection_close);
01017         wpabuf_put_str(buf, "Content-Length: 0\r\n");
01018         wpabuf_put_str(buf, "SID: uuid:");
01019         /* subscription id */
01020         b = wpabuf_put(buf, 0);
01021         uuid_bin2str(s->uuid, b, 80);
01022         wpabuf_put(buf, os_strlen(b));
01023         wpabuf_put_str(buf, "\r\n");
01024         wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC);
01025         http_put_date(buf);
01026         /* And empty line to terminate header: */
01027         wpabuf_put_str(buf, "\r\n");
01028 
01029         os_free(callback_urls);
01030         http_request_send_and_deinit(req, buf);
01031         return;
01032 
01033 error:
01034         /* Per UPnP spec:
01035         * Errors
01036         * Incompatible headers
01037         *   400 Bad Request. If SID header and one of NT or CALLBACK headers
01038         *     are present, the publisher must respond with HTTP error
01039         *     400 Bad Request.
01040         * Missing or invalid CALLBACK
01041         *   412 Precondition Failed. If CALLBACK header is missing or does not
01042         *     contain a valid HTTP URL, the publisher must respond with HTTP
01043         *     error 412 Precondition Failed.
01044         * Invalid NT
01045         *   412 Precondition Failed. If NT header does not equal upnp:event,
01046         *     the publisher must respond with HTTP error 412 Precondition
01047         *     Failed.
01048         * [For resubscription, use 412 if unknown uuid].
01049         * Unable to accept subscription
01050         *   5xx. If a publisher is not able to accept a subscription (such as
01051         *     due to insufficient resources), it must respond with a
01052         *     HTTP 500-series error code.
01053         *   599 Too many subscriptions (not a standard HTTP error)
01054         */
01055         http_put_empty(buf, ret);
01056         http_request_send_and_deinit(req, buf);
01057         os_free(callback_urls);
01058 }
01059 
01060 
01061 /* Given that we have received a header w/ UNSUBSCRIBE, act upon it
01062  *
01063  * Format of UNSUBSCRIBE (case-insensitive):
01064  *
01065  * First line must be:
01066  *      UNSUBSCRIBE /wps_event HTTP/1.1
01067  *
01068  * Our response (if no error) which includes only required lines is:
01069  * HTTP/1.1 200 OK
01070  * Content-Length: 0
01071  *
01072  * Header lines must end with \r\n
01073  * Per RFC 2616, content-length: is not required but connection:close
01074  * would appear to be required (given that we will be closing it!).
01075  */
01076 static void web_connection_parse_unsubscribe(struct upnp_wps_device_sm *sm,
01077                                              struct http_request *req,
01078                                              const char *filename)
01079 {
01080         struct wpabuf *buf;
01081         char *hdr = http_request_get_hdr(req);
01082         char *h;
01083         char *match;
01084         int match_len;
01085         char *end;
01086         u8 uuid[UUID_LEN];
01087         int got_uuid = 0;
01088         struct subscription *s = NULL;
01089         enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
01090 
01091         /* Parse/validate headers */
01092         h = hdr;
01093         /* First line: UNSUBSCRIBE /wps_event HTTP/1.1
01094          * has already been parsed.
01095          */
01096         if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
01097                 ret = HTTP_PRECONDITION_FAILED;
01098                 goto send_msg;
01099         }
01100         wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event");
01101         end = os_strchr(h, '\n');
01102 
01103         for (; end != NULL; h = end + 1) {
01104                 /* Option line by option line */
01105                 h = end + 1;
01106                 end = os_strchr(h, '\n');
01107                 if (end == NULL)
01108                         break; /* no unterminated lines allowed */
01109 
01110                 /* HOST should refer to us */
01111 #if 0
01112                 match = "HOST:";
01113                 match_len = os_strlen(match);
01114                 if (os_strncasecmp(h, match, match_len) == 0) {
01115                         h += match_len;
01116                         while (*h == ' ' || *h == '\t')
01117                                 h++;
01118                         .....
01119                 }
01120 #endif
01121                 /* SID is only for renewal */
01122                 match = "SID:";
01123                 match_len = os_strlen(match);
01124                 if (os_strncasecmp(h, match, match_len) == 0) {
01125                         h += match_len;
01126                         while (*h == ' ' || *h == '\t')
01127                                 h++;
01128                         match = "uuid:";
01129                         match_len = os_strlen(match);
01130                         if (os_strncasecmp(h, match, match_len) != 0) {
01131                                 ret = HTTP_BAD_REQUEST;
01132                                 goto send_msg;
01133                         }
01134                         h += match_len;
01135                         while (*h == ' ' || *h == '\t')
01136                                 h++;
01137                         if (uuid_str2bin(h, uuid)) {
01138                                 ret = HTTP_BAD_REQUEST;
01139                                 goto send_msg;
01140                         }
01141                         got_uuid = 1;
01142                         continue;
01143                 }
01144         }
01145 
01146         if (got_uuid) {
01147                 s = subscription_find(sm, uuid);
01148                 if (s) {
01149                         struct subscr_addr *sa;
01150                         sa = dl_list_first(&s->addr_list, struct subscr_addr,
01151                                            list);
01152                         wpa_printf(MSG_DEBUG, "WPS UPnP: Unsubscribing %p %s",
01153                                    s, (sa && sa->domain_and_port) ?
01154                                    sa->domain_and_port : "-null-");
01155                         dl_list_del(&s->list);
01156                         subscription_destroy(s);
01157                 }
01158         } else {
01159                 wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not "
01160                            "found)");
01161                 ret = HTTP_PRECONDITION_FAILED;
01162                 goto send_msg;
01163         }
01164 
01165         ret = HTTP_OK;
01166 
01167 send_msg:
01168         buf = wpabuf_alloc(200);
01169         if (buf == NULL) {
01170                 http_request_deinit(req);
01171                 return;
01172         }
01173         http_put_empty(buf, ret);
01174         http_request_send_and_deinit(req, buf);
01175 }
01176 
01177 
01178 /* Send error in response to unknown requests */
01179 static void web_connection_unimplemented(struct http_request *req)
01180 {
01181         struct wpabuf *buf;
01182         buf = wpabuf_alloc(200);
01183         if (buf == NULL) {
01184                 http_request_deinit(req);
01185                 return;
01186         }
01187         http_put_empty(buf, HTTP_UNIMPLEMENTED);
01188         http_request_send_and_deinit(req, buf);
01189 }
01190 
01191 
01192 
01193 /* Called when we have gotten an apparently valid http request.
01194  */
01195 static void web_connection_check_data(void *ctx, struct http_request *req)
01196 {
01197         struct upnp_wps_device_sm *sm = ctx;
01198         enum httpread_hdr_type htype = http_request_get_type(req);
01199         char *filename = http_request_get_uri(req);
01200         struct sockaddr_in *cli = http_request_get_cli_addr(req);
01201 
01202         if (!filename) {
01203                 wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
01204                 http_request_deinit(req);
01205                 return;
01206         }
01207         /* Trim leading slashes from filename */
01208         while (*filename == '/')
01209                 filename++;
01210 
01211         wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
01212                    htype, inet_ntoa(cli->sin_addr), htons(cli->sin_port));
01213 
01214         switch (htype) {
01215         case HTTPREAD_HDR_TYPE_GET:
01216                 web_connection_parse_get(sm, req, filename);
01217                 break;
01218         case HTTPREAD_HDR_TYPE_POST:
01219                 web_connection_parse_post(sm, cli, req, filename);
01220                 break;
01221         case HTTPREAD_HDR_TYPE_SUBSCRIBE:
01222                 web_connection_parse_subscribe(sm, req, filename);
01223                 break;
01224         case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
01225                 web_connection_parse_unsubscribe(sm, req, filename);
01226                 break;
01227 
01228                 /* We are not required to support M-POST; just plain
01229                  * POST is supposed to work, so we only support that.
01230                  * If for some reason we need to support M-POST, it is
01231                  * mostly the same as POST, with small differences.
01232                  */
01233         default:
01234                 /* Send 501 for anything else */
01235                 web_connection_unimplemented(req);
01236                 break;
01237         }
01238 }
01239 
01240 
01241 /*
01242  * Listening for web connections
01243  * We have a single TCP listening port, and hand off connections as we get
01244  * them.
01245  */
01246 
01247 void web_listener_stop(struct upnp_wps_device_sm *sm)
01248 {
01249         http_server_deinit(sm->web_srv);
01250         sm->web_srv = NULL;
01251 }
01252 
01253 
01254 int web_listener_start(struct upnp_wps_device_sm *sm)
01255 {
01256         struct in_addr addr;
01257         addr.s_addr = sm->ip_addr;
01258         sm->web_srv = http_server_init(&addr, -1, web_connection_check_data,
01259                                        sm);
01260         if (sm->web_srv == NULL) {
01261                 web_listener_stop(sm);
01262                 return -1;
01263         }
01264         sm->web_port = http_server_get_port(sm->web_srv);
01265 
01266         return 0;
01267 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:36