Initial revision
diff --git a/lib/sockopt.c b/lib/sockopt.c
new file mode 100644
index 0000000..e2beca9
--- /dev/null
+++ b/lib/sockopt.c
@@ -0,0 +1,199 @@
+/* setsockopt functions
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+#include "log.h"
+
+#ifdef HAVE_IPV6
+/* Set IPv6 packet info to the socket. */
+int
+setsockopt_ipv6_pktinfo (int sock, int val)
+{
+ int ret;
+
+#ifdef IPV6_RECVPKTINFO /*2292bis-01*/
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", strerror (errno));
+#else /*RFC2292*/
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", strerror (errno));
+#endif /* INIA_IPV6 */
+ return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_checksum (int sock, int val)
+{
+ int ret;
+
+#ifdef GNU_LINUX
+ ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
+#else
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
+#endif /* GNU_LINUX */
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_CHECKSUM");
+ return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_multicast_hops (int sock, int val)
+{
+ int ret;
+
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS");
+ return ret;
+}
+
+/* Set multicast hops val to the socket. */
+int
+setsockopt_ipv6_unicast_hops (int sock, int val)
+{
+ int ret;
+
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS");
+ return ret;
+}
+
+int
+setsockopt_ipv6_hoplimit (int sock, int val)
+{
+ int ret;
+
+#ifdef IPV6_RECVHOPLIMIT /*2292bis-01*/
+ ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT");
+#else /*RFC2292*/
+ ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_HOPLIMIT");
+#endif
+ return ret;
+}
+
+/* Set multicast loop zero to the socket. */
+int
+setsockopt_ipv6_multicast_loop (int sock, int val)
+{
+ int ret;
+
+ ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
+ sizeof (val));
+ if (ret < 0)
+ zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP");
+ return ret;
+}
+
+#endif /* HAVE_IPV6 */
+
+
+/* Set up a multicast socket options for IPv4
+ This is here so that people only have to do their OS multicast mess
+ in one place rather than all through zebra, ospfd, and ripd
+ NB: This is a hookpoint for specific OS functionality */
+int
+setsockopt_multicast_ipv4(int sock,
+ int optname,
+ struct in_addr if_addr,
+ unsigned int mcast_addr,
+ unsigned int ifindex)
+{
+
+ /* Linux 2.2.0 and up */
+#if defined(GNU_LINUX) && LINUX_VERSION_CODE > 131584
+ /* This is better because it uses ifindex directly */
+ struct ip_mreqn mreqn;
+
+ switch (optname)
+ {
+ case IP_MULTICAST_IF:
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ memset (&mreqn, 0, sizeof(mreqn));
+
+ if (mcast_addr)
+ mreqn.imr_multiaddr.s_addr = mcast_addr;
+
+ if (ifindex)
+ mreqn.imr_ifindex = ifindex;
+ else
+ mreqn.imr_address = if_addr;
+
+ return setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn));
+ break;
+
+ default:
+ /* Can out and give an understandable error */
+ errno = EINVAL;
+ return -1;
+ break;
+ }
+
+ /* Example defines for another OS, boilerplate off other code in this
+ function, AND handle optname as per other sections for consistency !! */
+ /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
+ /* Add your favourite OS here! */
+
+#else /* #if OS_TYPE */
+ /* default OS support */
+
+ struct in_addr m;
+ struct ip_mreq mreq;
+
+ switch (optname)
+ {
+ case IP_MULTICAST_IF:
+ m = if_addr;
+
+ return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m));
+ break;
+
+ case IP_ADD_MEMBERSHIP:
+ case IP_DROP_MEMBERSHIP:
+ memset (&mreq, 0, sizeof(mreq));
+ mreq.imr_multiaddr.s_addr = mcast_addr;
+ mreq.imr_interface = if_addr;
+
+ return setsockopt (sock,
+ IPPROTO_IP,
+ optname,
+ (void *)&mreq,
+ sizeof(mreq));
+ break;
+
+ default:
+ /* Can out and give an understandable error */
+ errno = EINVAL;
+ return -1;
+ break;
+ }
+#endif /* #if OS_TYPE */
+
+}