1/*
2 * Copyright (C) 1999 Yasuhiro Ohara
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
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22#include <zebra.h>
23#include "memory.h"
24#include "log.h"
25#include "sockunion.h"
26
27#include "ospf6d.h"
28#include "ospf6_proto.h"
29
30extern int errno;
31extern struct sockaddr_in6 allspfrouters6;
32extern struct sockaddr_in6 alldrouters6;
33extern int ospf6_sock;
34extern struct thread_master *master;
35
36/* iovec functions */
37void
38iov_clear (struct iovec *iov, size_t iovlen)
39{
40  int i;
41  for (i = 0; i < iovlen; i++)
42    {
43      iov[i].iov_base = NULL;
44      iov[i].iov_len = 0;
45    }
46}
47
48int
49iov_count (struct iovec *iov)
50{
51  int i;
52  for (i = 0; iov[i].iov_base; i++)
53    ;
54  return i;
55}
56
57int
58iov_totallen (struct iovec *iov)
59{
60  int i;
61  int totallen = 0;
62  for (i = 0; iov[i].iov_base; i++)
63    totallen += iov[i].iov_len;
64  return totallen;
65}
66
67void *
68iov_prepend (int mtype, struct iovec *iov, size_t len)
69{
70  int i, iovlen;
71  void *base;
72
73  base = (void *) XMALLOC (mtype, len);
74  if (!base)
75    {
76      zlog_warn ("Network: iov_prepend failed");
77      return NULL;
78    }
79  memset (base, 0, len);
80
81  iovlen = iov_count (iov);
82  for (i = iovlen; i; i--)
83    {
84      iov[i].iov_base = iov[i - 1].iov_base;
85      iov[i].iov_len = iov[i - 1].iov_len;
86    }
87  iov[0].iov_base = (char *)base;
88  iov[0].iov_len = len;
89
90  return base;
91}
92
93void *
94iov_append (int mtype, struct iovec *iov, size_t len)
95{
96  int i;
97  void *base;
98
99  base = (void *)XMALLOC (mtype, len);
100  if (!base)
101    {
102      zlog_warn ("Network: iov_append failed");
103      return NULL;
104    }
105  memset (base, 0, len);
106
107  /* proceed to the end */
108  i = iov_count (iov);
109
110  iov[i].iov_base = (char *)base;
111  iov[i].iov_len = len;
112
113  return base;
114}
115
116void *
117iov_attach_last (struct iovec *iov, void *base, size_t len)
118{
119  int i;
120  i = iov_count (iov);
121  iov[i].iov_base = (char *)base;
122  iov[i].iov_len = len;
123  return base;
124}
125
126void *
127iov_detach_first (struct iovec *iov)
128{
129  int i, iovlen;
130  void *base;
131  size_t len;
132
133  base = iov[0].iov_base;
134  len = iov[0].iov_len;
135  iovlen = iov_count (iov);
136  for (i = 0; i < iovlen; i++)
137    {
138      iov[i].iov_base = iov[i + 1].iov_base;
139      iov[i].iov_len = iov[i + 1].iov_len;
140    }
141  return base;
142}
143
144int
145iov_free (int mtype, struct iovec *iov, u_int begin, u_int end)
146{
147  int i;
148
149  for (i = begin; i < end; i++)
150    {
151      XFREE (mtype, iov[i].iov_base);
152      iov[i].iov_base = NULL;
153      iov[i].iov_len = 0;
154    }
155
156  return 0;
157}
158
159void
160iov_trim_head (int mtype, struct iovec *iov)
161{
162  void *base;
163
164  base = iov_detach_first (iov);
165  XFREE (mtype, base);
166  return;
167}
168
169void
170iov_free_all (int mtype, struct iovec *iov)
171{
172  int i, end = iov_count (iov);
173  for (i = 0; i < end; i++)
174    {
175      XFREE (mtype, iov[i].iov_base);
176      iov[i].iov_base = NULL;
177      iov[i].iov_len = 0;
178    }
179}
180
181void
182iov_copy_all (struct iovec *dst, struct iovec *src, size_t size)
183{
184  int i;
185  for (i = 0; i < size; i++)
186    {
187      dst[i].iov_base = src[i].iov_base;
188      dst[i].iov_len = src[i].iov_len;
189    }
190}
191
192
193/* Make ospf6d's server socket. */
194int
195ospf6_serv_sock ()
196{
197  ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP);
198  if (ospf6_sock < 0)
199    {
200      zlog_warn ("Network: can't create OSPF6 socket.");
201      return -1;
202    }
203  sockopt_reuseaddr (ospf6_sock);
204
205  /* setup global sockaddr_in6, allspf6 & alldr6 for later use */
206  allspfrouters6.sin6_family = AF_INET6;
207  alldrouters6.sin6_family = AF_INET6;
208#ifdef SIN6_LEN
209  allspfrouters6.sin6_len = sizeof (struct sockaddr_in6);
210  alldrouters6.sin6_len = sizeof (struct sockaddr_in6);
211#endif /* SIN6_LEN */
212  inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6.sin6_addr);
213  inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6.sin6_addr);
214
215  return 0;
216}
217
218/* returns 0 if succeed, else returns -1 */
219int
220ospf6_join_allspfrouters (u_int ifindex)
221{
222  struct ipv6_mreq mreq6;
223  int retval;
224
225  assert (ifindex);
226  mreq6.ipv6mr_interface = ifindex;
227  memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr,
228          sizeof (struct in6_addr));
229
230  retval = setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
231                       &mreq6, sizeof (mreq6));
232
233  if (retval < 0)
234    zlog_err ("Network: Join AllSPFRouters on ifindex %d failed: %s",
235               ifindex, strerror (errno));
236#if 0
237  else
238    zlog_info ("Network: Join AllSPFRouters on ifindex %d", ifindex);
239#endif
240
241  return retval;
242}
243
244void
245ospf6_leave_allspfrouters (u_int ifindex)
246{
247  struct ipv6_mreq mreq6;
248
249  assert (ifindex);
250  mreq6.ipv6mr_interface = ifindex;
251  memcpy (&mreq6.ipv6mr_multiaddr, &allspfrouters6.sin6_addr,
252          sizeof (struct in6_addr));
253
254  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
255                  &mreq6, sizeof (mreq6)) < 0)
256    zlog_warn ("Network: Leave AllSPFRouters on ifindex %d Failed: %s",
257               ifindex, strerror (errno));
258  else
259    zlog_info ("Network: Leave AllSPFRouters on ifindex %d", ifindex);
260}
261
262void
263ospf6_join_alldrouters (u_int ifindex)
264{
265  struct ipv6_mreq mreq6;
266
267  assert (ifindex);
268  mreq6.ipv6mr_interface = ifindex;
269  memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr,
270          sizeof (struct in6_addr));
271
272  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
273                  &mreq6, sizeof (mreq6)) < 0)
274    zlog_warn ("Network: Join AllDRouters on ifindex %d Failed: %s",
275               ifindex, strerror (errno));
276  else
277    zlog_info ("Network: Join AllDRouters on ifindex %d", ifindex);
278}
279
280void
281ospf6_leave_alldrouters (u_int ifindex)
282{
283  struct ipv6_mreq mreq6;
284
285  assert (ifindex);
286  mreq6.ipv6mr_interface = ifindex;
287  memcpy (&mreq6.ipv6mr_multiaddr, &alldrouters6.sin6_addr,
288          sizeof (struct in6_addr));
289
290  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
291                  &mreq6, sizeof (mreq6)) < 0)
292    zlog_warn ("Network: Leave AllDRouters on ifindex %d Failed", ifindex);
293  else
294    zlog_info ("Network: Leave AllDRouters on ifindex %d", ifindex);
295}
296
297/* setsockopt ReUseAddr to on */
298void
299ospf6_set_reuseaddr ()
300{
301  u_int on = 0;
302  if (setsockopt (ospf6_sock, SOL_SOCKET, SO_REUSEADDR, &on,
303                  sizeof (u_int)) < 0)
304    zlog_warn ("Network: set SO_REUSEADDR failed: %s", strerror (errno));
305}
306
307/* setsockopt MulticastLoop to off */
308void
309ospf6_reset_mcastloop ()
310{
311  u_int off = 0;
312  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
313                  &off, sizeof (u_int)) < 0)
314    zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s",
315               strerror (errno));
316}
317
318void
319ospf6_set_pktinfo ()
320{
321  u_int on = 1;
322#ifdef IPV6_RECVPKTINFO	/*2292bis-01*/
323  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
324                  &on, sizeof (u_int)) < 0)
325    zlog_warn ("Network: set IPV6_RECVPKTINFO failed: %s", strerror (errno));
326#else /*RFC2292*/
327  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_PKTINFO,
328                  &on, sizeof (u_int)) < 0)
329    zlog_warn ("Network: set IPV6_PKTINFO failed: %s", strerror (errno));
330#endif
331}
332
333void
334ospf6_set_checksum ()
335{
336  int offset = 12;
337#ifndef DISABLE_IPV6_CHECKSUM
338  if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM,
339                  &offset, sizeof (offset)) < 0)
340    zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", strerror (errno));
341#else
342  zlog_warn ("Network: Don't set IPV6_CHECKSUM");
343#endif /* DISABLE_IPV6_CHECKSUM */
344}
345
346void
347ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst,
348               unsigned int *ifindex, struct iovec *message)
349{
350  int retval;
351  struct msghdr smsghdr;
352  struct cmsghdr *scmsgp;
353  u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
354  struct in6_pktinfo *pktinfo;
355  struct sockaddr_in6 dst_sin6;
356
357  assert (dst);
358  assert (*ifindex);
359
360  scmsgp = (struct cmsghdr *)cmsgbuf;
361  pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
362  memset (&dst_sin6, 0, sizeof (struct sockaddr_in6));
363
364  /* source address */
365  pktinfo->ipi6_ifindex = *ifindex;
366  if (src)
367    memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr));
368  else
369    memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr));
370
371  /* destination address */
372  dst_sin6.sin6_family = AF_INET6;
373#ifdef SIN6_LEN
374  dst_sin6.sin6_len = sizeof (struct sockaddr_in6);
375#endif /*SIN6_LEN*/
376  memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr));
377#ifdef HAVE_SIN6_SCOPE_ID
378  dst_sin6.sin6_scope_id = *ifindex;
379#endif
380
381  /* send control msg */
382  scmsgp->cmsg_level = IPPROTO_IPV6;
383  scmsgp->cmsg_type = IPV6_PKTINFO;
384  scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
385  /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */
386
387  /* send msg hdr */
388  smsghdr.msg_iov = message;
389  smsghdr.msg_iovlen = iov_count (message);
390  smsghdr.msg_name = (caddr_t) &dst_sin6;
391  smsghdr.msg_namelen = sizeof (struct sockaddr_in6);
392  smsghdr.msg_control = (caddr_t) cmsgbuf;
393  smsghdr.msg_controllen = sizeof (cmsgbuf);
394
395  retval = sendmsg (ospf6_sock, &smsghdr, 0);
396  if (retval != iov_totallen (message))
397    zlog_warn ("Network: sendmsg (ifindex: %d) failed: %s(%d)",
398               *ifindex, strerror (errno), errno);
399}
400
401void
402ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst,
403               unsigned int *ifindex, struct iovec *message)
404{
405  int retval;
406  struct msghdr rmsghdr;
407  struct cmsghdr *rcmsgp;
408  u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
409  struct in6_pktinfo *pktinfo;
410  struct sockaddr_in6 src_sin6;
411
412  rcmsgp = (struct cmsghdr *)cmsgbuf;
413  pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp));
414  memset (&src_sin6, 0, sizeof (struct sockaddr_in6));
415
416  /* receive control msg */
417  rcmsgp->cmsg_level = IPPROTO_IPV6;
418  rcmsgp->cmsg_type = IPV6_PKTINFO;
419  rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
420  /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
421
422  /* receive msg hdr */
423  rmsghdr.msg_iov = message;
424  rmsghdr.msg_iovlen = iov_count (message);
425  rmsghdr.msg_name = (caddr_t) &src_sin6;
426  rmsghdr.msg_namelen = sizeof (struct sockaddr_in6);
427  rmsghdr.msg_control = (caddr_t) cmsgbuf;
428  rmsghdr.msg_controllen = sizeof (cmsgbuf);
429
430  retval = recvmsg (ospf6_sock, &rmsghdr, 0);
431  if (retval < 0)
432    {
433      zlog_warn ("Network: recvmsg failed: %s", strerror (errno));
434    }
435  else if (retval == iov_totallen (message))
436    {
437      zlog_warn ("Network: possibly buffer shortage: %d received, buffer size: %d",
438                  retval, iov_totallen (message));
439    }
440
441  /* source address */
442  assert (src);
443  memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr));
444
445  /* destination address */
446  if (ifindex)
447    *ifindex = pktinfo->ipi6_ifindex;
448  if (dst)
449    memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr));
450}
451
452void
453ospf6_recvmsg_peek (struct in6_addr *src, struct in6_addr *dst,
454                    unsigned int *ifindex, struct iovec *message)
455{
456  int retval;
457  struct msghdr rmsghdr;
458  struct cmsghdr *rcmsgp;
459  u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))];
460  struct in6_pktinfo *pktinfo;
461  struct sockaddr_in6 src_sin6;
462
463  rcmsgp = (struct cmsghdr *)cmsgbuf;
464  pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp));
465  memset (&src_sin6, 0, sizeof (struct sockaddr_in6));
466
467  /* receive control msg */
468  rcmsgp->cmsg_level = IPPROTO_IPV6;
469  rcmsgp->cmsg_type = IPV6_PKTINFO;
470  rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
471  /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */
472
473  /* receive msg hdr */
474  rmsghdr.msg_iov = message;
475  rmsghdr.msg_iovlen = iov_count (message);
476  rmsghdr.msg_name = (caddr_t) &src_sin6;
477  rmsghdr.msg_namelen = sizeof (struct sockaddr_in6);
478  rmsghdr.msg_control = (caddr_t) cmsgbuf;
479  rmsghdr.msg_controllen = sizeof (cmsgbuf);
480
481  retval = recvmsg (ospf6_sock, &rmsghdr, MSG_PEEK);
482  if (retval != iov_totallen (message))
483    zlog_warn ("Network: recvmsg failed: %s", strerror (errno));
484
485  /* source address */
486  assert (src);
487  memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr));
488
489  /* destination address */
490  if (ifindex)
491    *ifindex = pktinfo->ipi6_ifindex;
492  if (dst)
493    memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr));
494}
495
496