diff options
-rw-r--r-- | lib/ChangeLog | 17 | ||||
-rw-r--r-- | lib/sockopt.c | 124 | ||||
-rw-r--r-- | lib/sockopt.h | 20 |
3 files changed, 159 insertions, 2 deletions
diff --git a/lib/ChangeLog b/lib/ChangeLog index b3d452e0..ff813bba 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,20 @@ +2004-07-23 Paul Jakma <paul@dishone.st> + + * sockopt.h: Add SOPT_SIZE_CMSG_PKTINFO{_IPV{4,6}} define, for + sizeof pktinfo as appropriate, to be used when allocating msg + buffers. export setsockopt_pktinfo() and + getsockopt_pktinfo_ifindex() + * sockopt.c: (setsockopt_pktinfo_ifindex) new function to portably + set received ifindex sock option. + (getsockopt_pktinfo_ifindex) portably retrieve ifindex. + (getsockopt_cmsg_data) retrieve indicated control info from + message header. + (getsockopt_ipv6_pktinfo_ifindex) ipv6 version of above. + (setsockopt_ipv4_pktinfo) v4 version + (setsockopt_pktinfo) the exported version + (getsockopt_ipv4_pktinfo_ifindex) v4 specific version + (getsockopt_pktinfo_ifindex) the exported version + 2004-07-14 Paul Jakma <paul@dishone.st> * sigevent.c: (quagga_signal_handler) add a global caught flag, set diff --git a/lib/sockopt.c b/lib/sockopt.c index e2beca9f..ee10ac30 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -22,6 +22,19 @@ #include <zebra.h> #include "log.h" +static void * +getsockopt_cmsg_data (struct msghdr *msgh, int level, int type) +{ + struct cmsghdr *cmsg; + void *ptr = NULL; + + for (cmsg = CMSG_FIRSTHDR(msgh); + cmsg != NULL; + cmsg = CMSG_NXTHDR(msgh, cmsg)) + if (cmsg->cmsg_level == level && cmsg->cmsg_type) + return (ptr = CMSG_DATA(cmsg)); +} + #ifdef HAVE_IPV6 /* Set IPv6 packet info to the socket. */ int @@ -111,6 +124,15 @@ setsockopt_ipv6_multicast_loop (int sock, int val) return ret; } +static int +getsockopt_ipv6_pktinfo_ifindex (struct msghdr *msgh) +{ + struct in6_pktinfo *pktinfo; + + pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO); + + return pktinfo->ipi6_ifindex; +} #endif /* HAVE_IPV6 */ @@ -197,3 +219,105 @@ setsockopt_multicast_ipv4(int sock, #endif /* #if OS_TYPE */ } + +static int +setsockopt_ipv4_pktinfo (int sock, int val) +{ + int ret; + +#if defined (IP_PKTINFO) + ret = setsockopt (sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val)); +#elif defined (IP_RECVIF) + ret = setsockopt (sock, IPPROTO_IP, IP_RECVIF, &val, sizeof (val)); +#else +#warning "Neither IP_PKTINFO nor IP_RECVIF is available." +#warning "Will not be able to receive link info." +#warning "Things might be seriously broken.." +#endif + + if (ret < 0) + zlog_warn ("Can't set IP_PKTINFO option"); + return ret; +} + +/* set appropriate pktinfo socket option + * on systems without PKTINFO, sets RECVIF, which only retrieves + * interface index. + */ +int +setsockopt_pktinfo (int af, int sock, int val) +{ + int ret = -1; + + switch (af) + { + case AF_INET: + ret = setsockopt_ipv4_pktinfo (sock, val); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ret = setsockopt_ipv6_pktinfo (sock, val); + break; +#endif + default: + zlog_warn ("setsockopt_pktinfo: unknown address family %d"); + } + return ret; +} + + +static int +getsockopt_ipv4_pktinfo_ifindex (struct msghdr *msgh) +{ + int ifindex = 0; +#if defined (IP_PKTINFO) + struct in_pktinfo *pktinfo; +#elif defined (IP_REVCIF) +#ifndef SUNOS_5 + struct sockaddr_dl *sdl; +#endif /* SUNOS_5 */ +#else /* IP_RECVIF */ + char *pktinfo; +#endif /* IP_PKTINFO */ + +#ifdef IP_PKTINFO + pktinfo = + (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO); +#elif defined (IP_RECVIF) +#ifdef SUNOS_5 + ifindex = *(uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); +#else + pktinfo = + (struct sockaddr_dl *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); + ifindex = pktinfo->sdl_index; +#endif /* SUNOS_5 */ +#else +#warning "getsockopt_ipv4_pktinfo_ifindex: dont have PKTINFO or RECVIF" + ifindex = 0; +#endif /* IP_PKTINFO */ + + return ifindex; +} + +/* return ifindex, 0 if none found */ +int +getsockopt_pktinfo_ifindex (int af, struct msghdr *msgh) +{ + int ifindex = 0; + + switch (af) + { + case AF_INET: + return (getsockopt_ipv4_pktinfo_ifindex (msgh)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + return (getsockopt_ipv6_pktinfo_ifindex (msgh)); + break; +#endif + default: + zlog_warn ("getsockopt_pktinfo_ifindex: unknown address family %d"); + return (ifindex = 0); + } +} + diff --git a/lib/sockopt.h b/lib/sockopt.h index 7fb31c18..c5d171c2 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -31,11 +31,27 @@ int setsockopt_ipv6_hoplimit (int, int); int setsockopt_ipv6_multicast_loop (int, int); #endif /* HAVE_IPV6 */ +#if defined (IP_PKTINFO) +#define SOPT_SIZE_CMSG_PKTINFO_IPV4() (sizeof (struct in_pktinfo)) +#elif defined (IP_RECVIF) +#if defined (SUNOS_5) +#define SOPT_SIZE_CMSG_PKTINFO_IPV4() (sizeof (uint_t)) +#else +#define SOPT_SIZE_CMSG_PKTINFO_IPV4() (sizeof (struct sockaddr_dl)) +#endif /* SUNOS_5 */ +#endif + +#define SOPT_SIZE_CMSG_PKTINFO_IPV6() (sizeof (struct in6_pktinfo)); + +#define SOPT_SIZE_CMSG_PKTINFO(af) \ + ((af == AF_INET) ? SOPT_SIZE_CMSG_PKTINFO_IPV4() \ + : SOPT_SIZE_CMSG_PKTINFO_IPV6() + int setsockopt_multicast_ipv4(int sock, int optname, struct in_addr if_addr, unsigned int mcast_addr, unsigned int ifindex); - - +int setsockopt_pktinfo (int, int, int); +int getsockopt_pktinfo_ifindex (int, struct msghdr *); #endif /*_ZEBRA_SOCKOPT_H */ |