2 __RCSID("$NetBSD: if-bsd.c,v 1.24 2015/08/21 13:24:47 roy Exp $");
5 * dhcpcd - DHCP client daemon
6 * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/ioctl.h>
32 #include <sys/param.h>
33 #include <sys/socket.h>
35 #include <sys/sysctl.h>
37 #include <sys/types.h>
39 #include <sys/utsname.h>
41 #include <arpa/inet.h>
44 #include <net/if_dl.h>
45 #ifdef __FreeBSD__ /* Needed so that including netinet6/in6_var.h works */
46 # include <net/if_var.h>
48 #include <net/if_media.h>
49 #include <net/route.h>
50 #include <netinet/if_ether.h>
51 #include <netinet/in.h>
52 #include <netinet/in_var.h>
53 #include <netinet6/in6_var.h>
54 #include <netinet6/nd6.h>
56 # include <netproto/802_11/ieee80211_ioctl.h>
58 /* FIXME: Add apple includes so we can work out SSID */
60 # include <net80211/ieee80211.h>
61 # include <net80211/ieee80211_ioctl.h>
74 #if defined(OpenBSD) && OpenBSD >= 201411
75 /* OpenBSD dropped the global setting from sysctl but left the #define
76 * which causes a EPERM error when trying to use it.
77 * I think both the error and keeping the define are wrong, so we #undef it. */
78 #undef IPV6CTL_ACCEPT_RTADV
85 #include "if-options.h"
91 #include "bpf-filter.h"
94 #define RT_ROUNDUP(a) \
95 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
96 #define RT_ADVANCE(x, n) (x += RT_ROUNDUP((n)->sa_len))
99 #define COPYOUT(sin, sa) do { \
100 if ((sa) && ((sa)->sa_family == AF_INET || (sa)->sa_family == 255)) \
101 (sin) = ((struct sockaddr_in*)(void *)(sa))->sin_addr; \
104 #define COPYOUT6(sin, sa) do { \
105 if ((sa) && ((sa)->sa_family == AF_INET6 || (sa)->sa_family == 255)) \
106 (sin) = ((struct sockaddr_in6*)(void *)(sa))->sin6_addr; \
110 # define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
114 if_init(__unused
struct interface
*iface
)
116 /* BSD promotes secondary address by default */
121 if_conf(__unused
struct interface
*iface
)
123 /* No extra checks needed on BSD */
128 if_openlinksocket(void)
131 return xsocket(PF_ROUTE
, SOCK_RAW
, 0, O_NONBLOCK
|O_CLOEXEC
);
134 #if defined(INET) || defined(INET6)
136 if_linkaddr(struct sockaddr_dl
*sdl
, const struct interface
*ifp
)
139 memset(sdl
, 0, sizeof(*sdl
));
140 sdl
->sdl_family
= AF_LINK
;
141 sdl
->sdl_len
= sizeof(*sdl
);
142 sdl
->sdl_nlen
= sdl
->sdl_alen
= sdl
->sdl_slen
= 0;
143 sdl
->sdl_index
= (unsigned short)ifp
->index
;
148 if_getssid1(int s
, const char *ifname
, uint8_t *ssid
)
151 #if defined(SIOCG80211NWID)
153 struct ieee80211_nwid nwid
;
154 #elif defined(IEEE80211_IOC_SSID)
155 struct ieee80211req ireq
;
156 char nwid
[IEEE80211_NWID_LEN
+ 1];
159 #if defined(SIOCG80211NWID) /* NetBSD */
160 memset(&ifr
, 0, sizeof(ifr
));
161 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
162 memset(&nwid
, 0, sizeof(nwid
));
163 ifr
.ifr_data
= (void *)&nwid
;
164 if (ioctl(s
, SIOCG80211NWID
, &ifr
) == 0) {
167 else if (nwid
.i_len
> IF_SSIDSIZE
) {
172 memcpy(ssid
, nwid
.i_nwid
, nwid
.i_len
);
173 ssid
[nwid
.i_len
] = '\0';
176 #elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
177 memset(&ireq
, 0, sizeof(ireq
));
178 strlcpy(ireq
.i_name
, ifname
, sizeof(ireq
.i_name
));
179 ireq
.i_type
= IEEE80211_IOC_SSID
;
181 memset(nwid
, 0, sizeof(nwid
));
183 if (ioctl(s
, SIOCG80211
, &ireq
) == 0) {
186 else if (ireq
.i_len
> IF_SSIDSIZE
) {
191 memcpy(ssid
, nwid
, ireq
.i_len
);
192 ssid
[ireq
.i_len
] = '\0';
201 if_getssid(struct interface
*ifp
)
205 r
= if_getssid1(ifp
->ctx
->pf_inet_fd
, ifp
->name
, ifp
->ssid
);
207 ifp
->ssid_len
= (unsigned int)r
;
212 * FreeBSD allows for Virtual Access Points
213 * We need to check if the interface is a Virtual Interface Master
214 * and if so, don't use it.
215 * This check is made by virtue of being a IEEE80211 device but
216 * returning the SSID gives an error.
219 if_vimaster(const struct dhcpcd_ctx
*ctx
, const char *ifname
)
222 struct ifmediareq ifmr
;
224 memset(&ifmr
, 0, sizeof(ifmr
));
225 strlcpy(ifmr
.ifm_name
, ifname
, sizeof(ifmr
.ifm_name
));
226 r
= ioctl(ctx
->pf_inet_fd
, SIOCGIFMEDIA
, &ifmr
);
229 if (ifmr
.ifm_status
& IFM_AVALID
&&
230 IFM_TYPE(ifmr
.ifm_active
) == IFM_IEEE80211
)
232 if (if_getssid1(ctx
->pf_inet_fd
, ifname
, NULL
) == -1)
239 get_addrs(int type
, char *cp
, struct sockaddr
**sa
)
243 for (i
= 0; i
< RTAX_MAX
; i
++) {
244 if (type
& (1 << i
)) {
245 sa
[i
] = (struct sockaddr
*)cp
;
246 RT_ADVANCE(cp
, sa
[i
]);
252 #if defined(INET) || defined(INET6)
253 static struct interface
*
254 if_findsdl(struct dhcpcd_ctx
*ctx
, struct sockaddr_dl
*sdl
)
258 char ifname
[IF_NAMESIZE
];
259 memcpy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
260 ifname
[sdl
->sdl_nlen
] = '\0';
261 return if_find(ctx
->ifaces
, ifname
);
268 const char *if_pfname
= "Berkley Packet Filter";
271 if_openrawsocket(struct interface
*ifp
, uint16_t protocol
)
273 struct ipv4_state
*state
;
278 struct bpf_version pv
;
279 struct bpf_program pf
;
284 fd
= open(_PATH_BPF
, O_RDWR
| O_CLOEXEC
| O_NONBLOCK
);
290 snprintf(device
, sizeof(device
), "/dev/bpf%d", n
++);
291 fd
= open(device
, O_RDWR
| O_CLOEXEC
| O_NONBLOCK
);
292 } while (fd
== -1 && errno
== EBUSY
);
298 state
= IPV4_STATE(ifp
);
299 memset(&pv
, 0, sizeof(pv
));
300 if (ioctl(fd
, BIOCVERSION
, &pv
) == -1)
302 if (pv
.bv_major
!= BPF_MAJOR_VERSION
||
303 pv
.bv_minor
< BPF_MINOR_VERSION
) {
304 logger(ifp
->ctx
, LOG_ERR
, "BPF version mismatch - recompile");
308 memset(&ifr
, 0, sizeof(ifr
));
309 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
310 if (ioctl(fd
, BIOCSETIF
, &ifr
) == -1)
313 /* Get the required BPF buffer length from the kernel. */
314 if (ioctl(fd
, BIOCGBLEN
, &ibuf_len
) == -1)
316 buf_len
= (size_t)ibuf_len
;
317 if (state
->buffer_size
!= buf_len
) {
319 state
->buffer
= malloc(buf_len
);
320 if (state
->buffer
== NULL
)
322 state
->buffer_size
= buf_len
;
323 state
->buffer_len
= state
->buffer_pos
= 0;
328 if (ioctl(fd
, BIOCIMMEDIATE
, &flags
) == -1)
332 /* Install the DHCP filter */
333 memset(&pf
, 0, sizeof(pf
));
334 if (protocol
== ETHERTYPE_ARP
) {
335 pf
.bf_insns
= UNCONST(arp_bpf_filter
);
336 pf
.bf_len
= arp_bpf_filter_len
;
338 pf
.bf_insns
= UNCONST(dhcp_bpf_filter
);
339 pf
.bf_len
= dhcp_bpf_filter_len
;
341 if (ioctl(fd
, BIOCSETF
, &pf
) == -1)
348 state
->buffer
= NULL
;
354 if_sendrawpacket(const struct interface
*ifp
, uint16_t protocol
,
355 const void *data
, size_t len
)
358 struct ether_header hw
;
361 memset(&hw
, 0, ETHER_HDR_LEN
);
362 memset(&hw
.ether_dhost
, 0xff, ETHER_ADDR_LEN
);
363 hw
.ether_type
= htons(protocol
);
364 iov
[0].iov_base
= &hw
;
365 iov
[0].iov_len
= ETHER_HDR_LEN
;
366 iov
[1].iov_base
= UNCONST(data
);
367 iov
[1].iov_len
= len
;
368 fd
= ipv4_protocol_fd(ifp
, protocol
);
369 return writev(fd
, iov
, 2);
372 /* BPF requires that we read the entire buffer.
373 * So we pass the buffer in the API so we can loop on >1 packet. */
375 if_readrawpacket(struct interface
*ifp
, uint16_t protocol
,
376 void *data
, size_t len
, int *flags
)
379 struct bpf_hdr packet
;
381 const unsigned char *payload
;
382 struct ipv4_state
*state
;
384 state
= IPV4_STATE(ifp
);
385 fd
= ipv4_protocol_fd(ifp
, protocol
);
389 if (state
->buffer_len
== 0) {
390 bytes
= read(fd
, state
->buffer
, state
->buffer_size
);
391 if (bytes
== -1 || bytes
== 0)
393 state
->buffer_len
= (size_t)bytes
;
394 state
->buffer_pos
= 0;
397 memcpy(&packet
, state
->buffer
+ state
->buffer_pos
,
399 if (packet
.bh_caplen
!= packet
.bh_datalen
)
400 goto next
; /* Incomplete packet, drop. */
401 if (state
->buffer_pos
+ packet
.bh_caplen
+ packet
.bh_hdrlen
>
403 goto next
; /* Packet beyond buffer, drop. */
404 payload
= state
->buffer
+ state
->buffer_pos
+
405 packet
.bh_hdrlen
+ ETHER_HDR_LEN
;
406 bytes
= (ssize_t
)packet
.bh_caplen
- ETHER_HDR_LEN
;
407 if ((size_t)bytes
> len
)
408 bytes
= (ssize_t
)len
;
409 memcpy(data
, payload
, (size_t)bytes
);
411 state
->buffer_pos
+= BPF_WORDALIGN(packet
.bh_hdrlen
+
413 if (state
->buffer_pos
>= state
->buffer_len
) {
414 state
->buffer_len
= state
->buffer_pos
= 0;
423 if_address(const struct interface
*ifp
, const struct in_addr
*address
,
424 const struct in_addr
*netmask
, const struct in_addr
*broadcast
,
428 struct in_aliasreq ifra
;
430 memset(&ifra
, 0, sizeof(ifra
));
431 strlcpy(ifra
.ifra_name
, ifp
->name
, sizeof(ifra
.ifra_name
));
433 #define ADDADDR(var, addr) do { \
434 (var)->sin_family = AF_INET; \
435 (var)->sin_len = sizeof(*(var)); \
436 (var)->sin_addr = *(addr); \
437 } while (/*CONSTCOND*/0)
438 ADDADDR(&ifra
.ifra_addr
, address
);
439 ADDADDR(&ifra
.ifra_mask
, netmask
);
440 if (action
>= 0 && broadcast
)
441 ADDADDR(&ifra
.ifra_broadaddr
, broadcast
);
444 r
= ioctl(ifp
->ctx
->pf_inet_fd
,
445 action
< 0 ? SIOCDIFADDR
: SIOCAIFADDR
, &ifra
);
450 if_copyrt(struct dhcpcd_ctx
*ctx
, struct rt
*rt
, struct rt_msghdr
*rtm
)
453 struct sockaddr
*sa
, *rti_info
[RTAX_MAX
];
455 cp
= (char *)(void *)(rtm
+ 1);
456 sa
= (struct sockaddr
*)(void *)cp
;
457 if (sa
->sa_family
!= AF_INET
)
459 if (~rtm
->rtm_addrs
& (RTA_DST
| RTA_GATEWAY
))
462 if (rtm
->rtm_flags
& RTF_CLONED
)
466 if (rtm
->rtm_flags
& RTF_LOCAL
)
470 if (rtm
->rtm_flags
& RTF_BROADCAST
)
474 get_addrs(rtm
->rtm_addrs
, cp
, rti_info
);
475 memset(rt
, 0, sizeof(*rt
));
476 rt
->flags
= (unsigned int)rtm
->rtm_flags
;
477 COPYOUT(rt
->dest
, rti_info
[RTAX_DST
]);
478 if (rtm
->rtm_addrs
& RTA_NETMASK
)
479 COPYOUT(rt
->net
, rti_info
[RTAX_NETMASK
]);
481 rt
->net
.s_addr
= INADDR_BROADCAST
;
482 COPYOUT(rt
->gate
, rti_info
[RTAX_GATEWAY
]);
483 COPYOUT(rt
->src
, rti_info
[RTAX_IFA
]);
485 if (rtm
->rtm_inits
& RTV_MTU
)
486 rt
->mtu
= (unsigned int)rtm
->rtm_rmx
.rmx_mtu
;
489 rt
->iface
= if_findindex(ctx
->ifaces
, rtm
->rtm_index
);
490 else if (rtm
->rtm_addrs
& RTA_IFP
) {
491 struct sockaddr_dl
*sdl
;
493 sdl
= (struct sockaddr_dl
*)(void *)rti_info
[RTAX_IFP
];
494 rt
->iface
= if_findsdl(ctx
, sdl
);
497 /* If we don't have an interface and it's a host route, it maybe
498 * to a local ip via the loopback interface. */
499 if (rt
->iface
== NULL
&&
500 !(~rtm
->rtm_flags
& (RTF_HOST
| RTF_GATEWAY
)))
502 struct ipv4_addr
*ia
;
504 if ((ia
= ipv4_findaddr(ctx
, &rt
->dest
)))
505 rt
->iface
= ia
->iface
;
512 if_route(unsigned char cmd
, const struct rt
*rt
)
514 const struct dhcp_state
*state
;
515 const struct ipv4ll_state
*istate
;
518 struct sockaddr_in sin
;
519 struct sockaddr_dl sdl
;
523 struct rt_msghdr hdr
;
524 char buffer
[sizeof(su
) * RTAX_MAX
];
526 char *bp
= rtm
.buffer
;
530 l = RT_ROUNDUP(su.sa.sa_len); \
531 memcpy(bp, &su, l); \
534 #define ADDADDR(addr) { \
535 memset(&su, 0, sizeof(su)); \
536 su.sin.sin_family = AF_INET; \
537 su.sin.sin_len = sizeof(su.sin); \
538 (&su.sin)->sin_addr = *(addr); \
544 * It seems that when dhcpcd(8) is invoked on a single interface, which
545 * is what netconf(8) configures interfaces to do right now, dhcpcd
546 * sometimes tries to remove routes for interfaces it does not manage.
547 * These routes therefore do not have an associated "iface", causing
548 * dhcpcd to crash on a NULL pointer dereference in this function.
549 * This quick hack prevents it from attempting to perform such
550 * dereferences. The affected scenario seems to be mainly that dhcpcd
551 * is unable to replace a preexisting default route because of this,
552 * but arguably if it didn't set it, it shouldn't remove it either..
553 * Better solutions will have to come from upstream.
555 if (rt
->iface
== NULL
) {
559 #endif /* defined(__minix) */
561 if (cmd
!= RTM_DELETE
) {
562 state
= D_CSTATE(rt
->iface
);
563 istate
= IPV4LL_CSTATE(rt
->iface
);
569 memset(&rtm
, 0, sizeof(rtm
));
570 rtm
.hdr
.rtm_version
= RTM_VERSION
;
572 rtm
.hdr
.rtm_type
= cmd
;
573 rtm
.hdr
.rtm_addrs
= RTA_DST
;
574 if (cmd
== RTM_ADD
|| cmd
== RTM_CHANGE
)
575 rtm
.hdr
.rtm_addrs
|= RTA_GATEWAY
;
576 rtm
.hdr
.rtm_flags
= RTF_UP
;
579 rtm
.hdr
.rtm_flags
|= RTF_PINNED
;
582 if (cmd
!= RTM_DELETE
) {
583 rtm
.hdr
.rtm_addrs
|= RTA_IFA
| RTA_IFP
;
584 /* None interface subnet routes are static. */
585 if ((rt
->gate
.s_addr
!= INADDR_ANY
||
586 rt
->net
.s_addr
!= state
->net
.s_addr
||
588 (state
->addr
.s_addr
& state
->net
.s_addr
)) &&
591 (istate
->addr
.s_addr
& inaddr_llmask
.s_addr
) ||
592 rt
->net
.s_addr
!= inaddr_llmask
.s_addr
))
593 rtm
.hdr
.rtm_flags
|= RTF_STATIC
;
596 rtm
.hdr
.rtm_flags
|= RTF_CLONING
;
599 rtm
.hdr
.rtm_priority
= RTP_CONNECTED
;
603 if (rt
->net
.s_addr
== htonl(INADDR_BROADCAST
) &&
604 rt
->gate
.s_addr
== htonl(INADDR_ANY
))
607 /* We add a cloning network route for a single host.
608 * Traffic to the host will generate a cloned route and the
609 * hardware address will resolve correctly.
610 * It might be more correct to use RTF_HOST instead of
611 * RTF_CLONING, and that does work, but some OS generate
612 * an arp warning diagnostic which we don't want to do. */
613 rtm
.hdr
.rtm_flags
|= RTF_CLONING
;
614 rtm
.hdr
.rtm_addrs
|= RTA_NETMASK
;
616 rtm
.hdr
.rtm_flags
|= RTF_HOST
;
618 } else if (rt
->gate
.s_addr
== htonl(INADDR_LOOPBACK
) &&
619 rt
->net
.s_addr
== htonl(INADDR_BROADCAST
))
621 rtm
.hdr
.rtm_flags
|= RTF_HOST
| RTF_GATEWAY
;
622 /* Going via lo0 so remove the interface flags */
624 rtm
.hdr
.rtm_addrs
&= ~(RTA_IFA
| RTA_IFP
);
626 rtm
.hdr
.rtm_addrs
|= RTA_NETMASK
;
627 if (rtm
.hdr
.rtm_flags
& RTF_STATIC
)
628 rtm
.hdr
.rtm_flags
|= RTF_GATEWAY
;
630 if ((cmd
== RTM_ADD
|| cmd
== RTM_CHANGE
) &&
631 !(rtm
.hdr
.rtm_flags
& RTF_GATEWAY
))
632 rtm
.hdr
.rtm_addrs
|= RTA_IFA
| RTA_IFP
;
635 if (rtm
.hdr
.rtm_addrs
& RTA_GATEWAY
) {
637 if ((rtm
.hdr
.rtm_flags
& (RTF_HOST
| RTF_CLONING
) &&
639 if ((rtm
.hdr
.rtm_flags
& RTF_HOST
&&
641 rt
->gate
.s_addr
!= htonl(INADDR_LOOPBACK
)) ||
642 !(rtm
.hdr
.rtm_flags
& RTF_STATIC
))
644 if_linkaddr(&su
.sdl
, rt
->iface
);
650 if (rtm
.hdr
.rtm_addrs
& RTA_NETMASK
)
653 if ((cmd
== RTM_ADD
|| cmd
== RTM_CHANGE
) &&
654 (rtm
.hdr
.rtm_addrs
& (RTA_IFP
| RTA_IFA
)))
656 rtm
.hdr
.rtm_index
= (unsigned short)rt
->iface
->index
;
657 if (rtm
.hdr
.rtm_addrs
& RTA_IFP
) {
658 if_linkaddr(&su
.sdl
, rt
->iface
);
662 if (rtm
.hdr
.rtm_addrs
& RTA_IFA
)
663 ADDADDR(istate
== NULL
? &state
->addr
: &istate
->addr
);
666 rtm
.hdr
.rtm_inits
|= RTV_MTU
;
667 rtm
.hdr
.rtm_rmx
.rmx_mtu
= rt
->mtu
;
674 rtm
.hdr
.rtm_msglen
= (unsigned short)(bp
- (char *)&rtm
);
675 return write(rt
->iface
->ctx
->link_fd
,
676 &rtm
, rtm
.hdr
.rtm_msglen
) == -1 ? -1 : 0;
680 if_initrt(struct interface
*ifp
)
682 struct rt_msghdr
*rtm
;
688 ipv4_freerts(ifp
->ctx
->ipv4_kroutes
);
694 mib
[4] = NET_RT_DUMP
;
697 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) == -1)
701 if ((buf
= malloc(needed
)) == NULL
)
703 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) == -1)
707 for (p
= buf
; p
< end
; p
+= rtm
->rtm_msglen
) {
708 rtm
= (struct rt_msghdr
*)(void *)p
;
709 if (if_copyrt(ifp
->ctx
, &rt
, rtm
) == 0)
710 ipv4_handlert(ifp
->ctx
, RTM_ADD
, &rt
);
716 #ifdef SIOCGIFAFLAG_IN
718 if_addrflags(const struct in_addr
*addr
, const struct interface
*ifp
)
721 struct sockaddr_in
*sin
;
723 memset(&ifr
, 0, sizeof(ifr
));
724 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
725 sin
= (struct sockaddr_in
*)(void *)&ifr
.ifr_addr
;
726 sin
->sin_family
= AF_INET
;
727 sin
->sin_addr
= *addr
;
728 if (ioctl(ifp
->ctx
->pf_inet_fd
, SIOCGIFAFLAG_IN
, &ifr
) == -1)
730 return ifr
.ifr_addrflags
;
734 if_addrflags(__unused
const struct in_addr
*addr
,
735 __unused
const struct interface
*ifp
)
746 ifa_scope(struct sockaddr_in6
*sin
, unsigned int ifindex
)
750 /* KAME based systems want to store the scope inside the sin6_addr
751 * for link local addreses */
752 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
)) {
753 uint16_t scope
= htons((uint16_t)ifindex
);
754 memcpy(&sin
->sin6_addr
.s6_addr
[2], &scope
,
757 sin
->sin6_scope_id
= 0;
759 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
))
760 sin
->sin6_scope_id
= ifindex
;
762 sin
->sin6_scope_id
= 0;
767 #define DESCOPE(ia6) do { \
768 if (IN6_IS_ADDR_LINKLOCAL((ia6))) \
769 (ia6)->s6_addr[2] = (ia6)->s6_addr[3] = '\0'; \
770 } while (/*CONSTCOND */0)
776 if_address6(const struct ipv6_addr
*ia
, int action
)
778 struct in6_aliasreq ifa
;
779 struct in6_addr mask
;
781 memset(&ifa
, 0, sizeof(ifa
));
782 strlcpy(ifa
.ifra_name
, ia
->iface
->name
, sizeof(ifa
.ifra_name
));
784 * We should not set IN6_IFF_TENTATIVE as the kernel should be
785 * able to work out if it's a new address or not.
787 * We should set IN6_IFF_AUTOCONF, but the kernel won't let us.
788 * This is probably a safety measure, but still it's not entirely right
793 ifa
.ifra_flags
|= IN6_IFF_AUTOCONF
;
797 * On MINIX 3, do set the IN6_IFF_AUTOCONF flag: this tells the TCP/IP
798 * service that the address does not come with an implied subnet.
800 if (ia
->flags
& IPV6_AF_AUTOCONF
)
801 ifa
.ifra_flags
|= IN6_IFF_AUTOCONF
;
803 #ifdef IPV6_MANAGETEMPADDR /* XXX typo fix on MINIX3: "MANGE" -> "MANAGE" */
804 if (ia
->flags
& IPV6_AF_TEMPORARY
)
805 ifa
.ifra_flags
|= IN6_IFF_TEMPORARY
;
808 #define ADDADDR(v, addr) { \
809 (v)->sin6_family = AF_INET6; \
810 (v)->sin6_len = sizeof(*v); \
811 (v)->sin6_addr = *(addr); \
814 ADDADDR(&ifa
.ifra_addr
, &ia
->addr
);
815 ifa_scope(&ifa
.ifra_addr
, ia
->iface
->index
);
816 ipv6_mask(&mask
, ia
->prefix_len
);
817 ADDADDR(&ifa
.ifra_prefixmask
, &mask
);
818 ifa
.ifra_lifetime
.ia6t_vltime
= ia
->prefix_vltime
;
819 ifa
.ifra_lifetime
.ia6t_pltime
= ia
->prefix_pltime
;
822 return ioctl(ia
->iface
->ctx
->pf_inet6_fd
,
823 action
< 0 ? SIOCDIFADDR_IN6
: SIOCAIFADDR_IN6
, &ifa
);
828 if_copyrt6(struct dhcpcd_ctx
*ctx
, struct rt6
*rt
, struct rt_msghdr
*rtm
)
831 struct sockaddr
*sa
, *rti_info
[RTAX_MAX
];
833 cp
= (char *)(void *)(rtm
+ 1);
834 sa
= (struct sockaddr
*)(void *)cp
;
835 if (sa
->sa_family
!= AF_INET6
)
837 if (~rtm
->rtm_addrs
& (RTA_DST
| RTA_GATEWAY
))
840 if (rtm
->rtm_flags
& (RTF_CLONED
| RTF_HOST
))
843 if (rtm
->rtm_flags
& RTF_HOST
)
847 if (rtm
->rtm_flags
& RTF_LOCAL
)
851 get_addrs(rtm
->rtm_addrs
, cp
, rti_info
);
852 memset(rt
, 0, sizeof(*rt
));
853 rt
->flags
= (unsigned int)rtm
->rtm_flags
;
854 COPYOUT6(rt
->dest
, rti_info
[RTAX_DST
]);
855 if (rtm
->rtm_addrs
& RTA_NETMASK
) {
857 * We need to zero out the struct beyond sin6_len and
859 * I have no idea what the invalid data is for, could be
860 * a kernel bug or actually used for something.
861 * Either way it needs to be zeroed out.
863 struct sockaddr_in6
*sin6
;
864 size_t e
, i
, len
= 0, final
= 0;
866 sin6
= (struct sockaddr_in6
*)(void *)rti_info
[RTAX_NETMASK
];
867 rt
->net
= sin6
->sin6_addr
;
868 e
= sin6
->sin6_len
- offsetof(struct sockaddr_in6
, sin6_addr
);
869 if (e
> sizeof(struct in6_addr
))
870 e
= sizeof(struct in6_addr
);
871 for (i
= 0; i
< e
; i
++) {
872 switch (rt
->net
.s6_addr
[i
] & 0xff) {
874 /* We don't really want the length,
875 * just that it's valid */
889 rt
->net
.s6_addr
[i
] = 0x00;
898 while (i
< sizeof(rt
->net
.s6_addr
))
899 rt
->net
.s6_addr
[i
++] = 0x00;
901 ipv6_mask(&rt
->net
, 128);
902 COPYOUT6(rt
->gate
, rti_info
[RTAX_GATEWAY
]);
904 if (rtm
->rtm_inits
& RTV_MTU
)
905 rt
->mtu
= (unsigned int)rtm
->rtm_rmx
.rmx_mtu
;
908 rt
->iface
= if_findindex(ctx
->ifaces
, rtm
->rtm_index
);
909 else if (rtm
->rtm_addrs
& RTA_IFP
) {
910 struct sockaddr_dl
*sdl
;
912 sdl
= (struct sockaddr_dl
*)(void *)rti_info
[RTAX_IFP
];
913 rt
->iface
= if_findsdl(ctx
, sdl
);
915 /* If we don't have an interface and it's a host route, it maybe
916 * to a local ip via the loopback interface. */
917 if (rt
->iface
== NULL
&&
918 !(~rtm
->rtm_flags
& (RTF_HOST
| RTF_GATEWAY
)))
920 struct ipv6_addr
*ia
;
922 if ((ia
= ipv6_findaddr(ctx
, &rt
->dest
, 0)))
923 rt
->iface
= ia
->iface
;
930 if_route6(unsigned char cmd
, const struct rt6
*rt
)
934 struct sockaddr_in6 sin
;
935 struct sockaddr_dl sdl
;
939 struct rt_msghdr hdr
;
940 char buffer
[sizeof(su
) * RTAX_MAX
];
942 char *bp
= rtm
.buffer
;
946 l = RT_ROUNDUP(su.sa.sa_len); \
947 memcpy(bp, &su, l); \
950 #define ADDADDRS(addr, scope) { \
951 memset(&su, 0, sizeof(su)); \
952 su.sin.sin6_family = AF_INET6; \
953 su.sin.sin6_len = sizeof(su.sin); \
954 (&su.sin)->sin6_addr = *addr; \
956 ifa_scope(&su.sin, scope); \
959 #define ADDADDR(addr) ADDADDRS(addr, 0)
961 memset(&rtm
, 0, sizeof(rtm
));
962 rtm
.hdr
.rtm_version
= RTM_VERSION
;
964 rtm
.hdr
.rtm_type
= cmd
;
965 rtm
.hdr
.rtm_flags
= RTF_UP
| (int)rt
->flags
;
967 if (rtm
.hdr
.rtm_type
!= RTM_ADD
)
968 rtm
.hdr
.rtm_flags
|= RTF_PINNED
;
970 rtm
.hdr
.rtm_addrs
= RTA_DST
| RTA_NETMASK
;
971 /* None interface subnet routes are static. */
972 if (IN6_IS_ADDR_UNSPECIFIED(&rt
->gate
)) {
974 rtm
.hdr
.rtm_flags
|= RTF_CLONING
;
977 rtm
.hdr
.rtm_priority
= RTP_CONNECTED
;
980 rtm
.hdr
.rtm_flags
|= RTF_GATEWAY
| RTF_STATIC
;
983 rtm
.hdr
.rtm_addrs
|= RTA_GATEWAY
;
984 if (cmd
== RTM_ADD
&& !(rtm
.hdr
.rtm_flags
& RTF_REJECT
))
985 rtm
.hdr
.rtm_addrs
|= RTA_IFP
| RTA_IFA
;
988 if (rtm
.hdr
.rtm_addrs
& RTA_GATEWAY
) {
989 if (IN6_IS_ADDR_UNSPECIFIED(&rt
->gate
)) {
990 if_linkaddr(&su
.sdl
, rt
->iface
);
993 ADDADDRS(&rt
->gate
, rt
->iface
->index
);
997 if (rtm
.hdr
.rtm_addrs
& RTA_NETMASK
)
1000 if ((cmd
== RTM_ADD
|| cmd
== RTM_CHANGE
) &&
1001 (rtm
.hdr
.rtm_addrs
& (RTA_IFP
| RTA_IFA
)))
1003 rtm
.hdr
.rtm_index
= (unsigned short)rt
->iface
->index
;
1004 if (rtm
.hdr
.rtm_addrs
& RTA_IFP
) {
1005 if_linkaddr(&su
.sdl
, rt
->iface
);
1009 if (rtm
.hdr
.rtm_addrs
& RTA_IFA
) {
1010 const struct ipv6_addr
*lla
;
1012 lla
= ipv6_linklocal(rt
->iface
);
1013 if (lla
== NULL
) /* unlikely */
1015 ADDADDRS(&lla
->addr
, rt
->iface
->index
);
1019 rtm
.hdr
.rtm_inits
|= RTV_MTU
;
1020 rtm
.hdr
.rtm_rmx
.rmx_mtu
= rt
->mtu
;
1027 rtm
.hdr
.rtm_msglen
= (unsigned short)(bp
- (char *)&rtm
);
1028 return write(rt
->iface
->ctx
->link_fd
,
1029 &rtm
, rtm
.hdr
.rtm_msglen
) == -1 ? -1 : 0;
1033 if_initrt6(struct interface
*ifp
)
1035 struct rt_msghdr
*rtm
;
1038 char *buf
, *p
, *end
;
1041 ipv6_freerts(&ifp
->ctx
->ipv6
->kroutes
);
1047 mib
[4] = NET_RT_DUMP
;
1050 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) == -1)
1054 if ((buf
= malloc(needed
)) == NULL
)
1056 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) == -1)
1060 for (p
= buf
; p
< end
; p
+= rtm
->rtm_msglen
) {
1061 rtm
= (struct rt_msghdr
*)(void *)p
;
1062 if (if_copyrt6(ifp
->ctx
, &rt
, rtm
) == 0)
1063 ipv6_handlert(ifp
->ctx
, RTM_ADD
, &rt
);
1070 if_addrflags6(const struct in6_addr
*addr
, const struct interface
*ifp
)
1073 struct in6_ifreq ifr6
;
1075 memset(&ifr6
, 0, sizeof(ifr6
));
1076 strlcpy(ifr6
.ifr_name
, ifp
->name
, sizeof(ifr6
.ifr_name
));
1077 ifr6
.ifr_addr
.sin6_family
= AF_INET6
;
1078 ifr6
.ifr_addr
.sin6_addr
= *addr
;
1079 ifa_scope(&ifr6
.ifr_addr
, ifp
->index
);
1080 if (ioctl(ifp
->ctx
->pf_inet6_fd
, SIOCGIFAFLAG_IN6
, &ifr6
) != -1)
1081 flags
= ifr6
.ifr_ifru
.ifru_flags6
;
1088 if_getlifetime6(struct ipv6_addr
*ia
)
1090 struct in6_ifreq ifr6
;
1092 struct in6_addrlifetime
*lifetime
;
1094 memset(&ifr6
, 0, sizeof(ifr6
));
1095 strlcpy(ifr6
.ifr_name
, ia
->iface
->name
, sizeof(ifr6
.ifr_name
));
1096 ifr6
.ifr_addr
.sin6_family
= AF_INET6
;
1097 ifr6
.ifr_addr
.sin6_addr
= ia
->addr
;
1098 ifa_scope(&ifr6
.ifr_addr
, ia
->iface
->index
);
1099 if (ioctl(ia
->iface
->ctx
->pf_inet6_fd
,
1100 SIOCGIFALIFETIME_IN6
, &ifr6
) == -1)
1104 lifetime
= &ifr6
.ifr_ifru
.ifru_lifetime
;
1106 if (lifetime
->ia6t_preferred
)
1107 ia
->prefix_pltime
= (uint32_t)(lifetime
->ia6t_preferred
-
1108 MIN(t
, lifetime
->ia6t_preferred
));
1110 ia
->prefix_pltime
= ND6_INFINITE_LIFETIME
;
1111 if (lifetime
->ia6t_expire
) {
1112 ia
->prefix_vltime
= (uint32_t)(lifetime
->ia6t_expire
-
1113 MIN(t
, lifetime
->ia6t_expire
));
1114 /* Calculate the created time */
1115 clock_gettime(CLOCK_MONOTONIC
, &ia
->created
);
1116 ia
->created
.tv_sec
-= lifetime
->ia6t_vltime
- ia
->prefix_vltime
;
1118 ia
->prefix_vltime
= ND6_INFINITE_LIFETIME
;
1124 if_managelink(struct dhcpcd_ctx
*ctx
)
1126 /* route and ifwatchd like a msg buf size of 2048 */
1127 char msg
[2048], *p
, *e
, *cp
;
1129 struct rt_msghdr
*rtm
;
1130 struct if_announcemsghdr
*ifan
;
1131 struct if_msghdr
*ifm
;
1132 struct ifa_msghdr
*ifam
;
1133 struct sockaddr
*sa
, *rti_info
[RTAX_MAX
];
1135 struct sockaddr_dl sdl
;
1136 struct interface
*ifp
;
1142 struct in6_addr ia6
, net6
;
1143 struct sockaddr_in6
*sin6
;
1145 #if (defined(INET) && defined(IN_IFF_TENTATIVE)) || defined(INET6)
1147 #elif defined(__minix)
1148 int ifa_flags
; /* compilation fix for USE_INET6=no */
1151 if ((bytes
= read(ctx
->link_fd
, msg
, sizeof(msg
))) == -1)
1154 for (p
= msg
; p
< e
; p
+= rtm
->rtm_msglen
) {
1155 rtm
= (struct rt_msghdr
*)(void *)p
;
1156 // Ignore messages generated by us
1157 if (rtm
->rtm_pid
== getpid())
1159 switch(rtm
->rtm_type
) {
1160 #ifdef RTM_IFANNOUNCE
1161 case RTM_IFANNOUNCE
:
1162 ifan
= (struct if_announcemsghdr
*)(void *)p
;
1163 switch(ifan
->ifan_what
) {
1165 dhcpcd_handleinterface(ctx
, 1,
1168 case IFAN_DEPARTURE
:
1169 dhcpcd_handleinterface(ctx
, -1,
1176 ifm
= (struct if_msghdr
*)(void *)p
;
1177 ifp
= if_findindex(ctx
->ifaces
, ifm
->ifm_index
);
1180 switch (ifm
->ifm_data
.ifi_link_state
) {
1181 case LINK_STATE_DOWN
:
1188 /* handle_carrier will re-load
1189 * the interface flags and check for
1190 * IFF_RUNNING as some drivers that
1191 * don't handle link state also don't
1192 * set IFF_RUNNING when this routing
1193 * message is generated.
1194 * As such, it is a race ...*/
1198 dhcpcd_handlecarrier(ctx
, len
,
1199 (unsigned int)ifm
->ifm_flags
, ifp
->name
);
1204 cp
= (char *)(void *)(rtm
+ 1);
1205 sa
= (struct sockaddr
*)(void *)cp
;
1206 switch (sa
->sa_family
) {
1209 if (if_copyrt(ctx
, &rt
, rtm
) == 0)
1210 ipv4_handlert(ctx
, rtm
->rtm_type
, &rt
);
1215 if (~rtm
->rtm_addrs
& (RTA_DST
| RTA_GATEWAY
))
1218 * BSD caches host routes in the
1220 * As such, we should be notified of
1221 * reachability by its existance
1222 * with a hardware address
1224 if (rtm
->rtm_flags
& (RTF_HOST
)) {
1225 get_addrs(rtm
->rtm_addrs
, cp
, rti_info
);
1226 COPYOUT6(ia6
, rti_info
[RTAX_DST
]);
1228 if (rti_info
[RTAX_GATEWAY
]->sa_family
1231 rti_info
[RTAX_GATEWAY
],
1235 ipv6nd_neighbour(ctx
, &ia6
,
1236 rtm
->rtm_type
!= RTM_DELETE
&&
1238 IPV6ND_REACHABLE
: 0);
1242 if (if_copyrt6(ctx
, &rt6
, rtm
) == 0)
1243 ipv6_handlert(ctx
, rtm
->rtm_type
, &rt6
);
1249 case RTM_CHGADDR
: /* FALLTHROUGH */
1251 case RTM_DELADDR
: /* FALLTHROUGH */
1253 ifam
= (struct ifa_msghdr
*)(void *)p
;
1254 ifp
= if_findindex(ctx
->ifaces
, ifam
->ifam_index
);
1257 cp
= (char *)(void *)(ifam
+ 1);
1258 get_addrs(ifam
->ifam_addrs
, cp
, rti_info
);
1259 if (rti_info
[RTAX_IFA
] == NULL
)
1261 switch (rti_info
[RTAX_IFA
]->sa_family
) {
1264 if (rtm
->rtm_type
!= RTM_CHGADDR
)
1267 if (rtm
->rtm_type
!= RTM_NEWADDR
)
1270 memcpy(&sdl
, rti_info
[RTAX_IFA
],
1271 rti_info
[RTAX_IFA
]->sa_len
);
1272 dhcpcd_handlehwaddr(ctx
, ifp
->name
,
1273 (const unsigned char*)CLLADDR(&sdl
),
1278 case 255: /* FIXME: Why 255? */
1279 COPYOUT(rt
.dest
, rti_info
[RTAX_IFA
]);
1280 COPYOUT(rt
.net
, rti_info
[RTAX_NETMASK
]);
1281 COPYOUT(rt
.gate
, rti_info
[RTAX_BRD
]);
1282 if (rtm
->rtm_type
== RTM_NEWADDR
) {
1283 ifa_flags
= if_addrflags(&rt
.dest
, ifp
);
1284 if (ifa_flags
== -1)
1288 ipv4_handleifa(ctx
, rtm
->rtm_type
,
1290 &rt
.dest
, &rt
.net
, &rt
.gate
, ifa_flags
);
1295 sin6
= (struct sockaddr_in6
*)(void *)
1297 ia6
= sin6
->sin6_addr
;
1299 sin6
= (struct sockaddr_in6
*)(void *)
1300 rti_info
[RTAX_NETMASK
];
1301 net6
= sin6
->sin6_addr
;
1303 if (rtm
->rtm_type
== RTM_NEWADDR
) {
1304 ifa_flags
= if_addrflags6(&ia6
, ifp
);
1305 if (ifa_flags
== -1)
1309 ipv6_handleifa(ctx
, rtm
->rtm_type
, NULL
,
1310 ifp
->name
, &ia6
, ipv6_prefixlen(&net6
),
1321 #ifndef SYS_NMLN /* OSX */
1322 # define SYS_NMLN 256
1324 #ifndef HW_MACHINE_ARCH
1325 # ifdef HW_MODEL /* OpenBSD */
1326 # define HW_MACHINE_ARCH HW_MODEL
1330 if_machinearch(char *str
, size_t len
)
1332 int mib
[2] = { CTL_HW
, HW_MACHINE_ARCH
};
1333 char march
[SYS_NMLN
];
1334 size_t marchlen
= sizeof(march
);
1336 if (sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]),
1337 march
, &marchlen
, NULL
, 0) != 0)
1339 return snprintf(str
, len
, ":%s", march
);
1343 #ifdef IPV6CTL_ACCEPT_RTADV
1344 #define get_inet6_sysctl(code) inet6_sysctl(code, 0, 0)
1345 #define set_inet6_sysctl(code, val) inet6_sysctl(code, val, 1)
1347 inet6_sysctl(int code
, int val
, int action
)
1349 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, 0 };
1355 if (sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]),
1356 NULL
, 0, &val
, size
) == -1)
1360 if (sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]), &val
, &size
, NULL
, 0) == -1)
1366 #ifdef IPV6_MANAGETEMPADDR
1367 #ifndef IPV6CTL_TEMPVLTIME
1368 #define get_inet6_sysctlbyname(code) inet6_sysctlbyname(code, 0, 0)
1369 #define set_inet6_sysctlbyname(code, val) inet6_sysctlbyname(code, val, 1)
1371 inet6_sysctlbyname(const char *name
, int val
, int action
)
1377 if (sysctlbyname(name
, NULL
, 0, &val
, size
) == -1)
1381 if (sysctlbyname(name
, &val
, &size
, NULL
, 0) == -1)
1388 ip6_use_tempaddr(__unused
const char *ifname
)
1392 #ifdef IPV6CTL_USETEMPADDR
1393 val
= get_inet6_sysctl(IPV6CTL_USETEMPADDR
);
1395 val
= get_inet6_sysctlbyname("net.inet6.ip6.use_tempaddr");
1397 return val
== -1 ? 0 : val
;
1401 ip6_temp_preferred_lifetime(__unused
const char *ifname
)
1405 #ifdef IPV6CTL_TEMPPLTIME
1406 val
= get_inet6_sysctl(IPV6CTL_TEMPPLTIME
);
1408 val
= get_inet6_sysctlbyname("net.inet6.ip6.temppltime");
1410 return val
< 0 ? TEMP_PREFERRED_LIFETIME
: val
;
1414 ip6_temp_valid_lifetime(__unused
const char *ifname
)
1418 #ifdef IPV6CTL_TEMPVLTIME
1419 val
= get_inet6_sysctl(IPV6CTL_TEMPVLTIME
);
1421 val
= get_inet6_sysctlbyname("net.inet6.ip6.tempvltime");
1423 return val
< 0 ? TEMP_VALID_LIFETIME
: val
;
1427 #define del_if_nd6_flag(s, ifname, flag) if_nd6_flag((s), (ifp), (flag), -1)
1428 #define get_if_nd6_flag(s, ifname, flag) if_nd6_flag((s), (ifp), (flag), 0)
1429 #define set_if_nd6_flag(s, ifname, flag) if_nd6_flag((s), (ifp), (flag), 1)
1431 if_nd6_flag(int s
, const struct interface
*ifp
, unsigned int flag
, int set
)
1433 struct in6_ndireq nd
;
1434 unsigned int oflags
;
1436 memset(&nd
, 0, sizeof(nd
));
1437 strlcpy(nd
.ifname
, ifp
->name
, sizeof(nd
.ifname
));
1438 if (ioctl(s
, SIOCGIFINFO_IN6
, &nd
) == -1)
1441 return nd
.ndi
.flags
& flag
? 1 : 0;
1443 oflags
= nd
.ndi
.flags
;
1445 nd
.ndi
.flags
&= ~flag
;
1447 nd
.ndi
.flags
|= flag
;
1448 if (oflags
== nd
.ndi
.flags
)
1450 return ioctl(s
, SIOCSIFINFO_FLAGS
, &nd
);
1456 char dummy
[IFNAMSIZ
+ 8];
1458 strlcpy(dummy
, "lo0", sizeof(dummy
));
1459 if (ioctl(s
, SIOCSRTRFLUSH_IN6
, (void *)&dummy
) == -1 ||
1460 ioctl(s
, SIOCSPFXFLUSH_IN6
, (void *)&dummy
) == -1)
1465 #ifdef SIOCIFAFATTACH
1467 af_attach(int s
, const struct interface
*ifp
, int af
)
1469 struct if_afreq ifar
;
1471 strlcpy(ifar
.ifar_name
, ifp
->name
, sizeof(ifar
.ifar_name
));
1473 return ioctl(s
, SIOCIFAFATTACH
, (void *)&ifar
);
1477 #ifdef SIOCGIFXFLAGS
1479 set_ifxflags(int s
, const struct interface
*ifp
, int own
)
1484 #ifndef IFXF_NOINET6
1485 /* No point in removing the no inet6 flag if it doesn't
1486 * exist and we're not owning inet6. */
1491 strlcpy(ifr
.ifr_name
, ifp
->name
, sizeof(ifr
.ifr_name
));
1492 if (ioctl(s
, SIOCGIFXFLAGS
, (void *)&ifr
) == -1)
1494 flags
= ifr
.ifr_flags
;
1496 flags
&= ~IFXF_NOINET6
;
1499 flags
&= ~IFXF_AUTOCONF6
;
1500 if (ifr
.ifr_flags
== flags
)
1502 ifr
.ifr_flags
= flags
;
1503 return ioctl(s
, SIOCSIFXFLAGS
, (void *)&ifr
);
1508 _if_checkipv6(int s
, struct dhcpcd_ctx
*ctx
,
1509 const struct interface
*ifp
, int own
)
1514 #ifdef ND6_IFF_OVERRIDE_RTADV
1518 #ifdef ND6_IFF_IFDISABLED
1519 if (del_if_nd6_flag(s
, ifp
, ND6_IFF_IFDISABLED
) == -1) {
1520 logger(ifp
->ctx
, LOG_ERR
,
1521 "%s: del_if_nd6_flag: ND6_IFF_IFDISABLED: %m",
1527 #ifdef ND6_IFF_PERFORMNUD
1528 if (set_if_nd6_flag(s
, ifp
, ND6_IFF_PERFORMNUD
) == -1) {
1529 logger(ifp
->ctx
, LOG_ERR
,
1530 "%s: set_if_nd6_flag: ND6_IFF_PERFORMNUD: %m",
1536 #ifdef ND6_IFF_AUTO_LINKLOCAL
1540 all
= get_if_nd6_flag(s
, ifp
, ND6_IFF_AUTO_LINKLOCAL
);
1542 logger(ifp
->ctx
, LOG_ERR
,
1543 "%s: get_if_nd6_flag: "
1544 "ND6_IFF_AUTO_LINKLOCAL: %m",
1546 else if (all
!= 0) {
1547 logger(ifp
->ctx
, LOG_DEBUG
,
1548 "%s: disabling Kernel IPv6 "
1549 "auto link-local support",
1551 if (del_if_nd6_flag(s
, ifp
,
1552 ND6_IFF_AUTO_LINKLOCAL
) == -1)
1554 logger(ifp
->ctx
, LOG_ERR
,
1555 "%s: del_if_nd6_flag: "
1556 "ND6_IFF_AUTO_LINKLOCAL: %m",
1564 #ifdef SIOCIFAFATTACH
1565 if (af_attach(s
, ifp
, AF_INET6
) == -1) {
1566 logger(ifp
->ctx
, LOG_ERR
,
1567 "%s: af_attach: %m", ifp
->name
);
1572 #ifdef SIOCGIFXFLAGS
1573 if (set_ifxflags(s
, ifp
, own
) == -1) {
1574 logger(ifp
->ctx
, LOG_ERR
,
1575 "%s: set_ifxflags: %m", ifp
->name
);
1580 #ifdef ND6_IFF_OVERRIDE_RTADV
1581 override
= get_if_nd6_flag(s
, ifp
, ND6_IFF_OVERRIDE_RTADV
);
1583 logger(ifp
->ctx
, LOG_ERR
,
1584 "%s: get_if_nd6_flag: ND6_IFF_OVERRIDE_RTADV: %m",
1586 else if (override
== 0 && own
) {
1587 if (set_if_nd6_flag(s
, ifp
, ND6_IFF_OVERRIDE_RTADV
)
1589 logger(ifp
->ctx
, LOG_ERR
,
1590 "%s: set_if_nd6_flag: "
1591 "ND6_IFF_OVERRIDE_RTADV: %m",
1598 #ifdef ND6_IFF_ACCEPT_RTADV
1599 ra
= get_if_nd6_flag(s
, ifp
, ND6_IFF_ACCEPT_RTADV
);
1601 logger(ifp
->ctx
, LOG_ERR
,
1602 "%s: get_if_nd6_flag: ND6_IFF_ACCEPT_RTADV: %m",
1604 else if (ra
!= 0 && own
) {
1605 logger(ifp
->ctx
, LOG_DEBUG
,
1606 "%s: disabling Kernel IPv6 RA support",
1608 if (del_if_nd6_flag(s
, ifp
, ND6_IFF_ACCEPT_RTADV
)
1610 logger(ifp
->ctx
, LOG_ERR
,
1611 "%s: del_if_nd6_flag: "
1612 "ND6_IFF_ACCEPT_RTADV: %m",
1616 } else if (ra
== 0 && !own
)
1617 logger(ifp
->ctx
, LOG_WARNING
,
1618 "%s: IPv6 kernel autoconf disabled", ifp
->name
);
1619 #ifdef ND6_IFF_OVERRIDE_RTADV
1620 if (override
== 0 && ra
)
1621 return ctx
->ra_global
;
1625 return ctx
->ra_global
;
1629 #ifdef IPV6CTL_ACCEPT_RTADV
1630 ra
= get_inet6_sysctl(IPV6CTL_ACCEPT_RTADV
);
1632 /* The sysctl probably doesn't exist, but this isn't an
1633 * error as such so just log it and continue */
1634 logger(ifp
->ctx
, errno
== ENOENT
? LOG_DEBUG
: LOG_WARNING
,
1635 "IPV6CTL_ACCEPT_RTADV: %m");
1636 else if (ra
!= 0 && own
) {
1637 logger(ifp
->ctx
, LOG_DEBUG
, "disabling Kernel IPv6 RA support");
1638 if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV
, 0) == -1) {
1639 logger(ifp
->ctx
, LOG_ERR
, "IPV6CTL_ACCEPT_RTADV: %m");
1647 /* Flush the kernel knowledge of advertised routers
1648 * and prefixes so the kernel does not expire prefixes
1649 * and default routes we are trying to own. */
1650 if (if_raflush(s
) == -1)
1651 logger(ctx
, LOG_WARNING
, "if_raflush: %m");
1654 ctx
->ra_global
= ra
;
1659 if_checkipv6(struct dhcpcd_ctx
*ctx
, const struct interface
*ifp
, int own
)
1662 return _if_checkipv6(ctx
->pf_inet6_fd
, ctx
, ifp
, own
);