From 8ef970d1723ca10d5e2967600b37de028ffd4467 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Thu, 10 Oct 2024 14:19:46 +0100 Subject: [PATCH] linux: Support old kernels by not including linux/if.h I wish the linux team used #defines rather than enums, but heh ho. Ensure we can test IFF_LOWER_UP, IFF_DORMANT and IFA_FLAGS based on nearest matching #defines available when the respective feature was comitted. Fixes #373. --- src/if-linux.c | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/if-linux.c b/src/if-linux.c index ef73b305..3217161d 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -60,11 +60,6 @@ #include #endif -#ifndef IFF_DORMANT -/* Inlcude this *after* net/if.h so we get IFF_DORMANT */ -#include -#endif - #include #include #include @@ -109,6 +104,27 @@ int if_getssid_wext(const char *ifname, uint8_t *ssid); #define SOL_NETLINK 270 #endif +/* + * We cannot include linux/if.h due to the need to support old kernels. + * IFLA_LINKINFO is a define which was added after IFF_LOWER_UP and + * IFF_DORMANT. + * So we miss a few versions, but it's the best we can do. + */ +#ifdef IFLA_LINKINFO +#ifndef IFF_LOWER_UP +#define IFF_LOWER_UP 0x10000 +#endif +#ifndef IFF_DORMANT +#define IFF_DORMANT 0x20000 +#endif +#endif + +/* Linux defines IFA_FLAGS as an enum. + * For older kernels we know it exists if IFA_F_MANAGETEMPADDR does. */ +#ifdef IFA_F_MANAGETEMPADDR +#define IFA_FLAGS IFA_FLAGS +#endif + /* * Someone should fix kernel headers for clang alignment warnings. * But this is unlikely. @@ -1208,6 +1224,7 @@ add_attr_l(struct nlmsghdr *n, unsigned short maxlen, unsigned short type, return 0; } +#if defined(HAVE_ROUTE_PREF) || defined(HAVE_IN6_ADDR_GEN_MODE_NONE) static int add_attr_8(struct nlmsghdr *n, unsigned short maxlen, unsigned short type, uint8_t data) @@ -1215,6 +1232,7 @@ add_attr_8(struct nlmsghdr *n, unsigned short maxlen, unsigned short type, return add_attr_l(n, maxlen, type, &data, sizeof(data)); } +#endif static int add_attr_32(struct nlmsghdr *n, unsigned short maxlen, unsigned short type, @@ -1997,7 +2015,7 @@ if_address6(unsigned char cmd, const struct ipv6_addr *ia) nlm.ifa.ifa_flags |= IFA_F_TEMPORARY; #endif } -#elif IFA_F_MANAGETEMPADDR +#elif defined(IFA_F_MANAGETEMPADDR) if (ia->flags & IPV6_AF_AUTOCONF && IA6_CANAUTOCONF(ia)) flags |= IFA_F_MANAGETEMPADDR; #endif @@ -2037,12 +2055,15 @@ _if_addrflags6(__unused struct dhcpcd_ctx *ctx, struct rtattr *rta; struct ifaddrmsg *ifa; struct in6_addr *local = NULL, *address = NULL; - uint32_t *flags = NULL; + uint32_t flags; ifa = NLMSG_DATA(nlm); if (ifa->ifa_index != ia->ifa_ifindex || ifa->ifa_family != AF_INET6) return 0; + /* Old kernels set flags here, newer ones as attributed data. */ + flags = ifa->ifa_flags; + rta = IFA_RTA(ifa); len = NLMSG_PAYLOAD(nlm, sizeof(*ifa)); for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { @@ -2053,9 +2074,11 @@ _if_addrflags6(__unused struct dhcpcd_ctx *ctx, case IFA_LOCAL: local = (struct in6_addr *)RTA_DATA(rta); break; +#ifdef IFA_F_MANAGETEMPADDR /* IFA_FLAGS is an enum, can't test that */ case IFA_FLAGS: - flags = (uint32_t *)RTA_DATA(rta); + memcpy(&flags, RTA_DATA(rta), sizeof(flags)); break; +#endif } } @@ -2066,8 +2089,8 @@ _if_addrflags6(__unused struct dhcpcd_ctx *ctx, if (IN6_ARE_ADDR_EQUAL(&ia->ifa_addr, address)) ia->ifa_found = true; } - if (flags && ia->ifa_found) - memcpy(&ia->ifa_flags, flags, sizeof(ia->ifa_flags)); + if (ia->ifa_found) + ia->ifa_flags = flags; return 0; }