~ubuntu-branches/ubuntu/warty/quagga/warty

« back to all changes in this revision

Viewing changes to ospf6d/ospf6_network.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2004-06-29 09:50:59 UTC
  • Revision ID: james.westby@ubuntu.com-20040629095059-px1m2m108z4qw1mr
Tags: upstream-0.96.5
ImportĀ upstreamĀ versionĀ 0.96.5

Show diffs side-by-side

added added

removed removed

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