2 * Copyright (C) 2003 Yasuhiro Ohara
4 * This file is part of GNU Zebra.
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
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.
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
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
26 #include "sockunion.h"
31 #include "ospf6_proto.h"
32 #include "ospf6_network.h"
34 extern struct zebra_privs_t ospf6d_privs
;
37 struct in6_addr allspfrouters6
;
38 struct in6_addr alldrouters6
;
40 /* setsockopt ReUseAddr to on */
42 ospf6_set_reuseaddr (void)
45 if (setsockopt (ospf6_sock
, SOL_SOCKET
, SO_REUSEADDR
, &on
,
47 zlog_warn ("Network: set SO_REUSEADDR failed: %s", safe_strerror (errno
));
50 /* setsockopt MulticastLoop to off */
52 ospf6_reset_mcastloop (void)
55 if (setsockopt (ospf6_sock
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
,
56 &off
, sizeof (u_int
)) < 0)
57 zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s",
58 safe_strerror (errno
));
62 ospf6_set_pktinfo (void)
64 setsockopt_ipv6_pktinfo (ospf6_sock
, 1);
68 ospf6_set_transport_class (void)
70 #ifdef IPTOS_PREC_INTERNETCONTROL
71 setsockopt_ipv6_tclass (ospf6_sock
, IPTOS_PREC_INTERNETCONTROL
);
76 ospf6_set_checksum (void)
79 #ifndef DISABLE_IPV6_CHECKSUM
80 if (setsockopt (ospf6_sock
, IPPROTO_IPV6
, IPV6_CHECKSUM
,
81 &offset
, sizeof (offset
)) < 0)
82 zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", safe_strerror (errno
));
84 zlog_warn ("Network: Don't set IPV6_CHECKSUM");
85 #endif /* DISABLE_IPV6_CHECKSUM */
88 /* Make ospf6d's server socket. */
90 ospf6_serv_sock (void)
92 if (ospf6d_privs
.change (ZPRIVS_RAISE
))
93 zlog_err ("ospf6_serv_sock: could not raise privs");
95 ospf6_sock
= socket (AF_INET6
, SOCK_RAW
, IPPROTO_OSPFIGP
);
98 zlog_warn ("Network: can't create OSPF6 socket.");
99 if (ospf6d_privs
.change (ZPRIVS_LOWER
))
100 zlog_err ("ospf_sock_init: could not lower privs");
103 if (ospf6d_privs
.change (ZPRIVS_LOWER
))
104 zlog_err ("ospf_sock_init: could not lower privs");
106 /* set socket options */
108 sockopt_reuseaddr (ospf6_sock
);
110 ospf6_set_reuseaddr ();
112 ospf6_reset_mcastloop ();
113 ospf6_set_pktinfo ();
114 ospf6_set_transport_class ();
115 ospf6_set_checksum ();
117 /* setup global in6_addr, allspf6 and alldr6 for later use */
118 inet_pton (AF_INET6
, ALLSPFROUTERS6
, &allspfrouters6
);
119 inet_pton (AF_INET6
, ALLDROUTERS6
, &alldrouters6
);
124 /* ospf6 set socket option */
126 ospf6_sso (u_int ifindex
, struct in6_addr
*group
, int option
)
128 struct ipv6_mreq mreq6
;
130 int bufsize
= (8 * 1024 * 1024);
132 socklen_t optlen
= sizeof(optval
);
135 mreq6
.ipv6mr_interface
= ifindex
;
136 memcpy (&mreq6
.ipv6mr_multiaddr
, group
, sizeof (struct in6_addr
));
138 ret
= setsockopt (ospf6_sock
, IPPROTO_IPV6
, option
,
139 &mreq6
, sizeof (mreq6
));
142 zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s",
143 option
, ifindex
, safe_strerror (errno
));
147 if ((ret
= setsockopt (ospf6_sock
, SOL_SOCKET
, SO_SNDBUF
,
148 &bufsize
, sizeof (bufsize
))) < 0)
150 zlog_err ("Couldn't increase raw wbuf size: %s\n", safe_strerror(errno
));
154 if ((ret
= getsockopt (ospf6_sock
, SOL_SOCKET
, SO_SNDBUF
,
155 &optval
, &optlen
)) < 0)
157 zlog_err ("getsockopt of SO_SNDBUF failed with error %s\n", safe_strerror(errno
));
160 else if (optval
< bufsize
)
162 zlog_err ("Unable to SO_SNDBUF to %d, set to %d\n", bufsize
, optval
);
165 if ((ret
= setsockopt (ospf6_sock
, SOL_SOCKET
, SO_RCVBUF
,
166 &bufsize
, sizeof (bufsize
))) < 0)
168 zlog_err ("Couldn't increase raw rbuf size: %s\n", safe_strerror(errno
));
171 if ((ret
= getsockopt (ospf6_sock
, SOL_SOCKET
, SO_RCVBUF
,
172 &optval
, &optlen
)) < 0)
174 zlog_err ("getsockopt of SO_RCVBUF failed with error %s\n", safe_strerror(errno
));
177 else if (optval
< bufsize
)
179 zlog_err ("Unable to SO_RCVBUF to %d, set to %d\n", bufsize
, optval
);
186 iov_count (struct iovec
*iov
)
189 for (i
= 0; iov
[i
].iov_base
; i
++)
195 iov_totallen (struct iovec
*iov
)
199 for (i
= 0; iov
[i
].iov_base
; i
++)
200 totallen
+= iov
[i
].iov_len
;
205 ospf6_sendmsg (struct in6_addr
*src
, struct in6_addr
*dst
,
206 unsigned int *ifindex
, struct iovec
*message
)
209 struct msghdr smsghdr
;
210 struct cmsghdr
*scmsgp
;
211 u_char cmsgbuf
[CMSG_SPACE(sizeof (struct in6_pktinfo
))];
212 struct in6_pktinfo
*pktinfo
;
213 struct sockaddr_in6 dst_sin6
;
218 scmsgp
= (struct cmsghdr
*)cmsgbuf
;
219 pktinfo
= (struct in6_pktinfo
*)(CMSG_DATA(scmsgp
));
220 memset (&dst_sin6
, 0, sizeof (struct sockaddr_in6
));
223 pktinfo
->ipi6_ifindex
= *ifindex
;
225 memcpy (&pktinfo
->ipi6_addr
, src
, sizeof (struct in6_addr
));
227 memset (&pktinfo
->ipi6_addr
, 0, sizeof (struct in6_addr
));
229 /* destination address */
230 dst_sin6
.sin6_family
= AF_INET6
;
232 dst_sin6
.sin6_len
= sizeof (struct sockaddr_in6
);
234 memcpy (&dst_sin6
.sin6_addr
, dst
, sizeof (struct in6_addr
));
235 #ifdef HAVE_SIN6_SCOPE_ID
236 dst_sin6
.sin6_scope_id
= *ifindex
;
239 /* send control msg */
240 scmsgp
->cmsg_level
= IPPROTO_IPV6
;
241 scmsgp
->cmsg_type
= IPV6_PKTINFO
;
242 scmsgp
->cmsg_len
= CMSG_LEN (sizeof (struct in6_pktinfo
));
243 /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */
246 memset (&smsghdr
, 0, sizeof (smsghdr
));
247 smsghdr
.msg_iov
= message
;
248 smsghdr
.msg_iovlen
= iov_count (message
);
249 smsghdr
.msg_name
= (caddr_t
) &dst_sin6
;
250 smsghdr
.msg_namelen
= sizeof (struct sockaddr_in6
);
251 smsghdr
.msg_control
= (caddr_t
) cmsgbuf
;
252 smsghdr
.msg_controllen
= scmsgp
->cmsg_len
;
254 retval
= sendmsg (ospf6_sock
, &smsghdr
, 0);
255 if (retval
!= iov_totallen (message
))
256 zlog_warn ("sendmsg failed: ifindex: %d: %s (%d)",
257 *ifindex
, safe_strerror (errno
), errno
);
263 ospf6_recvmsg (struct in6_addr
*src
, struct in6_addr
*dst
,
264 unsigned int *ifindex
, struct iovec
*message
)
267 struct msghdr rmsghdr
;
268 struct cmsghdr
*rcmsgp
;
269 u_char cmsgbuf
[CMSG_SPACE(sizeof (struct in6_pktinfo
))];
270 struct in6_pktinfo
*pktinfo
;
271 struct sockaddr_in6 src_sin6
;
273 rcmsgp
= (struct cmsghdr
*)cmsgbuf
;
274 pktinfo
= (struct in6_pktinfo
*)(CMSG_DATA(rcmsgp
));
275 memset (&src_sin6
, 0, sizeof (struct sockaddr_in6
));
277 /* receive control msg */
278 rcmsgp
->cmsg_level
= IPPROTO_IPV6
;
279 rcmsgp
->cmsg_type
= IPV6_PKTINFO
;
280 rcmsgp
->cmsg_len
= CMSG_LEN (sizeof (struct in6_pktinfo
));
281 /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
283 /* receive msg hdr */
284 memset (&rmsghdr
, 0, sizeof (rmsghdr
));
285 rmsghdr
.msg_iov
= message
;
286 rmsghdr
.msg_iovlen
= iov_count (message
);
287 rmsghdr
.msg_name
= (caddr_t
) &src_sin6
;
288 rmsghdr
.msg_namelen
= sizeof (struct sockaddr_in6
);
289 rmsghdr
.msg_control
= (caddr_t
) cmsgbuf
;
290 rmsghdr
.msg_controllen
= sizeof (cmsgbuf
);
292 retval
= recvmsg (ospf6_sock
, &rmsghdr
, 0);
294 zlog_warn ("recvmsg failed: %s", safe_strerror (errno
));
295 else if (retval
== iov_totallen (message
))
296 zlog_warn ("recvmsg read full buffer size: %d", retval
);
300 memcpy (src
, &src_sin6
.sin6_addr
, sizeof (struct in6_addr
));
302 /* destination address */
304 *ifindex
= pktinfo
->ipi6_ifindex
;
306 memcpy (dst
, &pktinfo
->ipi6_addr
, sizeof (struct in6_addr
));