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