summaryrefslogtreecommitdiffstats
path: root/if-bsd.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2012-07-05 16:37:41 +0000
committerRoy Marples <roy@marples.name>2012-07-05 16:37:41 +0000
commiteebe9a1887bbf2f3bbb4fdb72e8d46ece25cdd0c (patch)
treeda2e3069767ce09c41eb2b32e6a3b7f01b164eca /if-bsd.c
parent359e9d397807079db8d68d5e60eb4396f41d1738 (diff)
downloaddhcpcd-eebe9a1887bbf2f3bbb4fdb72e8d46ece25cdd0c.tar.xz
Improve IPv6 RA support by allowing dhcpcd to manage the address and routesdhcpcd-5.6.0
instead of the kernel. dhcpcd will only do this if RA is disabled in the kernel or dhcpcd has been instructed to do this via dhcpcd.conf(5) ipv6ra_own and ipv6ra_own_default directives. Send and process IPv6 Neighbor Solicitions and Adverts to prove router reachability. If a router cannot be reached in this way then it is expired. When debugging, all ND messages are displayed which will create a lot of log spam. To ease packaging, ./configure now accepts LDFLAGS and --enable-static.
Diffstat (limited to 'if-bsd.c')
-rw-r--r--if-bsd.c171
1 files changed, 153 insertions, 18 deletions
diff --git a/if-bsd.c b/if-bsd.c
index c3ffcace..c4765385 100644
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -35,8 +35,12 @@
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_dl.h>
+#ifdef __FreeBSD__ /* Needed so that including netinet6/in6_var.h works */
+# include <net/if_var.h>
+#endif
#include <net/route.h>
#include <netinet/in.h>
+#include <netinet6/in6_var.h>
#ifdef __DragonFly__
# include <netproto/802_11/ieee80211_ioctl.h>
#elif __APPLE__
@@ -59,6 +63,7 @@
#include "configure.h"
#include "dhcp.h"
#include "if-options.h"
+#include "ipv6.h"
#include "net.h"
#ifndef RT_ROUNDUP
@@ -154,7 +159,6 @@ if_address(const struct interface *iface, const struct in_addr *address,
const struct in_addr *netmask, const struct in_addr *broadcast,
int action)
{
- int retval;
struct ifaliasreq ifa;
union {
struct sockaddr *sa;
@@ -178,23 +182,16 @@ if_address(const struct interface *iface, const struct in_addr *address,
}
#undef ADDADDR
- if (action < 0)
- retval = ioctl(socket_afnet, SIOCDIFADDR, &ifa);
- else
- retval = ioctl(socket_afnet, SIOCAIFADDR, &ifa);
- return retval;
+ return ioctl(socket_afnet,
+ action < 0 ? SIOCDIFADDR : SIOCAIFADDR, &ifa);
}
-/* ARGSUSED4 */
int
if_route(const struct rt *rt, int action)
{
union sockunion {
struct sockaddr sa;
struct sockaddr_in sin;
-#ifdef INET6
- struct sockaddr_in6 sin6;
-#endif
struct sockaddr_dl sdl;
struct sockaddr_storage ss;
} su;
@@ -207,17 +204,17 @@ if_route(const struct rt *rt, int action)
size_t l;
int retval = 0;
-#define ADDSU(_su) { \
- l = RT_ROUNDUP(_su.sa.sa_len); \
- memcpy(bp, &(_su), l); \
+#define ADDSU { \
+ l = RT_ROUNDUP(su.sa.sa_len); \
+ memcpy(bp, &su, l); \
bp += l; \
}
-#define ADDADDR(_a) { \
- memset (&su, 0, sizeof(su)); \
+#define ADDADDR(addr) { \
+ memset(&su, 0, sizeof(su)); \
su.sin.sin_family = AF_INET; \
su.sin.sin_len = sizeof(su.sin); \
- memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr)); \
- ADDSU(su); \
+ (&su.sin)->sin_addr = *addr; \
+ ADDSU; \
}
memset(&rtm, 0, sizeof(rtm));
@@ -255,16 +252,154 @@ if_route(const struct rt *rt, int action)
memset(&su, 0, sizeof(su));
su.sdl.sdl_len = sizeof(struct sockaddr_dl);
link_addr(rt->iface->name, &su.sdl);
- ADDSU(su);
+ ADDSU;
} else
ADDADDR(&rt->gate);
if (rtm.hdr.rtm_addrs & RTA_NETMASK)
ADDADDR(&rt->net);
+ /* IFP here if we need it */
+
if (rtm.hdr.rtm_addrs & RTA_IFA)
ADDADDR(&rt->iface->addr);
+#undef ADDADDR
+#undef ADDSU
+
+ rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
+ if (write(r_fd, &rtm, l) == -1)
+ retval = -1;
+ return retval;
+}
+
+int
+if_address6(const struct interface *ifp, const struct ipv6_addr *a, int action)
+{
+ struct in6_aliasreq ifa;
+ struct in6_addr mask;
+
+ memset(&ifa, 0, sizeof(ifa));
+ strlcpy(ifa.ifra_name, ifp->name, sizeof(ifa.ifra_name));
+
+#define ADDADDR(v, addr) { \
+ (v)->sin6_family = AF_INET6; \
+ (v)->sin6_len = sizeof(*v); \
+ (v)->sin6_addr = *addr; \
+ }
+
+ ADDADDR(&ifa.ifra_addr, &a->addr);
+ ipv6_mask(&mask, a->prefix_len);
+ ADDADDR(&ifa.ifra_prefixmask, &mask);
+ ifa.ifra_lifetime.ia6t_vltime = a->prefix_vltime;
+ ifa.ifra_lifetime.ia6t_pltime = a->prefix_pltime;
+#undef ADDADDR
+
+ return ioctl(socket_afnet6,
+ action < 0 ? SIOCDIFADDR_IN6 : SIOCAIFADDR_IN6, &ifa);
+}
+
+int
+if_route6(const struct rt6 *rt, int action)
+{
+ union sockunion {
+ struct sockaddr sa;
+ struct sockaddr_in6 sin;
+ struct sockaddr_dl sdl;
+ struct sockaddr_storage ss;
+ } su;
+ struct rtm
+ {
+ struct rt_msghdr hdr;
+ char buffer[sizeof(su) * 4];
+ } rtm;
+ char *bp = rtm.buffer;
+ size_t l;
+ int retval = 0;
+
+/* KAME based systems want to store the scope inside the sin6_addr
+ * for link local addreses */
+#ifdef __KAME__
+#define SCOPE { \
+ if (IN6_IS_ADDR_LINKLOCAL(&su.sin.sin6_addr)) { \
+ *(uint16_t *)(void *)&su.sin.sin6_addr.s6_addr[2] = \
+ htons(su.sin.sin6_scope_id); \
+ su.sin.sin6_scope_id = 0; \
+ } \
+ }
+#else
+#define SCOPE
+#endif
+
+#define ADDSU { \
+ l = RT_ROUNDUP(su.sa.sa_len); \
+ memcpy(bp, &su, l); \
+ bp += l; \
+ }
+#define ADDADDRS(addr, scope) { \
+ memset(&su, 0, sizeof(su)); \
+ su.sin.sin6_family = AF_INET6; \
+ su.sin.sin6_len = sizeof(su.sin); \
+ (&su.sin)->sin6_addr = *addr; \
+ su.sin.sin6_scope_id = scope; \
+ SCOPE; \
+ ADDSU; \
+ }
+#define ADDADDR(addr) ADDADDRS(addr, 0)
+
+ memset(&rtm, 0, sizeof(rtm));
+ rtm.hdr.rtm_version = RTM_VERSION;
+ rtm.hdr.rtm_seq = 1;
+ if (action == 0)
+ rtm.hdr.rtm_type = RTM_CHANGE;
+ else if (action > 0)
+ rtm.hdr.rtm_type = RTM_ADD;
+ else
+ rtm.hdr.rtm_type = RTM_DELETE;
+
+ rtm.hdr.rtm_flags = RTF_UP;
+ /* None interface subnet routes are static. */
+ if (IN6_IS_ADDR_UNSPECIFIED(&rt->dest) &&
+ IN6_IS_ADDR_UNSPECIFIED(&rt->net))
+ rtm.hdr.rtm_flags |= RTF_GATEWAY;
+ else
+ rtm.hdr.rtm_flags |= RTF_CLONING;
+
+ rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+// if (action >= 0)
+// rtm.hdr.rtm_addrs |= RTA_IFA;
+
+ ADDADDR(&rt->dest);
+ if (rtm.hdr.rtm_flags & (RTF_HOST | RTF_CLONING)) {
+ /* Make us a link layer socket for the host gateway */
+ memset(&su, 0, sizeof(su));
+ su.sdl.sdl_len = sizeof(struct sockaddr_dl);
+ link_addr(rt->iface->name, &su.sdl);
+ ADDSU;
+ } else
+ ADDADDRS(&rt->gate, rt->iface->index);
+
+ if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
+ if (rtm.hdr.rtm_flags & RTF_GATEWAY) {
+ memset(&su, 0, sizeof(su));
+ su.sin.sin6_family = AF_INET6;
+ ADDSU;
+ } else
+ ADDADDR(&rt->net);
+ }
+
+ /* IFP here if we need it */
+ /* IFA here if we need it */
+
+#undef ADDADDR
+#undef ADDSU
+#undef SCOPE
+
+ if (action >= 0 && rt->mtu) {
+ rtm.hdr.rtm_inits |= RTV_MTU;
+ rtm.hdr.rtm_rmx.rmx_mtu = rt->mtu;
+ }
+
rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
if (write(r_fd, &rtm, l) == -1)
retval = -1;