]> git.proxmox.com Git - mirror_frr.git/blame - lib/sockopt.c
2004-10-10 Paul Jakma <paul@dishone.st>
[mirror_frr.git] / lib / sockopt.c
CommitLineData
718e3744 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"
e6822768 24#include "sockopt.h"
718e3744 25
0b3acf4f 26int
27setsockopt_so_recvbuf (int sock, int size)
28{
29 int ret;
30
b89e60c7 31 if ( (ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *)
32 &size, sizeof (int))) < 0);
0b3acf4f 33 zlog_err ("can't setsockopt SO_RCVBUF");
34
35 return ret;
36}
37
4f7baa0e 38static void *
39getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
40{
41 struct cmsghdr *cmsg;
42 void *ptr = NULL;
43
44 for (cmsg = CMSG_FIRSTHDR(msgh);
45 cmsg != NULL;
46 cmsg = CMSG_NXTHDR(msgh, cmsg))
47 if (cmsg->cmsg_level == level && cmsg->cmsg_type)
48 return (ptr = CMSG_DATA(cmsg));
49}
50
718e3744 51#ifdef HAVE_IPV6
52/* Set IPv6 packet info to the socket. */
53int
54setsockopt_ipv6_pktinfo (int sock, int val)
55{
56 int ret;
57
58#ifdef IPV6_RECVPKTINFO /*2292bis-01*/
59 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
60 if (ret < 0)
61 zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", strerror (errno));
62#else /*RFC2292*/
63 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
64 if (ret < 0)
65 zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", strerror (errno));
66#endif /* INIA_IPV6 */
67 return ret;
68}
69
70/* Set multicast hops val to the socket. */
71int
72setsockopt_ipv6_checksum (int sock, int val)
73{
74 int ret;
75
76#ifdef GNU_LINUX
77 ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
78#else
79 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
80#endif /* GNU_LINUX */
81 if (ret < 0)
82 zlog_warn ("can't setsockopt IPV6_CHECKSUM");
83 return ret;
84}
85
86/* Set multicast hops val to the socket. */
87int
88setsockopt_ipv6_multicast_hops (int sock, int val)
89{
90 int ret;
91
92 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
93 if (ret < 0)
94 zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS");
95 return ret;
96}
97
98/* Set multicast hops val to the socket. */
99int
100setsockopt_ipv6_unicast_hops (int sock, int val)
101{
102 int ret;
103
104 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
105 if (ret < 0)
106 zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS");
107 return ret;
108}
109
110int
111setsockopt_ipv6_hoplimit (int sock, int val)
112{
113 int ret;
114
115#ifdef IPV6_RECVHOPLIMIT /*2292bis-01*/
116 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
117 if (ret < 0)
118 zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT");
119#else /*RFC2292*/
120 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
121 if (ret < 0)
122 zlog_warn ("can't setsockopt IPV6_HOPLIMIT");
123#endif
124 return ret;
125}
126
127/* Set multicast loop zero to the socket. */
128int
129setsockopt_ipv6_multicast_loop (int sock, int val)
130{
131 int ret;
132
133 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
134 sizeof (val));
135 if (ret < 0)
136 zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP");
137 return ret;
138}
139
4f7baa0e 140static int
e6822768 141getsockopt_ipv6_ifindex (struct msghdr *msgh)
4f7baa0e 142{
143 struct in6_pktinfo *pktinfo;
144
145 pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO);
146
147 return pktinfo->ipi6_ifindex;
148}
718e3744 149#endif /* HAVE_IPV6 */
150
151
152/* Set up a multicast socket options for IPv4
153 This is here so that people only have to do their OS multicast mess
154 in one place rather than all through zebra, ospfd, and ripd
155 NB: This is a hookpoint for specific OS functionality */
156int
157setsockopt_multicast_ipv4(int sock,
158 int optname,
159 struct in_addr if_addr,
160 unsigned int mcast_addr,
161 unsigned int ifindex)
162{
163
164 /* Linux 2.2.0 and up */
165#if defined(GNU_LINUX) && LINUX_VERSION_CODE > 131584
166 /* This is better because it uses ifindex directly */
167 struct ip_mreqn mreqn;
168
169 switch (optname)
170 {
171 case IP_MULTICAST_IF:
172 case IP_ADD_MEMBERSHIP:
173 case IP_DROP_MEMBERSHIP:
174 memset (&mreqn, 0, sizeof(mreqn));
175
176 if (mcast_addr)
177 mreqn.imr_multiaddr.s_addr = mcast_addr;
178
179 if (ifindex)
180 mreqn.imr_ifindex = ifindex;
181 else
182 mreqn.imr_address = if_addr;
183
184 return setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn, sizeof(mreqn));
185 break;
186
187 default:
188 /* Can out and give an understandable error */
189 errno = EINVAL;
190 return -1;
191 break;
192 }
193
194 /* Example defines for another OS, boilerplate off other code in this
195 function, AND handle optname as per other sections for consistency !! */
196 /* #elif defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
197 /* Add your favourite OS here! */
198
199#else /* #if OS_TYPE */
200 /* default OS support */
201
202 struct in_addr m;
203 struct ip_mreq mreq;
204
205 switch (optname)
206 {
207 case IP_MULTICAST_IF:
208 m = if_addr;
209
210 return setsockopt (sock, IPPROTO_IP, optname, (void *)&m, sizeof(m));
211 break;
212
213 case IP_ADD_MEMBERSHIP:
214 case IP_DROP_MEMBERSHIP:
215 memset (&mreq, 0, sizeof(mreq));
216 mreq.imr_multiaddr.s_addr = mcast_addr;
217 mreq.imr_interface = if_addr;
218
219 return setsockopt (sock,
220 IPPROTO_IP,
221 optname,
222 (void *)&mreq,
223 sizeof(mreq));
224 break;
225
226 default:
227 /* Can out and give an understandable error */
228 errno = EINVAL;
229 return -1;
230 break;
231 }
232#endif /* #if OS_TYPE */
233
234}
4f7baa0e 235
236static int
e6822768 237setsockopt_ipv4_ifindex (int sock, int val)
4f7baa0e 238{
239 int ret;
240
241#if defined (IP_PKTINFO)
242 ret = setsockopt (sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val));
243#elif defined (IP_RECVIF)
244 ret = setsockopt (sock, IPPROTO_IP, IP_RECVIF, &val, sizeof (val));
245#else
246#warning "Neither IP_PKTINFO nor IP_RECVIF is available."
247#warning "Will not be able to receive link info."
248#warning "Things might be seriously broken.."
249#endif
250
251 if (ret < 0)
252 zlog_warn ("Can't set IP_PKTINFO option");
253 return ret;
254}
255
256/* set appropriate pktinfo socket option
257 * on systems without PKTINFO, sets RECVIF, which only retrieves
258 * interface index.
e6822768 259 * Not portable for IPv4, use only setsockopt_ifindex for v4.
4f7baa0e 260 */
261int
262setsockopt_pktinfo (int af, int sock, int val)
263{
264 int ret = -1;
265
266 switch (af)
267 {
268 case AF_INET:
e6822768 269 /* _ifindex will use PKTINFO if available.. */
270 ret = setsockopt_ipv4_ifindex (sock, val);
4f7baa0e 271 break;
272#ifdef HAVE_IPV6
273 case AF_INET6:
274 ret = setsockopt_ipv6_pktinfo (sock, val);
275 break;
276#endif
277 default:
e473b032 278 zlog_warn ("setsockopt_pktinfo: unknown address family %d", af);
4f7baa0e 279 }
280 return ret;
281}
282
e6822768 283int
284setsockopt_ifindex (int af, int sock, int val)
285{
286 int ret = -1;
287
288 switch (af)
289 {
290 case AF_INET:
291 ret = setsockopt_ipv4_ifindex (sock, val);
292 break;
293#ifdef HAVE_IPV6
294 case AF_INET6:
295 ret = setsockopt_ipv6_pktinfo (sock, val);
296 break;
297#endif
298 default:
e473b032 299 zlog_warn ("setsockopt_ifindex: unknown address family %d", af);
e6822768 300 }
301 return ret;
302}
303
4f7baa0e 304static int
e6822768 305getsockopt_ipv4_ifindex (struct msghdr *msgh)
4f7baa0e 306{
e6822768 307 int ifindex = -1;
308#if defined(IP_PKTINFO)
309/* Linux pktinfo based ifindex retrieval */
4f7baa0e 310 struct in_pktinfo *pktinfo;
e6822768 311
312 pktinfo =
313 (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
314 ifindex = pktinfo->ipi_ifindex;
315
316#elif defined(IP_RECVIF)
317/* BSD/other IP_RECVIF based ifindex retrieval */
4f7baa0e 318#ifndef SUNOS_5
33f92320 319 /* RECVIF, but not SUNOS, so BSD */
4f7baa0e 320 struct sockaddr_dl *sdl;
321#endif /* SUNOS_5 */
33f92320 322 /* SUNOS_5 doesn't need a structure to extract ifindex */
e6822768 323
33f92320 324#ifndef SUNOS_5
325 sdl =
4f7baa0e 326 (struct sockaddr_dl *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF);
33f92320 327 ifindex = sdl->sdl_index;
e6822768 328#else /* !SUNOS_5 */
33f92320 329 ifindex = *(uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF);
4f7baa0e 330#endif /* SUNOS_5 */
e6822768 331
332#else /* neither IP_PKTINFO nor IP_RECVIF, broken */
333
4f7baa0e 334#warning "getsockopt_ipv4_pktinfo_ifindex: dont have PKTINFO or RECVIF"
e6822768 335#warning "things will be broken on this platform!"
33f92320 336 /* XXX why not -1 - this is a failure condition. */
e6822768 337 ifindex = -1;
338#endif /* IP_PKTINFO */
4f7baa0e 339 return ifindex;
340}
341
342/* return ifindex, 0 if none found */
343int
e6822768 344getsockopt_ifindex (int af, struct msghdr *msgh)
4f7baa0e 345{
346 int ifindex = 0;
347
348 switch (af)
349 {
350 case AF_INET:
e6822768 351 return (getsockopt_ipv4_ifindex (msgh));
4f7baa0e 352 break;
353#ifdef HAVE_IPV6
354 case AF_INET6:
e6822768 355 return (getsockopt_ipv6_ifindex (msgh));
4f7baa0e 356 break;
357#endif
358 default:
e473b032 359 zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
4f7baa0e 360 return (ifindex = 0);
361 }
362}
96e27c99 363
364/* swab iph between order system uses for IP_HDRINCL and host order */
365void
366sockopt_iphdrincl_swab_htosys (struct ip *iph)
367{
368 /* BSD and derived take iph in network order, except for
369 * ip_len and ip_off
370 */
371#ifndef HAVE_IP_HDRINCL_BSD_ORDER
372 iph->ip_len = htons(iph->ip_len);
373 iph->ip_off = htons(iph->ip_off);
374#endif /* HAVE_IP_HDRINCL_BSD_ORDER */
375
376 iph->ip_id = htons(iph->ip_id);
377}
378
379void
380sockopt_iphdrincl_swab_systoh (struct ip *iph)
381{
382#ifndef HAVE_IP_HDRINCL_BSD_ORDER
383 iph->ip_len = ntohs(iph->ip_len);
384 iph->ip_off = ntohs(iph->ip_off);
385#endif /* HAVE_IP_HDRINCL_BSD_ORDER */
386
387 iph->ip_id = ntohs(iph->ip_id);
388}