1 /* 2 * This program is free software; you can redistribute it and/or modify 3 * it under the terms of the GNU General Public License as published by 4 * the Free Software Foundation; either version 2 of the License. 5 * 6 * This program is distributed in the hope that it will be useful, 7 * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 * GNU General Public License for more details. 10 * 11 * You should have received a copy of the GNU General Public License 12 * along with this program; if not, write to the Free Software 13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 14 * 15 * Copyright (C) 2020 embedd.ch 16 * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> 17 * Copyright (C) 2020 John Crispin <john@phrozen.org> 18 */ 19 20 #define _GNU_SOURCE 21 22 #include <sys/types.h> 23 #include <sys/socket.h> 24 #include <netinet/in.h> 25 #include <net/if.h> 26 #include <arpa/inet.h> 27 #include <errno.h> 28 #include <unistd.h> 29 30 #include <libubox/vlist.h> 31 #include <libubox/avl-cmp.h> 32 #include <libubox/usock.h> 33 #include "usteer.h" 34 #include "remote.h" 35 #include "node.h" 36 37 static uint32_t local_id; 38 static struct uloop_fd remote_fd; 39 static struct uloop_timeout remote_timer; 40 static struct uloop_timeout reload_timer; 41 42 static struct blob_buf buf; 43 static uint32_t msg_seq; 44 45 struct interface { 46 struct vlist_node node; 47 int ifindex; 48 }; 49 50 static void 51 interfaces_update_cb(struct vlist_tree *tree, 52 struct vlist_node *node_new, 53 struct vlist_node *node_old); 54 55 static int remote_host_cmp(const void *k1, const void *k2, void *ptr) 56 { 57 unsigned long v1 = (unsigned long) k1; 58 unsigned long v2 = (unsigned long) k2; 59 60 return v2 - v1; 61 } 62 63 static VLIST_TREE(interfaces, avl_strcmp, interfaces_update_cb, true, true); 64 LIST_HEAD(remote_nodes); 65 AVL_TREE(remote_hosts, remote_host_cmp, false, NULL); 66 67 static const char * 68 interface_name(struct interface *iface) 69 { 70 return iface->node.avl.key; 71 } 72 73 static void 74 interface_check(struct interface *iface) 75 { 76 iface->ifindex = if_nametoindex(interface_name(iface)); 77 uloop_timeout_set(&reload_timer, 1); 78 } 79 80 static void 81 interface_init(struct interface *iface) 82 { 83 interface_check(iface); 84 } 85 86 static void 87 interface_free(struct interface *iface) 88 { 89 avl_delete(&interfaces.avl, &iface->node.avl); 90 free(iface); 91 } 92 93 static void 94 interfaces_update_cb(struct vlist_tree *tree, 95 struct vlist_node *node_new, 96 struct vlist_node *node_old) 97 { 98 struct interface *iface; 99 100 if (node_new && node_old) { 101 iface = container_of(node_new, struct interface, node); 102 free(iface); 103 iface = container_of(node_old, struct interface, node); 104 interface_check(iface); 105 } else if (node_old) { 106 iface = container_of(node_old, struct interface, node); 107 interface_free(iface); 108 } else { 109 iface = container_of(node_new, struct interface, node); 110 interface_init(iface); 111 } 112 } 113 114 void usteer_interface_add(const char *name) 115 { 116 struct interface *iface; 117 char *name_buf; 118 119 iface = calloc_a(sizeof(*iface), &name_buf, strlen(name) + 1); 120 strcpy(name_buf, name); 121 vlist_add(&interfaces, &iface->node, name_buf); 122 } 123 124 void config_set_interfaces(struct blob_attr *data) 125 { 126 struct blob_attr *cur; 127 int rem; 128 129 if (!data) 130 return; 131 132 if (!blobmsg_check_attr_list(data, BLOBMSG_TYPE_STRING)) 133 return; 134 135 vlist_update(&interfaces); 136 blobmsg_for_each_attr(cur, data, rem) { 137 usteer_interface_add(blobmsg_data(cur)); 138 } 139 vlist_flush(&interfaces); 140 } 141 142 void config_get_interfaces(struct blob_buf *buf) 143 { 144 struct interface *iface; 145 void *c; 146 147 c = blobmsg_open_array(buf, "interfaces"); 148 vlist_for_each_element(&interfaces, iface, node) { 149 blobmsg_add_string(buf, NULL, interface_name(iface)); 150 } 151 blobmsg_close_array(buf, c); 152 } 153 154 static void 155 interface_add_station(struct usteer_remote_node *node, struct blob_attr *data) 156 { 157 struct sta *sta; 158 struct sta_info *si, *local_si; 159 struct apmsg_sta msg; 160 struct usteer_node *local_node; 161 bool create; 162 bool connect_change; 163 164 if (!parse_apmsg_sta(&msg, data)) { 165 MSG(DEBUG, "Cannot parse station in message\n"); 166 return; 167 } 168 169 if (msg.timeout <= 0) { 170 MSG(DEBUG, "Refuse to add an already expired station entry\n"); 171 return; 172 } 173 174 sta = usteer_sta_get(msg.addr, true); 175 if (!sta) 176 return; 177 178 si = usteer_sta_info_get(sta, &node->node, &create); 179 if (!si) 180 return; 181 182 connect_change = si->connected != msg.connected; 183 si->connected = msg.connected; 184 si->signal = msg.signal; 185 si->seen = current_time - msg.seen; 186 si->last_connected = current_time - msg.last_connected; 187 188 /* Check if client roamed to this foreign node */ 189 if ((connect_change || create) && si->connected == STA_CONNECTED) { 190 for_each_local_node(local_node) { 191 local_si = usteer_sta_info_get(sta, local_node, NULL); 192 if (!local_si) 193 continue; 194 195 if (current_time - local_si->last_connected < config.roam_process_timeout) { 196 node->node.roam_events.target++; 197 break; 198 } 199 } 200 } 201 202 usteer_sta_info_update_timeout(si, msg.timeout); 203 } 204 205 static void 206 remote_node_free(struct usteer_remote_node *node) 207 { 208 struct usteer_remote_host *host = node->host; 209 210 list_del(&node->list); 211 list_del(&node->host_list); 212 usteer_sta_node_cleanup(&node->node); 213 usteer_measurement_report_node_cleanup(&node->node); 214 free(node); 215 216 if (!list_empty(&host->nodes)) 217 return; 218 219 avl_delete(&remote_hosts, &host->avl); 220 free(host->addr); 221 free(host); 222 } 223 224 static struct usteer_remote_host * 225 interface_get_host(const char *addr, unsigned long id) 226 { 227 struct usteer_remote_host *host; 228 229 host = avl_find_element(&remote_hosts, (void *)id, host, avl); 230 if (host) 231 goto out; 232 233 host = calloc(1, sizeof(*host)); 234 host->avl.key = (void *)id; 235 INIT_LIST_HEAD(&host->nodes); 236 avl_insert(&remote_hosts, &host->avl); 237 238 out: 239 if (host->addr && !strcmp(host->addr, addr)) 240 return host; 241 242 free(host->addr); 243 host->addr = strdup(addr); 244 245 return host; 246 } 247 248 static struct usteer_remote_node * 249 interface_get_node(struct usteer_remote_host *host, const char *name) 250 { 251 struct usteer_remote_node *node; 252 int addr_len = strlen(host->addr); 253 char *buf; 254 255 list_for_each_entry(node, &host->nodes, host_list) 256 if (!strcmp(node->name, name)) 257 return node; 258 259 node = calloc_a(sizeof(*node), &buf, addr_len + 1 + strlen(name) + 1); 260 node->node.type = NODE_TYPE_REMOTE; 261 node->node.created = current_time; 262 263 sprintf(buf, "%s#%s", host->addr, name); 264 node->node.avl.key = buf; 265 node->name = buf + addr_len + 1; 266 node->host = host; 267 INIT_LIST_HEAD(&node->node.sta_info); 268 INIT_LIST_HEAD(&node->node.measurements); 269 270 list_add_tail(&node->list, &remote_nodes); 271 list_add_tail(&node->host_list, &host->nodes); 272 273 return node; 274 } 275 276 static void 277 interface_add_node(struct usteer_remote_host *host, struct blob_attr *data) 278 { 279 struct usteer_remote_node *node; 280 struct apmsg_node msg; 281 struct blob_attr *cur; 282 int rem; 283 284 if (!parse_apmsg_node(&msg, data)) { 285 MSG(DEBUG, "Cannot parse node in message\n"); 286 return; 287 } 288 289 node = interface_get_node(host, msg.name); 290 node->check = 0; 291 node->node.freq = msg.freq; 292 node->node.channel = msg.channel; 293 node->node.op_class = msg.op_class; 294 node->node.n_assoc = msg.n_assoc; 295 node->node.max_assoc = msg.max_assoc; 296 node->node.noise = msg.noise; 297 node->node.load = msg.load; 298 299 memcpy(node->node.bssid, msg.bssid, sizeof(node->node.bssid)); 300 301 snprintf(node->node.ssid, sizeof(node->node.ssid), "%s", msg.ssid); 302 usteer_node_set_blob(&node->node.rrm_nr, msg.rrm_nr); 303 usteer_node_set_blob(&node->node.node_info, msg.node_info); 304 305 blob_for_each_attr(cur, msg.stations, rem) 306 interface_add_station(node, cur); 307 } 308 309 static void 310 interface_recv_msg(struct interface *iface, char *addr_str, void *buf, int len) 311 { 312 struct usteer_remote_host *host; 313 struct blob_attr *data = buf; 314 struct apmsg msg; 315 struct blob_attr *cur; 316 int rem; 317 318 if (config.local_mode) 319 return; 320 321 if (blob_pad_len(data) != len) { 322 MSG(DEBUG, "Invalid message length (header: %d, real: %d)\n", blob_pad_len(data), len); 323 return; 324 } 325 326 if (!parse_apmsg(&msg, data)) { 327 MSG(DEBUG, "Missing fields in message\n"); 328 return; 329 } 330 331 if (msg.id == local_id) 332 return; 333 334 MSG(NETWORK, "Received message on %s (id=%08x->%08x seq=%d len=%d)\n", 335 interface_name(iface), msg.id, local_id, msg.seq, len); 336 337 host = interface_get_host(addr_str, msg.id); 338 usteer_node_set_blob(&host->host_info, msg.host_info); 339 340 blob_for_each_attr(cur, msg.nodes, rem) 341 interface_add_node(host, cur); 342 } 343 344 static struct interface * 345 interface_find_by_ifindex(int index) 346 { 347 struct interface *iface; 348 349 vlist_for_each_element(&interfaces, iface, node) { 350 if (iface->ifindex == index) 351 return iface; 352 } 353 354 return NULL; 355 } 356 357 static void 358 interface_recv_v4(struct uloop_fd *u, unsigned int events) 359 { 360 static char buf[APMGR_BUFLEN]; 361 static char cmsg_buf[( CMSG_SPACE(sizeof(struct in_pktinfo)) + sizeof(int)) + 1]; 362 static struct sockaddr_in sin; 363 char addr_str[INET_ADDRSTRLEN]; 364 static struct iovec iov = { 365 .iov_base = buf, 366 .iov_len = sizeof(buf) 367 }; 368 static struct msghdr msg = { 369 .msg_name = &sin, 370 .msg_namelen = sizeof(sin), 371 .msg_iov = &iov, 372 .msg_iovlen = 1, 373 .msg_control = cmsg_buf, 374 .msg_controllen = sizeof(cmsg_buf), 375 }; 376 struct cmsghdr *cmsg; 377 int len; 378 379 do { 380 struct in_pktinfo *pkti = NULL; 381 struct interface *iface; 382 383 len = recvmsg(u->fd, &msg, 0); 384 if (len < 0) { 385 switch (errno) { 386 case EAGAIN: 387 return; 388 case EINTR: 389 continue; 390 default: 391 perror("recvmsg"); 392 uloop_fd_delete(u); 393 return; 394 } 395 } 396 397 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 398 if (cmsg->cmsg_type != IP_PKTINFO) 399 continue; 400 401 pkti = (struct in_pktinfo *) CMSG_DATA(cmsg); 402 } 403 404 if (!pkti) { 405 MSG(DEBUG, "Received packet without ifindex\n"); 406 continue; 407 } 408 409 iface = interface_find_by_ifindex(pkti->ipi_ifindex); 410 if (!iface) { 411 MSG(DEBUG, "Received packet from unconfigured interface %d\n", pkti->ipi_ifindex); 412 continue; 413 } 414 415 inet_ntop(AF_INET, &sin.sin_addr, addr_str, sizeof(addr_str)); 416 417 interface_recv_msg(iface, addr_str, buf, len); 418 } while (1); 419 } 420 421 422 static void interface_recv_v6(struct uloop_fd *u, unsigned int events){ 423 static char buf[APMGR_BUFLEN]; 424 static char cmsg_buf[( CMSG_SPACE(sizeof(struct in6_pktinfo)) + sizeof(int)) + 1]; 425 static struct sockaddr_in6 sin; 426 static struct iovec iov = { 427 .iov_base = buf, 428 .iov_len = sizeof(buf) 429 }; 430 static struct msghdr msg = { 431 .msg_name = &sin, 432 .msg_namelen = sizeof(sin), 433 .msg_iov = &iov, 434 .msg_iovlen = 1, 435 .msg_control = cmsg_buf, 436 .msg_controllen = sizeof(cmsg_buf), 437 }; 438 struct cmsghdr *cmsg; 439 char addr_str[INET6_ADDRSTRLEN]; 440 int len; 441 442 do { 443 struct in6_pktinfo *pkti = NULL; 444 struct interface *iface; 445 446 len = recvmsg(u->fd, &msg, 0); 447 if (len < 0) { 448 switch (errno) { 449 case EAGAIN: 450 return; 451 case EINTR: 452 continue; 453 default: 454 perror("recvmsg"); 455 uloop_fd_delete(u); 456 return; 457 } 458 } 459 460 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 461 if (cmsg->cmsg_type != IPV6_PKTINFO) 462 continue; 463 464 pkti = (struct in6_pktinfo *) CMSG_DATA(cmsg); 465 } 466 467 if (!pkti) { 468 MSG(DEBUG, "Received packet without ifindex\n"); 469 continue; 470 } 471 472 iface = interface_find_by_ifindex(pkti->ipi6_ifindex); 473 if (!iface) { 474 MSG(DEBUG, "Received packet from unconfigured interface %d\n", pkti->ipi6_ifindex); 475 continue; 476 } 477 478 inet_ntop(AF_INET6, &sin.sin6_addr, addr_str, sizeof(addr_str)); 479 if (sin.sin6_addr.s6_addr[0] == 0) { 480 /* IPv4 mapped address. Ignore. */ 481 continue; 482 } 483 484 interface_recv_msg(iface, addr_str, buf, len); 485 } while (1); 486 } 487 488 static void interface_send_msg_v4(struct interface *iface, struct blob_attr *data) 489 { 490 static size_t cmsg_data[( CMSG_SPACE(sizeof(struct in_pktinfo)) / sizeof(size_t)) + 1]; 491 static struct sockaddr_in a; 492 static struct iovec iov; 493 static struct msghdr m = { 494 .msg_name = (struct sockaddr *) &a, 495 .msg_namelen = sizeof(a), 496 .msg_iov = &iov, 497 .msg_iovlen = 1, 498 .msg_control = cmsg_data, 499 .msg_controllen = CMSG_LEN(sizeof(struct in_pktinfo)), 500 }; 501 struct in_pktinfo *pkti; 502 struct cmsghdr *cmsg; 503 504 a.sin_family = AF_INET; 505 a.sin_port = htons(APMGR_PORT); 506 a.sin_addr.s_addr = ~0; 507 508 memset(cmsg_data, 0, sizeof(cmsg_data)); 509 cmsg = CMSG_FIRSTHDR(&m); 510 cmsg->cmsg_len = m.msg_controllen; 511 cmsg->cmsg_level = IPPROTO_IP; 512 cmsg->cmsg_type = IP_PKTINFO; 513 514 pkti = (struct in_pktinfo *) CMSG_DATA(cmsg); 515 pkti->ipi_ifindex = iface->ifindex; 516 517 iov.iov_base = data; 518 iov.iov_len = blob_pad_len(data); 519 520 if (sendmsg(remote_fd.fd, &m, 0) < 0) 521 perror("sendmsg"); 522 } 523 524 525 static void interface_send_msg_v6(struct interface *iface, struct blob_attr *data) { 526 static struct sockaddr_in6 groupSock = {}; 527 528 groupSock.sin6_family = AF_INET6; 529 inet_pton(AF_INET6, APMGR_V6_MCAST_GROUP, &groupSock.sin6_addr); 530 groupSock.sin6_port = htons(APMGR_PORT); 531 532 setsockopt(remote_fd.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface->ifindex, sizeof(iface->ifindex)); 533 534 if (sendto(remote_fd.fd, data, blob_pad_len(data), 0, (const struct sockaddr *)&groupSock, sizeof(groupSock)) < 0) 535 perror("sendmsg"); 536 } 537 538 static void interface_send_msg(struct interface *iface, struct blob_attr *data){ 539 if (config.ipv6) { 540 interface_send_msg_v6(iface, data); 541 } else { 542 interface_send_msg_v4(iface, data); 543 } 544 } 545 546 static void usteer_send_sta_info(struct sta_info *sta) 547 { 548 int seen = current_time - sta->seen; 549 int last_connected = !!sta->connected ? 0 : current_time - sta->last_connected; 550 void *c; 551 552 c = blob_nest_start(&buf, 0); 553 blob_put(&buf, APMSG_STA_ADDR, sta->sta->addr, 6); 554 blob_put_int8(&buf, APMSG_STA_CONNECTED, !!sta->connected); 555 blob_put_int32(&buf, APMSG_STA_SIGNAL, sta->signal); 556 blob_put_int32(&buf, APMSG_STA_SEEN, seen); 557 blob_put_int32(&buf, APMSG_STA_LAST_CONNECTED, last_connected); 558 blob_put_int32(&buf, APMSG_STA_TIMEOUT, config.local_sta_timeout - seen); 559 blob_nest_end(&buf, c); 560 } 561 562 static void usteer_send_node(struct usteer_node *node, struct sta_info *sta) 563 { 564 void *c, *s, *r; 565 566 c = blob_nest_start(&buf, 0); 567 568 blob_put_string(&buf, APMSG_NODE_NAME, usteer_node_name(node)); 569 blob_put_string(&buf, APMSG_NODE_SSID, node->ssid); 570 blob_put_int32(&buf, APMSG_NODE_FREQ, node->freq); 571 blob_put_int32(&buf, APMSG_NODE_NOISE, node->noise); 572 blob_put_int32(&buf, APMSG_NODE_LOAD, node->load); 573 blob_put_int32(&buf, APMSG_NODE_N_ASSOC, node->n_assoc); 574 blob_put_int32(&buf, APMSG_NODE_MAX_ASSOC, node->max_assoc); 575 blob_put_int32(&buf, APMSG_NODE_OP_CLASS, node->op_class); 576 blob_put_int32(&buf, APMSG_NODE_CHANNEL, node->channel); 577 blob_put(&buf, APMSG_NODE_BSSID, node->bssid, sizeof(node->bssid)); 578 if (node->rrm_nr) { 579 r = blob_nest_start(&buf, APMSG_NODE_RRM_NR); 580 blobmsg_add_field(&buf, BLOBMSG_TYPE_ARRAY, "", 581 blobmsg_data(node->rrm_nr), 582 blobmsg_data_len(node->rrm_nr)); 583 blob_nest_end(&buf, r); 584 } 585 586 if (node->node_info) 587 blob_put(&buf, APMSG_NODE_NODE_INFO, 588 blob_data(node->node_info), 589 blob_len(node->node_info)); 590 591 s = blob_nest_start(&buf, APMSG_NODE_STATIONS); 592 593 if (sta) { 594 usteer_send_sta_info(sta); 595 } else { 596 list_for_each_entry(sta, &node->sta_info, node_list) 597 usteer_send_sta_info(sta); 598 } 599 600 blob_nest_end(&buf, s); 601 602 blob_nest_end(&buf, c); 603 } 604 605 static void 606 usteer_check_timeout(void) 607 { 608 struct usteer_remote_node *node, *tmp; 609 int timeout = config.remote_node_timeout; 610 611 list_for_each_entry_safe(node, tmp, &remote_nodes, list) { 612 if (config.local_mode || node->check++ > timeout) 613 remote_node_free(node); 614 } 615 } 616 617 static void * 618 usteer_update_init(void) 619 { 620 blob_buf_init(&buf, 0); 621 blob_put_int32(&buf, APMSG_ID, local_id); 622 blob_put_int32(&buf, APMSG_SEQ, ++msg_seq); 623 if (host_info_blob) 624 blob_put(&buf, APMSG_HOST_INFO, 625 blob_data(host_info_blob), 626 blob_len(host_info_blob)); 627 628 return blob_nest_start(&buf, APMSG_NODES); 629 } 630 631 static void 632 usteer_update_send(void *c) 633 { 634 struct interface *iface; 635 636 blob_nest_end(&buf, c); 637 638 vlist_for_each_element(&interfaces, iface, node) 639 interface_send_msg(iface, buf.head); 640 } 641 642 void 643 usteer_send_sta_update(struct sta_info *si) 644 { 645 void *c = usteer_update_init(); 646 usteer_send_node(si->node, si); 647 usteer_update_send(c); 648 } 649 650 static void 651 usteer_send_update_timer(struct uloop_timeout *t) 652 { 653 struct usteer_node *node; 654 void *c; 655 656 usteer_update_time(); 657 uloop_timeout_set(t, config.remote_update_interval); 658 659 if (!config.local_mode && 660 (!avl_is_empty(&local_nodes) || host_info_blob)) { 661 c = usteer_update_init(); 662 for_each_local_node(node) 663 usteer_send_node(node, NULL); 664 665 usteer_update_send(c); 666 } 667 usteer_check_timeout(); 668 } 669 670 static int 671 usteer_init_local_id(void) 672 { 673 FILE *f; 674 675 f = fopen("/dev/urandom", "r"); 676 if (!f) { 677 perror("fopen(/dev/urandom)"); 678 return -1; 679 } 680 681 if (fread(&local_id, sizeof(local_id), 1, f) < 1) { 682 fclose(f); 683 return -1; 684 } 685 686 fclose(f); 687 return 0; 688 } 689 690 static int usteer_create_v4_socket() { 691 int yes = 1; 692 int fd; 693 694 fd = usock(USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK | 695 USOCK_NUMERIC | USOCK_IPV4ONLY, 696 "0.0.0.0", APMGR_PORT_STR); 697 if (fd < 0) { 698 perror("usock"); 699 return - 1; 700 } 701 702 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) 703 perror("setsockopt(IP_PKTINFO)"); 704 705 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)) < 0) 706 perror("setsockopt(SO_BROADCAST)"); 707 708 return fd; 709 } 710 711 712 static int usteer_create_v6_socket() { 713 struct interface *iface; 714 struct ipv6_mreq group; 715 int yes = 1; 716 int fd; 717 718 fd = usock(USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK | 719 USOCK_NUMERIC | USOCK_IPV6ONLY, 720 "::", APMGR_PORT_STR); 721 if (fd < 0) { 722 perror("usock"); 723 return fd; 724 } 725 726 if (!inet_pton(AF_INET6, APMGR_V6_MCAST_GROUP, &group.ipv6mr_multiaddr.s6_addr)) 727 perror("inet_pton(AF_INET6)"); 728 729 /* Membership has to be added for every interface we listen on. */ 730 vlist_for_each_element(&interfaces, iface, node) { 731 group.ipv6mr_interface = iface->ifindex; 732 if(setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&group, sizeof group) < 0) 733 perror("setsockopt(IPV6_ADD_MEMBERSHIP)"); 734 } 735 736 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &yes, sizeof(yes)) < 0) 737 perror("setsockopt(IPV6_RECVPKTINFO)"); 738 739 if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)) < 0) 740 perror("setsockopt(SO_BROADCAST)"); 741 742 return fd; 743 } 744 745 static void usteer_reload_timer(struct uloop_timeout *t) { 746 /* Remove uloop descriptor */ 747 if (remote_fd.fd && remote_fd.registered) { 748 uloop_fd_delete(&remote_fd); 749 close(remote_fd.fd); 750 } 751 752 if (config.ipv6) { 753 remote_fd.fd = usteer_create_v6_socket(); 754 remote_fd.cb = interface_recv_v6; 755 } else { 756 remote_fd.fd = usteer_create_v4_socket(); 757 remote_fd.cb = interface_recv_v4; 758 } 759 760 if (remote_fd.fd < 0) 761 return; 762 763 uloop_fd_add(&remote_fd, ULOOP_READ); 764 } 765 766 int usteer_interface_init(void) 767 { 768 if (usteer_init_local_id()) 769 return -1; 770 771 remote_timer.cb = usteer_send_update_timer; 772 remote_timer.cb(&remote_timer); 773 774 reload_timer.cb = usteer_reload_timer; 775 reload_timer.cb(&reload_timer); 776 777 return 0; 778 } 779
This page was automatically generated by LXR 0.3.1. • OpenWrt