]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/rtadvd/if.c
MFS11 r335088 (dim):
[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         case IFT_L2VLAN:
118         case IFT_BRIDGE:
119                 return (ROUNDUP8(ETHER_ADDR_LEN + 2));
120         default:
121                 return (0);
122         }
123 }
124
125 void
126 lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
127 {
128         char *addr;
129
130         ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
131
132         switch (sdl->sdl_type) {
133         case IFT_ETHER:
134         case IFT_L2VLAN:
135         case IFT_BRIDGE:
136                 ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
137                 addr = (char *)(ndopt + 1);
138                 memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
139                 break;
140         default:
141                 syslog(LOG_ERR, "<%s> unsupported link type(%d)",
142                     __func__, sdl->sdl_type);
143                 exit(1);
144         }
145
146         return;
147 }
148
149 int
150 rtbuf_len(void)
151 {
152         size_t len;
153         int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
154
155         if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
156                 return (-1);
157
158         return (len);
159 }
160
161 #define FILTER_MATCH(type, filter) ((0x1 << type) & filter)
162 #define SIN6(s) ((struct sockaddr_in6 *)(s))
163 #define SDL(s) ((struct sockaddr_dl *)(s))
164 char *
165 get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
166 {
167         struct rt_msghdr *rtm;
168         struct ifa_msghdr *ifam;
169         struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX];
170
171         *lenp = 0;
172         for (rtm = (struct rt_msghdr *)buf;
173              rtm < (struct rt_msghdr *)lim;
174              rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) {
175                 /* just for safety */
176                 if (!rtm->rtm_msglen) {
177                         syslog(LOG_WARNING, "<%s> rtm_msglen is 0 "
178                             "(buf=%p lim=%p rtm=%p)", __func__,
179                             buf, lim, rtm);
180                         break;
181                 }
182                 if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) {
183                         syslog(LOG_WARNING,
184                             "<%s> routing message version mismatch "
185                             "(buf=%p lim=%p rtm=%p)", __func__,
186                             buf, lim, rtm);
187                         continue;
188                 }
189
190                 if (FILTER_MATCH(rtm->rtm_type, filter) == 0)
191                         continue;
192
193                 switch (rtm->rtm_type) {
194                 case RTM_GET:
195                 case RTM_ADD:
196                 case RTM_DELETE:
197                         /* address related checks */
198                         sa = (struct sockaddr *)(rtm + 1);
199                         get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
200                         if ((dst = rti_info[RTAX_DST]) == NULL ||
201                             dst->sa_family != AF_INET6)
202                                 continue;
203
204                         if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
205                             IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
206                                 continue;
207
208                         if ((gw = rti_info[RTAX_GATEWAY]) == NULL ||
209                             gw->sa_family != AF_LINK)
210                                 continue;
211                         if (ifindex && SDL(gw)->sdl_index != ifindex)
212                                 continue;
213
214                         if (rti_info[RTAX_NETMASK] == NULL)
215                                 continue;
216
217                         /* found */
218                         *lenp = rtm->rtm_msglen;
219                         return (char *)rtm;
220                         /* NOTREACHED */
221                 case RTM_NEWADDR:
222                 case RTM_DELADDR:
223                         ifam = (struct ifa_msghdr *)rtm;
224
225                         /* address related checks */
226                         sa = (struct sockaddr *)(ifam + 1);
227                         get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
228                         if ((ifa = rti_info[RTAX_IFA]) == NULL ||
229                             (ifa->sa_family != AF_INET &&
230                              ifa->sa_family != AF_INET6))
231                                 continue;
232
233                         if (ifa->sa_family == AF_INET6 &&
234                             (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
235                              IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
236                                 continue;
237
238                         if (ifindex && ifam->ifam_index != ifindex)
239                                 continue;
240
241                         /* found */
242                         *lenp = ifam->ifam_msglen;
243                         return (char *)rtm;
244                         /* NOTREACHED */
245                 case RTM_IFINFO:
246                 case RTM_IFANNOUNCE:
247                         /* found */
248                         *lenp = rtm->rtm_msglen;
249                         return (char *)rtm;
250                         /* NOTREACHED */
251                 }
252         }
253
254         return ((char *)rtm);
255 }
256 #undef FILTER_MATCH
257
258 struct in6_addr *
259 get_addr(char *buf)
260 {
261         struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
262         struct sockaddr *sa, *rti_info[RTAX_MAX];
263
264         sa = (struct sockaddr *)(rtm + 1);
265         get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
266
267         return (&SIN6(rti_info[RTAX_DST])->sin6_addr);
268 }
269
270 int
271 get_rtm_ifindex(char *buf)
272 {
273         struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
274         struct sockaddr *sa, *rti_info[RTAX_MAX];
275
276         sa = (struct sockaddr *)(rtm + 1);
277         get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
278
279         return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
280 }
281
282 int
283 get_prefixlen(char *buf)
284 {
285         struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
286         struct sockaddr *sa, *rti_info[RTAX_MAX];
287         char *p, *lim;
288
289         sa = (struct sockaddr *)(rtm + 1);
290         get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
291         sa = rti_info[RTAX_NETMASK];
292
293         p = (char *)(&SIN6(sa)->sin6_addr);
294         lim = (char *)sa + sa->sa_len;
295         return prefixlen(p, lim);
296 }
297
298 int
299 prefixlen(unsigned char *p, unsigned char *lim)
300 {
301         int masklen;
302
303         for (masklen = 0; p < lim; p++) {
304                 switch (*p) {
305                 case 0xff:
306                         masklen += 8;
307                         break;
308                 case 0xfe:
309                         masklen += 7;
310                         break;
311                 case 0xfc:
312                         masklen += 6;
313                         break;
314                 case 0xf8:
315                         masklen += 5;
316                         break;
317                 case 0xf0:
318                         masklen += 4;
319                         break;
320                 case 0xe0:
321                         masklen += 3;
322                         break;
323                 case 0xc0:
324                         masklen += 2;
325                         break;
326                 case 0x80:
327                         masklen += 1;
328                         break;
329                 case 0x00:
330                         break;
331                 default:
332                         return (-1);
333                 }
334         }
335
336         return (masklen);
337 }
338
339 struct ifinfo *
340 update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname)
341 {
342         struct ifinfo *ifi;
343         int ifindex;
344
345         ifi = NULL;
346         ifindex = if_nametoindex(ifname);
347         TAILQ_FOREACH(ifi, ifi_head, ifi_next) {
348                 if (ifindex != 0) {
349                         if (ifindex == ifi->ifi_ifindex)
350                                 break;
351                 } else {
352                         if (strncmp(ifname, ifi->ifi_ifname,
353                                 sizeof(ifi->ifi_ifname)) == 0)
354                                 break;
355                 }
356         }
357
358         if (ifi == NULL) {
359                 /* A new ifinfo element is needed. */
360                 syslog(LOG_DEBUG, "<%s> new entry: %s", __func__,
361                     ifname);
362
363                 ELM_MALLOC(ifi, exit(1));
364                 ifi->ifi_ifindex = 0;
365                 strlcpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname));
366                 ifi->ifi_rainfo = NULL;
367                 ifi->ifi_state = IFI_STATE_UNCONFIGURED;
368                 TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next);
369         }
370
371         ifi->ifi_persist = 1;
372
373         syslog(LOG_DEBUG, "<%s> %s is marked PERSIST", __func__,
374             ifi->ifi_ifname);
375         syslog(LOG_DEBUG, "<%s> %s is state = %d", __func__,
376             ifi->ifi_ifname, ifi->ifi_state);
377         return (ifi);
378 }
379
380 int
381 update_ifinfo_nd_flags(struct ifinfo *ifi)
382 {
383         struct in6_ndireq nd;
384         int s;
385         int error;
386
387         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
388                 syslog(LOG_ERR,
389                     "<%s> socket() failed.", __func__);
390                 return (1);
391         }
392         /* ND flags */
393         memset(&nd, 0, sizeof(nd));
394         strlcpy(nd.ifname, ifi->ifi_ifname,
395             sizeof(nd.ifname));
396         error = ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd);
397         if (error) {
398                 close(s);
399                 if (errno != EPFNOSUPPORT)
400                         syslog(LOG_ERR, "<%s> ioctl() failed.", __func__);
401                 return (1);
402         }
403         ifi->ifi_nd_flags = nd.ndi.flags;
404         close(s);
405
406         return (0);
407 }
408
409 struct ifinfo *
410 update_ifinfo(struct ifilist_head_t *ifi_head, int ifindex)
411 {
412         struct if_msghdr *ifm;
413         struct ifinfo *ifi = NULL;
414         struct sockaddr *sa;
415         struct sockaddr *rti_info[RTAX_MAX];
416         char *msg;
417         size_t len;
418         char *lim;
419         int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_IFLIST, 0 };
420         int error;
421
422         syslog(LOG_DEBUG, "<%s> enter", __func__);
423
424         if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, &len, NULL, 0) <
425             0) {
426                 syslog(LOG_ERR,
427                     "<%s> sysctl: NET_RT_IFLIST size get failed", __func__);
428                 exit(1);
429         }
430         if ((msg = malloc(len)) == NULL) {
431                 syslog(LOG_ERR, "<%s> malloc failed", __func__);
432                 exit(1);
433         }
434         if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), msg, &len, NULL, 0) <
435             0) {
436                 syslog(LOG_ERR,
437                     "<%s> sysctl: NET_RT_IFLIST get failed", __func__);
438                 exit(1);
439         }
440
441         lim = msg + len;
442         for (ifm = (struct if_msghdr *)msg;
443              ifm != NULL && ifm < (struct if_msghdr *)lim;
444              ifm = get_next_msghdr(ifm,(struct if_msghdr *)lim)) {
445                 int ifi_new;
446
447                 syslog(LOG_DEBUG, "<%s> ifm = %p, lim = %p, diff = %zu",
448                     __func__, ifm, lim, (char *)lim - (char *)ifm);
449
450                 if (ifm->ifm_version != RTM_VERSION) {
451                         syslog(LOG_ERR,
452                             "<%s> ifm_vesrion mismatch", __func__);
453                         exit(1);
454                 }
455                 if (ifm->ifm_msglen == 0) {
456                         syslog(LOG_WARNING,
457                             "<%s> ifm_msglen is 0", __func__);
458                         free(msg);
459                         return (NULL);
460                 }
461
462                 ifi_new = 0;
463                 if (ifm->ifm_type == RTM_IFINFO) {
464                         struct ifreq ifr;
465                         int s;
466                         char ifname[IFNAMSIZ];
467
468                         syslog(LOG_DEBUG, "<%s> RTM_IFINFO found. "
469                             "ifm_index = %d, ifindex = %d",
470                             __func__, ifm->ifm_index, ifindex);
471
472                         /* when ifindex is specified */
473                         if (ifindex != UPDATE_IFINFO_ALL &&
474                             ifindex != ifm->ifm_index)
475                                 continue;
476
477                         /* ifname */
478                         if (if_indextoname(ifm->ifm_index, ifname) == NULL) {
479                                 syslog(LOG_WARNING,
480                                     "<%s> ifname not found (idx=%d)",
481                                     __func__, ifm->ifm_index);
482                                 continue;
483                         }
484
485                         /* lookup an entry with the same ifindex */
486                         TAILQ_FOREACH(ifi, ifi_head, ifi_next) {
487                                 if (ifm->ifm_index == ifi->ifi_ifindex)
488                                         break;
489                                 if (strncmp(ifname, ifi->ifi_ifname,
490                                         sizeof(ifname)) == 0)
491                                         break;
492                         }
493                         if (ifi == NULL) {
494                                 syslog(LOG_DEBUG,
495                                     "<%s> new entry for idx=%d",
496                                     __func__, ifm->ifm_index);
497                                 ELM_MALLOC(ifi, exit(1));
498                                 ifi->ifi_rainfo = NULL;
499                                 ifi->ifi_state = IFI_STATE_UNCONFIGURED;
500                                 ifi->ifi_persist = 0;
501                                 ifi_new = 1;
502                         }
503                         /* ifindex */
504                         ifi->ifi_ifindex = ifm->ifm_index;
505
506                         /* ifname */
507                         strlcpy(ifi->ifi_ifname, ifname, IFNAMSIZ);
508
509                         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
510                                 syslog(LOG_ERR,
511                                     "<%s> socket() failed.", __func__);
512                                 if (ifi_new)
513                                         free(ifi);
514                                 continue;
515                         }
516
517                         /* MTU  */
518                         ifi->ifi_phymtu = ifm->ifm_data.ifi_mtu;
519                         if (ifi->ifi_phymtu == 0) {
520                                 memset(&ifr, 0, sizeof(ifr));
521                                 ifr.ifr_addr.sa_family = AF_INET6;
522                                 strlcpy(ifr.ifr_name, ifi->ifi_ifname,
523                                     sizeof(ifr.ifr_name));
524                                 error = ioctl(s, SIOCGIFMTU, (caddr_t)&ifr);
525                                 if (error) {
526                                         close(s);
527                                         syslog(LOG_ERR,
528                                             "<%s> ioctl() failed.",
529                                             __func__);
530                                         if (ifi_new)
531                                                 free(ifi);
532                                         continue;
533                                 }
534                                 ifi->ifi_phymtu = ifr.ifr_mtu;
535                                 if (ifi->ifi_phymtu == 0) {
536                                         syslog(LOG_WARNING,
537                                             "<%s> no interface mtu info"
538                                             " on %s.  %d will be used.",
539                                             __func__, ifi->ifi_ifname,
540                                             IPV6_MMTU);
541                                         ifi->ifi_phymtu = IPV6_MMTU;
542                                 }
543                         }
544                         close(s);
545
546                         /* ND flags */
547                         error = update_ifinfo_nd_flags(ifi);
548                         if (error) {
549                                 if (ifi_new)
550                                         free(ifi);
551                                 continue;
552                         }
553
554                         /* SDL */
555                         sa = (struct sockaddr *)(ifm + 1);
556                         get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
557                         if ((sa = rti_info[RTAX_IFP]) != NULL) {
558                                 if (sa->sa_family == AF_LINK) {
559                                         memcpy(&ifi->ifi_sdl,
560                                             (struct sockaddr_dl *)sa,
561                                             sizeof(ifi->ifi_sdl));
562                                 }
563                         } else
564                                 memset(&ifi->ifi_sdl, 0,
565                                     sizeof(ifi->ifi_sdl));
566
567                         /* flags */
568                         ifi->ifi_flags = ifm->ifm_flags;
569
570                         /* type */
571                         ifi->ifi_type = ifm->ifm_type;
572                 } else {
573                         syslog(LOG_ERR,
574                             "out of sync parsing NET_RT_IFLIST\n"
575                             "expected %d, got %d\n msglen = %d\n",
576                             RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen);
577                         exit(1);
578                 }
579
580                 if (ifi_new) {
581                         syslog(LOG_DEBUG,
582                             "<%s> adding %s(idx=%d) to ifilist",
583                             __func__, ifi->ifi_ifname, ifi->ifi_ifindex);
584                         TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next);
585                 }
586         }
587         free(msg);
588
589         if (mcastif != NULL) {
590                 error = sock_mc_rr_update(&sock, mcastif);
591                 if (error)
592                         exit(1);
593         }
594
595         return (ifi);
596 }
597
598 static struct if_msghdr *
599 get_next_msghdr(struct if_msghdr *ifm, struct if_msghdr *lim)
600 {
601         struct ifa_msghdr *ifam;
602
603         for (ifam = (struct ifa_msghdr *)((char *)ifm + ifm->ifm_msglen);
604              ifam < (struct ifa_msghdr *)lim;
605              ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen)) {
606                 if (!ifam->ifam_msglen) {
607                         syslog(LOG_WARNING,
608                             "<%s> ifa_msglen is 0", __func__);
609                         return (NULL);
610                 }
611                 if (ifam->ifam_type != RTM_NEWADDR)
612                         break;
613         }
614
615         return ((struct if_msghdr *)ifam);
616 }
617
618 int
619 getinet6sysctl(int code)
620 {
621         int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
622         int value;
623         size_t size;
624
625         mib[3] = code;
626         size = sizeof(value);
627         if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
628             < 0) {
629                 syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s",
630                     __func__, code,
631                     strerror(errno));
632                 return (-1);
633         }
634         else
635                 return (value);
636 }
637
638
639 int
640 sock_mc_join(struct sockinfo *s, int ifindex)
641 {
642         struct ipv6_mreq mreq;
643         char ifname[IFNAMSIZ];
644
645         syslog(LOG_DEBUG, "<%s> enter", __func__);
646
647         if (ifindex == 0)
648                 return (1);
649
650         /*
651          * join all routers multicast address on each advertising
652          * interface.
653          */
654         memset(&mreq, 0, sizeof(mreq));
655         /* XXX */
656         memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
657             &sin6_linklocal_allrouters.sin6_addr,
658             sizeof(mreq.ipv6mr_multiaddr.s6_addr));
659
660         mreq.ipv6mr_interface = ifindex;
661         if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
662                 sizeof(mreq)) < 0) {
663                 syslog(LOG_ERR,
664                     "<%s> IPV6_JOIN_GROUP(link) on %s: %s",
665                     __func__, if_indextoname(ifindex, ifname),
666                     strerror(errno));
667                 return (1);
668         }
669         syslog(LOG_DEBUG,
670             "<%s> %s: join link-local all-routers MC group",
671             __func__, if_indextoname(ifindex, ifname));
672
673         return (0);
674 }
675
676 int
677 sock_mc_leave(struct sockinfo *s, int ifindex)
678 {
679         struct ipv6_mreq mreq;
680         char ifname[IFNAMSIZ];
681
682         syslog(LOG_DEBUG, "<%s> enter", __func__);
683
684         if (ifindex == 0)
685                 return (1);
686
687         /*
688          * join all routers multicast address on each advertising
689          * interface.
690          */
691
692         memset(&mreq, 0, sizeof(mreq));
693         /* XXX */
694         memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
695             &sin6_linklocal_allrouters.sin6_addr,
696             sizeof(mreq.ipv6mr_multiaddr.s6_addr));
697
698         mreq.ipv6mr_interface = ifindex;
699         if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq,
700                 sizeof(mreq)) < 0) {
701                 syslog(LOG_ERR,
702                     "<%s> IPV6_JOIN_LEAVE(link) on %s: %s",
703                     __func__, if_indextoname(ifindex, ifname),
704                     strerror(errno));
705                 return (1);
706         }
707         syslog(LOG_DEBUG,
708             "<%s> %s: leave link-local all-routers MC group",
709             __func__, if_indextoname(ifindex, ifname));
710
711         return (0);
712 }
713
714 int
715 sock_mc_rr_update(struct sockinfo *s, char *mif)
716 {
717         struct ipv6_mreq mreq;
718
719         syslog(LOG_DEBUG, "<%s> enter", __func__);
720
721         if (mif == NULL)
722                 return (1);
723         /*
724          * When attending router renumbering, join all-routers site-local
725          * multicast group.
726          */
727         /* XXX */
728         memcpy(&mreq.ipv6mr_multiaddr.s6_addr,
729             &sin6_sitelocal_allrouters.sin6_addr,
730             sizeof(mreq.ipv6mr_multiaddr.s6_addr));
731         if ((mreq.ipv6mr_interface = if_nametoindex(mif)) == 0) {
732                 syslog(LOG_ERR,
733                     "<%s> invalid interface: %s",
734                     __func__, mif);
735                 return (1);
736         }
737
738         if (setsockopt(s->si_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
739                 &mreq, sizeof(mreq)) < 0) {
740                 syslog(LOG_ERR,
741                     "<%s> IPV6_JOIN_GROUP(site) on %s: %s",
742                     __func__, mif, strerror(errno));
743                 return (1);
744         }
745
746         syslog(LOG_DEBUG,
747             "<%s> %s: join site-local all-routers MC group",
748             __func__, mif);
749
750         return (0);
751 }