1/* setsockopt functions
2 * Copyright (C) 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING.  If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23#include "log.h"
24
25#ifdef HAVE_IPV6
26/* Set IPv6 packet info to the socket. */
27int
28setsockopt_ipv6_pktinfo (int sock, int val)
29{
30  int ret;
31
32#ifdef IPV6_RECVPKTINFO		/*2292bis-01*/
33  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
34  if (ret < 0)
35    zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", strerror (errno));
36#else	/*RFC2292*/
37  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
38  if (ret < 0)
39    zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", strerror (errno));
40#endif /* INIA_IPV6 */
41  return ret;
42}
43
44/* Set multicast hops val to the socket. */
45int
46setsockopt_ipv6_checksum (int sock, int val)
47{
48  int ret;
49
50#ifdef GNU_LINUX
51  ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
52#else
53  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
54#endif /* GNU_LINUX */
55  if (ret < 0)
56    zlog_warn ("can't setsockopt IPV6_CHECKSUM");
57  return ret;
58}
59
60/* Set multicast hops val to the socket. */
61int
62setsockopt_ipv6_multicast_hops (int sock, int val)
63{
64  int ret;
65
66  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
67  if (ret < 0)
68    zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS");
69  return ret;
70}
71
72/* Set multicast hops val to the socket. */
73int
74setsockopt_ipv6_unicast_hops (int sock, int val)
75{
76  int ret;
77
78  ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
79  if (ret < 0)
80    zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS");
81  return ret;
82}
83
84int
85setsockopt_ipv6_hoplimit (int sock, int val)
86{
87  int ret;
88
89#ifdef IPV6_RECVHOPLIMIT	/*2292bis-01*/
90  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
91  if (ret < 0)
92    zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT");
93#else	/*RFC2292*/
94  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
95  if (ret < 0)
96    zlog_warn ("can't setsockopt IPV6_HOPLIMIT");
97#endif
98  return ret;
99}
100
101/* Set multicast loop zero to the socket. */
102int
103setsockopt_ipv6_multicast_loop (int sock, int val)
104{
105  int ret;
106
107  ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
108		    sizeof (val));
109  if (ret < 0)
110    zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP");
111  return ret;
112}
113
114#endif /* HAVE_IPV6 */
115
116
117/* Set up a multicast socket options for IPv4
118   This is here so that people only have to do their OS multicast mess
119   in one place rather than all through zebra, ospfd, and ripd
120   NB: This is a hookpoint for specific OS functionality */
121int
122setsockopt_multicast_ipv4(int sock,
123			int optname,
124			struct in_addr if_addr,
125			unsigned int mcast_addr,
126			unsigned int ifindex)
127{
128
129  /* Linux 2.2.0 and up */
130#if defined(GNU_LINUX) && LINUX_VERSION_CODE > 131584
131  /* This is better because it uses ifindex directly */
132  struct ip_mreqn mreqn;
133
134  switch (optname)
135    {
136    case IP_MULTICAST_IF:
137    case IP_ADD_MEMBERSHIP:
138    case IP_DROP_MEMBERSHIP:
139      memset (&mreqn, 0, sizeof(mreqn));
140
141      if (mcast_addr)
142	mreqn.imr_multiaddr.s_addr = mcast_addr;
143
144      if (ifindex)
145	mreqn.imr_ifindex = ifindex;
146      else
147	mreqn.imr_address = if_addr;
148
149      return setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn));
150      break;
151
152    default:
153      /* Can out and give an understandable error */
154      errno = EINVAL;
155      return -1;
156      break;
157    }
158
159  /* Example defines for another OS, boilerplate off other code in this
160     function, AND handle optname as per other sections for consistency !! */
161  /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
162  /* Add your favourite OS here! */
163
164#else /* #if OS_TYPE */
165  /* default OS support */
166
167  struct in_addr m;
168  struct ip_mreq mreq;
169
170  switch (optname)
171    {
172    case IP_MULTICAST_IF:
173      m = if_addr;
174
175      return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m));
176      break;
177
178    case IP_ADD_MEMBERSHIP:
179    case IP_DROP_MEMBERSHIP:
180      memset (&mreq, 0, sizeof(mreq));
181      mreq.imr_multiaddr.s_addr = mcast_addr;
182      mreq.imr_interface = if_addr;
183
184      return setsockopt (sock,
185			 IPPROTO_IP,
186			 optname,
187			 (void *)&mreq,
188			 sizeof(mreq));
189      break;
190
191    default:
192      /* Can out and give an understandable error */
193      errno = EINVAL;
194      return -1;
195      break;
196    }
197#endif /* #if OS_TYPE */
198
199}
200