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