blob: b4f37f6a9c9fa39518983d2257946cdebb915dd5 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
hasso508e53e2004-05-18 18:57:06 +00002 * Copyright (C) 2003 Yasuhiro Ohara
paul718e3742002-12-13 20:15:29 +00003 *
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
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22#include <zebra.h>
hasso508e53e2004-05-18 18:57:06 +000023
paul718e3742002-12-13 20:15:29 +000024#include "log.h"
hasso508e53e2004-05-18 18:57:06 +000025#include "memory.h"
paul718e3742002-12-13 20:15:29 +000026#include "sockunion.h"
pauledd7c242003-06-04 13:59:38 +000027#include "privs.h"
paul718e3742002-12-13 20:15:29 +000028
paul718e3742002-12-13 20:15:29 +000029#include "ospf6_proto.h"
hasso508e53e2004-05-18 18:57:06 +000030#include "ospf6_network.h"
paul718e3742002-12-13 20:15:29 +000031
pauledd7c242003-06-04 13:59:38 +000032extern struct zebra_privs_t ospf6d_privs;
paul718e3742002-12-13 20:15:29 +000033
hasso508e53e2004-05-18 18:57:06 +000034int ospf6_sock;
35struct in6_addr allspfrouters6;
36struct in6_addr alldrouters6;
paul718e3742002-12-13 20:15:29 +000037
38/* setsockopt ReUseAddr to on */
39void
40ospf6_set_reuseaddr ()
41{
42 u_int on = 0;
43 if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on,
44 sizeof (u_int)) < 0)
45 zlog_warn ("Network: set SO_REUSEADDR failed: %s", strerror (errno));
46}
47
48/* setsockopt MulticastLoop to off */
49void
50ospf6_reset_mcastloop ()
51{
52 u_int off = 0;
53 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
54 &off, sizeof (u_int)) < 0)
55 zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s",
56 strerror (errno));
57}
58
59void
60ospf6_set_pktinfo ()
61{
62 u_int on = 1;
63#ifdef IPV6_RECVPKTINFO /*2292bis-01*/
64 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
65 &on, sizeof (u_int)) < 0)
66 zlog_warn ("Network: set IPV6_RECVPKTINFO failed: %s", strerror (errno));
67#else /*RFC2292*/
68 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_PKTINFO,
69 &on, sizeof (u_int)) < 0)
70 zlog_warn ("Network: set IPV6_PKTINFO failed: %s", strerror (errno));
71#endif
72}
73
74void
75ospf6_set_checksum ()
76{
77 int offset = 12;
hasso508e53e2004-05-18 18:57:06 +000078#ifndef DISABLE_IPV6_CHECKSUM
paul718e3742002-12-13 20:15:29 +000079 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM,
80 &offset, sizeof (offset)) < 0)
81 zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", strerror (errno));
82#else
83 zlog_warn ("Network: Don't set IPV6_CHECKSUM");
84#endif /* DISABLE_IPV6_CHECKSUM */
85}
86
hasso508e53e2004-05-18 18:57:06 +000087/* Make ospf6d's server socket. */
88int
89ospf6_serv_sock ()
90{
91 if (ospf6d_privs.change (ZPRIVS_RAISE))
92 zlog_err ("ospf6_serv_sock: could not raise privs");
93
94 ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP);
95 if (ospf6_sock < 0)
96 {
97 zlog_warn ("Network: can't create OSPF6 socket.");
98 if (ospf6d_privs.change (ZPRIVS_LOWER))
99 zlog_err ("ospf_sock_init: could not lower privs");
100 return -1;
101 }
102 if (ospf6d_privs.change (ZPRIVS_LOWER))
103 zlog_err ("ospf_sock_init: could not lower privs");
104
105 /* set socket options */
106#if 1
107 sockopt_reuseaddr (ospf6_sock);
108#else
109 ospf6_set_reuseaddr ();
110#endif /*1*/
111 ospf6_reset_mcastloop ();
112 ospf6_set_pktinfo ();
113 ospf6_set_checksum ();
114
115 /* setup global in6_addr, allspf6 and alldr6 for later use */
116 inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6);
117 inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6);
118
119 return 0;
120}
121
paul718e3742002-12-13 20:15:29 +0000122void
hasso508e53e2004-05-18 18:57:06 +0000123ospf6_join_allspfrouters (u_int ifindex)
124{
125 struct ipv6_mreq mreq6;
126 int retval;
127
128 assert (ifindex);
129 mreq6.ipv6mr_interface = ifindex;
130 memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6,
131 sizeof (struct in6_addr));
132
133 retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
134 &mreq6, sizeof (mreq6));
135
136 if (retval < 0)
137 zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s",
138 ifindex, strerror (errno));
139#if 0
140 else
141 zlog_info ("Network: Join AllSPFRouters on ifindex %d", ifindex);
142#endif
143}
144
145void
146ospf6_leave_allspfrouters (u_int ifindex)
147{
148 struct ipv6_mreq mreq6;
149
150 assert (ifindex);
151 mreq6.ipv6mr_interface = ifindex;
152 memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6,
153 sizeof (struct in6_addr));
154
155 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
156 &mreq6, sizeof (mreq6)) < 0)
157 zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s",
158 ifindex, strerror (errno));
159#if 0
160 else
161 zlog_info ("Network: Leave AllSPFRouters on ifindex %d", ifindex);
162#endif
163}
164
165void
166ospf6_join_alldrouters (u_int ifindex)
167{
168 struct ipv6_mreq mreq6;
169
170 assert (ifindex);
171 mreq6.ipv6mr_interface = ifindex;
172 memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6,
173 sizeof (struct in6_addr));
174
175 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
176 &mreq6, sizeof (mreq6)) < 0)
177 zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s",
178 ifindex, strerror (errno));
179#if 0
180 else
181 zlog_info ("Network: Join AllDRouters on ifindex %d", ifindex);
182#endif
183}
184
185void
186ospf6_leave_alldrouters (u_int ifindex)
187{
188 struct ipv6_mreq mreq6;
189
190 assert (ifindex);
191 mreq6.ipv6mr_interface = ifindex;
192 memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6,
193 sizeof (struct in6_addr));
194
195 if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
196 &mreq6, sizeof (mreq6)) < 0)
197 zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex);
198#if 0
199 else
200 zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex);
201#endif
202}
203
204int
205iov_count (struct iovec *iov)
206{
207 int i;
208 for (i = 0; iov[i].iov_base; i++)
209 ;
210 return i;
211}
212
213int
214iov_totallen (struct iovec *iov)
215{
216 int i;
217 int totallen = 0;
218 for (i = 0; iov[i].iov_base; i++)
219 totallen += iov[i].iov_len;
220 return totallen;
221}
222
223int
paul718e3742002-12-13 20:15:29 +0000224ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst,
225 unsigned int *ifindex, struct iovec *message)
226{
227 int retval;
228 struct msghdr smsghdr;
229 struct cmsghdr *scmsgp;
230 u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
231 struct in6_pktinfo *pktinfo;
232 struct sockaddr_in6 dst_sin6;
233
234 assert (dst);
235 assert (*ifindex);
236
237 scmsgp = (struct cmsghdr *)cmsgbuf;
238 pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
239 memset (&dst_sin6, 0, sizeof (struct sockaddr_in6));
240
241 /* source address */
242 pktinfo->ipi6_ifindex = *ifindex;
243 if (src)
244 memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr));
245 else
246 memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr));
247
248 /* destination address */
249 dst_sin6.sin6_family = AF_INET6;
250#ifdef SIN6_LEN
251 dst_sin6.sin6_len = sizeof (struct sockaddr_in6);
252#endif /*SIN6_LEN*/
253 memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr));
254#ifdef HAVE_SIN6_SCOPE_ID
255 dst_sin6.sin6_scope_id = *ifindex;
256#endif
257
258 /* send control msg */
259 scmsgp->cmsg_level = IPPROTO_IPV6;
260 scmsgp->cmsg_type = IPV6_PKTINFO;
261 scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
262 /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */
263
264 /* send msg hdr */
265 smsghdr.msg_iov = message;
266 smsghdr.msg_iovlen = iov_count (message);
267 smsghdr.msg_name = (caddr_t) &dst_sin6;
268 smsghdr.msg_namelen = sizeof (struct sockaddr_in6);
269 smsghdr.msg_control = (caddr_t) cmsgbuf;
270 smsghdr.msg_controllen = sizeof (cmsgbuf);
271
272 retval = sendmsg (ospf6_sock, &smsghdr, 0);
273 if (retval != iov_totallen (message))
hasso508e53e2004-05-18 18:57:06 +0000274 zlog_warn ("sendmsg failed: ifindex: %d: %s (%d)",
paul718e3742002-12-13 20:15:29 +0000275 *ifindex, strerror (errno), errno);
hasso508e53e2004-05-18 18:57:06 +0000276
277 return retval;
paul718e3742002-12-13 20:15:29 +0000278}
279
hasso508e53e2004-05-18 18:57:06 +0000280int
paul718e3742002-12-13 20:15:29 +0000281ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst,
282 unsigned int *ifindex, struct iovec *message)
283{
284 int retval;
285 struct msghdr rmsghdr;
286 struct cmsghdr *rcmsgp;
287 u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
288 struct in6_pktinfo *pktinfo;
289 struct sockaddr_in6 src_sin6;
290
291 rcmsgp = (struct cmsghdr *)cmsgbuf;
292 pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp));
293 memset (&src_sin6, 0, sizeof (struct sockaddr_in6));
294
295 /* receive control msg */
296 rcmsgp->cmsg_level = IPPROTO_IPV6;
297 rcmsgp->cmsg_type = IPV6_PKTINFO;
298 rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
299 /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
300
301 /* receive msg hdr */
302 rmsghdr.msg_iov = message;
303 rmsghdr.msg_iovlen = iov_count (message);
304 rmsghdr.msg_name = (caddr_t) &src_sin6;
305 rmsghdr.msg_namelen = sizeof (struct sockaddr_in6);
306 rmsghdr.msg_control = (caddr_t) cmsgbuf;
307 rmsghdr.msg_controllen = sizeof (cmsgbuf);
308
309 retval = recvmsg (ospf6_sock, &rmsghdr, 0);
310 if (retval < 0)
hasso508e53e2004-05-18 18:57:06 +0000311 zlog_warn ("recvmsg failed: %s", strerror (errno));
paul718e3742002-12-13 20:15:29 +0000312 else if (retval == iov_totallen (message))
hasso508e53e2004-05-18 18:57:06 +0000313 zlog_warn ("recvmsg read full buffer size: %d", retval);
paul718e3742002-12-13 20:15:29 +0000314
315 /* source address */
316 assert (src);
317 memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr));
318
319 /* destination address */
320 if (ifindex)
321 *ifindex = pktinfo->ipi6_ifindex;
322 if (dst)
323 memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr));
hasso508e53e2004-05-18 18:57:06 +0000324
325 return retval;
paul718e3742002-12-13 20:15:29 +0000326}
327
paul718e3742002-12-13 20:15:29 +0000328