]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/rtadvd/if.c
Import sqlite3 3.12.1
[FreeBSD/FreeBSD.git] / usr.sbin / rtadvd / if.c
1 /*      $FreeBSD$       */
2 /*      $KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun Exp $     */
3
4 /*
5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6  * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include <sys/param.h>
35 #include <sys/socket.h>
36 #include <sys/sysctl.h>
37 #include <sys/ioctl.h>
38 #include <net/if.h>
39 #include <net/if_dl.h>
40 #include <net/if_types.h>
41 #include <net/ethernet.h>
42 #include <net/route.h>
43 #include <netinet/in.h>
44 #include <netinet/in_var.h>
45 #include <netinet/ip6.h>
46 #include <netinet/icmp6.h>
47 #include <netinet6/nd6.h>
48 #include <unistd.h>
49 #include <errno.h>
50 #include <netdb.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <syslog.h>
54
55 #include "pathnames.h"
56 #include "rtadvd.h"
57 #include "if.h"
58
59 #define ROUNDUP(a, size)                                        \
60         (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
61
62 #define NEXT_SA(ap)                                                     \
63         (ap) = (struct sockaddr *)((caddr_t)(ap) +                      \
64             ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) :     \
65             sizeof(u_long)))
66
67 struct sockaddr_in6 sin6_linklocal_allnodes = {
68         .sin6_len =     sizeof(sin6_linklocal_allnodes),
69         .sin6_family =  AF_INET6,
70         .sin6_addr =    IN6ADDR_LINKLOCAL_ALLNODES_INIT,
71 };
72
73 struct sockaddr_in6 sin6_linklocal_allrouters = {
74         .sin6_len =     sizeof(sin6_linklocal_allrouters),
75         .sin6_family =  AF_INET6,
76         .sin6_addr =    IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
77 };
78
79 struct sockaddr_in6 sin6_sitelocal_allrouters = {
80         .sin6_len =     sizeof(sin6_sitelocal_allrouters),
81         .sin6_family =  AF_INET6,
82         .sin6_addr =    IN6ADDR_SITELOCAL_ALLROUTERS_INIT,
83 };
84
85 struct sockinfo sock = { .si_fd = -1, .si_name = NULL };
86 struct sockinfo rtsock = { .si_fd = -1, .si_name = NULL };
87 struct sockinfo ctrlsock = { .si_fd = -1, .si_name = _PATH_CTRL_SOCK };
88
89 char *mcastif;
90
91 static void             get_rtaddrs(int, struct sockaddr *,
92                             struct sockaddr **);
93 static struct if_msghdr *get_next_msghdr(struct if_msghdr *,
94                             struct if_msghdr *);
95
96 static void
97 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
98 {
99         int i;
100
101         for (i = 0; i < RTAX_MAX; i++) {
102                 if (addrs & (1 << i)) {
103                         rti_info[i] = sa;
104                         NEXT_SA(sa);
105                 }
106                 else
107                         rti_info[i] = NULL;
108         }
109 }
110
111 #define ROUNDUP8(a) (1 + (((a) - 1) | 7))
112 int
113 lladdropt_length(struct sockaddr_dl *sdl)
114 {
115         switch (sdl->sdl_type) {
116         case IFT_ETHER:
117                 return (ROUNDUP8(ETHER_ADDR_LEN + 2));
118         default:
119                 return (0);
120         }
121 }
122
123 void
124 lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
125 {
126         char *addr;
127
128         ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
129
130         switch (sdl->sdl_type) {
131         case IFT_ETHER:
132                 ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
133                 addr = (char *)(ndopt + 1);
134                 memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
135                 break;
136         default:
137                 syslog(LOG_ERR, "<%s> unsupported link type(%d)",
138                     __func__, sdl->sdl_type);
139                 exit(1);
140         }
141
142         return;
143 }
144
145 int
146 rtbuf_len(void)
147 {
148         size_t len;
149         int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
150
151         if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
152                 return (-1);
153
154         return (len);
155 }
156
157 #define FILTER_MATCH(type, filter) ((0x1 << type) & filter)
158 #define SIN6(s) ((struct sockaddr_in6 *)(s))
159 #define SDL(s) ((struct sockaddr_dl *)(s))
160 char *
161 get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
162 {
163         struct rt_msghdr *rtm;
164         struct ifa_msghdr *ifam;
165         struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX];
166
167         *lenp = 0;
168         for (rtm = (struct rt_msghdr *)buf;
169              rtm < (struct rt_msghdr *)lim;
170              rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) {
171                 /* just for safety */
172                 if (!rtm->rtm_msglen) {
173                         syslog(LOG_WARNING, "<%s> rtm_msglen is 0 "
174                             "(buf=%p lim=%p rtm=%p)", __func__,
175                             buf, lim, rtm);
176                         break;
177                 }
178                 if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) {
179                         syslog(LOG_WARNING,
180                             "<%s> routing message version mismatch "
181                             "(buf=%p lim=%p rtm=%p)", __func__,
182                             buf, lim, rtm);
183                         continue;
184                 }
185
186                 if (FILTER_MATCH(rtm->rtm_type, filter) == 0)
187                         continue;
188
189                 switch (rtm->rtm_type) {
190                 case RTM_GET:
191                 case RTM_ADD:
192                 case RTM_DELETE:
193                         /* address related checks */
194                         sa = (struct sockaddr *)(rtm + 1);
195                         get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
196                         if ((dst = rti_info[RTAX_DST]) == NULL ||
197                             dst->sa_family != AF_INET6)
198                                 continue;
199
200                         if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
201                             IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
202                                 continue;
203
204                         if ((gw = rti_info[RTAX_GATEWAY]) == NULL ||
205                             gw->sa_family != AF_LINK)
206                                 continue;
207                         if (ifindex && SDL(gw)->sdl_index != ifindex)
208                                 continue;
209
210                         if (rti_info[RTAX_NETMASK] == NULL)
211                                 continue;
212
213                         /* found */
214                         *lenp = rtm->rtm_msglen;
215                         return (char *)rtm;
216                         /* NOTREACHED */
217                 case RTM_NEWADDR:
218                 case RTM_DELADDR:
219                         ifam = (struct ifa_msghdr *)rtm;
220
221                         /* address related checks */
222                         sa = (struct sockaddr *)(ifam + 1);
223                         get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
224                         if ((ifa = rti_info[RTAX_IFA]) == NULL ||
225                             (ifa->sa_family != AF_INET &&
226                              ifa->sa_family != AF_INET6))
227                                 continue;
228
229                         if (ifa->sa_family == AF_INET6 &&
230                             (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
231                              IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
232                                 continue;
233
234                         if (ifindex && ifam->ifam_index != ifindex)
235                                 continue;
236
237                         /* found */
238                         *lenp = ifam->ifam_msglen;
239                         return (char *)rtm;
240                         /* NOTREACHED */
241                 case RTM_IFINFO:
242                 case RTM_IFANNOUNCE:
243                         /* found */
244                         *lenp = rtm->rtm_msglen;
245                         return (char *)rtm;
246                         /* NOTREACHED */
247                 }
248         }
249
250         return ((char *)rtm);
251 }
252 #undef FILTER_MATCH
253
254 struct in6_addr *
255 get_addr(char *buf)
256 {
257         struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
258         struct sockaddr *sa, *rti_info[RTAX_MAX];
259
260         sa = (struct sockaddr *)(rtm + 1);
261         get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
262
263         return (&SIN6(rti_info[RTAX_DST])->sin6_addr);
264 }
265
266 int
267 get_rtm_ifindex(char *buf)
268 {
269         struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
270         struct sockaddr *sa, *rti_info[RTAX_MAX];
271
272         sa = (struct sockaddr *)(rtm + 1);
273         get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
274
275         return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
276 }
277
278 int
279 get_prefixlen(char *buf)
280 {
281         struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
282         struct sockaddr *sa, *rti_info[RTAX_MAX];
283         char *p, *lim;
284
285         sa = (struct sockaddr *)(rtm + 1);
286         get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
287         sa = rti_info[RTAX_NETMASK];
288
289         p = (char *)(&SIN6(sa)->sin6_addr);
290         lim = (char *)sa + sa->sa_len;
291         return prefixlen(p, lim);
292 }
293
294 int
295 prefixlen(unsigned char *p, unsigned char *lim)
296 {
297         int masklen;
298
299         for (masklen = 0; p < lim; p++) {
300                 switch (*p) {
301                 case 0xff:
302                         masklen += 8;
303                         break;
304                 case 0xfe:
305                         masklen += 7;
306                         break;
307                 case 0xfc:
308                         masklen += 6;
309                         break;
310                 case 0xf8:
311                         masklen += 5;
312                         break;
313                 case 0xf0:
314                         masklen += 4;
315                         break;
316                 case 0xe0:
317                         masklen += 3;
318                         break;
319                 case 0xc0:
320                         masklen += 2;
321                         break;
322                 case 0x80:
323                         masklen += 1;
324                         break;
325                 case 0x00:
326                         break;
327                 default:
328                         return (-1);
329                 }
330         }
331
332         return (masklen);
333 }
334
335 struct ifinfo *
336 update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname)
337 {
338         struct ifinfo *ifi;
339         int ifindex;
340
341         ifi = NULL;
342         ifindex = if_nametoindex(ifname);
343         TAILQ_FOREACH(ifi, ifi_head, ifi_next) {
344                 if (ifindex != 0) {
345                         if (ifindex == ifi->ifi_ifindex)
346                                 break;
347                 } else {
348                         if (strncmp(ifname, ifi->ifi_ifname,
349                                 sizeof(ifi->ifi_ifname)) == 0)
350                                 break;
351                 }
352         }
353
354         if (ifi == NULL) {
355                 /* A new ifinfo element is needed. */
356                 syslog(LOG_DEBUG, "<%s> new entry: %s", __func__,
357                     ifname);
358
359                 ELM_MALLOC(ifi, exit(1));
360                 ifi->ifi_ifindex = 0;
361                 strlcpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname));
362                 ifi->ifi_rainfo = NULL;
363                 ifi->ifi_state = IFI_STATE_UNCONFIGURED;
364                 TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next);
365         }
366
367         ifi->ifi_persist = 1;
368
369         syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__,
370             ifi->ifi_ifname);
371         syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__,
372             ifi->ifi_ifname, ifi->ifi_state);
373         return (ifi);
374 }
375
376 int
377 update_ifinfo_nd_flags(struct ifinfo *ifi)
378 {
379         struct in6_ndireq nd;
380         int s;
381         int error;
382
383         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
384                 syslog(LOG_ERR,
385                     "<%s> socket() failed.", __func__);
386                 return (1);
387         }
388         /* ND flags */
389         memset(&nd, 0, sizeof(nd));
390         strncpy(nd.ifname, ifi->ifi_ifname,
391             sizeof(nd.ifname));
392         error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd);
393         if (error) {
394                 close(s);
395                 if (errno != EPFNOSUPPORT)
396                         syslog(LOG_ERR, "<%s> ioctl() failed.", __func__);
397                 return (1);
398         }
399         ifi->ifi_nd_flags = nd.ndi.flags;
400         close(s);
401
402         return (0);
403 }
404
405 struct ifinfo *
406 update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex)
407 {
408         struct if_msghdr *ifm;
409         struct ifinfo *ifi = NULL;
410         struct sockaddr *sa;
411         struct sockaddr *rti_info[RTAX_MAX];
412         char *msg;
413         size_t len;
414         char *lim;
415         int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 };
416         int error;
417
418         syslog(LOG_DEBUG, "<%s> enter", __func__);
419
420         if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) <
421             0) {
422                 syslog(LOG_ERR,
423                     "<%s> sysctl: NET_RT_IFLIST size get failed", __func__);
424                 exit(1);
425         }
426         if ((msg = malloc(len)) == NULL) {
427                 syslog(LOG_ERR, "<%s> malloc failed", __func__);
428                 exit(1);
429         }
430         if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) <
431             0) {
432                 syslog(LOG_ERR,
433                     "<%s> sysctl: NET_RT_IFLIST get failed", __func__);
434                 exit(1);
435         }
436
437         lim = msg + len;
438         for (ifm = (struct if_msghdr *)msg;
439              ifm != NULL && ifm < (struct if_msghdr *)lim;
440              ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) {
441                 int ifi_new;
442
443                 syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu",
444                     __func__, ifm, lim, (char *)lim - (char *)ifm);
445
446                 if (ifm->ifm_version != RTM_VERSION) {
447                         syslog(LOG_ERR,
448                             "<%s> ifm_vesrion mismatch", __func__);
449                         exit(1);
450                 }
451                 if (ifm->ifm_msglen == 0) {
452                         syslog(LOG_WARNING,
453                             "<%s> ifm_msglen is 0", __func__);
454                         free(msg);
455                         return (NULL);
456                 }
457
458                 ifi_new = 0;
459                 if (ifm->ifm_type == RTM_IFINFO) {
460                         struct ifreq ifr;
461                         int s;
462                         char ifname[IFNAMSIZ];
463
464                         syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. "
465                             "ifm_index = %d, ifindex = %d",
466                             __func__, ifm->ifm_index, ifindex);
467
468                         /* when ifindex is specified */
469                         if (ifindex != UPDATE_IFINFO_ALL &&
470                             ifindex != ifm->ifm_index)
471                                 continue;
472
473                         /* lookup an entry with the same ifindex */
474                         TAILQ_FOREACH(ifi, ifi_head, ifi_next) {
475                                 if (ifm->ifm_index == ifi->ifi_ifindex)
476                                         break;
477                                 if_indextoname(ifm->ifm_index, ifname);
478                                 if (strncmp(ifname, ifi->ifi_ifname,
479                                         sizeof(ifname)) == 0)
480                                         break;
481                         }
482                         if (ifi == NULL) {
483                                 syslog(LOG_DEBUG,
484                                     "<%s> new entry for idx=%d",
485                                     __func__, ifm->ifm_index);
486                                 ELM_MALLOC(ifi, exit(1));
487                                 ifi->ifi_rainfo = NULL;
488                                 ifi->ifi_state = IFI_STATE_UNCONFIGURED;
489                                 ifi->ifi_persist = 0;
490                                 ifi_new = 1;
491                         }
492                         /* ifindex */
493                         ifi->ifi_ifindex = ifm->ifm_index;
494
495                         /* ifname */
496                         if_indextoname(ifm->ifm_index, ifi->ifi_ifname);
497                         if (ifi->ifi_ifname == NULL) {
498                                 syslog(LOG_WARNING,
499                                     "<%s> ifname not found (idx=%d)",
500                                     __func__, ifm->ifm_index);
501                                 if (ifi_new)
502                                         free(ifi);
503                                 continue;
504                         }
505
506                         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
507                                 syslog(LOG_ERR,
508                                     "<%s> socket() failed.", __func__);
509                                 if (ifi_new)
510                                         free(ifi);
511                                 continue;
512                         }
513
514                         /* MTU  */
515                         ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu;
516                         if (ifi->ifi_phymtu == 0) {
517                                 memset(&ifr, 0, sizeof(ifr));
518                                 ifr.ifr_addr.sa_family = AF_INET6;
519                                 strncpy(ifr.ifr_name, ifi->ifi_ifname,
520                                     sizeof(ifr.ifr_name));
521                                 error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr);
522                                 if (error) {
523                                         close(s);
524                                         syslog(LOG_ERR,
525                                             "<%s> ioctl() failed.",
526                                             __func__);
527                                         if (ifi_new)
528                                                 free(ifi);
529                                         continue;
530                                 }
531                                 ifi->ifi_phymtu = ifr.ifr_mtu;
532                                 if (ifi->ifi_phymtu == 0) {
533                                         syslog(LOG_WARNING,
534                                             "<%s> no interface mtu info"
535                                             " on %s.  %d will be used.",
536                                             __func__, ifi->ifi_ifname,
537                                             IPV6_MMTU);
538                                         ifi->ifi_phymtu = IPV6_MMTU;
539                                 }
540                         }
541                         close(s);
542
543                         /* ND flags */
544                         error = update_ifinfo_nd_flags(ifi);
545                         if (error) {
546                                 if (ifi_new)
547                                         free(ifi);
548                                 continue;
549                         }
550
551                         /* SDL */
552                         sa = (struct sockaddr *)(ifm + 1);
553                         get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
554                         if ((sa = rti_info[RTAX_IFP]) != NULL) {
555                                 if (sa->sa_family == AF_LINK) {
556                                         memcpy(&ifi->ifi_sdl,
557                                             (struct sockaddr_dl *)sa,
558                                             sizeof(ifi->ifi_sdl));
559                                 }
560                         } else
561                                 memset(&ifi->ifi_sdl, 0,
562                                     sizeof(ifi->ifi_sdl));
563
564                         /* flags */
565                         ifi->ifi_flags = ifm->ifm_flags;
566
567                         /* type */
568                         ifi->ifi_type = ifm->ifm_type;
569                 } else {
570                         syslog(LOG_ERR,
571                             "out of sync parsing NET_RT_IFLIST\n"
572                             "expected %d, got %d\n msglen = %d\n",
573                             RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen);
574                         exit(1);
575                 }
576
577                 if (ifi_new) {
578                         syslog(LOG_DEBUG,
579                             "<%s> adding %s(idx=%d) to ifilist",
580                             __func__, ifi->ifi_ifname, ifi->ifi_ifindex);
581                         TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next);
582                 }
583         }
584         free(msg);
585
586         if (mcastif != NULL) {
587                 error = sock_mc_rr_update(&sock, mcastif);
588                 if (error)
589                         exit(1);
590         }
591
592         return (ifi);
593 }
594
595 static struct if_msghdr *
596 get_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim)
597 {
598         struct ifa_msghdr *ifam;
599
600         for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen);
601              ifam < (struct ifa_msghdr *)lim;
602              ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) {
603                 if (!ifam->ifam_msglen) {
604                         syslog(LOG_WARNING,
605                             "<%s> ifa_msglen is 0", __func__);
606                         return (NULL);
607                 }
608                 if (ifam->ifam_type != RTM_NEWADDR)
609                         break;
610         }
611
612         return ((struct if_msghdr *)ifam);
613 }
614
615 int
616 getinet6sysctl(int code)
617 {
618         int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
619         int value;
620         size_t size;
621
622         mib[3] = code;
623         size = sizeof(value);
624         if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
625             < 0) {
626                 syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s",
627                     __func__, code,
628                     strerror(errno));
629                 return (-1);
630         }
631         else
632                 return (value);
633 }
634
635
636 int
637 sock_mc_join(struct sockinfo *s, int ifindex)
638 {
639         struct ipv6_mreq mreq;
640         char ifname[IFNAMSIZ];
641
642         syslog(LOG_DEBUG, "<%s> enter", __func__);
643
644         if (ifindex == 0)
645                 return (1);
646
647         /*
648          * join all routers multicast address on each advertising
649          * interface.
650          */
651         memset(&mreq, 0, sizeof(mreq));
652         /* XXX */
653         memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
654             &sin6_linklocal_allrouters.sin6_addr,
655             sizeof(mreq.ipv6mr_multiaddr.s6_addr));
656
657         mreq.ipv6mr_interface = ifindex;
658         if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
659                 sizeof(mreq)) < 0) {
660                 syslog(LOG_ERR,
661                     "<%s> IPV6_JOIN_GROUP(link) on %s: %s",
662                     __func__, if_indextoname(ifindex, ifname),
663                     strerror(errno));
664                 return (1);
665         }
666         syslog(LOG_DEBUG,
667             "<%s> %s: join link-local all-routers MC group",
668             __func__, if_indextoname(ifindex, ifname));
669
670         return (0);
671 }
672
673 int
674 sock_mc_leave(struct sockinfo *s, int ifindex)
675 {
676         struct ipv6_mreq mreq;
677         char ifname[IFNAMSIZ];
678
679         syslog(LOG_DEBUG, "<%s> enter", __func__);
680
681         if (ifindex == 0)
682                 return (1);
683
684         /*
685          * join all routers multicast address on each advertising
686          * interface.
687          */
688
689         memset(&mreq, 0, sizeof(mreq));
690         /* XXX */
691         memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
692             &sin6_linklocal_allrouters.sin6_addr,
693             sizeof(mreq.ipv6mr_multiaddr.s6_addr));
694
695         mreq.ipv6mr_interface = ifindex;
696         if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq,
697                 sizeof(mreq)) < 0) {
698                 syslog(LOG_ERR,
699                     "<%s> IPV6_JOIN_LEAVE(link) on %s: %s",
700                     __func__, if_indextoname(ifindex, ifname),
701                     strerror(errno));
702                 return (1);
703         }
704         syslog(LOG_DEBUG,
705             "<%s> %s: leave link-local all-routers MC group",
706             __func__, if_indextoname(ifindex, ifname));
707
708         return (0);
709 }
710
711 int
712 sock_mc_rr_update(struct sockinfo *s, char *mif)
713 {
714         struct ipv6_mreq mreq;
715
716         syslog(LOG_DEBUG, "<%s> enter", __func__);
717
718         if (mif == NULL)
719                 return (1);
720         /*
721          * When attending router renumbering, join all-routers site-local
722          * multicast group.
723          */
724         /* XXX */
725         memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
726             &sin6_sitelocal_allrouters.sin6_addr,
727             sizeof(mreq.ipv6mr_multiaddr.s6_addr));
728         if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) {
729                 syslog(LOG_ERR,
730                     "<%s> invalid interface: %s",
731                     __func__, mif);
732                 return (1);
733         }
734
735         if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
736                 &mreq, sizeof(mreq)) < 0) {
737                 syslog(LOG_ERR,
738                     "<%s> IPV6_JOIN_GROUP(site) on %s: %s",
739                     __func__, mif, strerror(errno));
740                 return (1);
741         }
742
743         syslog(LOG_DEBUG,
744             "<%s> %s: join site-local all-routers MC group",
745             __func__, mif);
746
747         return (0);
748 }