• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/usteer/remote.c

  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                 return -1;
683 
684         fclose(f);
685         return 0;
686 }
687 
688 static int usteer_create_v4_socket() {
689         int yes = 1;
690         int fd;
691 
692         fd = usock(USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK |
693                    USOCK_NUMERIC | USOCK_IPV4ONLY,
694                    "0.0.0.0", APMGR_PORT_STR);
695         if (fd < 0) {
696                 perror("usock");
697                 return - 1;
698         }
699 
700         if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0)
701                 perror("setsockopt(IP_PKTINFO)");
702 
703         if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)) < 0)
704                 perror("setsockopt(SO_BROADCAST)");
705 
706         return fd;
707 }
708 
709 
710 static int usteer_create_v6_socket() {
711         struct interface *iface;
712         struct ipv6_mreq group;
713         int yes = 1;
714         int fd;
715 
716         fd = usock(USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK |
717                    USOCK_NUMERIC | USOCK_IPV6ONLY,
718                    "::", APMGR_PORT_STR);
719         if (fd < 0) {
720                 perror("usock");
721                 return fd;
722         }
723 
724         if (!inet_pton(AF_INET6, APMGR_V6_MCAST_GROUP, &group.ipv6mr_multiaddr.s6_addr))
725                 perror("inet_pton(AF_INET6)");
726 
727         /* Membership has to be added for every interface we listen on. */
728         vlist_for_each_element(&interfaces, iface, node) {
729                 group.ipv6mr_interface = iface->ifindex;
730                 if(setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&group, sizeof group) < 0)
731                         perror("setsockopt(IPV6_ADD_MEMBERSHIP)");
732         }
733 
734         if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &yes, sizeof(yes)) < 0)
735                 perror("setsockopt(IPV6_RECVPKTINFO)");
736 
737         if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)) < 0)
738                 perror("setsockopt(SO_BROADCAST)");
739 
740         return fd;
741 }
742 
743 static void usteer_reload_timer(struct uloop_timeout *t) {
744         /* Remove uloop descriptor */
745         if (remote_fd.fd && remote_fd.registered) {
746                 uloop_fd_delete(&remote_fd);
747                 close(remote_fd.fd);
748         }
749 
750         if (config.ipv6) {
751                 remote_fd.fd = usteer_create_v6_socket();
752                 remote_fd.cb = interface_recv_v6;
753         } else {
754                 remote_fd.fd = usteer_create_v4_socket();
755                 remote_fd.cb = interface_recv_v4;
756         }
757 
758         if (remote_fd.fd < 0)
759                 return;
760 
761         uloop_fd_add(&remote_fd, ULOOP_READ);
762 }
763 
764 int usteer_interface_init(void)
765 {
766         if (usteer_init_local_id())
767                 return -1;
768 
769         remote_timer.cb = usteer_send_update_timer;
770         remote_timer.cb(&remote_timer);
771 
772         reload_timer.cb = usteer_reload_timer;
773         reload_timer.cb(&reload_timer);
774 
775         return 0;
776 }
777 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt