Home | History | Annotate | Download | only in wps
      1 /*
      2  * UPnP WPS Device - Web connections
      3  * Copyright (c) 2000-2003 Intel Corporation
      4  * Copyright (c) 2006-2007 Sony Corporation
      5  * Copyright (c) 2008-2009 Atheros Communications
      6  * Copyright (c) 2009, Jouni Malinen <j (at) w1.fi>
      7  *
      8  * See wps_upnp.c for more details on licensing and code history.
      9  */
     10 
     11 #include "includes.h"
     12 #include <fcntl.h>
     13 
     14 #include "common.h"
     15 #include "base64.h"
     16 #include "eloop.h"
     17 #include "uuid.h"
     18 #include "httpread.h"
     19 #include "wps_i.h"
     20 #include "wps_upnp.h"
     21 #include "wps_upnp_i.h"
     22 
     23 /***************************************************************************
     24  * Web connections (we serve pages of info about ourselves, handle
     25  * requests, etc. etc.).
     26  **************************************************************************/
     27 
     28 #define WEB_CONNECTION_TIMEOUT_SEC 30   /* Drop web connection after t.o. */
     29 #define WEB_CONNECTION_MAX_READ 8000    /* Max we'll read for TCP request */
     30 #define MAX_WEB_CONNECTIONS 10          /* max simultaneous web connects */
     31 
     32 
     33 static const char *urn_wfawlanconfig =
     34 	"urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
     35 static const char *http_server_hdr =
     36 	"Server: unspecified, UPnP/1.0, unspecified\r\n";
     37 static const char *http_connection_close =
     38 	"Connection: close\r\n";
     39 
     40 /*
     41  * Incoming web connections are recorded in this struct.
     42  * A web connection is a TCP connection to us, the server;
     43  * it is called a "web connection" because we use http and serve
     44  * data that looks like web pages.
     45  * State information is need to track the connection until we figure
     46  * out what they want and what we want to do about it.
     47  */
     48 struct web_connection {
     49 	/* double linked list */
     50 	struct web_connection *next;
     51 	struct web_connection *prev;
     52 	struct upnp_wps_device_sm *sm; /* parent */
     53 	int sd; /* socket to read from */
     54 	struct sockaddr_in cli_addr;
     55 	int sd_registered; /* nonzero if we must cancel registration */
     56 	struct httpread *hread; /* state machine for reading socket */
     57 	int n_rcvd_data; /* how much data read so far */
     58 	int done; /* internal flag, set when we've finished */
     59 };
     60 
     61 
     62 /*
     63  * XML parsing and formatting
     64  *
     65  * XML is a markup language based on unicode; usually (and in our case,
     66  * always!) based on utf-8. utf-8 uses a variable number of bytes per
     67  * character. utf-8 has the advantage that all non-ASCII unicode characters are
     68  * represented by sequences of non-ascii (high bit set) bytes, whereas ASCII
     69  * characters are single ascii bytes, thus we can use typical text processing.
     70  *
     71  * (One other interesting thing about utf-8 is that it is possible to look at
     72  * any random byte and determine if it is the first byte of a character as
     73  * versus a continuation byte).
     74  *
     75  * The base syntax of XML uses a few ASCII punctionation characters; any
     76  * characters that would appear in the payload data are rewritten using
     77  * sequences, e.g., &amp; for ampersand(&) and &lt for left angle bracket (<).
     78  * Five such escapes total (more can be defined but that does not apply to our
     79  * case). Thus we can safely parse for angle brackets etc.
     80  *
     81  * XML describes tree structures of tagged data, with each element beginning
     82  * with an opening tag <label> and ending with a closing tag </label> with
     83  * matching label. (There is also a self-closing tag <label/> which is supposed
     84  * to be equivalent to <label></label>, i.e., no payload, but we are unlikely
     85  * to see it for our purpose).
     86  *
     87  * Actually the opening tags are a little more complicated because they can
     88  * contain "attributes" after the label (delimited by ascii space or tab chars)
     89  * of the form attribute_label="value" or attribute_label='value'; as it turns
     90  * out we do not have to read any of these attributes, just ignore them.
     91  *
     92  * Labels are any sequence of chars other than space, tab, right angle bracket
     93  * (and ?), but may have an inner structure of <namespace><colon><plain_label>.
     94  * As it turns out, we can ignore the namespaces, in fact we can ignore the
     95  * entire tree hierarchy, because the plain labels we are looking for will be
     96  * unique (not in general, but for this application). We do however have to be
     97  * careful to skip over the namespaces.
     98  *
     99  * In generating XML we have to be more careful, but that is easy because
    100  * everything we do is pretty canned. The only real care to take is to escape
    101  * any special chars in our payload.
    102  */
    103 
    104 /**
    105  * xml_next_tag - Advance to next tag
    106  * @in: Input
    107  * @out: OUT: start of tag just after '<'
    108  * @out_tagname: OUT: start of name of tag, skipping namespace
    109  * @end: OUT: one after tag
    110  * Returns: 0 on success, 1 on failure
    111  *
    112  * A tag has form:
    113  *     <left angle bracket><...><right angle bracket>
    114  * Within the angle brackets, there is an optional leading forward slash (which
    115  * makes the tag an ending tag), then an optional leading label (followed by
    116  * colon) and then the tag name itself.
    117  *
    118  * Note that angle brackets present in the original data must have been encoded
    119  * as &lt; and &gt; so they will not trouble us.
    120  */
    121 static int xml_next_tag(char *in, char **out, char **out_tagname,
    122 			char **end)
    123 {
    124 	while (*in && *in != '<')
    125 		in++;
    126 	if (*in != '<')
    127 		return 1;
    128 	*out = ++in;
    129 	if (*in == '/')
    130 		in++;
    131 	*out_tagname = in; /* maybe */
    132 	while (isalnum(*in) || *in == '-')
    133 		in++;
    134 	if (*in == ':')
    135 		*out_tagname = ++in;
    136 	while (*in && *in != '>')
    137 		in++;
    138 	if (*in != '>')
    139 		return 1;
    140 	*end = ++in;
    141 	return 0;
    142 }
    143 
    144 
    145 /* xml_data_encode -- format data for xml file, escaping special characters.
    146  *
    147  * Note that we assume we are using utf8 both as input and as output!
    148  * In utf8, characters may be classed as follows:
    149  *     0xxxxxxx(2) -- 1 byte ascii char
    150  *     11xxxxxx(2) -- 1st byte of multi-byte char w/ unicode value >= 0x80
    151  *         110xxxxx(2) -- 1st byte of 2 byte sequence (5 payload bits here)
    152  *         1110xxxx(2) -- 1st byte of 3 byte sequence (4 payload bits here)
    153  *         11110xxx(2) -- 1st byte of 4 byte sequence (3 payload bits here)
    154  *      10xxxxxx(2) -- extension byte (6 payload bits per byte)
    155  *      Some values implied by the above are however illegal because they
    156  *      do not represent unicode chars or are not the shortest encoding.
    157  * Actually, we can almost entirely ignore the above and just do
    158  * text processing same as for ascii text.
    159  *
    160  * XML is written with arbitrary unicode characters, except that five
    161  * characters have special meaning and so must be escaped where they
    162  * appear in payload data... which we do here.
    163  */
    164 static void xml_data_encode(struct wpabuf *buf, const char *data, int len)
    165 {
    166 	int i;
    167 	for (i = 0; i < len; i++) {
    168 		u8 c = ((u8 *) data)[i];
    169 		if (c == '<') {
    170 			wpabuf_put_str(buf, "&lt;");
    171 			continue;
    172 		}
    173 		if (c == '>') {
    174 			wpabuf_put_str(buf, "&gt;");
    175 			continue;
    176 		}
    177 		if (c == '&') {
    178 			wpabuf_put_str(buf, "&amp;");
    179 			continue;
    180 		}
    181 		if (c == '\'') {
    182 			wpabuf_put_str(buf, "&apos;");
    183 			continue;
    184 		}
    185 		if (c == '"') {
    186 			wpabuf_put_str(buf, "&quot;");
    187 			continue;
    188 		}
    189 		/*
    190 		 * We could try to represent control characters using the
    191 		 * sequence: &#x; where x is replaced by a hex numeral, but not
    192 		 * clear why we would do this.
    193 		 */
    194 		wpabuf_put_u8(buf, c);
    195 	}
    196 }
    197 
    198 
    199 /* xml_add_tagged_data -- format tagged data as a new xml line.
    200  *
    201  * tag must not have any special chars.
    202  * data may have special chars, which are escaped.
    203  */
    204 static void xml_add_tagged_data(struct wpabuf *buf, const char *tag,
    205 				const char *data)
    206 {
    207 	wpabuf_printf(buf, "<%s>", tag);
    208 	xml_data_encode(buf, data, os_strlen(data));
    209 	wpabuf_printf(buf, "</%s>\n", tag);
    210 }
    211 
    212 
    213 /* A POST body looks something like (per upnp spec):
    214  * <?xml version="1.0"?>
    215  * <s:Envelope
    216  *     xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
    217  *     s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    218  *   <s:Body>
    219  *     <u:actionName xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
    220  *       <argumentName>in arg value</argumentName>
    221  *       other in args and their values go here, if any
    222  *     </u:actionName>
    223  *   </s:Body>
    224  * </s:Envelope>
    225  *
    226  * where :
    227  *      s: might be some other namespace name followed by colon
    228  *      u: might be some other namespace name followed by colon
    229  *      actionName will be replaced according to action requested
    230  *      schema following actionName will be WFA scheme instead
    231  *      argumentName will be actual argument name
    232  *      (in arg value) will be actual argument value
    233  */
    234 static int
    235 upnp_get_first_document_item(char *doc, const char *item, char **value)
    236 {
    237 	const char *match = item;
    238 	int match_len = os_strlen(item);
    239 	char *tag;
    240 	char *tagname;
    241 	char *end;
    242 
    243 	*value = NULL;          /* default, bad */
    244 
    245 	/*
    246 	 * This is crude: ignore any possible tag name conflicts and go right
    247 	 * to the first tag of this name. This should be ok for the limited
    248 	 * domain of UPnP messages.
    249 	 */
    250 	for (;;) {
    251 		if (xml_next_tag(doc, &tag, &tagname, &end))
    252 			return 1;
    253 		doc = end;
    254 		if (!os_strncasecmp(tagname, match, match_len) &&
    255 		    *tag != '/' &&
    256 		    (tagname[match_len] == '>' ||
    257 		     !isgraph(tagname[match_len]))) {
    258 			break;
    259 		}
    260 	}
    261 	end = doc;
    262 	while (*end && *end != '<')
    263 		end++;
    264 	*value = os_zalloc(1 + (end - doc));
    265 	if (*value == NULL)
    266 		return 1;
    267 	os_memcpy(*value, doc, end - doc);
    268 	return 0;
    269 }
    270 
    271 
    272 /*
    273  * "Files" that we serve via HTTP. The format of these files is given by
    274  * WFA WPS specifications. Extra white space has been removed to save space.
    275  */
    276 
    277 static const char wps_scpd_xml[] =
    278 "<?xml version=\"1.0\"?>\n"
    279 "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">\n"
    280 "<specVersion><major>1</major><minor>0</minor></specVersion>\n"
    281 "<actionList>\n"
    282 "<action>\n"
    283 "<name>GetDeviceInfo</name>\n"
    284 "<argumentList>\n"
    285 "<argument>\n"
    286 "<name>NewDeviceInfo</name>\n"
    287 "<direction>out</direction>\n"
    288 "<relatedStateVariable>DeviceInfo</relatedStateVariable>\n"
    289 "</argument>\n"
    290 "</argumentList>\n"
    291 "</action>\n"
    292 "<action>\n"
    293 "<name>PutMessage</name>\n"
    294 "<argumentList>\n"
    295 "<argument>\n"
    296 "<name>NewInMessage</name>\n"
    297 "<direction>in</direction>\n"
    298 "<relatedStateVariable>InMessage</relatedStateVariable>\n"
    299 "</argument>\n"
    300 "<argument>\n"
    301 "<name>NewOutMessage</name>\n"
    302 "<direction>out</direction>\n"
    303 "<relatedStateVariable>OutMessage</relatedStateVariable>\n"
    304 "</argument>\n"
    305 "</argumentList>\n"
    306 "</action>\n"
    307 "<action>\n"
    308 "<name>GetAPSettings</name>\n"
    309 "<argumentList>\n"
    310 "<argument>\n"
    311 "<name>NewMessage</name>\n"
    312 "<direction>in</direction>\n"
    313 "<relatedStateVariable>Message</relatedStateVariable>\n"
    314 "</argument>\n"
    315 "<argument>\n"
    316 "<name>NewAPSettings</name>\n"
    317 "<direction>out</direction>\n"
    318 "<relatedStateVariable>APSettings</relatedStateVariable>\n"
    319 "</argument>\n"
    320 "</argumentList>\n"
    321 "</action>\n"
    322 "<action>\n"
    323 "<name>SetAPSettings</name>\n"
    324 "<argumentList>\n"
    325 "<argument>\n"
    326 "<name>APSettings</name>\n"
    327 "<direction>in</direction>\n"
    328 "<relatedStateVariable>APSettings</relatedStateVariable>\n"
    329 "</argument>\n"
    330 "</argumentList>\n"
    331 "</action>\n"
    332 "<action>\n"
    333 "<name>DelAPSettings</name>\n"
    334 "<argumentList>\n"
    335 "<argument>\n"
    336 "<name>NewAPSettings</name>\n"
    337 "<direction>in</direction>\n"
    338 "<relatedStateVariable>APSettings</relatedStateVariable>\n"
    339 "</argument>\n"
    340 "</argumentList>\n"
    341 "</action>\n"
    342 "<action>\n"
    343 "<name>GetSTASettings</name>\n"
    344 "<argumentList>\n"
    345 "<argument>\n"
    346 "<name>NewMessage</name>\n"
    347 "<direction>in</direction>\n"
    348 "<relatedStateVariable>Message</relatedStateVariable>\n"
    349 "</argument>\n"
    350 "<argument>\n"
    351 "<name>NewSTASettings</name>\n"
    352 "<direction>out</direction>\n"
    353 "<relatedStateVariable>STASettings</relatedStateVariable>\n"
    354 "</argument>\n"
    355 "</argumentList>\n"
    356 "</action>\n"
    357 "<action>\n"
    358 "<name>SetSTASettings</name>\n"
    359 "<argumentList>\n"
    360 "<argument>\n"
    361 "<name>NewSTASettings</name>\n"
    362 "<direction>out</direction>\n"
    363 "<relatedStateVariable>STASettings</relatedStateVariable>\n"
    364 "</argument>\n"
    365 "</argumentList>\n"
    366 "</action>\n"
    367 "<action>\n"
    368 "<name>DelSTASettings</name>\n"
    369 "<argumentList>\n"
    370 "<argument>\n"
    371 "<name>NewSTASettings</name>\n"
    372 "<direction>in</direction>\n"
    373 "<relatedStateVariable>STASettings</relatedStateVariable>\n"
    374 "</argument>\n"
    375 "</argumentList>\n"
    376 "</action>\n"
    377 "<action>\n"
    378 "<name>PutWLANResponse</name>\n"
    379 "<argumentList>\n"
    380 "<argument>\n"
    381 "<name>NewMessage</name>\n"
    382 "<direction>in</direction>\n"
    383 "<relatedStateVariable>Message</relatedStateVariable>\n"
    384 "</argument>\n"
    385 "<argument>\n"
    386 "<name>NewWLANEventType</name>\n"
    387 "<direction>in</direction>\n"
    388 "<relatedStateVariable>WLANEventType</relatedStateVariable>\n"
    389 "</argument>\n"
    390 "<argument>\n"
    391 "<name>NewWLANEventMAC</name>\n"
    392 "<direction>in</direction>\n"
    393 "<relatedStateVariable>WLANEventMAC</relatedStateVariable>\n"
    394 "</argument>\n"
    395 "</argumentList>\n"
    396 "</action>\n"
    397 "<action>\n"
    398 "<name>SetSelectedRegistrar</name>\n"
    399 "<argumentList>\n"
    400 "<argument>\n"
    401 "<name>NewMessage</name>\n"
    402 "<direction>in</direction>\n"
    403 "<relatedStateVariable>Message</relatedStateVariable>\n"
    404 "</argument>\n"
    405 "</argumentList>\n"
    406 "</action>\n"
    407 "<action>\n"
    408 "<name>RebootAP</name>\n"
    409 "<argumentList>\n"
    410 "<argument>\n"
    411 "<name>NewAPSettings</name>\n"
    412 "<direction>in</direction>\n"
    413 "<relatedStateVariable>APSettings</relatedStateVariable>\n"
    414 "</argument>\n"
    415 "</argumentList>\n"
    416 "</action>\n"
    417 "<action>\n"
    418 "<name>ResetAP</name>\n"
    419 "<argumentList>\n"
    420 "<argument>\n"
    421 "<name>NewMessage</name>\n"
    422 "<direction>in</direction>\n"
    423 "<relatedStateVariable>Message</relatedStateVariable>\n"
    424 "</argument>\n"
    425 "</argumentList>\n"
    426 "</action>\n"
    427 "<action>\n"
    428 "<name>RebootSTA</name>\n"
    429 "<argumentList>\n"
    430 "<argument>\n"
    431 "<name>NewSTASettings</name>\n"
    432 "<direction>in</direction>\n"
    433 "<relatedStateVariable>APSettings</relatedStateVariable>\n"
    434 "</argument>\n"
    435 "</argumentList>\n"
    436 "</action>\n"
    437 "<action>\n"
    438 "<name>ResetSTA</name>\n"
    439 "<argumentList>\n"
    440 "<argument>\n"
    441 "<name>NewMessage</name>\n"
    442 "<direction>in</direction>\n"
    443 "<relatedStateVariable>Message</relatedStateVariable>\n"
    444 "</argument>\n"
    445 "</argumentList>\n"
    446 "</action>\n"
    447 "</actionList>\n"
    448 "<serviceStateTable>\n"
    449 "<stateVariable sendEvents=\"no\">\n"
    450 "<name>Message</name>\n"
    451 "<dataType>bin.base64</dataType>\n"
    452 "</stateVariable>\n"
    453 "<stateVariable sendEvents=\"no\">\n"
    454 "<name>InMessage</name>\n"
    455 "<dataType>bin.base64</dataType>\n"
    456 "</stateVariable>\n"
    457 "<stateVariable sendEvents=\"no\">\n"
    458 "<name>OutMessage</name>\n"
    459 "<dataType>bin.base64</dataType>\n"
    460 "</stateVariable>\n"
    461 "<stateVariable sendEvents=\"no\">\n"
    462 "<name>DeviceInfo</name>\n"
    463 "<dataType>bin.base64</dataType>\n"
    464 "</stateVariable>\n"
    465 "<stateVariable sendEvents=\"no\">\n"
    466 "<name>APSettings</name>\n"
    467 "<dataType>bin.base64</dataType>\n"
    468 "</stateVariable>\n"
    469 "<stateVariable sendEvents=\"yes\">\n"
    470 "<name>APStatus</name>\n"
    471 "<dataType>ui1</dataType>\n"
    472 "</stateVariable>\n"
    473 "<stateVariable sendEvents=\"no\">\n"
    474 "<name>STASettings</name>\n"
    475 "<dataType>bin.base64</dataType>\n"
    476 "</stateVariable>\n"
    477 "<stateVariable sendEvents=\"yes\">\n"
    478 "<name>STAStatus</name>\n"
    479 "<dataType>ui1</dataType>\n"
    480 "</stateVariable>\n"
    481 "<stateVariable sendEvents=\"yes\">\n"
    482 "<name>WLANEvent</name>\n"
    483 "<dataType>bin.base64</dataType>\n"
    484 "</stateVariable>\n"
    485 "<stateVariable sendEvents=\"no\">\n"
    486 "<name>WLANEventType</name>\n"
    487 "<dataType>ui1</dataType>\n"
    488 "</stateVariable>\n"
    489 "<stateVariable sendEvents=\"no\">\n"
    490 "<name>WLANEventMAC</name>\n"
    491 "<dataType>string</dataType>\n"
    492 "</stateVariable>\n"
    493 "<stateVariable sendEvents=\"no\">\n"
    494 "<name>WLANResponse</name>\n"
    495 "<dataType>bin.base64</dataType>\n"
    496 "</stateVariable>\n"
    497 "</serviceStateTable>\n"
    498 "</scpd>\n"
    499 ;
    500 
    501 
    502 static const char *wps_device_xml_prefix =
    503 	"<?xml version=\"1.0\"?>\n"
    504 	"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
    505 	"<specVersion>\n"
    506 	"<major>1</major>\n"
    507 	"<minor>0</minor>\n"
    508 	"</specVersion>\n"
    509 	"<device>\n"
    510 	"<deviceType>urn:schemas-wifialliance-org:device:WFADevice:1"
    511 	"</deviceType>\n";
    512 
    513 static const char *wps_device_xml_postfix =
    514 	"<serviceList>\n"
    515 	"<service>\n"
    516 	"<serviceType>urn:schemas-wifialliance-org:service:WFAWLANConfig:1"
    517 	"</serviceType>\n"
    518 	"<serviceId>urn:wifialliance-org:serviceId:WFAWLANConfig1</serviceId>"
    519 	"\n"
    520 	"<SCPDURL>" UPNP_WPS_SCPD_XML_FILE "</SCPDURL>\n"
    521 	"<controlURL>" UPNP_WPS_DEVICE_CONTROL_FILE "</controlURL>\n"
    522 	"<eventSubURL>" UPNP_WPS_DEVICE_EVENT_FILE "</eventSubURL>\n"
    523 	"</service>\n"
    524 	"</serviceList>\n"
    525 	"</device>\n"
    526 	"</root>\n";
    527 
    528 
    529 /* format_wps_device_xml -- produce content of "file" wps_device.xml
    530  * (UPNP_WPS_DEVICE_XML_FILE)
    531  */
    532 static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
    533 				  struct wpabuf *buf)
    534 {
    535 	const char *s;
    536 	char uuid_string[80];
    537 
    538 	wpabuf_put_str(buf, wps_device_xml_prefix);
    539 
    540 	/*
    541 	 * Add required fields with default values if not configured. Add
    542 	 * optional and recommended fields only if configured.
    543 	 */
    544 	s = sm->wps->friendly_name;
    545 	s = ((s && *s) ? s : "WPS Access Point");
    546 	xml_add_tagged_data(buf, "friendlyName", s);
    547 
    548 	s = sm->wps->dev.manufacturer;
    549 	s = ((s && *s) ? s : "");
    550 	xml_add_tagged_data(buf, "manufacturer", s);
    551 
    552 	if (sm->wps->manufacturer_url)
    553 		xml_add_tagged_data(buf, "manufacturerURL",
    554 				    sm->wps->manufacturer_url);
    555 
    556 	if (sm->wps->model_description)
    557 		xml_add_tagged_data(buf, "modelDescription",
    558 				    sm->wps->model_description);
    559 
    560 	s = sm->wps->dev.model_name;
    561 	s = ((s && *s) ? s : "");
    562 	xml_add_tagged_data(buf, "modelName", s);
    563 
    564 	if (sm->wps->dev.model_number)
    565 		xml_add_tagged_data(buf, "modelNumber",
    566 				    sm->wps->dev.model_number);
    567 
    568 	if (sm->wps->model_url)
    569 		xml_add_tagged_data(buf, "modelURL", sm->wps->model_url);
    570 
    571 	if (sm->wps->dev.serial_number)
    572 		xml_add_tagged_data(buf, "serialNumber",
    573 				    sm->wps->dev.serial_number);
    574 
    575 	uuid_bin2str(sm->wps->uuid, uuid_string, sizeof(uuid_string));
    576 	s = uuid_string;
    577 	/* Need "uuid:" prefix, thus we can't use xml_add_tagged_data()
    578 	 * easily...
    579 	 */
    580 	wpabuf_put_str(buf, "<UDN>uuid:");
    581 	xml_data_encode(buf, s, os_strlen(s));
    582 	wpabuf_put_str(buf, "</UDN>\n");
    583 
    584 	if (sm->wps->upc)
    585 		xml_add_tagged_data(buf, "UPC", sm->wps->upc);
    586 
    587 	wpabuf_put_str(buf, wps_device_xml_postfix);
    588 }
    589 
    590 
    591 void web_connection_stop(struct web_connection *c)
    592 {
    593 	struct upnp_wps_device_sm *sm = c->sm;
    594 
    595 	httpread_destroy(c->hread);
    596 	c->hread = NULL;
    597 	close(c->sd);
    598 	c->sd = -1;
    599 	if (c->next == c) {
    600 		sm->web_connections = NULL;
    601 	} else {
    602 		if (sm->web_connections == c)
    603 			sm->web_connections = c->next;
    604 		c->next->prev = c->prev;
    605 		c->prev->next = c->next;
    606 	}
    607 	os_free(c);
    608 	sm->n_web_connections--;
    609 }
    610 
    611 
    612 static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code)
    613 {
    614 	wpabuf_put_str(buf, "HTTP/1.1 ");
    615 	switch (code) {
    616 	case HTTP_OK:
    617 		wpabuf_put_str(buf, "200 OK\r\n");
    618 		break;
    619 	case HTTP_BAD_REQUEST:
    620 		wpabuf_put_str(buf, "400 Bad request\r\n");
    621 		break;
    622 	case HTTP_PRECONDITION_FAILED:
    623 		wpabuf_put_str(buf, "412 Precondition failed\r\n");
    624 		break;
    625 	case HTTP_UNIMPLEMENTED:
    626 		wpabuf_put_str(buf, "501 Unimplemented\r\n");
    627 		break;
    628 	case HTTP_INTERNAL_SERVER_ERROR:
    629 	default:
    630 		wpabuf_put_str(buf, "500 Internal server error\r\n");
    631 		break;
    632 	}
    633 }
    634 
    635 
    636 static void http_put_date(struct wpabuf *buf)
    637 {
    638 	wpabuf_put_str(buf, "Date: ");
    639 	format_date(buf);
    640 	wpabuf_put_str(buf, "\r\n");
    641 }
    642 
    643 
    644 static void http_put_empty(struct wpabuf *buf, enum http_reply_code code)
    645 {
    646 	http_put_reply_code(buf, code);
    647 	wpabuf_put_str(buf, http_server_hdr);
    648 	wpabuf_put_str(buf, http_connection_close);
    649 	wpabuf_put_str(buf, "Content-Length: 0\r\n"
    650 		       "\r\n");
    651 }
    652 
    653 
    654 /* Given that we have received a header w/ GET, act upon it
    655  *
    656  * Format of GET (case-insensitive):
    657  *
    658  * First line must be:
    659  *      GET /<file> HTTP/1.1
    660  * Since we don't do anything fancy we just ignore other lines.
    661  *
    662  * Our response (if no error) which includes only required lines is:
    663  * HTTP/1.1 200 OK
    664  * Connection: close
    665  * Content-Type: text/xml
    666  * Date: <rfc1123-date>
    667  *
    668  * Header lines must end with \r\n
    669  * Per RFC 2616, content-length: is not required but connection:close
    670  * would appear to be required (given that we will be closing it!).
    671  */
    672 static void web_connection_parse_get(struct web_connection *c, char *filename)
    673 {
    674 	struct upnp_wps_device_sm *sm = c->sm;
    675 	struct wpabuf *buf; /* output buffer, allocated */
    676 	char *put_length_here;
    677 	char *body_start;
    678 	enum {
    679 		GET_DEVICE_XML_FILE,
    680 		GET_SCPD_XML_FILE
    681 	} req;
    682 	size_t extra_len = 0;
    683 	int body_length;
    684 	char len_buf[10];
    685 
    686 	/*
    687 	 * It is not required that filenames be case insensitive but it is
    688 	 * allowed and cannot hurt here.
    689 	 */
    690 	if (filename == NULL)
    691 		filename = "(null)"; /* just in case */
    692 	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) {
    693 		wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML");
    694 		req = GET_DEVICE_XML_FILE;
    695 		extra_len = 3000;
    696 		if (sm->wps->friendly_name)
    697 			extra_len += os_strlen(sm->wps->friendly_name);
    698 		if (sm->wps->manufacturer_url)
    699 			extra_len += os_strlen(sm->wps->manufacturer_url);
    700 		if (sm->wps->model_description)
    701 			extra_len += os_strlen(sm->wps->model_description);
    702 		if (sm->wps->model_url)
    703 			extra_len += os_strlen(sm->wps->model_url);
    704 		if (sm->wps->upc)
    705 			extra_len += os_strlen(sm->wps->upc);
    706 	} else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) {
    707 		wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML");
    708 		req = GET_SCPD_XML_FILE;
    709 		extra_len = os_strlen(wps_scpd_xml);
    710 	} else {
    711 		/* File not found */
    712 		wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s",
    713 			   filename);
    714 		buf = wpabuf_alloc(200);
    715 		if (buf == NULL)
    716 			return;
    717 		wpabuf_put_str(buf,
    718 			       "HTTP/1.1 404 Not Found\r\n"
    719 			       "Connection: close\r\n");
    720 
    721 		http_put_date(buf);
    722 
    723 		/* terminating empty line */
    724 		wpabuf_put_str(buf, "\r\n");
    725 
    726 		goto send_buf;
    727 	}
    728 
    729 	buf = wpabuf_alloc(1000 + extra_len);
    730 	if (buf == NULL)
    731 		return;
    732 
    733 	wpabuf_put_str(buf,
    734 		       "HTTP/1.1 200 OK\r\n"
    735 		       "Content-Type: text/xml; charset=\"utf-8\"\r\n");
    736 	wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n");
    737 	wpabuf_put_str(buf, "Connection: close\r\n");
    738 	wpabuf_put_str(buf, "Content-Length: ");
    739 	/*
    740 	 * We will paste the length in later, leaving some extra whitespace.
    741 	 * HTTP code is supposed to be tolerant of extra whitespace.
    742 	 */
    743 	put_length_here = wpabuf_put(buf, 0);
    744 	wpabuf_put_str(buf, "        \r\n");
    745 
    746 	http_put_date(buf);
    747 
    748 	/* terminating empty line */
    749 	wpabuf_put_str(buf, "\r\n");
    750 
    751 	body_start = wpabuf_put(buf, 0);
    752 
    753 	switch (req) {
    754 	case GET_DEVICE_XML_FILE:
    755 		format_wps_device_xml(sm, buf);
    756 		break;
    757 	case GET_SCPD_XML_FILE:
    758 		wpabuf_put_str(buf, wps_scpd_xml);
    759 		break;
    760 	}
    761 
    762 	/* Now patch in the content length at the end */
    763 	body_length = (char *) wpabuf_put(buf, 0) - body_start;
    764 	os_snprintf(len_buf, 10, "%d", body_length);
    765 	os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
    766 
    767 send_buf:
    768 	send_wpabuf(c->sd, buf);
    769 	wpabuf_free(buf);
    770 }
    771 
    772 
    773 static struct wpabuf * web_get_item(char *data, const char *name,
    774 				    enum http_reply_code *ret)
    775 {
    776 	char *msg;
    777 	struct wpabuf *buf;
    778 	unsigned char *decoded;
    779 	size_t len;
    780 
    781 	if (upnp_get_first_document_item(data, name, &msg)) {
    782 		*ret = UPNP_ARG_VALUE_INVALID;
    783 		return NULL;
    784 	}
    785 
    786 	decoded = base64_decode((unsigned char *) msg, os_strlen(msg), &len);
    787 	os_free(msg);
    788 	if (decoded == NULL) {
    789 		*ret = UPNP_OUT_OF_MEMORY;
    790 		return NULL;
    791 	}
    792 
    793 	buf = wpabuf_alloc_ext_data(decoded, len);
    794 	if (buf == NULL) {
    795 		os_free(decoded);
    796 		*ret = UPNP_OUT_OF_MEMORY;
    797 		return NULL;
    798 	}
    799 	return buf;
    800 }
    801 
    802 
    803 static enum http_reply_code
    804 web_process_get_device_info(struct upnp_wps_device_sm *sm,
    805 			    struct wpabuf **reply, const char **replyname)
    806 {
    807 	static const char *name = "NewDeviceInfo";
    808 
    809 	wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
    810 	if (sm->ctx->rx_req_get_device_info == NULL)
    811 		return HTTP_INTERNAL_SERVER_ERROR;
    812 	*reply = sm->ctx->rx_req_get_device_info(sm->priv, &sm->peer);
    813 	if (*reply == NULL) {
    814 		wpa_printf(MSG_INFO, "WPS UPnP: Failed to get DeviceInfo");
    815 		return HTTP_INTERNAL_SERVER_ERROR;
    816 	}
    817 	*replyname = name;
    818 	return HTTP_OK;
    819 }
    820 
    821 
    822 static enum http_reply_code
    823 web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
    824 			struct wpabuf **reply, const char **replyname)
    825 {
    826 	struct wpabuf *msg;
    827 	static const char *name = "NewOutMessage";
    828 	enum http_reply_code ret;
    829 
    830 	/*
    831 	 * PutMessage is used by external UPnP-based Registrar to perform WPS
    832 	 * operation with the access point itself; as compared with
    833 	 * PutWLANResponse which is for proxying.
    834 	 */
    835 	wpa_printf(MSG_DEBUG, "WPS UPnP: PutMessage");
    836 	if (sm->ctx->rx_req_put_message == NULL)
    837 		return HTTP_INTERNAL_SERVER_ERROR;
    838 	msg = web_get_item(data, "NewInMessage", &ret);
    839 	if (msg == NULL)
    840 		return ret;
    841 	*reply = sm->ctx->rx_req_put_message(sm->priv, &sm->peer, msg);
    842 	wpabuf_free(msg);
    843 	if (*reply == NULL)
    844 		return HTTP_INTERNAL_SERVER_ERROR;
    845 	*replyname = name;
    846 	return HTTP_OK;
    847 }
    848 
    849 
    850 static enum http_reply_code
    851 web_process_get_ap_settings(struct upnp_wps_device_sm *sm, char *data,
    852 			    struct wpabuf **reply, const char **replyname)
    853 {
    854 	struct wpabuf *msg;
    855 	static const char *name = "NewAPSettings";
    856 	enum http_reply_code ret;
    857 
    858 	wpa_printf(MSG_DEBUG, "WPS UPnP: GetAPSettings");
    859 	if (sm->ctx->rx_req_get_ap_settings == NULL)
    860 		return HTTP_INTERNAL_SERVER_ERROR;
    861 	msg = web_get_item(data, "NewMessage", &ret);
    862 	if (msg == NULL)
    863 		return ret;
    864 	*reply = sm->ctx->rx_req_get_ap_settings(sm->priv, msg);
    865 	wpabuf_free(msg);
    866 	if (*reply == NULL)
    867 		return HTTP_INTERNAL_SERVER_ERROR;
    868 	*replyname = name;
    869 	return HTTP_OK;
    870 }
    871 
    872 
    873 static enum http_reply_code
    874 web_process_set_ap_settings(struct upnp_wps_device_sm *sm, char *data,
    875 			    struct wpabuf **reply, const char **replyname)
    876 {
    877 	struct wpabuf *msg;
    878 	enum http_reply_code ret;
    879 
    880 	wpa_printf(MSG_DEBUG, "WPS UPnP: SetAPSettings");
    881 	msg = web_get_item(data, "NewAPSettings", &ret);
    882 	if (msg == NULL)
    883 		return ret;
    884 	if (!sm->ctx->rx_req_set_ap_settings ||
    885 	    sm->ctx->rx_req_set_ap_settings(sm->priv, msg)) {
    886 		wpabuf_free(msg);
    887 		return HTTP_INTERNAL_SERVER_ERROR;
    888 	}
    889 	wpabuf_free(msg);
    890 	*replyname = NULL;
    891 	*reply = NULL;
    892 	return HTTP_OK;
    893 }
    894 
    895 
    896 static enum http_reply_code
    897 web_process_del_ap_settings(struct upnp_wps_device_sm *sm, char *data,
    898 			    struct wpabuf **reply, const char **replyname)
    899 {
    900 	struct wpabuf *msg;
    901 	enum http_reply_code ret;
    902 
    903 	wpa_printf(MSG_DEBUG, "WPS UPnP: DelAPSettings");
    904 	msg = web_get_item(data, "NewAPSettings", &ret);
    905 	if (msg == NULL)
    906 		return ret;
    907 	if (!sm->ctx->rx_req_del_ap_settings ||
    908 	    sm->ctx->rx_req_del_ap_settings(sm->priv, msg)) {
    909 		wpabuf_free(msg);
    910 		return HTTP_INTERNAL_SERVER_ERROR;
    911 	}
    912 	wpabuf_free(msg);
    913 	*replyname = NULL;
    914 	*reply = NULL;
    915 	return HTTP_OK;
    916 }
    917 
    918 
    919 static enum http_reply_code
    920 web_process_get_sta_settings(struct upnp_wps_device_sm *sm, char *data,
    921 			     struct wpabuf **reply, const char **replyname)
    922 {
    923 	struct wpabuf *msg;
    924 	static const char *name = "NewSTASettings";
    925 	enum http_reply_code ret;
    926 
    927 	wpa_printf(MSG_DEBUG, "WPS UPnP: GetSTASettings");
    928 	if (sm->ctx->rx_req_get_sta_settings == NULL)
    929 		return HTTP_INTERNAL_SERVER_ERROR;
    930 	msg = web_get_item(data, "NewMessage", &ret);
    931 	if (msg == NULL)
    932 		return ret;
    933 	*reply = sm->ctx->rx_req_get_sta_settings(sm->priv, msg);
    934 	wpabuf_free(msg);
    935 	if (*reply == NULL)
    936 		return HTTP_INTERNAL_SERVER_ERROR;
    937 	*replyname = name;
    938 	return HTTP_OK;
    939 }
    940 
    941 
    942 static enum http_reply_code
    943 web_process_set_sta_settings(struct upnp_wps_device_sm *sm, char *data,
    944 			     struct wpabuf **reply, const char **replyname)
    945 {
    946 	struct wpabuf *msg;
    947 	enum http_reply_code ret;
    948 
    949 	wpa_printf(MSG_DEBUG, "WPS UPnP: SetSTASettings");
    950 	msg = web_get_item(data, "NewSTASettings", &ret);
    951 	if (msg == NULL)
    952 		return ret;
    953 	if (!sm->ctx->rx_req_set_sta_settings ||
    954 	    sm->ctx->rx_req_set_sta_settings(sm->priv, msg)) {
    955 		wpabuf_free(msg);
    956 		return HTTP_INTERNAL_SERVER_ERROR;
    957 	}
    958 	wpabuf_free(msg);
    959 	*replyname = NULL;
    960 	*reply = NULL;
    961 	return HTTP_OK;
    962 }
    963 
    964 
    965 static enum http_reply_code
    966 web_process_del_sta_settings(struct upnp_wps_device_sm *sm, char *data,
    967 			     struct wpabuf **reply, const char **replyname)
    968 {
    969 	struct wpabuf *msg;
    970 	enum http_reply_code ret;
    971 
    972 	wpa_printf(MSG_DEBUG, "WPS UPnP: DelSTASettings");
    973 	msg = web_get_item(data, "NewSTASettings", &ret);
    974 	if (msg == NULL)
    975 		return ret;
    976 	if (!sm->ctx->rx_req_del_sta_settings ||
    977 	    sm->ctx->rx_req_del_sta_settings(sm->priv, msg)) {
    978 		wpabuf_free(msg);
    979 		return HTTP_INTERNAL_SERVER_ERROR;
    980 	}
    981 	wpabuf_free(msg);
    982 	*replyname = NULL;
    983 	*reply = NULL;
    984 	return HTTP_OK;
    985 }
    986 
    987 
    988 static enum http_reply_code
    989 web_process_put_wlan_response(struct upnp_wps_device_sm *sm, char *data,
    990 			      struct wpabuf **reply, const char **replyname)
    991 {
    992 	struct wpabuf *msg;
    993 	enum http_reply_code ret;
    994 	u8 macaddr[ETH_ALEN];
    995 	int ev_type;
    996 	int type;
    997 	char *val;
    998 
    999 	/*
   1000 	 * External UPnP-based Registrar is passing us a message to be proxied
   1001 	 * over to a Wi-Fi -based client of ours.
   1002 	 */
   1003 
   1004 	wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse");
   1005 	msg = web_get_item(data, "NewMessage", &ret);
   1006 	if (msg == NULL)
   1007 		return ret;
   1008 	if (upnp_get_first_document_item(data, "NewWLANEventType", &val)) {
   1009 		wpabuf_free(msg);
   1010 		return UPNP_ARG_VALUE_INVALID;
   1011 	}
   1012 	ev_type = atol(val);
   1013 	os_free(val);
   1014 	val = NULL;
   1015 	if (upnp_get_first_document_item(data, "NewWLANEventMAC", &val) ||
   1016 	    hwaddr_aton(val, macaddr)) {
   1017 		wpabuf_free(msg);
   1018 		os_free(val);
   1019 		return UPNP_ARG_VALUE_INVALID;
   1020 	}
   1021 	os_free(val);
   1022 	if (ev_type == UPNP_WPS_WLANEVENT_TYPE_EAP) {
   1023 		struct wps_parse_attr attr;
   1024 		if (wps_parse_msg(msg, &attr) < 0 ||
   1025 		    attr.msg_type == NULL)
   1026 			type = -1;
   1027 		else
   1028 			type = *attr.msg_type;
   1029 		wpa_printf(MSG_DEBUG, "WPS UPnP: Message Type %d", type);
   1030 	} else
   1031 		type = -1;
   1032 	if (!sm->ctx->rx_req_put_wlan_response ||
   1033 	    sm->ctx->rx_req_put_wlan_response(sm->priv, ev_type, macaddr, msg,
   1034 					      type)) {
   1035 		wpa_printf(MSG_INFO, "WPS UPnP: Fail: sm->ctx->"
   1036 			   "rx_req_put_wlan_response");
   1037 		wpabuf_free(msg);
   1038 		return HTTP_INTERNAL_SERVER_ERROR;
   1039 	}
   1040 	wpabuf_free(msg);
   1041 	*replyname = NULL;
   1042 	*reply = NULL;
   1043 	return HTTP_OK;
   1044 }
   1045 
   1046 
   1047 static enum http_reply_code
   1048 web_process_set_selected_registrar(struct upnp_wps_device_sm *sm, char *data,
   1049 				   struct wpabuf **reply,
   1050 				   const char **replyname)
   1051 {
   1052 	struct wpabuf *msg;
   1053 	enum http_reply_code ret;
   1054 
   1055 	wpa_printf(MSG_DEBUG, "WPS UPnP: SetSelectedRegistrar");
   1056 	msg = web_get_item(data, "NewMessage", &ret);
   1057 	if (msg == NULL)
   1058 		return ret;
   1059 	if (!sm->ctx->rx_req_set_selected_registrar ||
   1060 	    sm->ctx->rx_req_set_selected_registrar(sm->priv, msg)) {
   1061 		wpabuf_free(msg);
   1062 		return HTTP_INTERNAL_SERVER_ERROR;
   1063 	}
   1064 	wpabuf_free(msg);
   1065 	*replyname = NULL;
   1066 	*reply = NULL;
   1067 	return HTTP_OK;
   1068 }
   1069 
   1070 
   1071 static enum http_reply_code
   1072 web_process_reboot_ap(struct upnp_wps_device_sm *sm, char *data,
   1073 		      struct wpabuf **reply, const char **replyname)
   1074 {
   1075 	struct wpabuf *msg;
   1076 	enum http_reply_code ret;
   1077 
   1078 	wpa_printf(MSG_DEBUG, "WPS UPnP: RebootAP");
   1079 	msg = web_get_item(data, "NewAPSettings", &ret);
   1080 	if (msg == NULL)
   1081 		return ret;
   1082 	if (!sm->ctx->rx_req_reboot_ap ||
   1083 	    sm->ctx->rx_req_reboot_ap(sm->priv, msg)) {
   1084 		wpabuf_free(msg);
   1085 		return HTTP_INTERNAL_SERVER_ERROR;
   1086 	}
   1087 	wpabuf_free(msg);
   1088 	*replyname = NULL;
   1089 	*reply = NULL;
   1090 	return HTTP_OK;
   1091 }
   1092 
   1093 
   1094 static enum http_reply_code
   1095 web_process_reset_ap(struct upnp_wps_device_sm *sm, char *data,
   1096 		     struct wpabuf **reply, const char **replyname)
   1097 {
   1098 	struct wpabuf *msg;
   1099 	enum http_reply_code ret;
   1100 
   1101 	wpa_printf(MSG_DEBUG, "WPS UPnP: ResetAP");
   1102 	msg = web_get_item(data, "NewMessage", &ret);
   1103 	if (msg == NULL)
   1104 		return ret;
   1105 	if (!sm->ctx->rx_req_reset_ap ||
   1106 	    sm->ctx->rx_req_reset_ap(sm->priv, msg)) {
   1107 		wpabuf_free(msg);
   1108 		return HTTP_INTERNAL_SERVER_ERROR;
   1109 	}
   1110 	wpabuf_free(msg);
   1111 	*replyname = NULL;
   1112 	*reply = NULL;
   1113 	return HTTP_OK;
   1114 }
   1115 
   1116 
   1117 static enum http_reply_code
   1118 web_process_reboot_sta(struct upnp_wps_device_sm *sm, char *data,
   1119 		       struct wpabuf **reply, const char **replyname)
   1120 {
   1121 	struct wpabuf *msg;
   1122 	enum http_reply_code ret;
   1123 
   1124 	wpa_printf(MSG_DEBUG, "WPS UPnP: RebootSTA");
   1125 	msg = web_get_item(data, "NewSTASettings", &ret);
   1126 	if (msg == NULL)
   1127 		return ret;
   1128 	if (!sm->ctx->rx_req_reboot_sta ||
   1129 	    sm->ctx->rx_req_reboot_sta(sm->priv, msg)) {
   1130 		wpabuf_free(msg);
   1131 		return HTTP_INTERNAL_SERVER_ERROR;
   1132 	}
   1133 	wpabuf_free(msg);
   1134 	*replyname = NULL;
   1135 	*reply = NULL;
   1136 	return HTTP_OK;
   1137 }
   1138 
   1139 
   1140 static enum http_reply_code
   1141 web_process_reset_sta(struct upnp_wps_device_sm *sm, char *data,
   1142 		      struct wpabuf **reply, const char **replyname)
   1143 {
   1144 	struct wpabuf *msg;
   1145 	enum http_reply_code ret;
   1146 
   1147 	wpa_printf(MSG_DEBUG, "WPS UPnP: ResetSTA");
   1148 	msg = web_get_item(data, "NewMessage", &ret);
   1149 	if (msg == NULL)
   1150 		return ret;
   1151 	if (!sm->ctx->rx_req_reset_sta ||
   1152 	    sm->ctx->rx_req_reset_sta(sm->priv, msg)) {
   1153 		wpabuf_free(msg);
   1154 		return HTTP_INTERNAL_SERVER_ERROR;
   1155 	}
   1156 	wpabuf_free(msg);
   1157 	*replyname = NULL;
   1158 	*reply = NULL;
   1159 	return HTTP_OK;
   1160 }
   1161 
   1162 
   1163 static const char *soap_prefix =
   1164 	"<?xml version=\"1.0\"?>\n"
   1165 	"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
   1166 	"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
   1167 	"<s:Body>\n";
   1168 static const char *soap_postfix =
   1169 	"</s:Body>\n</s:Envelope>\n";
   1170 
   1171 static const char *soap_error_prefix =
   1172 	"<s:Fault>\n"
   1173 	"<faultcode>s:Client</faultcode>\n"
   1174 	"<faultstring>UPnPError</faultstring>\n"
   1175 	"<detail>\n"
   1176 	"<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n";
   1177 static const char *soap_error_postfix =
   1178 	"<errorDescription>Error</errorDescription>\n"
   1179 	"</UPnPError>\n"
   1180 	"</detail>\n"
   1181 	"</s:Fault>\n";
   1182 
   1183 static void web_connection_send_reply(struct web_connection *c,
   1184 				      enum http_reply_code ret,
   1185 				      const char *action, int action_len,
   1186 				      const struct wpabuf *reply,
   1187 				      const char *replyname)
   1188 {
   1189 	struct wpabuf *buf;
   1190 	char *replydata;
   1191 	char *put_length_here = NULL;
   1192 	char *body_start = NULL;
   1193 
   1194 	if (reply) {
   1195 		size_t len;
   1196 		replydata = (char *) base64_encode(wpabuf_head(reply),
   1197 						   wpabuf_len(reply), &len);
   1198 	} else
   1199 		replydata = NULL;
   1200 
   1201 	/* Parameters of the response:
   1202 	 *      action(action_len) -- action we are responding to
   1203 	 *      replyname -- a name we need for the reply
   1204 	 *      replydata -- NULL or null-terminated string
   1205 	 */
   1206 	buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) +
   1207 			   (action_len > 0 ? action_len * 2 : 0));
   1208 	if (buf == NULL) {
   1209 		wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to "
   1210 			   "POST");
   1211 		wpabuf_free(buf);
   1212 		os_free(replydata);
   1213 		return;
   1214 	}
   1215 
   1216 	/*
   1217 	 * Assuming we will be successful, put in the output header first.
   1218 	 * Note: we do not keep connections alive (and httpread does
   1219 	 * not support it)... therefore we must have Connection: close.
   1220 	 */
   1221 	if (ret == HTTP_OK) {
   1222 		wpabuf_put_str(buf,
   1223 			       "HTTP/1.1 200 OK\r\n"
   1224 			       "Content-Type: text/xml; "
   1225 			       "charset=\"utf-8\"\r\n");
   1226 	} else {
   1227 		wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret);
   1228 	}
   1229 	wpabuf_put_str(buf, http_connection_close);
   1230 
   1231 	wpabuf_put_str(buf, "Content-Length: ");
   1232 	/*
   1233 	 * We will paste the length in later, leaving some extra whitespace.
   1234 	 * HTTP code is supposed to be tolerant of extra whitespace.
   1235 	 */
   1236 	put_length_here = wpabuf_put(buf, 0);
   1237 	wpabuf_put_str(buf, "        \r\n");
   1238 
   1239 	http_put_date(buf);
   1240 
   1241 	/* terminating empty line */
   1242 	wpabuf_put_str(buf, "\r\n");
   1243 
   1244 	body_start = wpabuf_put(buf, 0);
   1245 
   1246 	if (ret == HTTP_OK) {
   1247 		wpabuf_put_str(buf, soap_prefix);
   1248 		wpabuf_put_str(buf, "<u:");
   1249 		wpabuf_put_data(buf, action, action_len);
   1250 		wpabuf_put_str(buf, "Response xmlns:u=\"");
   1251 		wpabuf_put_str(buf, urn_wfawlanconfig);
   1252 		wpabuf_put_str(buf, "\">\n");
   1253 		if (replydata && replyname) {
   1254 			/* TODO: might possibly need to escape part of reply
   1255 			 * data? ...
   1256 			 * probably not, unlikely to have ampersand(&) or left
   1257 			 * angle bracket (<) in it...
   1258 			 */
   1259 			wpabuf_printf(buf, "<%s>", replyname);
   1260 			wpabuf_put_str(buf, replydata);
   1261 			wpabuf_printf(buf, "</%s>\n", replyname);
   1262 		}
   1263 		wpabuf_put_str(buf, "</u:");
   1264 		wpabuf_put_data(buf, action, action_len);
   1265 		wpabuf_put_str(buf, "Response>\n");
   1266 		wpabuf_put_str(buf, soap_postfix);
   1267 	} else {
   1268 		/* Error case */
   1269 		wpabuf_put_str(buf, soap_prefix);
   1270 		wpabuf_put_str(buf, soap_error_prefix);
   1271 		wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret);
   1272 		wpabuf_put_str(buf, soap_error_postfix);
   1273 		wpabuf_put_str(buf, soap_postfix);
   1274 	}
   1275 	os_free(replydata);
   1276 
   1277 	/* Now patch in the content length at the end */
   1278 	if (body_start && put_length_here) {
   1279 		int body_length = (char *) wpabuf_put(buf, 0) - body_start;
   1280 		char len_buf[10];
   1281 		os_snprintf(len_buf, sizeof(len_buf), "%d", body_length);
   1282 		os_memcpy(put_length_here, len_buf, os_strlen(len_buf));
   1283 	}
   1284 
   1285 	send_wpabuf(c->sd, buf);
   1286 	wpabuf_free(buf);
   1287 }
   1288 
   1289 
   1290 static const char * web_get_action(struct web_connection *c,
   1291 				   const char *filename, size_t *action_len)
   1292 {
   1293 	const char *match;
   1294 	int match_len;
   1295 	char *b;
   1296 	char *action;
   1297 
   1298 	*action_len = 0;
   1299 	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) {
   1300 		wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s",
   1301 			   filename);
   1302 		return NULL;
   1303 	}
   1304 	/* The SOAPAction line of the header tells us what we want to do */
   1305 	b = httpread_hdr_line_get(c->hread, "SOAPAction:");
   1306 	if (b == NULL)
   1307 		return NULL;
   1308 	if (*b == '"')
   1309 		b++;
   1310 	else
   1311 		return NULL;
   1312 	match = urn_wfawlanconfig;
   1313 	match_len = os_strlen(urn_wfawlanconfig) - 1;
   1314 	if (os_strncasecmp(b, match, match_len))
   1315 		return NULL;
   1316 	b += match_len;
   1317 	/* skip over version */
   1318 	while (isgraph(*b) && *b != '#')
   1319 		b++;
   1320 	if (*b != '#')
   1321 		return NULL;
   1322 	b++;
   1323 	/* Following the sharp(#) should be the action and a double quote */
   1324 	action = b;
   1325 	while (isgraph(*b) && *b != '"')
   1326 		b++;
   1327 	if (*b != '"')
   1328 		return NULL;
   1329 	*action_len = b - action;
   1330 	return action;
   1331 }
   1332 
   1333 
   1334 /* Given that we have received a header w/ POST, act upon it
   1335  *
   1336  * Format of POST (case-insensitive):
   1337  *
   1338  * First line must be:
   1339  *      POST /<file> HTTP/1.1
   1340  * Since we don't do anything fancy we just ignore other lines.
   1341  *
   1342  * Our response (if no error) which includes only required lines is:
   1343  * HTTP/1.1 200 OK
   1344  * Connection: close
   1345  * Content-Type: text/xml
   1346  * Date: <rfc1123-date>
   1347  *
   1348  * Header lines must end with \r\n
   1349  * Per RFC 2616, content-length: is not required but connection:close
   1350  * would appear to be required (given that we will be closing it!).
   1351  */
   1352 static void web_connection_parse_post(struct web_connection *c,
   1353 				      const char *filename)
   1354 {
   1355 	enum http_reply_code ret;
   1356 	struct upnp_wps_device_sm *sm = c->sm;
   1357 	char *data = httpread_data_get(c->hread); /* body of http msg */
   1358 	const char *action;
   1359 	size_t action_len;
   1360 	const char *replyname = NULL; /* argument name for the reply */
   1361 	struct wpabuf *reply = NULL; /* data for the reply */
   1362 
   1363 	ret = UPNP_INVALID_ACTION;
   1364 	action = web_get_action(c, filename, &action_len);
   1365 	if (action == NULL)
   1366 		goto bad;
   1367 
   1368 	/*
   1369 	 * There are quite a few possible actions. Although we appear to
   1370 	 * support them all here, not all of them are necessarily supported by
   1371 	 * callbacks at higher levels.
   1372 	 */
   1373 	if (!os_strncasecmp("GetDeviceInfo", action, action_len))
   1374 		ret = web_process_get_device_info(sm, &reply, &replyname);
   1375 	else if (!os_strncasecmp("PutMessage", action, action_len))
   1376 		ret = web_process_put_message(sm, data, &reply, &replyname);
   1377 	else if (!os_strncasecmp("GetAPSettings", action, action_len))
   1378 		ret = web_process_get_ap_settings(sm, data, &reply,
   1379 						  &replyname);
   1380 	else if (!os_strncasecmp("SetAPSettings", action, action_len))
   1381 		ret = web_process_set_ap_settings(sm, data, &reply,
   1382 						  &replyname);
   1383 	else if (!os_strncasecmp("DelAPSettings", action, action_len))
   1384 		ret = web_process_del_ap_settings(sm, data, &reply,
   1385 						  &replyname);
   1386 	else if (!os_strncasecmp("GetSTASettings", action, action_len))
   1387 		ret = web_process_get_sta_settings(sm, data, &reply,
   1388 						   &replyname);
   1389 	else if (!os_strncasecmp("SetSTASettings", action, action_len))
   1390 		ret = web_process_set_sta_settings(sm, data, &reply,
   1391 						   &replyname);
   1392 	else if (!os_strncasecmp("DelSTASettings", action, action_len))
   1393 		ret = web_process_del_sta_settings(sm, data, &reply,
   1394 						  &replyname);
   1395 	else if (!os_strncasecmp("PutWLANResponse", action, action_len))
   1396 		ret = web_process_put_wlan_response(sm, data, &reply,
   1397 						    &replyname);
   1398 	else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len))
   1399 		ret = web_process_set_selected_registrar(sm, data, &reply,
   1400 							 &replyname);
   1401 	else if (!os_strncasecmp("RebootAP", action, action_len))
   1402 		ret = web_process_reboot_ap(sm, data, &reply, &replyname);
   1403 	else if (!os_strncasecmp("ResetAP", action, action_len))
   1404 		ret = web_process_reset_ap(sm, data, &reply, &replyname);
   1405 	else if (!os_strncasecmp("RebootSTA", action, action_len))
   1406 		ret = web_process_reboot_sta(sm, data, &reply, &replyname);
   1407 	else if (!os_strncasecmp("ResetSTA", action, action_len))
   1408 		ret = web_process_reset_sta(sm, data, &reply, &replyname);
   1409 	else
   1410 		wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type");
   1411 
   1412 bad:
   1413 	if (ret != HTTP_OK)
   1414 		wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret);
   1415 	web_connection_send_reply(c, ret, action, action_len, reply,
   1416 				  replyname);
   1417 	wpabuf_free(reply);
   1418 }
   1419 
   1420 
   1421 /* Given that we have received a header w/ SUBSCRIBE, act upon it
   1422  *
   1423  * Format of SUBSCRIBE (case-insensitive):
   1424  *
   1425  * First line must be:
   1426  *      SUBSCRIBE /wps_event HTTP/1.1
   1427  *
   1428  * Our response (if no error) which includes only required lines is:
   1429  * HTTP/1.1 200 OK
   1430  * Server: xx, UPnP/1.0, xx
   1431  * SID: uuid:xxxxxxxxx
   1432  * Timeout: Second-<n>
   1433  * Content-Length: 0
   1434  * Date: xxxx
   1435  *
   1436  * Header lines must end with \r\n
   1437  * Per RFC 2616, content-length: is not required but connection:close
   1438  * would appear to be required (given that we will be closing it!).
   1439  */
   1440 static void web_connection_parse_subscribe(struct web_connection *c,
   1441 					   const char *filename)
   1442 {
   1443 	struct upnp_wps_device_sm *sm = c->sm;
   1444 	struct wpabuf *buf;
   1445 	char *b;
   1446 	char *hdr = httpread_hdr_get(c->hread);
   1447 	char *h;
   1448 	char *match;
   1449 	int match_len;
   1450 	char *end;
   1451 	int len;
   1452 	int got_nt = 0;
   1453 	u8 uuid[UUID_LEN];
   1454 	int got_uuid = 0;
   1455 	char *callback_urls = NULL;
   1456 	struct subscription *s = NULL;
   1457 	enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
   1458 
   1459 	buf = wpabuf_alloc(1000);
   1460 	if (buf == NULL)
   1461 		return;
   1462 
   1463 	/* Parse/validate headers */
   1464 	h = hdr;
   1465 	/* First line: SUBSCRIBE /wps_event HTTP/1.1
   1466 	 * has already been parsed.
   1467 	 */
   1468 	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
   1469 		ret = HTTP_PRECONDITION_FAILED;
   1470 		goto error;
   1471 	}
   1472 	wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event");
   1473 	end = os_strchr(h, '\n');
   1474 
   1475 	for (; end != NULL; h = end + 1) {
   1476 		/* Option line by option line */
   1477 		h = end + 1;
   1478 		end = os_strchr(h, '\n');
   1479 		if (end == NULL)
   1480 			break; /* no unterminated lines allowed */
   1481 
   1482 		/* NT assures that it is our type of subscription;
   1483 		 * not used for a renewl.
   1484 		 **/
   1485 		match = "NT:";
   1486 		match_len = os_strlen(match);
   1487 		if (os_strncasecmp(h, match, match_len) == 0) {
   1488 			h += match_len;
   1489 			while (*h == ' ' || *h == '\t')
   1490 				h++;
   1491 			match = "upnp:event";
   1492 			match_len = os_strlen(match);
   1493 			if (os_strncasecmp(h, match, match_len) != 0) {
   1494 				ret = HTTP_BAD_REQUEST;
   1495 				goto error;
   1496 			}
   1497 			got_nt = 1;
   1498 			continue;
   1499 		}
   1500 		/* HOST should refer to us */
   1501 #if 0
   1502 		match = "HOST:";
   1503 		match_len = os_strlen(match);
   1504 		if (os_strncasecmp(h, match, match_len) == 0) {
   1505 			h += match_len;
   1506 			while (*h == ' ' || *h == '\t')
   1507 				h++;
   1508 			.....
   1509 		}
   1510 #endif
   1511 		/* CALLBACK gives one or more URLs for NOTIFYs
   1512 		 * to be sent as a result of the subscription.
   1513 		 * Each URL is enclosed in angle brackets.
   1514 		 */
   1515 		match = "CALLBACK:";
   1516 		match_len = os_strlen(match);
   1517 		if (os_strncasecmp(h, match, match_len) == 0) {
   1518 			h += match_len;
   1519 			while (*h == ' ' || *h == '\t')
   1520 				h++;
   1521 			len = end - h;
   1522 			os_free(callback_urls);
   1523 			callback_urls = os_malloc(len + 1);
   1524 			if (callback_urls == NULL) {
   1525 				ret = HTTP_INTERNAL_SERVER_ERROR;
   1526 				goto error;
   1527 			}
   1528 			os_memcpy(callback_urls, h, len);
   1529 			callback_urls[len] = 0;
   1530 			continue;
   1531 		}
   1532 		/* SID is only for renewal */
   1533 		match = "SID:";
   1534 		match_len = os_strlen(match);
   1535 		if (os_strncasecmp(h, match, match_len) == 0) {
   1536 			h += match_len;
   1537 			while (*h == ' ' || *h == '\t')
   1538 				h++;
   1539 			match = "uuid:";
   1540 			match_len = os_strlen(match);
   1541 			if (os_strncasecmp(h, match, match_len) != 0) {
   1542 				ret = HTTP_BAD_REQUEST;
   1543 				goto error;
   1544 			}
   1545 			h += match_len;
   1546 			while (*h == ' ' || *h == '\t')
   1547 				h++;
   1548 			if (uuid_str2bin(h, uuid)) {
   1549 				ret = HTTP_BAD_REQUEST;
   1550 				goto error;
   1551 			}
   1552 			got_uuid = 1;
   1553 			continue;
   1554 		}
   1555 		/* TIMEOUT is requested timeout, but apparently we can
   1556 		 * just ignore this.
   1557 		 */
   1558 	}
   1559 
   1560 	if (got_uuid) {
   1561 		/* renewal */
   1562 		if (callback_urls) {
   1563 			ret = HTTP_BAD_REQUEST;
   1564 			goto error;
   1565 		}
   1566 		s = subscription_renew(sm, uuid);
   1567 		if (s == NULL) {
   1568 			ret = HTTP_PRECONDITION_FAILED;
   1569 			goto error;
   1570 		}
   1571 	} else if (callback_urls) {
   1572 		if (!got_nt) {
   1573 			ret = HTTP_PRECONDITION_FAILED;
   1574 			goto error;
   1575 		}
   1576 		s = subscription_start(sm, callback_urls);
   1577 		if (s == NULL) {
   1578 			ret = HTTP_INTERNAL_SERVER_ERROR;
   1579 			goto error;
   1580 		}
   1581 	} else {
   1582 		ret = HTTP_PRECONDITION_FAILED;
   1583 		goto error;
   1584 	}
   1585 
   1586 	/* success */
   1587 	http_put_reply_code(buf, HTTP_OK);
   1588 	wpabuf_put_str(buf, http_server_hdr);
   1589 	wpabuf_put_str(buf, http_connection_close);
   1590 	wpabuf_put_str(buf, "Content-Length: 0\r\n");
   1591 	wpabuf_put_str(buf, "SID: uuid:");
   1592 	/* subscription id */
   1593 	b = wpabuf_put(buf, 0);
   1594 	uuid_bin2str(s->uuid, b, 80);
   1595 	wpabuf_put(buf, os_strlen(b));
   1596 	wpabuf_put_str(buf, "\r\n");
   1597 	wpabuf_printf(buf, "Timeout: Second-%d\r\n", UPNP_SUBSCRIBE_SEC);
   1598 	http_put_date(buf);
   1599 	/* And empty line to terminate header: */
   1600 	wpabuf_put_str(buf, "\r\n");
   1601 
   1602 	send_wpabuf(c->sd, buf);
   1603 	wpabuf_free(buf);
   1604 	os_free(callback_urls);
   1605 	return;
   1606 
   1607 error:
   1608 	/* Per UPnP spec:
   1609 	* Errors
   1610 	* Incompatible headers
   1611 	*   400 Bad Request. If SID header and one of NT or CALLBACK headers
   1612 	*     are present, the publisher must respond with HTTP error
   1613 	*     400 Bad Request.
   1614 	* Missing or invalid CALLBACK
   1615 	*   412 Precondition Failed. If CALLBACK header is missing or does not
   1616 	*     contain a valid HTTP URL, the publisher must respond with HTTP
   1617 	*     error 412 Precondition Failed.
   1618 	* Invalid NT
   1619 	*   412 Precondition Failed. If NT header does not equal upnp:event,
   1620 	*     the publisher must respond with HTTP error 412 Precondition
   1621 	*     Failed.
   1622 	* [For resubscription, use 412 if unknown uuid].
   1623 	* Unable to accept subscription
   1624 	*   5xx. If a publisher is not able to accept a subscription (such as
   1625 	*     due to insufficient resources), it must respond with a
   1626 	*     HTTP 500-series error code.
   1627 	*   599 Too many subscriptions (not a standard HTTP error)
   1628 	*/
   1629 	http_put_empty(buf, ret);
   1630 	send_wpabuf(c->sd, buf);
   1631 	wpabuf_free(buf);
   1632 	os_free(callback_urls);
   1633 }
   1634 
   1635 
   1636 /* Given that we have received a header w/ UNSUBSCRIBE, act upon it
   1637  *
   1638  * Format of UNSUBSCRIBE (case-insensitive):
   1639  *
   1640  * First line must be:
   1641  *      UNSUBSCRIBE /wps_event HTTP/1.1
   1642  *
   1643  * Our response (if no error) which includes only required lines is:
   1644  * HTTP/1.1 200 OK
   1645  * Content-Length: 0
   1646  *
   1647  * Header lines must end with \r\n
   1648  * Per RFC 2616, content-length: is not required but connection:close
   1649  * would appear to be required (given that we will be closing it!).
   1650  */
   1651 static void web_connection_parse_unsubscribe(struct web_connection *c,
   1652 					     const char *filename)
   1653 {
   1654 	struct upnp_wps_device_sm *sm = c->sm;
   1655 	struct wpabuf *buf;
   1656 	char *hdr = httpread_hdr_get(c->hread);
   1657 	char *h;
   1658 	char *match;
   1659 	int match_len;
   1660 	char *end;
   1661 	u8 uuid[UUID_LEN];
   1662 	int got_uuid = 0;
   1663 	struct subscription *s = NULL;
   1664 	enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR;
   1665 
   1666 	/* Parse/validate headers */
   1667 	h = hdr;
   1668 	/* First line: UNSUBSCRIBE /wps_event HTTP/1.1
   1669 	 * has already been parsed.
   1670 	 */
   1671 	if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) {
   1672 		ret = HTTP_PRECONDITION_FAILED;
   1673 		goto send_msg;
   1674 	}
   1675 	wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP UNSUBSCRIBE for event");
   1676 	end = os_strchr(h, '\n');
   1677 
   1678 	for (; end != NULL; h = end + 1) {
   1679 		/* Option line by option line */
   1680 		h = end + 1;
   1681 		end = os_strchr(h, '\n');
   1682 		if (end == NULL)
   1683 			break; /* no unterminated lines allowed */
   1684 
   1685 		/* HOST should refer to us */
   1686 #if 0
   1687 		match = "HOST:";
   1688 		match_len = os_strlen(match);
   1689 		if (os_strncasecmp(h, match, match_len) == 0) {
   1690 			h += match_len;
   1691 			while (*h == ' ' || *h == '\t')
   1692 				h++;
   1693 			.....
   1694 		}
   1695 #endif
   1696 		/* SID is only for renewal */
   1697 		match = "SID:";
   1698 		match_len = os_strlen(match);
   1699 		if (os_strncasecmp(h, match, match_len) == 0) {
   1700 			h += match_len;
   1701 			while (*h == ' ' || *h == '\t')
   1702 				h++;
   1703 			match = "uuid:";
   1704 			match_len = os_strlen(match);
   1705 			if (os_strncasecmp(h, match, match_len) != 0) {
   1706 				ret = HTTP_BAD_REQUEST;
   1707 				goto send_msg;
   1708 			}
   1709 			h += match_len;
   1710 			while (*h == ' ' || *h == '\t')
   1711 				h++;
   1712 			if (uuid_str2bin(h, uuid)) {
   1713 				ret = HTTP_BAD_REQUEST;
   1714 				goto send_msg;
   1715 			}
   1716 			got_uuid = 1;
   1717 			continue;
   1718 		}
   1719 	}
   1720 
   1721 	if (got_uuid) {
   1722 		s = subscription_find(sm, uuid);
   1723 		if (s) {
   1724 			wpa_printf(MSG_DEBUG, "WPS UPnP: Unsubscribing %p %s",
   1725 				   s,
   1726 				   (s && s->addr_list &&
   1727 				    s->addr_list->domain_and_port) ?
   1728 				   s->addr_list->domain_and_port : "-null-");
   1729 			subscription_unlink(s);
   1730 			subscription_destroy(s);
   1731 		}
   1732 	} else {
   1733 		wpa_printf(MSG_INFO, "WPS UPnP: Unsubscribe fails (not "
   1734 			   "found)");
   1735 		ret = HTTP_PRECONDITION_FAILED;
   1736 		goto send_msg;
   1737 	}
   1738 
   1739 	ret = HTTP_OK;
   1740 
   1741 send_msg:
   1742 	buf = wpabuf_alloc(200);
   1743 	if (buf == NULL)
   1744 		return;
   1745 	http_put_empty(buf, ret);
   1746 	send_wpabuf(c->sd, buf);
   1747 	wpabuf_free(buf);
   1748 }
   1749 
   1750 
   1751 /* Send error in response to unknown requests */
   1752 static void web_connection_unimplemented(struct web_connection *c)
   1753 {
   1754 	struct wpabuf *buf;
   1755 	buf = wpabuf_alloc(200);
   1756 	if (buf == NULL)
   1757 		return;
   1758 	http_put_empty(buf, HTTP_UNIMPLEMENTED);
   1759 	send_wpabuf(c->sd, buf);
   1760 	wpabuf_free(buf);
   1761 }
   1762 
   1763 
   1764 
   1765 /* Called when we have gotten an apparently valid http request.
   1766  */
   1767 static void web_connection_check_data(struct web_connection *c)
   1768 {
   1769 	struct httpread *hread = c->hread;
   1770 	enum httpread_hdr_type htype = httpread_hdr_type_get(hread);
   1771 	/* char *data = httpread_data_get(hread); */
   1772 	char *filename = httpread_uri_get(hread);
   1773 
   1774 	c->done = 1;
   1775 	if (!filename) {
   1776 		wpa_printf(MSG_INFO, "WPS UPnP: Could not get HTTP URI");
   1777 		return;
   1778 	}
   1779 	/* Trim leading slashes from filename */
   1780 	while (*filename == '/')
   1781 		filename++;
   1782 
   1783 	wpa_printf(MSG_DEBUG, "WPS UPnP: Got HTTP request type %d from %s:%d",
   1784 		   htype, inet_ntoa(c->cli_addr.sin_addr),
   1785 		   htons(c->cli_addr.sin_port));
   1786 
   1787 	switch (htype) {
   1788 	case HTTPREAD_HDR_TYPE_GET:
   1789 		web_connection_parse_get(c, filename);
   1790 		break;
   1791 	case HTTPREAD_HDR_TYPE_POST:
   1792 		web_connection_parse_post(c, filename);
   1793 		break;
   1794 	case HTTPREAD_HDR_TYPE_SUBSCRIBE:
   1795 		web_connection_parse_subscribe(c, filename);
   1796 		break;
   1797 	case HTTPREAD_HDR_TYPE_UNSUBSCRIBE:
   1798 		web_connection_parse_unsubscribe(c, filename);
   1799 		break;
   1800 		/* We are not required to support M-POST; just plain
   1801 		 * POST is supposed to work, so we only support that.
   1802 		 * If for some reason we need to support M-POST, it is
   1803 		 * mostly the same as POST, with small differences.
   1804 		 */
   1805 	default:
   1806 		/* Send 501 for anything else */
   1807 		web_connection_unimplemented(c);
   1808 		break;
   1809 	}
   1810 }
   1811 
   1812 
   1813 
   1814 /* called back when we have gotten request */
   1815 static void web_connection_got_file_handler(struct httpread *handle,
   1816 					    void *cookie,
   1817 					    enum httpread_event en)
   1818 {
   1819 	struct web_connection *c = cookie;
   1820 
   1821 	if (en == HTTPREAD_EVENT_FILE_READY)
   1822 		web_connection_check_data(c);
   1823 	web_connection_stop(c);
   1824 }
   1825 
   1826 
   1827 /* web_connection_start - Start web connection
   1828  * @sm: WPS UPnP state machine from upnp_wps_device_init()
   1829  * @sd: Socket descriptor
   1830  * @addr: Client address
   1831  *
   1832  * The socket descriptor sd is handed over for ownership by the WPS UPnP
   1833  * state machine.
   1834  */
   1835 static void web_connection_start(struct upnp_wps_device_sm *sm,
   1836 				 int sd, struct sockaddr_in *addr)
   1837 {
   1838 	struct web_connection *c = NULL;
   1839 
   1840 	/* if too many connections, bail */
   1841 	if (sm->n_web_connections >= MAX_WEB_CONNECTIONS) {
   1842 		close(sd);
   1843 		return;
   1844 	}
   1845 
   1846 	c = os_zalloc(sizeof(*c));
   1847 	if (c == NULL)
   1848 		return;
   1849 	os_memcpy(&c->cli_addr, addr, sizeof(c->cli_addr));
   1850 	c->sm = sm;
   1851 	c->sd = sd;
   1852 #if 0
   1853 	/*
   1854 	 * Setting non-blocking should not be necessary for read, and can mess
   1855 	 * up sending where blocking might be better.
   1856 	 */
   1857 	if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
   1858 		break;
   1859 #endif
   1860 	c->hread = httpread_create(c->sd, web_connection_got_file_handler,
   1861 				   c /* cookie */,
   1862 				   WEB_CONNECTION_MAX_READ,
   1863 				   WEB_CONNECTION_TIMEOUT_SEC);
   1864 	if (c->hread == NULL)
   1865 		goto fail;
   1866 	if (sm->web_connections) {
   1867 		c->next = sm->web_connections;
   1868 		c->prev = c->next->prev;
   1869 		c->prev->next = c;
   1870 		c->next->prev = c;
   1871 	} else {
   1872 		sm->web_connections = c->next = c->prev = c;
   1873 	}
   1874 	sm->n_web_connections++;
   1875 	return;
   1876 
   1877 fail:
   1878 	if (c)
   1879 		web_connection_stop(c);
   1880 }
   1881 
   1882 
   1883 /*
   1884  * Listening for web connections
   1885  * We have a single TCP listening port, and hand off connections as we get
   1886  * them.
   1887  */
   1888 
   1889 void web_listener_stop(struct upnp_wps_device_sm *sm)
   1890 {
   1891 	if (sm->web_sd_registered) {
   1892 		sm->web_sd_registered = 0;
   1893 		eloop_unregister_sock(sm->web_sd, EVENT_TYPE_READ);
   1894 	}
   1895 	if (sm->web_sd >= 0)
   1896 		close(sm->web_sd);
   1897 	sm->web_sd = -1;
   1898 }
   1899 
   1900 
   1901 static void web_listener_handler(int sd, void *eloop_ctx, void *sock_ctx)
   1902 {
   1903 	struct sockaddr_in addr;
   1904 	socklen_t addr_len = sizeof(addr);
   1905 	struct upnp_wps_device_sm *sm = sock_ctx;
   1906 	int new_sd;
   1907 
   1908 	/* Create state for new connection */
   1909 	/* Remember so we can cancel if need be */
   1910 	new_sd = accept(sm->web_sd, (struct sockaddr *) &addr, &addr_len);
   1911 	if (new_sd < 0) {
   1912 		wpa_printf(MSG_ERROR, "WPS UPnP: web listener accept "
   1913 			   "errno=%d (%s) web_sd=%d",
   1914 			   errno, strerror(errno), sm->web_sd);
   1915 		return;
   1916 	}
   1917 	web_connection_start(sm, new_sd, &addr);
   1918 }
   1919 
   1920 
   1921 int web_listener_start(struct upnp_wps_device_sm *sm)
   1922 {
   1923 	struct sockaddr_in addr;
   1924 	int port;
   1925 
   1926 	sm->web_sd = socket(AF_INET, SOCK_STREAM, 0);
   1927 	if (sm->web_sd < 0)
   1928 		goto fail;
   1929 	if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0)
   1930 		goto fail;
   1931 	port = 49152;  /* first non-reserved port */
   1932 	for (;;) {
   1933 		os_memset(&addr, 0, sizeof(addr));
   1934 		addr.sin_family = AF_INET;
   1935 		addr.sin_addr.s_addr = sm->ip_addr;
   1936 		addr.sin_port = htons(port);
   1937 		if (bind(sm->web_sd, (struct sockaddr *) &addr,
   1938 			 sizeof(addr)) == 0)
   1939 			break;
   1940 		if (errno == EADDRINUSE) {
   1941 			/* search for unused port */
   1942 			if (++port == 65535)
   1943 				goto fail;
   1944 			continue;
   1945 		}
   1946 		goto fail;
   1947 	}
   1948 	if (listen(sm->web_sd, 10 /* max backlog */) != 0)
   1949 		goto fail;
   1950 	if (fcntl(sm->web_sd, F_SETFL, O_NONBLOCK) != 0)
   1951 		goto fail;
   1952 	if (eloop_register_sock(sm->web_sd, EVENT_TYPE_READ,
   1953 				web_listener_handler, NULL, sm))
   1954 		goto fail;
   1955 	sm->web_sd_registered = 1;
   1956 	sm->web_port = port;
   1957 
   1958 	return 0;
   1959 
   1960 fail:
   1961 	/* Error */
   1962 	web_listener_stop(sm);
   1963 	return -1;
   1964 }
   1965