00001
00012 #include "includes.h"
00013
00014 #include <fcntl.h>
00015 #include <sys/ioctl.h>
00016 #include <net/route.h>
00017
00018 #include "common.h"
00019 #include "uuid.h"
00020 #include "eloop.h"
00021 #include "wps.h"
00022 #include "wps_upnp.h"
00023 #include "wps_upnp_i.h"
00024
00025 #define UPNP_CACHE_SEC (UPNP_CACHE_SEC_MIN + 1)
00026 #define UPNP_CACHE_SEC_MIN 1800
00027 #define UPNP_ADVERTISE_REPEAT 2
00028 #define MAX_MSEARCH 20
00029 #define SSDP_TARGET "239.0.0.0"
00030 #define SSDP_NETMASK "255.0.0.0"
00031
00032
00033
00034
00035
00036 static int token_eq(const char *s1, const char *s2)
00037 {
00038 int c1;
00039 int c2;
00040 int end1 = 0;
00041 int end2 = 0;
00042 for (;;) {
00043 c1 = *s1++;
00044 c2 = *s2++;
00045 if (isalpha(c1) && isupper(c1))
00046 c1 = tolower(c1);
00047 if (isalpha(c2) && isupper(c2))
00048 c2 = tolower(c2);
00049 end1 = !(isalnum(c1) || c1 == '_' || c1 == '-');
00050 end2 = !(isalnum(c2) || c2 == '_' || c2 == '-');
00051 if (end1 || end2 || c1 != c2)
00052 break;
00053 }
00054 return end1 && end2;
00055 }
00056
00057
00058
00059 static int token_length(const char *s)
00060 {
00061 const char *begin = s;
00062 for (;; s++) {
00063 int c = *s;
00064 int end = !(isalnum(c) || c == '_' || c == '-');
00065 if (end)
00066 break;
00067 }
00068 return s - begin;
00069 }
00070
00071
00072
00073
00074
00075
00076 static int word_separation_length(const char *s)
00077 {
00078 const char *begin = s;
00079 for (;; s++) {
00080 int c = *s;
00081 if (c == ' ' || c == '\t')
00082 continue;
00083 break;
00084 }
00085 return s - begin;
00086 }
00087
00088
00089
00090 static int line_length(const char *l)
00091 {
00092 const char *lp = l;
00093 while (*lp && *lp != '\n')
00094 lp++;
00095 if (*lp == '\n')
00096 lp++;
00097 return lp - l;
00098 }
00099
00100
00101
00102 static int line_length_stripped(const char *l)
00103 {
00104 const char *lp = l + line_length(l);
00105 while (lp > l && !isgraph(lp[-1]))
00106 lp--;
00107 return lp - l;
00108 }
00109
00110
00111 static int str_starts(const char *str, const char *start)
00112 {
00113 return os_strncmp(str, start, os_strlen(start)) == 0;
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00134 static struct wpabuf *
00135 next_advertisement(struct advertisement_state_machine *a, int *islast)
00136 {
00137 struct wpabuf *msg;
00138 char *NTString = "";
00139 char uuid_string[80];
00140
00141 *islast = 0;
00142 uuid_bin2str(a->sm->wps->uuid, uuid_string, sizeof(uuid_string));
00143 msg = wpabuf_alloc(800);
00144 if (msg == NULL)
00145 goto fail;
00146 switch (a->type) {
00147 case ADVERTISE_UP:
00148 case ADVERTISE_DOWN:
00149 NTString = "NT";
00150 wpabuf_put_str(msg, "NOTIFY * HTTP/1.1\r\n");
00151 wpabuf_printf(msg, "HOST: %s:%d\r\n",
00152 UPNP_MULTICAST_ADDRESS, UPNP_MULTICAST_PORT);
00153 wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",
00154 UPNP_CACHE_SEC);
00155 wpabuf_printf(msg, "NTS: %s\r\n",
00156 (a->type == ADVERTISE_UP ?
00157 "ssdp:alive" : "ssdp:byebye"));
00158 break;
00159 case MSEARCH_REPLY:
00160 NTString = "ST";
00161 wpabuf_put_str(msg, "HTTP/1.1 200 OK\r\n");
00162 wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",
00163 UPNP_CACHE_SEC);
00164
00165 wpabuf_put_str(msg, "DATE: ");
00166 format_date(msg);
00167 wpabuf_put_str(msg, "\r\n");
00168
00169 wpabuf_put_str(msg, "EXT:\r\n");
00170 break;
00171 }
00172
00173 if (a->type != ADVERTISE_DOWN) {
00174
00175 wpabuf_printf(msg, "LOCATION: http://%s:%d/%s\r\n",
00176 a->sm->ip_addr_text, a->sm->web_port,
00177 UPNP_WPS_DEVICE_XML_FILE);
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 wpabuf_put_str(msg, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
00189
00190 switch (a->state / UPNP_ADVERTISE_REPEAT) {
00191 case 0:
00192 wpabuf_printf(msg, "%s: upnp:rootdevice\r\n", NTString);
00193 wpabuf_printf(msg, "USN: uuid:%s::upnp:rootdevice\r\n",
00194 uuid_string);
00195 break;
00196 case 1:
00197 wpabuf_printf(msg, "%s: uuid:%s\r\n", NTString, uuid_string);
00198 wpabuf_printf(msg, "USN: uuid:%s\r\n", uuid_string);
00199 break;
00200 case 2:
00201 wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:device:"
00202 "WFADevice:1\r\n", NTString);
00203 wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"
00204 "org:device:WFADevice:1\r\n", uuid_string);
00205 break;
00206 case 3:
00207 wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:service:"
00208 "WFAWLANConfig:1\r\n", NTString);
00209 wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"
00210 "org:service:WFAWLANConfig:1\r\n", uuid_string);
00211 break;
00212 }
00213 wpabuf_put_str(msg, "\r\n");
00214
00215 if (a->state + 1 >= 4 * UPNP_ADVERTISE_REPEAT)
00216 *islast = 1;
00217
00218 return msg;
00219
00220 fail:
00221 wpabuf_free(msg);
00222 return NULL;
00223 }
00224
00225
00226 static void advertisement_state_machine_handler(void *eloop_data,
00227 void *user_ctx);
00228
00229
00236 void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm,
00237 int send_byebye)
00238 {
00239 struct advertisement_state_machine *a = &sm->advertisement;
00240 int islast = 0;
00241 struct wpabuf *msg;
00242 struct sockaddr_in dest;
00243
00244 eloop_cancel_timeout(advertisement_state_machine_handler, NULL, sm);
00245 if (!send_byebye || sm->multicast_sd < 0)
00246 return;
00247
00248 a->type = ADVERTISE_DOWN;
00249 a->state = 0;
00250 a->sm = sm;
00251
00252 os_memset(&dest, 0, sizeof(dest));
00253 dest.sin_family = AF_INET;
00254 dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
00255 dest.sin_port = htons(UPNP_MULTICAST_PORT);
00256
00257 while (!islast) {
00258 msg = next_advertisement(a, &islast);
00259 if (msg == NULL)
00260 break;
00261 if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg),
00262 0, (struct sockaddr *) &dest, sizeof(dest)) < 0) {
00263 wpa_printf(MSG_INFO, "WPS UPnP: Advertisement sendto "
00264 "failed: %d (%s)", errno, strerror(errno));
00265 }
00266 wpabuf_free(msg);
00267 a->state++;
00268 }
00269 }
00270
00271
00272 static void advertisement_state_machine_handler(void *eloop_data,
00273 void *user_ctx)
00274 {
00275 struct upnp_wps_device_sm *sm = user_ctx;
00276 struct advertisement_state_machine *a = &sm->advertisement;
00277 struct wpabuf *msg;
00278 int next_timeout_msec = 100;
00279 int next_timeout_sec = 0;
00280 struct sockaddr_in dest;
00281 int islast = 0;
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 wpa_printf(MSG_MSGDUMP, "WPS UPnP: Advertisement state=%d", a->state);
00297 msg = next_advertisement(a, &islast);
00298 if (msg == NULL)
00299 return;
00300
00301 os_memset(&dest, 0, sizeof(dest));
00302 dest.sin_family = AF_INET;
00303 dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
00304 dest.sin_port = htons(UPNP_MULTICAST_PORT);
00305
00306 if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
00307 (struct sockaddr *) &dest, sizeof(dest)) == -1) {
00308 wpa_printf(MSG_ERROR, "WPS UPnP: Advertisement sendto failed:"
00309 "%d (%s)", errno, strerror(errno));
00310 next_timeout_msec = 0;
00311 next_timeout_sec = 10;
00312 } else if (islast) {
00313 a->state = 0;
00314 if (a->type == ADVERTISE_DOWN) {
00315 wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_DOWN->UP");
00316 a->type = ADVERTISE_UP;
00317
00318 } else {
00319 u16 r;
00320
00321
00322
00323
00324 next_timeout_msec = 0;
00325 os_get_random((void *) &r, sizeof(r));
00326 next_timeout_sec = UPNP_CACHE_SEC / 4 +
00327 (((UPNP_CACHE_SEC / 4) * r) >> 16);
00328 sm->advertise_count++;
00329 wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_UP (#%u); "
00330 "next in %d sec",
00331 sm->advertise_count, next_timeout_sec);
00332 }
00333 } else {
00334 a->state++;
00335 }
00336
00337 wpabuf_free(msg);
00338
00339 eloop_register_timeout(next_timeout_sec, next_timeout_msec,
00340 advertisement_state_machine_handler, NULL, sm);
00341 }
00342
00343
00350 int advertisement_state_machine_start(struct upnp_wps_device_sm *sm)
00351 {
00352 struct advertisement_state_machine *a = &sm->advertisement;
00353 int next_timeout_msec;
00354
00355 advertisement_state_machine_stop(sm, 0);
00356
00357
00358
00359
00360
00361 a->type = ADVERTISE_DOWN;
00362 a->state = 0;
00363 a->sm = sm;
00364
00365
00366
00367 next_timeout_msec = (100 * (os_random() & 0xFF)) >> 8;
00368 return eloop_register_timeout(0, next_timeout_msec,
00369 advertisement_state_machine_handler,
00370 NULL, sm);
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 static void msearchreply_state_machine_handler(void *eloop_data,
00383 void *user_ctx);
00384
00385
00391 void msearchreply_state_machine_stop(struct advertisement_state_machine *a)
00392 {
00393 struct upnp_wps_device_sm *sm = a->sm;
00394 wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH stop");
00395 if (a->next == a) {
00396 sm->msearch_replies = NULL;
00397 } else {
00398 if (sm->msearch_replies == a)
00399 sm->msearch_replies = a->next;
00400 a->next->prev = a->prev;
00401 a->prev->next = a->next;
00402 }
00403 os_free(a);
00404 sm->n_msearch_replies--;
00405 }
00406
00407
00408 static void msearchreply_state_machine_handler(void *eloop_data,
00409 void *user_ctx)
00410 {
00411 struct advertisement_state_machine *a = user_ctx;
00412 struct upnp_wps_device_sm *sm = a->sm;
00413 struct wpabuf *msg;
00414 int next_timeout_msec = 100;
00415 int next_timeout_sec = 0;
00416 int islast = 0;
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply state=%d (%s:%d)",
00428 a->state, inet_ntoa(a->client.sin_addr),
00429 ntohs(a->client.sin_port));
00430 msg = next_advertisement(a, &islast);
00431 if (msg == NULL)
00432 return;
00433
00434
00435
00436
00437
00438 if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
00439 (struct sockaddr *) &a->client, sizeof(a->client)) < 0) {
00440 wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply sendto "
00441 "errno %d (%s) for %s:%d",
00442 errno, strerror(errno),
00443 inet_ntoa(a->client.sin_addr),
00444 ntohs(a->client.sin_port));
00445
00446 }
00447 wpabuf_free(msg);
00448 if (islast) {
00449 wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply done");
00450 msearchreply_state_machine_stop(a);
00451 return;
00452 }
00453 a->state++;
00454
00455 wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply in %d.%03d sec",
00456 next_timeout_sec, next_timeout_msec);
00457 eloop_register_timeout(next_timeout_sec, next_timeout_msec,
00458 msearchreply_state_machine_handler, sm, a);
00459 }
00460
00461
00478 static void msearchreply_state_machine_start(struct upnp_wps_device_sm *sm,
00479 struct sockaddr_in *client,
00480 int mx)
00481 {
00482 struct advertisement_state_machine *a;
00483 int next_timeout_sec;
00484 int next_timeout_msec;
00485
00486 wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply start (%d "
00487 "outstanding)", sm->n_msearch_replies);
00488 if (sm->n_msearch_replies >= MAX_MSEARCH) {
00489 wpa_printf(MSG_INFO, "WPS UPnP: Too many outstanding "
00490 "M-SEARCH replies");
00491 return;
00492 }
00493
00494 a = os_zalloc(sizeof(*a));
00495 if (a == NULL)
00496 return;
00497 a->type = MSEARCH_REPLY;
00498 a->state = 0;
00499 a->sm = sm;
00500 os_memcpy(&a->client, client, sizeof(*client));
00501
00502 next_timeout_msec = (1000 * mx * (os_random() & 0xFF)) >> 8;
00503 next_timeout_sec = next_timeout_msec / 1000;
00504 next_timeout_msec = next_timeout_msec % 1000;
00505 if (eloop_register_timeout(next_timeout_sec, next_timeout_msec,
00506 msearchreply_state_machine_handler, sm,
00507 a)) {
00508
00509 goto fail;
00510 }
00511
00512 if (sm->msearch_replies) {
00513 a->next = sm->msearch_replies;
00514 a->prev = a->next->prev;
00515 a->prev->next = a;
00516 a->next->prev = a;
00517 } else {
00518 sm->msearch_replies = a->next = a->prev = a;
00519 }
00520 sm->n_msearch_replies++;
00521 return;
00522
00523 fail:
00524 wpa_printf(MSG_INFO, "WPS UPnP: M-SEARCH reply failure!");
00525 eloop_cancel_timeout(msearchreply_state_machine_handler, sm, a);
00526 os_free(a);
00527 }
00528
00529
00552 static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
00553 struct sockaddr_in *client, const char *data)
00554 {
00555 const char *start = data;
00556 const char *end;
00557 int got_host = 0;
00558 int got_st = 0, st_match = 0;
00559 int got_man = 0;
00560 int got_mx = 0;
00561 int mx = 0;
00562
00563
00564
00565
00566
00567 data += line_length(data);
00568
00569
00570 for (; *data != '\0'; data += line_length(data)) {
00571 end = data + line_length_stripped(data);
00572 if (token_eq(data, "host")) {
00573
00574
00575
00576
00577
00578 #if 0
00579 data += token_length(data);
00580 data += word_separation_length(data);
00581 if (*data != ':')
00582 goto bad;
00583 data++;
00584 data += word_separation_length(data);
00585
00586 if (!str_starts(data, "239.255.255.250"))
00587 goto bad;
00588 data += os_strlen("239.255.255.250");
00589 if (*data == ':') {
00590 if (!str_starts(data, ":1900"))
00591 goto bad;
00592 }
00593 #endif
00594 got_host = 1;
00595 continue;
00596 } else if (token_eq(data, "st")) {
00597
00598
00599
00600 got_st = 1;
00601 data += token_length(data);
00602 data += word_separation_length(data);
00603 if (*data != ':')
00604 continue;
00605 data++;
00606 data += word_separation_length(data);
00607 if (str_starts(data, "ssdp:all")) {
00608 st_match = 1;
00609 continue;
00610 }
00611 if (str_starts(data, "upnp:rootdevice")) {
00612 st_match = 1;
00613 continue;
00614 }
00615 if (str_starts(data, "uuid:")) {
00616 char uuid_string[80];
00617 data += os_strlen("uuid:");
00618 uuid_bin2str(sm->wps->uuid, uuid_string,
00619 sizeof(uuid_string));
00620 if (str_starts(data, uuid_string))
00621 st_match = 1;
00622 continue;
00623 }
00624 #if 0
00625
00626 if (str_starts(data, "urn:schemas-upnp-org:device:"
00627 "InternetGatewayDevice:1")) {
00628 st_match = 1;
00629 continue;
00630 }
00631 #endif
00632 if (str_starts(data, "urn:schemas-wifialliance-org:"
00633 "service:WFAWLANConfig:1")) {
00634 st_match = 1;
00635 continue;
00636 }
00637 if (str_starts(data, "urn:schemas-wifialliance-org:"
00638 "device:WFADevice:1")) {
00639 st_match = 1;
00640 continue;
00641 }
00642 continue;
00643 } else if (token_eq(data, "man")) {
00644 data += token_length(data);
00645 data += word_separation_length(data);
00646 if (*data != ':')
00647 continue;
00648 data++;
00649 data += word_separation_length(data);
00650 if (!str_starts(data, "\"ssdp:discover\"")) {
00651 wpa_printf(MSG_DEBUG, "WPS UPnP: Unexpected "
00652 "M-SEARCH man-field");
00653 goto bad;
00654 }
00655 got_man = 1;
00656 continue;
00657 } else if (token_eq(data, "mx")) {
00658 data += token_length(data);
00659 data += word_separation_length(data);
00660 if (*data != ':')
00661 continue;
00662 data++;
00663 data += word_separation_length(data);
00664 mx = atol(data);
00665 got_mx = 1;
00666 continue;
00667 }
00668
00669 }
00670 if (!got_host || !got_st || !got_man || !got_mx || mx < 0) {
00671 wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid M-SEARCH: %d %d %d "
00672 "%d mx=%d", got_host, got_st, got_man, got_mx, mx);
00673 goto bad;
00674 }
00675 if (!st_match) {
00676 wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored M-SEARCH (no ST "
00677 "match)");
00678 return;
00679 }
00680 if (mx > 120)
00681 mx = 120;
00682 msearchreply_state_machine_start(sm, client, mx);
00683 return;
00684
00685 bad:
00686 wpa_printf(MSG_INFO, "WPS UPnP: Failed to parse M-SEARCH");
00687 wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH data:\n%s", start);
00688 }
00689
00690
00691
00692
00701 void ssdp_listener_stop(struct upnp_wps_device_sm *sm)
00702 {
00703 if (sm->ssdp_sd_registered) {
00704 eloop_unregister_sock(sm->ssdp_sd, EVENT_TYPE_READ);
00705 sm->ssdp_sd_registered = 0;
00706 }
00707
00708 if (sm->ssdp_sd != -1) {
00709 close(sm->ssdp_sd);
00710 sm->ssdp_sd = -1;
00711 }
00712
00713 eloop_cancel_timeout(msearchreply_state_machine_handler, sm,
00714 ELOOP_ALL_CTX);
00715 }
00716
00717
00718 static void ssdp_listener_handler(int sd, void *eloop_ctx, void *sock_ctx)
00719 {
00720 struct upnp_wps_device_sm *sm = sock_ctx;
00721 struct sockaddr_in addr;
00722 socklen_t addr_len;
00723 int nread;
00724 char buf[MULTICAST_MAX_READ], *pos;
00725
00726 addr_len = sizeof(addr);
00727 nread = recvfrom(sm->ssdp_sd, buf, sizeof(buf) - 1, 0,
00728 (struct sockaddr *) &addr, &addr_len);
00729 if (nread <= 0)
00730 return;
00731 buf[nread] = '\0';
00732
00733 if (str_starts(buf, "NOTIFY ")) {
00734
00735
00736
00737
00738 return;
00739 }
00740
00741 pos = os_strchr(buf, '\n');
00742 if (pos)
00743 *pos = '\0';
00744 wpa_printf(MSG_MSGDUMP, "WPS UPnP: Received SSDP packet from %s:%d: "
00745 "%s", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), buf);
00746 if (pos)
00747 *pos = '\n';
00748
00749
00750 if (os_strncasecmp(buf, "M-SEARCH", os_strlen("M-SEARCH")) == 0 &&
00751 !isgraph(buf[strlen("M-SEARCH")])) {
00752 ssdp_parse_msearch(sm, &addr, buf);
00753 return;
00754 }
00755
00756
00757 }
00758
00759
00760 int ssdp_listener_open(void)
00761 {
00762 struct sockaddr_in addr;
00763 struct ip_mreq mcast_addr;
00764 int on = 1;
00765
00766 unsigned char ttl = 4;
00767 int sd;
00768
00769 sd = socket(AF_INET, SOCK_DGRAM, 0);
00770 if (sd < 0)
00771 goto fail;
00772 if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
00773 goto fail;
00774 if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
00775 goto fail;
00776 os_memset(&addr, 0, sizeof(addr));
00777 addr.sin_family = AF_INET;
00778 addr.sin_addr.s_addr = htonl(INADDR_ANY);
00779 addr.sin_port = htons(UPNP_MULTICAST_PORT);
00780 if (bind(sd, (struct sockaddr *) &addr, sizeof(addr)))
00781 goto fail;
00782 os_memset(&mcast_addr, 0, sizeof(mcast_addr));
00783 mcast_addr.imr_interface.s_addr = htonl(INADDR_ANY);
00784 mcast_addr.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
00785 if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
00786 (char *) &mcast_addr, sizeof(mcast_addr)))
00787 goto fail;
00788 if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
00789 &ttl, sizeof(ttl)))
00790 goto fail;
00791
00792 return sd;
00793
00794 fail:
00795 if (sd >= 0)
00796 close(sd);
00797 return -1;
00798 }
00799
00800
00809 int ssdp_listener_start(struct upnp_wps_device_sm *sm)
00810 {
00811 sm->ssdp_sd = ssdp_listener_open();
00812
00813 if (eloop_register_sock(sm->ssdp_sd, EVENT_TYPE_READ,
00814 ssdp_listener_handler, NULL, sm))
00815 goto fail;
00816 sm->ssdp_sd_registered = 1;
00817 return 0;
00818
00819 fail:
00820
00821 wpa_printf(MSG_ERROR, "WPS UPnP: ssdp_listener_start failed");
00822 ssdp_listener_stop(sm);
00823 return -1;
00824 }
00825
00826
00839 int add_ssdp_network(const char *net_if)
00840 {
00841 #ifdef __linux__
00842 int ret = -1;
00843 int sock = -1;
00844 struct rtentry rt;
00845 struct sockaddr_in *sin;
00846
00847 if (!net_if)
00848 goto fail;
00849
00850 os_memset(&rt, 0, sizeof(rt));
00851 sock = socket(AF_INET, SOCK_DGRAM, 0);
00852 if (sock < 0)
00853 goto fail;
00854
00855 rt.rt_dev = (char *) net_if;
00856 sin = aliasing_hide_typecast(&rt.rt_dst, struct sockaddr_in);
00857 sin->sin_family = AF_INET;
00858 sin->sin_port = 0;
00859 sin->sin_addr.s_addr = inet_addr(SSDP_TARGET);
00860 sin = aliasing_hide_typecast(&rt.rt_genmask, struct sockaddr_in);
00861 sin->sin_family = AF_INET;
00862 sin->sin_port = 0;
00863 sin->sin_addr.s_addr = inet_addr(SSDP_NETMASK);
00864 rt.rt_flags = RTF_UP;
00865 if (ioctl(sock, SIOCADDRT, &rt) < 0) {
00866 if (errno == EPERM) {
00867 wpa_printf(MSG_DEBUG, "add_ssdp_network: No "
00868 "permissions to add routing table entry");
00869
00870 } else if (errno != EEXIST) {
00871 wpa_printf(MSG_INFO, "add_ssdp_network() ioctl errno "
00872 "%d (%s)", errno, strerror(errno));
00873 goto fail;
00874 }
00875 }
00876
00877 ret = 0;
00878
00879 fail:
00880 if (sock >= 0)
00881 close(sock);
00882
00883 return ret;
00884 #else
00885 return 0;
00886 #endif
00887 }
00888
00889
00890 int ssdp_open_multicast_sock(u32 ip_addr)
00891 {
00892 int sd;
00893
00894
00895 unsigned char ttl = 4;
00896
00897 sd = socket(AF_INET, SOCK_DGRAM, 0);
00898 if (sd < 0)
00899 return -1;
00900
00901 #if 0
00902 if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
00903 return -1;
00904 #endif
00905
00906 if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF,
00907 &ip_addr, sizeof(ip_addr)))
00908 return -1;
00909 if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL,
00910 &ttl, sizeof(ttl)))
00911 return -1;
00912
00913 #if 0
00914 {
00915 struct ip_mreq mreq;
00916 mreq.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
00917 mreq.imr_interface.s_addr = ip_addr;
00918 wpa_printf(MSG_DEBUG, "WPS UPnP: Multicast addr 0x%x if addr "
00919 "0x%x",
00920 mreq.imr_multiaddr.s_addr,
00921 mreq.imr_interface.s_addr);
00922 if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
00923 sizeof(mreq))) {
00924 wpa_printf(MSG_ERROR,
00925 "WPS UPnP: setsockopt "
00926 "IP_ADD_MEMBERSHIP errno %d (%s)",
00927 errno, strerror(errno));
00928 return -1;
00929 }
00930 }
00931 #endif
00932
00933
00934
00935
00936
00937
00938 return sd;
00939 }
00940
00941
00948 int ssdp_open_multicast(struct upnp_wps_device_sm *sm)
00949 {
00950 sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr);
00951 if (sm->multicast_sd < 0)
00952 return -1;
00953 return 0;
00954 }
00955