OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [bsd_tcpip/] [v2_0/] [src/] [sys/] [netinet6/] [ip6_mroute.c] - Blame information for rev 308

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      src/sys/netinet6/ip6_mroute.c
4
//
5
//==========================================================================
6
//####BSDCOPYRIGHTBEGIN####
7
//
8
// -------------------------------------------
9
//
10
// Portions of this software may have been derived from OpenBSD, 
11
// FreeBSD or other sources, and are covered by the appropriate
12
// copyright disclaimers included herein.
13
//
14
// Portions created by Red Hat are
15
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16
//
17
// -------------------------------------------
18
//
19
//####BSDCOPYRIGHTEND####
20
//==========================================================================
21
 
22
/*      $KAME: ip6_mroute.c,v 1.58 2001/12/18 02:36:31 itojun Exp $     */
23
 
24
/*
25
 * Copyright (C) 1998 WIDE Project.
26
 * All rights reserved.
27
 *
28
 * Redistribution and use in source and binary forms, with or without
29
 * modification, are permitted provided that the following conditions
30
 * are met:
31
 * 1. Redistributions of source code must retain the above copyright
32
 *    notice, this list of conditions and the following disclaimer.
33
 * 2. Redistributions in binary form must reproduce the above copyright
34
 *    notice, this list of conditions and the following disclaimer in the
35
 *    documentation and/or other materials provided with the distribution.
36
 * 3. Neither the name of the project nor the names of its contributors
37
 *    may be used to endorse or promote products derived from this software
38
 *    without specific prior written permission.
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50
 * SUCH DAMAGE.
51
 */
52
 
53
/*      BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp     */
54
 
55
/*
56
 * IP multicast forwarding procedures
57
 *
58
 * Written by David Waitzman, BBN Labs, August 1988.
59
 * Modified by Steve Deering, Stanford, February 1989.
60
 * Modified by Mark J. Steiglitz, Stanford, May, 1991
61
 * Modified by Van Jacobson, LBL, January 1993
62
 * Modified by Ajit Thyagarajan, PARC, August 1993
63
 * Modified by Bill Fenenr, PARC, April 1994
64
 *
65
 * MROUTING Revision: 3.5.1.2 + PIM-SMv2 (pimd) Support
66
 */
67
 
68
/*
69
 * XXX it seems that home address option processing should be reverted
70
 * before calls to socket_send().  see sys/netinet6/dest6.c for details.
71
 */
72
 
73
#include <sys/param.h>
74
#include <sys/malloc.h>
75
#include <sys/mbuf.h>
76
#include <sys/socket.h>
77
#include <sys/socketvar.h>
78
#include <sys/sockio.h>
79
#include <sys/protosw.h>
80
#include <sys/errno.h>
81
#include <sys/time.h>
82
 
83
#include <net/if.h>
84
#include <net/route.h>
85
#include <net/raw_cb.h>
86
 
87
#include <netinet/in.h>
88
#include <netinet/in_var.h>
89
 
90
#include <netinet/ip6.h>
91
#include <netinet6/ip6_var.h>
92
#include <netinet6/ip6_mroute.h>
93
#include <netinet6/pim6.h>
94
#include <netinet6/pim6_var.h>
95
 
96
#define M_HASCL(m) ((m)->m_flags & M_EXT)
97
 
98
static int ip6_mdq __P((struct mbuf *, struct ifnet *, struct mf6c *));
99
static void phyint_send __P((struct ip6_hdr *, struct mif6 *, struct mbuf *));
100
 
101
static int set_pim6 __P((int *));
102
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
103
static int get_pim6 __P((struct mbuf *));
104
#endif
105
static int socket_send __P((struct socket *, struct mbuf *,
106
                            struct sockaddr_in6 *));
107
static int register_send __P((struct ip6_hdr *, struct mif6 *,
108
                              struct mbuf *));
109
 
110
/*
111
 * Globals.  All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
112
 * except for netstat or debugging purposes.
113
 */
114
struct socket  *ip6_mrouter = NULL;
115
int             ip6_mrouter_ver = 0;
116
int             ip6_mrtproto = IPPROTO_PIM;    /* for netstat only */
117
struct mrt6stat mrt6stat;
118
 
119
#define NO_RTE_FOUND    0x1
120
#define RTE_FOUND       0x2
121
 
122
struct mf6c     *mf6ctable[MF6CTBLSIZ];
123
u_char          n6expire[MF6CTBLSIZ];
124
#if (defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)) 
125
struct mif6 mif6table[MAXMIFS];
126
#else
127
static struct mif6 mif6table[MAXMIFS];
128
#endif
129
#ifdef MRT6DEBUG
130
u_int           mrt6debug = 0;     /* debug level        */
131
#define         DEBUG_MFC       0x02
132
#define         DEBUG_FORWARD   0x04
133
#define         DEBUG_EXPIRE    0x08
134
#define         DEBUG_XMIT      0x10
135
#define         DEBUG_REG       0x20
136
#define         DEBUG_PIM       0x40
137
#endif
138
 
139
static void     expire_upcalls __P((void *));
140
#define         EXPIRE_TIMEOUT  (hz / 4)        /* 4x / second */
141
#define         UPCALL_EXPIRE   6               /* number of timeouts */
142
 
143
#ifdef INET
144
#ifdef MROUTING
145
extern struct socket *ip_mrouter;
146
#endif
147
#endif
148
 
149
/*
150
 * 'Interfaces' associated with decapsulator (so we can tell
151
 * packets that went through it from ones that get reflected
152
 * by a broken gateway).  These interfaces are never linked into
153
 * the system ifnet list & no routes point to them.  I.e., packets
154
 * can't be sent this way.  They only exist as a placeholder for
155
 * multicast source verification.
156
 */
157
struct ifnet multicast_register_if;
158
 
159
#define ENCAP_HOPS 64
160
 
161
/*
162
 * Private variables.
163
 */
164
static mifi_t nummifs = 0;
165
static mifi_t reg_mif_num = (mifi_t)-1;
166
 
167
static struct pim6stat pim6stat;
168
static int pim6;
169
 
170
/*
171
 * Hash function for a source, group entry
172
 */
173
#define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
174
                                   (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \
175
                                   (g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \
176
                                   (g).s6_addr32[2] ^ (g).s6_addr32[3])
177
 
178
/*
179
 * Find a route for a given origin IPv6 address and Multicast group address.
180
 * Quality of service parameter to be added in the future!!!
181
 */
182
 
183
#define MF6CFIND(o, g, rt) do { \
184
        struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
185
        rt = NULL; \
186
        mrt6stat.mrt6s_mfc_lookups++; \
187
        while (_rt) { \
188
                if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \
189
                    IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \
190
                    (_rt->mf6c_stall == NULL)) { \
191
                        rt = _rt; \
192
                        break; \
193
                } \
194
                _rt = _rt->mf6c_next; \
195
        } \
196
        if (rt == NULL) { \
197
                mrt6stat.mrt6s_mfc_misses++; \
198
        } \
199
} while (0)
200
 
201
/*
202
 * Macros to compute elapsed time efficiently
203
 * Borrowed from Van Jacobson's scheduling code
204
 */
205
#define TV_DELTA(a, b, delta) do { \
206
            int xxs; \
207
                \
208
            delta = (a).tv_usec - (b).tv_usec; \
209
            if ((xxs = (a).tv_sec - (b).tv_sec)) { \
210
               switch (xxs) { \
211
                      case 2: \
212
                          delta += 1000000; \
213
                              /* fall through */ \
214
                      case 1: \
215
                          delta += 1000000; \
216
                          break; \
217
                      default: \
218
                          delta += (1000000 * xxs); \
219
               } \
220
            } \
221
} while (0)
222
 
223
#define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
224
              (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
225
 
226
#ifdef UPCALL_TIMING
227
#define UPCALL_MAX      50
228
u_long upcall_data[UPCALL_MAX + 1];
229
static void collate();
230
#endif /* UPCALL_TIMING */
231
 
232
static int get_sg_cnt __P((struct sioc_sg_req6 *));
233
static int get_mif6_cnt __P((struct sioc_mif_req6 *));
234
static int ip6_mrouter_init __P((struct socket *, struct mbuf *, int));
235
static int add_m6if __P((struct mif6ctl *));
236
static int del_m6if __P((mifi_t *));
237
static int add_m6fc __P((struct mf6cctl *));
238
static int del_m6fc __P((struct mf6cctl *));
239
 
240
#ifdef __NetBSD__
241
static struct callout expire_upcalls_ch = CALLOUT_INITIALIZER;
242
#elif (defined(__FreeBSD__) && __FreeBSD__ >= 3)
243
static struct callout expire_upcalls_ch;
244
#elif defined(__OpenBSD__)
245
static struct timeout expire_upcalls_ch;
246
#endif
247
 
248
/*
249
 * Handle MRT setsockopt commands to modify the multicast routing tables.
250
 */
251
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
252
int
253
ip6_mrouter_set(so, sopt)
254
        struct socket *so;
255
        struct sockopt *sopt;
256
{
257
        int     error = 0;
258
        struct mbuf *m;
259
 
260
        if (so != ip6_mrouter && sopt->sopt_name != MRT6_INIT)
261
                return (EACCES);
262
 
263
        if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */
264
                return (error);
265
        if ((error = soopt_mcopyin(sopt, m)) != 0) /* XXX */
266
                return (error);
267
 
268
        switch (sopt->sopt_name) {
269
        case MRT6_INIT:
270
#ifdef MRT6_OINIT
271
        case MRT6_OINIT:
272
#endif
273
                error = ip6_mrouter_init(so, m, sopt->sopt_name);
274
                break;
275
        case MRT6_DONE:
276
                error = ip6_mrouter_done();
277
                break;
278
        case MRT6_ADD_MIF:
279
                error = add_m6if(mtod(m, struct mif6ctl *));
280
                break;
281
        case MRT6_DEL_MIF:
282
                error = del_m6if(mtod(m, mifi_t *));
283
                break;
284
        case MRT6_ADD_MFC:
285
                error = add_m6fc(mtod(m, struct mf6cctl *));
286
                break;
287
        case MRT6_DEL_MFC:
288
                error = del_m6fc(mtod(m, struct mf6cctl *));
289
                break;
290
        case MRT6_PIM:
291
                error = set_pim6(mtod(m, int *));
292
                break;
293
        default:
294
                error = EOPNOTSUPP;
295
                break;
296
        }
297
 
298
        (void)m_freem(m);
299
        return(error);
300
}
301
#else
302
int
303
ip6_mrouter_set(cmd, so, m)
304
        int cmd;
305
        struct socket *so;
306
        struct mbuf *m;
307
{
308
        if (cmd != MRT6_INIT && so != ip6_mrouter)
309
                return EACCES;
310
 
311
        switch (cmd) {
312
#ifdef MRT6_OINIT
313
        case MRT6_OINIT:        return ip6_mrouter_init(so, m, cmd);
314
#endif
315
        case MRT6_INIT:         return ip6_mrouter_init(so, m, cmd);
316
        case MRT6_DONE:         return ip6_mrouter_done();
317
        case MRT6_ADD_MIF:      return add_m6if(mtod(m, struct mif6ctl *));
318
        case MRT6_DEL_MIF:      return del_m6if(mtod(m, mifi_t *));
319
        case MRT6_ADD_MFC:      return add_m6fc(mtod(m, struct mf6cctl *));
320
        case MRT6_DEL_MFC:      return del_m6fc(mtod(m, struct mf6cctl *));
321
        case MRT6_PIM:          return set_pim6(mtod(m, int *));
322
        default:                return EOPNOTSUPP;
323
        }
324
}
325
#endif
326
 
327
/*
328
 * Handle MRT getsockopt commands
329
 */
330
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
331
int
332
ip6_mrouter_get(so, sopt)
333
        struct socket *so;
334
        struct sockopt *sopt;
335
{
336
        int error = 0;
337
 
338
        if (so != ip6_mrouter) return EACCES;
339
 
340
        switch (sopt->sopt_name) {
341
                case MRT6_PIM:
342
                        error = sooptcopyout(sopt, &pim6, sizeof(pim6));
343
                        break;
344
        }
345
        return (error);
346
}
347
#else
348
int
349
ip6_mrouter_get(cmd, so, m)
350
        int cmd;
351
        struct socket *so;
352
        struct mbuf **m;
353
{
354
        struct mbuf *mb;
355
 
356
        if (so != ip6_mrouter) return EACCES;
357
 
358
        *m = mb = m_get(M_WAIT, MT_SOOPTS);
359
 
360
        switch (cmd) {
361
        case MRT6_PIM:
362
                return get_pim6(mb);
363
        default:
364
                m_free(mb);
365
                return EOPNOTSUPP;
366
        }
367
}
368
#endif
369
 
370
/*
371
 * Handle ioctl commands to obtain information from the cache
372
 */
373
int
374
mrt6_ioctl(cmd, data)
375
        int cmd;
376
        caddr_t data;
377
{
378
        int error = 0;
379
 
380
        switch (cmd) {
381
        case SIOCGETSGCNT_IN6:
382
                return(get_sg_cnt((struct sioc_sg_req6 *)data));
383
                break;          /* for safety */
384
        case SIOCGETMIFCNT_IN6:
385
                return(get_mif6_cnt((struct sioc_mif_req6 *)data));
386
                break;          /* for safety */
387
        default:
388
                return (EINVAL);
389
                break;
390
        }
391
        return error;
392
}
393
 
394
/*
395
 * returns the packet, byte, rpf-failure count for the source group provided
396
 */
397
static int
398
get_sg_cnt(req)
399
        struct sioc_sg_req6 *req;
400
{
401
        struct mf6c *rt;
402
        int s;
403
 
404
#ifdef __NetBSD__
405
        s = splsoftnet();
406
#else
407
        s = splnet();
408
#endif
409
        MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
410
        splx(s);
411
        if (rt != NULL) {
412
                req->pktcnt = rt->mf6c_pkt_cnt;
413
                req->bytecnt = rt->mf6c_byte_cnt;
414
                req->wrong_if = rt->mf6c_wrong_if;
415
        } else
416
                return(ESRCH);
417
#if 0
418
                req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
419
#endif
420
 
421
        return 0;
422
}
423
 
424
/*
425
 * returns the input and output packet and byte counts on the mif provided
426
 */
427
static int
428
get_mif6_cnt(req)
429
        struct sioc_mif_req6 *req;
430
{
431
        mifi_t mifi = req->mifi;
432
 
433
        if (mifi >= nummifs)
434
                return EINVAL;
435
 
436
        req->icount = mif6table[mifi].m6_pkt_in;
437
        req->ocount = mif6table[mifi].m6_pkt_out;
438
        req->ibytes = mif6table[mifi].m6_bytes_in;
439
        req->obytes = mif6table[mifi].m6_bytes_out;
440
 
441
        return 0;
442
}
443
 
444
#if !(defined(__FreeBSD__) && __FreeBSD__ >=3)
445
/*
446
 * Get PIM processiong global
447
 */
448
static int
449
get_pim6(m)
450
        struct mbuf *m;
451
{
452
        int *i;
453
 
454
        i = mtod(m, int *);
455
 
456
        *i = pim6;
457
 
458
        return 0;
459
}
460
#endif
461
 
462
static int
463
set_pim6(i)
464
        int *i;
465
{
466
        if ((*i != 1) && (*i != 0))
467
                return EINVAL;
468
 
469
        pim6 = *i;
470
 
471
        return 0;
472
}
473
 
474
/*
475
 * Enable multicast routing
476
 */
477
static int
478
ip6_mrouter_init(so, m, cmd)
479
        struct socket *so;
480
        struct mbuf *m;
481
        int cmd;
482
{
483
        int *v;
484
 
485
#ifdef MRT6DEBUG
486
        if (mrt6debug)
487
                log(LOG_DEBUG,
488
                    "ip6_mrouter_init: so_type = %d, pr_protocol = %d\n",
489
                    so->so_type, so->so_proto->pr_protocol);
490
#endif
491
 
492
        if (so->so_type != SOCK_RAW ||
493
            so->so_proto->pr_protocol != IPPROTO_ICMPV6)
494
                return EOPNOTSUPP;
495
 
496
        if (!m || (m->m_len != sizeof(int *)))
497
                return ENOPROTOOPT;
498
 
499
        v = mtod(m, int *);
500
        if (*v != 1)
501
                return ENOPROTOOPT;
502
 
503
        if (ip6_mrouter != NULL) return EADDRINUSE;
504
 
505
        ip6_mrouter = so;
506
        ip6_mrouter_ver = cmd;
507
 
508
        bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
509
        bzero((caddr_t)n6expire, sizeof(n6expire));
510
 
511
        pim6 = 0;/* used for stubbing out/in pim stuff */
512
 
513
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
514
        callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
515
            expire_upcalls, NULL);
516
#elif defined(__OpenBSD__)
517
        timeout_set(&expire_upcalls_ch, expire_upcalls, NULL);
518
        timeout_add(&expire_upcalls_ch, EXPIRE_TIMEOUT);
519
#else
520
        timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
521
#endif
522
 
523
#ifdef MRT6DEBUG
524
        if (mrt6debug)
525
                log(LOG_DEBUG, "ip6_mrouter_init\n");
526
#endif
527
 
528
        return 0;
529
}
530
 
531
/*
532
 * Disable multicast routing
533
 */
534
int
535
ip6_mrouter_done()
536
{
537
        mifi_t mifi;
538
        int i;
539
        struct ifnet *ifp;
540
        struct in6_ifreq ifr;
541
        struct mf6c *rt;
542
        struct rtdetq *rte;
543
        int s;
544
 
545
#ifdef __NetBSD__
546
        s = splsoftnet();
547
#else
548
        s = splnet();
549
#endif
550
 
551
        /*
552
         * For each phyint in use, disable promiscuous reception of all IPv6
553
         * multicasts.
554
         */
555
#ifdef INET
556
#ifdef MROUTING
557
        /*
558
         * If there is still IPv4 multicast routing daemon,
559
         * we remain interfaces to receive all muliticasted packets.
560
         * XXX: there may be an interface in which the IPv4 multicast
561
         * daemon is not interested...
562
         */
563
        if (!ip_mrouter)
564
#endif
565
#endif
566
        {
567
                for (mifi = 0; mifi < nummifs; mifi++) {
568
                        if (mif6table[mifi].m6_ifp &&
569
                            !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
570
                                ifr.ifr_addr.sin6_family = AF_INET6;
571
                                ifr.ifr_addr.sin6_addr= in6addr_any;
572
                                ifp = mif6table[mifi].m6_ifp;
573
                                (*ifp->if_ioctl)(ifp, SIOCDELMULTI,
574
                                                 (caddr_t)&ifr);
575
                        }
576
                }
577
        }
578
#ifdef notyet
579
        bzero((caddr_t)qtable, sizeof(qtable));
580
        bzero((caddr_t)tbftable, sizeof(tbftable));
581
#endif
582
        bzero((caddr_t)mif6table, sizeof(mif6table));
583
        nummifs = 0;
584
 
585
        pim6 = 0; /* used to stub out/in pim specific code */
586
 
587
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
588
        callout_stop(&expire_upcalls_ch);
589
#elif defined(__OpenBSD__)
590
        timeout_del(&expire_upcalls_ch);
591
#else
592
        untimeout(expire_upcalls, (caddr_t)NULL);
593
#endif
594
 
595
        /*
596
         * Free all multicast forwarding cache entries.
597
         */
598
        for (i = 0; i < MF6CTBLSIZ; i++) {
599
                rt = mf6ctable[i];
600
                while (rt) {
601
                        struct mf6c *frt;
602
 
603
                        for (rte = rt->mf6c_stall; rte != NULL; ) {
604
                                struct rtdetq *n = rte->next;
605
 
606
                                m_free(rte->m);
607
                                free(rte, M_MRTABLE);
608
                                rte = n;
609
                        }
610
                        frt = rt;
611
                        rt = rt->mf6c_next;
612
                        free(frt, M_MRTABLE);
613
                }
614
        }
615
 
616
        bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
617
 
618
        /*
619
         * Reset de-encapsulation cache
620
         */
621
        reg_mif_num = -1;
622
 
623
        ip6_mrouter = NULL;
624
        ip6_mrouter_ver = 0;
625
 
626
        splx(s);
627
 
628
#ifdef MRT6DEBUG
629
        if (mrt6debug)
630
                log(LOG_DEBUG, "ip6_mrouter_done\n");
631
#endif
632
 
633
        return 0;
634
}
635
 
636
static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
637
 
638
/*
639
 * Add a mif to the mif table
640
 */
641
static int
642
add_m6if(mifcp)
643
        struct mif6ctl *mifcp;
644
{
645
        struct mif6 *mifp;
646
        struct ifnet *ifp;
647
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
648
        struct in6_ifreq ifr;
649
#endif
650
        int error, s;
651
#ifdef notyet
652
        struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi;
653
#endif
654
 
655
        if (mifcp->mif6c_mifi >= MAXMIFS)
656
                return EINVAL;
657
        mifp = mif6table + mifcp->mif6c_mifi;
658
        if (mifp->m6_ifp)
659
                return EADDRINUSE; /* XXX: is it appropriate? */
660
        if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > if_index)
661
                return ENXIO;
662
        /*
663
         * XXX: some OSes can remove ifp and clear ifindex2ifnet[id]
664
         * even for id between 0 and if_index.
665
         */
666
#if defined(__FreeBSD__) && __FreeBSD__ >= 5
667
        ifp = ifnet_byindex(mifcp->mif6c_pifi);
668
#else
669
        ifp = ifindex2ifnet[mifcp->mif6c_pifi];
670
#endif
671
        if (ifp == NULL)
672
                return ENXIO;
673
 
674
        if (mifcp->mif6c_flags & MIFF_REGISTER) {
675
                if (reg_mif_num == (mifi_t)-1) {
676
#if defined(__NetBSD__) || defined(__OpenBSD__)
677
                        strcpy(multicast_register_if.if_xname,
678
                               "register_mif"); /* XXX */
679
#else
680
                        multicast_register_if.if_name = "register_mif";
681
#endif
682
                        multicast_register_if.if_flags |= IFF_LOOPBACK;
683
                        multicast_register_if.if_index = mifcp->mif6c_mifi;
684
                        reg_mif_num = mifcp->mif6c_mifi;
685
                }
686
 
687
                ifp = &multicast_register_if;
688
 
689
        } /* if REGISTER */
690
        else {
691
                /* Make sure the interface supports multicast */
692
                if ((ifp->if_flags & IFF_MULTICAST) == 0)
693
                        return EOPNOTSUPP;
694
 
695
#ifdef __NetBSD__
696
                s = splsoftnet();
697
#else
698
                s = splnet();
699
#endif
700
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
701
                error = if_allmulti(ifp, 1);
702
#else
703
                /*
704
                 * Enable promiscuous reception of all IPv6 multicasts
705
                 * from the interface.
706
                 */
707
                ifr.ifr_addr.sin6_family = AF_INET6;
708
                ifr.ifr_addr.sin6_addr = in6addr_any;
709
                error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
710
#endif
711
                splx(s);
712
                if (error)
713
                        return error;
714
        }
715
 
716
#ifdef __NetBSD__
717
        s = splsoftnet();
718
#else
719
        s = splnet();
720
#endif
721
        mifp->m6_flags     = mifcp->mif6c_flags;
722
        mifp->m6_ifp       = ifp;
723
#ifdef notyet
724
        /* scaling up here allows division by 1024 in critical code */
725
        mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
726
#endif
727
        /* initialize per mif pkt counters */
728
        mifp->m6_pkt_in    = 0;
729
        mifp->m6_pkt_out   = 0;
730
        mifp->m6_bytes_in  = 0;
731
        mifp->m6_bytes_out = 0;
732
        splx(s);
733
 
734
        /* Adjust nummifs up if the mifi is higher than nummifs */
735
        if (nummifs <= mifcp->mif6c_mifi)
736
                nummifs = mifcp->mif6c_mifi + 1;
737
 
738
#ifdef MRT6DEBUG
739
        if (mrt6debug)
740
                log(LOG_DEBUG,
741
                    "add_mif #%d, phyint %s%d\n",
742
                    mifcp->mif6c_mifi,
743
                    ifp->if_name, ifp->if_unit);
744
#endif
745
 
746
        return 0;
747
}
748
 
749
/*
750
 * Delete a mif from the mif table
751
 */
752
static int
753
del_m6if(mifip)
754
        mifi_t *mifip;
755
{
756
        struct mif6 *mifp = mif6table + *mifip;
757
        mifi_t mifi;
758
        struct ifnet *ifp;
759
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
760
        struct in6_ifreq ifr;
761
#endif
762
        int s;
763
 
764
        if (*mifip >= nummifs)
765
                return EINVAL;
766
        if (mifp->m6_ifp == NULL)
767
                return EINVAL;
768
 
769
#ifdef __NetBSD__
770
        s = splsoftnet();
771
#else
772
        s = splnet();
773
#endif
774
 
775
        if (!(mifp->m6_flags & MIFF_REGISTER)) {
776
                /*
777
                 * XXX: what if there is yet IPv4 multicast daemon
778
                 *      using the interface?
779
                 */
780
                ifp = mifp->m6_ifp;
781
 
782
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
783
                if_allmulti(ifp, 0);
784
#else
785
                ifr.ifr_addr.sin6_family = AF_INET6;
786
                ifr.ifr_addr.sin6_addr = in6addr_any;
787
                (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
788
#endif
789
        }
790
 
791
#ifdef notyet
792
        bzero((caddr_t)qtable[*mifip], sizeof(qtable[*mifip]));
793
        bzero((caddr_t)mifp->m6_tbf, sizeof(*(mifp->m6_tbf)));
794
#endif
795
        bzero((caddr_t)mifp, sizeof (*mifp));
796
 
797
        /* Adjust nummifs down */
798
        for (mifi = nummifs; mifi > 0; mifi--)
799
                if (mif6table[mifi - 1].m6_ifp)
800
                        break;
801
        nummifs = mifi;
802
 
803
        splx(s);
804
 
805
#ifdef MRT6DEBUG
806
        if (mrt6debug)
807
                log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs);
808
#endif
809
 
810
        return 0;
811
}
812
 
813
/*
814
 * Add an mfc entry
815
 */
816
static int
817
add_m6fc(mfccp)
818
        struct mf6cctl *mfccp;
819
{
820
        struct mf6c *rt;
821
        u_long hash;
822
        struct rtdetq *rte;
823
        u_short nstl;
824
        int s;
825
 
826
        MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
827
                 mfccp->mf6cc_mcastgrp.sin6_addr, rt);
828
 
829
        /* If an entry already exists, just update the fields */
830
        if (rt) {
831
#ifdef MRT6DEBUG
832
                if (mrt6debug & DEBUG_MFC)
833
                        log(LOG_DEBUG,"add_m6fc update o %s g %s p %x\n",
834
                            ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
835
                            ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
836
                            mfccp->mf6cc_parent);
837
#endif
838
 
839
#ifdef __NetBSD__
840
                s = splsoftnet();
841
#else
842
                s = splnet();
843
#endif
844
                rt->mf6c_parent = mfccp->mf6cc_parent;
845
                rt->mf6c_ifset = mfccp->mf6cc_ifset;
846
                splx(s);
847
                return 0;
848
        }
849
 
850
        /*
851
         * Find the entry for which the upcall was made and update
852
         */
853
#ifdef __NetBSD__
854
        s = splsoftnet();
855
#else
856
        s = splnet();
857
#endif
858
        hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
859
                        mfccp->mf6cc_mcastgrp.sin6_addr);
860
        for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
861
                if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
862
                                       &mfccp->mf6cc_origin.sin6_addr) &&
863
                    IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
864
                                       &mfccp->mf6cc_mcastgrp.sin6_addr) &&
865
                    (rt->mf6c_stall != NULL)) {
866
 
867
                        if (nstl++)
868
                                log(LOG_ERR,
869
                                    "add_m6fc: %s o %s g %s p %x dbx %p\n",
870
                                    "multiple kernel entries",
871
                                    ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
872
                                    ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
873
                                    mfccp->mf6cc_parent, rt->mf6c_stall);
874
 
875
#ifdef MRT6DEBUG
876
                        if (mrt6debug & DEBUG_MFC)
877
                                log(LOG_DEBUG,
878
                                    "add_m6fc o %s g %s p %x dbg %x\n",
879
                                    ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
880
                                    ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
881
                                    mfccp->mf6cc_parent, rt->mf6c_stall);
882
#endif
883
 
884
                        rt->mf6c_origin     = mfccp->mf6cc_origin;
885
                        rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
886
                        rt->mf6c_parent     = mfccp->mf6cc_parent;
887
                        rt->mf6c_ifset      = mfccp->mf6cc_ifset;
888
                        /* initialize pkt counters per src-grp */
889
                        rt->mf6c_pkt_cnt    = 0;
890
                        rt->mf6c_byte_cnt   = 0;
891
                        rt->mf6c_wrong_if   = 0;
892
 
893
                        rt->mf6c_expire = 0;     /* Don't clean this guy up */
894
                        n6expire[hash]--;
895
 
896
                        /* free packets Qed at the end of this entry */
897
                        for (rte = rt->mf6c_stall; rte != NULL; ) {
898
                                struct rtdetq *n = rte->next;
899
                                ip6_mdq(rte->m, rte->ifp, rt);
900
                                m_freem(rte->m);
901
#ifdef UPCALL_TIMING
902
                                collate(&(rte->t));
903
#endif /* UPCALL_TIMING */
904
                                free(rte, M_MRTABLE);
905
                                rte = n;
906
                        }
907
                        rt->mf6c_stall = NULL;
908
                }
909
        }
910
 
911
        /*
912
         * It is possible that an entry is being inserted without an upcall
913
         */
914
        if (nstl == 0) {
915
#ifdef MRT6DEBUG
916
                if (mrt6debug & DEBUG_MFC)
917
                        log(LOG_DEBUG,
918
                            "add_m6fc no upcall h %d o %s g %s p %x\n",
919
                            hash,
920
                            ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
921
                            ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
922
                            mfccp->mf6cc_parent);
923
#endif
924
 
925
                for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
926
 
927
                        if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
928
                                               &mfccp->mf6cc_origin.sin6_addr)&&
929
                            IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
930
                                               &mfccp->mf6cc_mcastgrp.sin6_addr)) {
931
 
932
                                rt->mf6c_origin     = mfccp->mf6cc_origin;
933
                                rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
934
                                rt->mf6c_parent     = mfccp->mf6cc_parent;
935
                                rt->mf6c_ifset      = mfccp->mf6cc_ifset;
936
                                /* initialize pkt counters per src-grp */
937
                                rt->mf6c_pkt_cnt    = 0;
938
                                rt->mf6c_byte_cnt   = 0;
939
                                rt->mf6c_wrong_if   = 0;
940
 
941
                                if (rt->mf6c_expire)
942
                                        n6expire[hash]--;
943
                                rt->mf6c_expire    = 0;
944
                        }
945
                }
946
                if (rt == NULL) {
947
                        /* no upcall, so make a new entry */
948
                        rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
949
                                                  M_NOWAIT);
950
                        if (rt == NULL) {
951
                                splx(s);
952
                                return ENOBUFS;
953
                        }
954
 
955
                        /* insert new entry at head of hash chain */
956
                        rt->mf6c_origin     = mfccp->mf6cc_origin;
957
                        rt->mf6c_mcastgrp   = mfccp->mf6cc_mcastgrp;
958
                        rt->mf6c_parent     = mfccp->mf6cc_parent;
959
                        rt->mf6c_ifset      = mfccp->mf6cc_ifset;
960
                        /* initialize pkt counters per src-grp */
961
                        rt->mf6c_pkt_cnt    = 0;
962
                        rt->mf6c_byte_cnt   = 0;
963
                        rt->mf6c_wrong_if   = 0;
964
                        rt->mf6c_expire     = 0;
965
                        rt->mf6c_stall = NULL;
966
 
967
                        /* link into table */
968
                        rt->mf6c_next  = mf6ctable[hash];
969
                        mf6ctable[hash] = rt;
970
                }
971
        }
972
        splx(s);
973
        return 0;
974
}
975
 
976
#ifdef UPCALL_TIMING
977
/*
978
 * collect delay statistics on the upcalls
979
 */
980
static void
981
collate(t)
982
        struct timeval *t;
983
{
984
        u_long d;
985
        struct timeval tp;
986
        u_long delta;
987
 
988
        GET_TIME(tp);
989
 
990
        if (TV_LT(*t, tp))
991
        {
992
                TV_DELTA(tp, *t, delta);
993
 
994
                d = delta >> 10;
995
                if (d > UPCALL_MAX)
996
                        d = UPCALL_MAX;
997
 
998
                ++upcall_data[d];
999
        }
1000
}
1001
#endif /* UPCALL_TIMING */
1002
 
1003
/*
1004
 * Delete an mfc entry
1005
 */
1006
static int
1007
del_m6fc(mfccp)
1008
        struct mf6cctl *mfccp;
1009
{
1010
        struct sockaddr_in6     origin;
1011
        struct sockaddr_in6     mcastgrp;
1012
        struct mf6c             *rt;
1013
        struct mf6c             **nptr;
1014
        u_long          hash;
1015
        int s;
1016
 
1017
        origin = mfccp->mf6cc_origin;
1018
        mcastgrp = mfccp->mf6cc_mcastgrp;
1019
        hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr);
1020
 
1021
#ifdef MRT6DEBUG
1022
        if (mrt6debug & DEBUG_MFC)
1023
                log(LOG_DEBUG,"del_m6fc orig %s mcastgrp %s\n",
1024
                    ip6_sprintf(&origin.sin6_addr),
1025
                    ip6_sprintf(&mcastgrp.sin6_addr));
1026
#endif
1027
 
1028
#ifdef __NetBSD__
1029
        s = splsoftnet();
1030
#else
1031
        s = splnet();
1032
#endif
1033
 
1034
        nptr = &mf6ctable[hash];
1035
        while ((rt = *nptr) != NULL) {
1036
                if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr,
1037
                                       &rt->mf6c_origin.sin6_addr) &&
1038
                    IN6_ARE_ADDR_EQUAL(&mcastgrp.sin6_addr,
1039
                                       &rt->mf6c_mcastgrp.sin6_addr) &&
1040
                    rt->mf6c_stall == NULL)
1041
                        break;
1042
 
1043
                nptr = &rt->mf6c_next;
1044
        }
1045
        if (rt == NULL) {
1046
                splx(s);
1047
                return EADDRNOTAVAIL;
1048
        }
1049
 
1050
        *nptr = rt->mf6c_next;
1051
        free(rt, M_MRTABLE);
1052
 
1053
        splx(s);
1054
 
1055
        return 0;
1056
}
1057
 
1058
static int
1059
socket_send(s, mm, src)
1060
        struct socket *s;
1061
        struct mbuf *mm;
1062
        struct sockaddr_in6 *src;
1063
{
1064
        if (s) {
1065
                if (sbappendaddr(&s->so_rcv,
1066
                                 (struct sockaddr *)src,
1067
                                 mm, (struct mbuf *)0) != 0) {
1068
                        sorwakeup(s);
1069
                        return 0;
1070
                }
1071
        }
1072
        m_freem(mm);
1073
        return -1;
1074
}
1075
 
1076
/*
1077
 * IPv6 multicast forwarding function. This function assumes that the packet
1078
 * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
1079
 * pointed to by "ifp", and the packet is to be relayed to other networks
1080
 * that have members of the packet's destination IPv6 multicast group.
1081
 *
1082
 * The packet is returned unscathed to the caller, unless it is
1083
 * erroneous, in which case a non-zero return value tells the caller to
1084
 * discard it.
1085
 */
1086
 
1087
int
1088
ip6_mforward(ip6, ifp, m)
1089
        struct ip6_hdr *ip6;
1090
        struct ifnet *ifp;
1091
        struct mbuf *m;
1092
{
1093
        struct mf6c *rt;
1094
        struct mif6 *mifp;
1095
        struct mbuf *mm;
1096
        int s;
1097
        mifi_t mifi;
1098
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
1099
        long time_second = time.tv_sec;
1100
#endif
1101
 
1102
#ifdef MRT6DEBUG
1103
        if (mrt6debug & DEBUG_FORWARD)
1104
                log(LOG_DEBUG, "ip6_mforward: src %s, dst %s, ifindex %d\n",
1105
                    ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst),
1106
                    ifp->if_index);
1107
#endif
1108
 
1109
        /*
1110
         * Don't forward a packet with Hop limit of zero or one,
1111
         * or a packet destined to a local-only group.
1112
         */
1113
        if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
1114
            IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
1115
                return 0;
1116
        ip6->ip6_hlim--;
1117
 
1118
        /*
1119
         * Source address check: do not forward packets with unspecified
1120
         * source. It was discussed in July 2000, on ipngwg mailing list.
1121
         * This is rather more serious than unicast cases, because some
1122
         * MLD packets can be sent with the unspecified source address
1123
         * (although such packets must normally set 1 to the hop limit field).
1124
         */
1125
        if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1126
                ip6stat.ip6s_cantforward++;
1127
                if (ip6_log_time + ip6_log_interval < time_second) {
1128
                        ip6_log_time = time_second;
1129
                        log(LOG_DEBUG,
1130
                            "cannot forward "
1131
                            "from %s to %s nxt %d received on %s\n",
1132
                            ip6_sprintf(&ip6->ip6_src),
1133
                            ip6_sprintf(&ip6->ip6_dst),
1134
                            ip6->ip6_nxt,
1135
                            m->m_pkthdr.rcvif ?
1136
                            if_name(m->m_pkthdr.rcvif) : "?");
1137
                }
1138
                return 0;
1139
        }
1140
 
1141
        /*
1142
         * Determine forwarding mifs from the forwarding cache table
1143
         */
1144
#ifdef __NetBSD__
1145
        s = splsoftnet();
1146
#else
1147
        s = splnet();
1148
#endif
1149
        MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
1150
 
1151
        /* Entry exists, so forward if necessary */
1152
        if (rt) {
1153
                splx(s);
1154
                return (ip6_mdq(m, ifp, rt));
1155
        } else {
1156
                /*
1157
                 * If we don't have a route for packet's origin,
1158
                 * Make a copy of the packet &
1159
                 * send message to routing daemon
1160
                 */
1161
 
1162
                struct mbuf *mb0;
1163
                struct rtdetq *rte;
1164
                u_long hash;
1165
/*              int i, npkts;*/
1166
#ifdef UPCALL_TIMING
1167
                struct timeval tp;
1168
 
1169
                GET_TIME(tp);
1170
#endif /* UPCALL_TIMING */
1171
 
1172
                mrt6stat.mrt6s_no_route++;
1173
#ifdef MRT6DEBUG
1174
                if (mrt6debug & (DEBUG_FORWARD | DEBUG_MFC))
1175
                        log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n",
1176
                            ip6_sprintf(&ip6->ip6_src),
1177
                            ip6_sprintf(&ip6->ip6_dst));
1178
#endif
1179
 
1180
                /*
1181
                 * Allocate mbufs early so that we don't do extra work if we
1182
                 * are just going to fail anyway.
1183
                 */
1184
                rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE,
1185
                                              M_NOWAIT);
1186
                if (rte == NULL) {
1187
                        splx(s);
1188
                        return ENOBUFS;
1189
                }
1190
                mb0 = m_copy(m, 0, M_COPYALL);
1191
                /*
1192
                 * Pullup packet header if needed before storing it,
1193
                 * as other references may modify it in the meantime.
1194
                 */
1195
                if (mb0 &&
1196
                    (M_HASCL(mb0) || mb0->m_len < sizeof(struct ip6_hdr)))
1197
                        mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
1198
                if (mb0 == NULL) {
1199
                        free(rte, M_MRTABLE);
1200
                        splx(s);
1201
                        return ENOBUFS;
1202
                }
1203
 
1204
                /* is there an upcall waiting for this packet? */
1205
                hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
1206
                for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
1207
                        if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,
1208
                                               &rt->mf6c_origin.sin6_addr) &&
1209
                            IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
1210
                                               &rt->mf6c_mcastgrp.sin6_addr) &&
1211
                            (rt->mf6c_stall != NULL))
1212
                                break;
1213
                }
1214
 
1215
                if (rt == NULL) {
1216
                        struct mrt6msg *im;
1217
#ifdef MRT6_OINIT
1218
                        struct omrt6msg *oim;
1219
#endif
1220
 
1221
                        /* no upcall, so make a new entry */
1222
                        rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
1223
                                                  M_NOWAIT);
1224
                        if (rt == NULL) {
1225
                                free(rte, M_MRTABLE);
1226
                                m_freem(mb0);
1227
                                splx(s);
1228
                                return ENOBUFS;
1229
                        }
1230
                        /*
1231
                         * Make a copy of the header to send to the user
1232
                         * level process
1233
                         */
1234
                        mm = m_copy(mb0, 0, sizeof(struct ip6_hdr));
1235
 
1236
                        if (mm == NULL) {
1237
                                free(rte, M_MRTABLE);
1238
                                m_freem(mb0);
1239
                                free(rt, M_MRTABLE);
1240
                                splx(s);
1241
                                return ENOBUFS;
1242
                        }
1243
 
1244
                        /*
1245
                         * Send message to routing daemon
1246
                         */
1247
                        sin6.sin6_addr = ip6->ip6_src;
1248
 
1249
                        im = NULL;
1250
#ifdef MRT6_OINIT
1251
                        oim = NULL;
1252
#endif
1253
                        switch (ip6_mrouter_ver) {
1254
#ifdef MRT6_OINIT
1255
                        case MRT6_OINIT:
1256
                                oim = mtod(mm, struct omrt6msg *);
1257
                                oim->im6_msgtype = MRT6MSG_NOCACHE;
1258
                                oim->im6_mbz = 0;
1259
                                break;
1260
#endif
1261
                        case MRT6_INIT:
1262
                                im = mtod(mm, struct mrt6msg *);
1263
                                im->im6_msgtype = MRT6MSG_NOCACHE;
1264
                                im->im6_mbz = 0;
1265
                                break;
1266
                        default:
1267
                                free(rte, M_MRTABLE);
1268
                                m_freem(mb0);
1269
                                free(rt, M_MRTABLE);
1270
                                splx(s);
1271
                                return EINVAL;
1272
                        }
1273
 
1274
#ifdef MRT6DEBUG
1275
                        if (mrt6debug & DEBUG_FORWARD)
1276
                                log(LOG_DEBUG,
1277
                                    "getting the iif info in the kernel\n");
1278
#endif
1279
 
1280
                        for (mifp = mif6table, mifi = 0;
1281
                             mifi < nummifs && mifp->m6_ifp != ifp;
1282
                             mifp++, mifi++)
1283
                                ;
1284
 
1285
                        switch (ip6_mrouter_ver) {
1286
#ifdef MRT6_OINIT
1287
                        case MRT6_OINIT:
1288
                                oim->im6_mif = mifi;
1289
                                break;
1290
#endif
1291
                        case MRT6_INIT:
1292
                                im->im6_mif = mifi;
1293
                                break;
1294
                        }
1295
 
1296
                        if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1297
                                log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
1298
                                    "socket queue full\n");
1299
                                mrt6stat.mrt6s_upq_sockfull++;
1300
                                free(rte, M_MRTABLE);
1301
                                m_freem(mb0);
1302
                                free(rt, M_MRTABLE);
1303
                                splx(s);
1304
                                return ENOBUFS;
1305
                        }
1306
 
1307
                        mrt6stat.mrt6s_upcalls++;
1308
 
1309
                        /* insert new entry at head of hash chain */
1310
                        bzero(rt, sizeof(*rt));
1311
                        rt->mf6c_origin.sin6_family = AF_INET6;
1312
                        rt->mf6c_origin.sin6_len = sizeof(struct sockaddr_in6);
1313
                        rt->mf6c_origin.sin6_addr = ip6->ip6_src;
1314
                        rt->mf6c_mcastgrp.sin6_family = AF_INET6;
1315
                        rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);
1316
                        rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst;
1317
                        rt->mf6c_expire = UPCALL_EXPIRE;
1318
                        n6expire[hash]++;
1319
                        rt->mf6c_parent = MF6C_INCOMPLETE_PARENT;
1320
 
1321
                        /* link into table */
1322
                        rt->mf6c_next  = mf6ctable[hash];
1323
                        mf6ctable[hash] = rt;
1324
                        /* Add this entry to the end of the queue */
1325
                        rt->mf6c_stall = rte;
1326
                } else {
1327
                        /* determine if q has overflowed */
1328
                        struct rtdetq **p;
1329
                        int npkts = 0;
1330
 
1331
                        for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
1332
                                if (++npkts > MAX_UPQ6) {
1333
                                        mrt6stat.mrt6s_upq_ovflw++;
1334
                                        free(rte, M_MRTABLE);
1335
                                        m_freem(mb0);
1336
                                        splx(s);
1337
                                        return 0;
1338
                                }
1339
 
1340
                        /* Add this entry to the end of the queue */
1341
                        *p = rte;
1342
                }
1343
 
1344
                rte->next = NULL;
1345
                rte->m = mb0;
1346
                rte->ifp = ifp;
1347
#ifdef UPCALL_TIMING
1348
                rte->t = tp;
1349
#endif /* UPCALL_TIMING */
1350
 
1351
                splx(s);
1352
 
1353
                return 0;
1354
        }
1355
}
1356
 
1357
/*
1358
 * Clean up cache entries if upcalls are not serviced
1359
 * Call from the Slow Timeout mechanism, every half second.
1360
 */
1361
static void
1362
expire_upcalls(unused)
1363
        void *unused;
1364
{
1365
        struct rtdetq *rte;
1366
        struct mf6c *mfc, **nptr;
1367
        int i;
1368
        int s;
1369
 
1370
#ifdef __NetBSD__
1371
        s = splsoftnet();
1372
#else
1373
        s = splnet();
1374
#endif
1375
        for (i = 0; i < MF6CTBLSIZ; i++) {
1376
                if (n6expire[i] == 0)
1377
                        continue;
1378
                nptr = &mf6ctable[i];
1379
                while ((mfc = *nptr) != NULL) {
1380
                        rte = mfc->mf6c_stall;
1381
                        /*
1382
                         * Skip real cache entries
1383
                         * Make sure it wasn't marked to not expire (shouldn't happen)
1384
                         * If it expires now
1385
                         */
1386
                        if (rte != NULL &&
1387
                            mfc->mf6c_expire != 0 &&
1388
                            --mfc->mf6c_expire == 0) {
1389
#ifdef MRT6DEBUG
1390
                                if (mrt6debug & DEBUG_EXPIRE)
1391
                                        log(LOG_DEBUG, "expire_upcalls: expiring (%s %s)\n",
1392
                                            ip6_sprintf(&mfc->mf6c_origin.sin6_addr),
1393
                                            ip6_sprintf(&mfc->mf6c_mcastgrp.sin6_addr));
1394
#endif
1395
                                /*
1396
                                 * drop all the packets
1397
                                 * free the mbuf with the pkt, if, timing info
1398
                                 */
1399
                                do {
1400
                                        struct rtdetq *n = rte->next;
1401
                                        m_freem(rte->m);
1402
                                        free(rte, M_MRTABLE);
1403
                                        rte = n;
1404
                                } while (rte != NULL);
1405
                                mrt6stat.mrt6s_cache_cleanups++;
1406
                                n6expire[i]--;
1407
 
1408
                                *nptr = mfc->mf6c_next;
1409
                                free(mfc, M_MRTABLE);
1410
                        } else {
1411
                                nptr = &mfc->mf6c_next;
1412
                        }
1413
                }
1414
        }
1415
        splx(s);
1416
#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
1417
        callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT,
1418
            expire_upcalls, NULL);
1419
#elif defined(__OpenBSD__)
1420
        timeout_set(&expire_upcalls_ch, expire_upcalls, NULL);
1421
        timeout_add(&expire_upcalls_ch, EXPIRE_TIMEOUT);
1422
#else
1423
        timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
1424
#endif
1425
}
1426
 
1427
/*
1428
 * Packet forwarding routine once entry in the cache is made
1429
 */
1430
static int
1431
ip6_mdq(m, ifp, rt)
1432
        struct mbuf *m;
1433
        struct ifnet *ifp;
1434
        struct mf6c *rt;
1435
{
1436
        struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1437
        mifi_t mifi, iif;
1438
        struct mif6 *mifp;
1439
        int plen = m->m_pkthdr.len;
1440
 
1441
/*
1442
 * Macro to send packet on mif.  Since RSVP packets don't get counted on
1443
 * input, they shouldn't get counted on output, so statistics keeping is
1444
 * seperate.
1445
 */
1446
 
1447
#define MC6_SEND(ip6, mifp, m) do {                             \
1448
                if ((mifp)->m6_flags & MIFF_REGISTER)           \
1449
                    register_send((ip6), (mifp), (m));          \
1450
                else                                            \
1451
                    phyint_send((ip6), (mifp), (m));            \
1452
} while (0)
1453
 
1454
        /*
1455
         * Don't forward if it didn't arrive from the parent mif
1456
         * for its origin.
1457
         */
1458
        mifi = rt->mf6c_parent;
1459
        if ((mifi >= nummifs) || (mif6table[mifi].m6_ifp != ifp)) {
1460
                /* came in the wrong interface */
1461
#ifdef MRT6DEBUG
1462
                if (mrt6debug & DEBUG_FORWARD)
1463
                        log(LOG_DEBUG,
1464
                            "wrong if: ifid %d mifi %d mififid %x\n",
1465
                            ifp->if_index, mifi,
1466
                            mif6table[mifi].m6_ifp->if_index);
1467
#endif
1468
                mrt6stat.mrt6s_wrong_if++;
1469
                rt->mf6c_wrong_if++;
1470
                /*
1471
                 * If we are doing PIM processing, and we are forwarding
1472
                 * packets on this interface, send a message to the
1473
                 * routing daemon.
1474
                 */
1475
                /* have to make sure this is a valid mif */
1476
                if (mifi < nummifs && mif6table[mifi].m6_ifp)
1477
                        if (pim6 && (m->m_flags & M_LOOP) == 0) {
1478
                                /*
1479
                                 * Check the M_LOOP flag to avoid an
1480
                                 * unnecessary PIM assert.
1481
                                 * XXX: M_LOOP is an ad-hoc hack...
1482
                                 */
1483
                                static struct sockaddr_in6 sin6 =
1484
                                { sizeof(sin6), AF_INET6 };
1485
 
1486
                                struct mbuf *mm;
1487
                                struct mrt6msg *im;
1488
#ifdef MRT6_OINIT
1489
                                struct omrt6msg *oim;
1490
#endif
1491
 
1492
                                mm = m_copy(m, 0, sizeof(struct ip6_hdr));
1493
                                if (mm &&
1494
                                    (M_HASCL(mm) ||
1495
                                     mm->m_len < sizeof(struct ip6_hdr)))
1496
                                        mm = m_pullup(mm, sizeof(struct ip6_hdr));
1497
                                if (mm == NULL)
1498
                                        return ENOBUFS;
1499
 
1500
#ifdef MRT6_OINIT
1501
                                oim = NULL;
1502
#endif
1503
                                im = NULL;
1504
                                switch (ip6_mrouter_ver) {
1505
#ifdef MRT6_OINIT
1506
                                case MRT6_OINIT:
1507
                                        oim = mtod(mm, struct omrt6msg *);
1508
                                        oim->im6_msgtype = MRT6MSG_WRONGMIF;
1509
                                        oim->im6_mbz = 0;
1510
                                        break;
1511
#endif
1512
                                case MRT6_INIT:
1513
                                        im = mtod(mm, struct mrt6msg *);
1514
                                        im->im6_msgtype = MRT6MSG_WRONGMIF;
1515
                                        im->im6_mbz = 0;
1516
                                        break;
1517
                                default:
1518
                                        m_freem(mm);
1519
                                        return EINVAL;
1520
                                }
1521
 
1522
                                for (mifp = mif6table, iif = 0;
1523
                                     iif < nummifs && mifp &&
1524
                                             mifp->m6_ifp != ifp;
1525
                                     mifp++, iif++)
1526
                                        ;
1527
 
1528
                                switch (ip6_mrouter_ver) {
1529
#ifdef MRT6_OINIT
1530
                                case MRT6_OINIT:
1531
                                        oim->im6_mif = iif;
1532
                                        sin6.sin6_addr = oim->im6_src;
1533
                                        break;
1534
#endif
1535
                                case MRT6_INIT:
1536
                                        im->im6_mif = iif;
1537
                                        sin6.sin6_addr = im->im6_src;
1538
                                        break;
1539
                                }
1540
 
1541
                                mrt6stat.mrt6s_upcalls++;
1542
 
1543
                                if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1544
#ifdef MRT6DEBUG
1545
                                        if (mrt6debug)
1546
                                                log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");
1547
#endif
1548
                                        ++mrt6stat.mrt6s_upq_sockfull;
1549
                                        return ENOBUFS;
1550
                                }       /* if socket Q full */
1551
                        }               /* if PIM */
1552
                return 0;
1553
        }                       /* if wrong iif */
1554
 
1555
        /* If I sourced this packet, it counts as output, else it was input. */
1556
        if (m->m_pkthdr.rcvif == NULL) {
1557
                /* XXX: is rcvif really NULL when output?? */
1558
                mif6table[mifi].m6_pkt_out++;
1559
                mif6table[mifi].m6_bytes_out += plen;
1560
        } else {
1561
                mif6table[mifi].m6_pkt_in++;
1562
                mif6table[mifi].m6_bytes_in += plen;
1563
        }
1564
        rt->mf6c_pkt_cnt++;
1565
        rt->mf6c_byte_cnt += plen;
1566
 
1567
        /*
1568
         * For each mif, forward a copy of the packet if there are group
1569
         * members downstream on the interface.
1570
         */
1571
        for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++)
1572
                if (IF_ISSET(mifi, &rt->mf6c_ifset)) {
1573
                        int64_t dscopein, sscopein, dscopeout, sscopeout;
1574
 
1575
                        /*
1576
                         * check if the outgoing packet is going to break
1577
                         * a scope boundary.
1578
                         * XXX For packets through PIM register tunnel
1579
                         * interface, we believe a routing daemon.
1580
                         */
1581
                        if ((mif6table[rt->mf6c_parent].m6_flags &
1582
                             MIFF_REGISTER) == 0 &&
1583
                            (mif6table[mifi].m6_flags & MIFF_REGISTER) == 0) {
1584
                                if ((dscopein = in6_addr2zoneid(ifp, &ip6->ip6_dst)) < 0 ||
1585
                                    (dscopeout = in6_addr2zoneid(mif6table[mifi].m6_ifp, &ip6->ip6_dst)) < 0 ||
1586
                                    (sscopein = in6_addr2zoneid(ifp, &ip6->ip6_src)) < 0 ||
1587
                                    (sscopeout = in6_addr2zoneid(mif6table[mifi].m6_ifp, &ip6->ip6_src)) < 0 ||
1588
                                    dscopein != dscopeout ||
1589
                                    sscopein != sscopeout) {
1590
                                        ip6stat.ip6s_badscope++;
1591
                                        continue;
1592
                                }
1593
                        }
1594
 
1595
                        mifp->m6_pkt_out++;
1596
                        mifp->m6_bytes_out += plen;
1597
                        MC6_SEND(ip6, mifp, m);
1598
                }
1599
        return 0;
1600
}
1601
 
1602
static void
1603
phyint_send(ip6, mifp, m)
1604
    struct ip6_hdr *ip6;
1605
    struct mif6 *mifp;
1606
    struct mbuf *m;
1607
{
1608
        struct mbuf *mb_copy;
1609
        struct ifnet *ifp = mifp->m6_ifp;
1610
        int error = 0;
1611
#ifdef __NetBSD__
1612
        int s = splsoftnet();   /* needs to protect static "ro" below. */
1613
#else
1614
        int s = splnet();       /* needs to protect static "ro" below. */
1615
#endif
1616
#ifdef NEW_STRUCT_ROUTE
1617
        static struct route ro;
1618
#else
1619
        static struct route_in6 ro;
1620
#endif
1621
        struct  in6_multi *in6m;
1622
        struct sockaddr_in6 *dst6;
1623
 
1624
        /*
1625
         * Make a new reference to the packet; make sure that
1626
         * the IPv6 header is actually copied, not just referenced,
1627
         * so that ip6_output() only scribbles on the copy.
1628
         */
1629
        mb_copy = m_copy(m, 0, M_COPYALL);
1630
        if (mb_copy &&
1631
            (M_HASCL(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
1632
                mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
1633
        if (mb_copy == NULL) {
1634
                splx(s);
1635
                return;
1636
        }
1637
        /* set MCAST flag to the outgoing packet */
1638
        mb_copy->m_flags |= M_MCAST;
1639
 
1640
        /*
1641
         * If we sourced the packet, call ip6_output since we may devide
1642
         * the packet into fragments when the packet is too big for the
1643
         * outgoing interface.
1644
         * Otherwise, we can simply send the packet to the interface
1645
         * sending queue.
1646
         */
1647
        if (m->m_pkthdr.rcvif == NULL) {
1648
                struct ip6_moptions im6o;
1649
 
1650
                im6o.im6o_multicast_ifp = ifp;
1651
                /* XXX: ip6_output will override ip6->ip6_hlim */
1652
                im6o.im6o_multicast_hlim = ip6->ip6_hlim;
1653
                im6o.im6o_multicast_loop = 1;
1654
                error = ip6_output(mb_copy, NULL, &ro,
1655
                                   IPV6_FORWARDING, &im6o, NULL);
1656
 
1657
#ifdef MRT6DEBUG
1658
                if (mrt6debug & DEBUG_XMIT)
1659
                        log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
1660
                            mifp - mif6table, error);
1661
#endif
1662
                splx(s);
1663
                return;
1664
        }
1665
 
1666
        /*
1667
         * If we belong to the destination multicast group
1668
         * on the outgoing interface, loop back a copy.
1669
         */
1670
        dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
1671
        IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
1672
        if (in6m != NULL) {
1673
                dst6->sin6_len = sizeof(struct sockaddr_in6);
1674
                dst6->sin6_family = AF_INET6;
1675
                dst6->sin6_addr = ip6->ip6_dst;
1676
                ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst);
1677
        }
1678
        /*
1679
         * Put the packet into the sending queue of the outgoing interface
1680
         * if it would fit in the MTU of the interface.
1681
         */
1682
        if (mb_copy->m_pkthdr.len < ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) {
1683
                dst6->sin6_len = sizeof(struct sockaddr_in6);
1684
                dst6->sin6_family = AF_INET6;
1685
                dst6->sin6_addr = ip6->ip6_dst;
1686
                /*
1687
                 * We just call if_output instead of nd6_output here, since
1688
                 * we need no ND for a multicast forwarded packet...right?
1689
                 */
1690
                error = (*ifp->if_output)(ifp, mb_copy,
1691
                    (struct sockaddr *)&ro.ro_dst, NULL);
1692
#ifdef MRT6DEBUG
1693
                if (mrt6debug & DEBUG_XMIT)
1694
                        log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
1695
                            mifp - mif6table, error);
1696
#endif
1697
        } else {
1698
#ifdef MULTICAST_PMTUD
1699
                icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
1700
#else
1701
#ifdef MRT6DEBUG
1702
                if (mrt6debug & DEBUG_XMIT)
1703
                        log(LOG_DEBUG,
1704
                            "phyint_send: packet too big on %s o %s g %s"
1705
                            " size %d(discarded)\n",
1706
                            if_name(ifp),
1707
                            ip6_sprintf(&ip6->ip6_src),
1708
                            ip6_sprintf(&ip6->ip6_dst),
1709
                            mb_copy->m_pkthdr.len);
1710
#endif /* MRT6DEBUG */
1711
                m_freem(mb_copy); /* simply discard the packet */
1712
#endif
1713
        }
1714
 
1715
        splx(s);
1716
}
1717
 
1718
static int
1719
register_send(ip6, mif, m)
1720
        struct ip6_hdr *ip6;
1721
        struct mif6 *mif;
1722
        struct mbuf *m;
1723
{
1724
        struct mbuf *mm;
1725
        int i, len = m->m_pkthdr.len;
1726
        static struct sockaddr_in6 sin6 = { sizeof(sin6), AF_INET6 };
1727
        struct mrt6msg *im6;
1728
 
1729
#ifdef MRT6DEBUG
1730
        if (mrt6debug)
1731
                log(LOG_DEBUG, "** IPv6 register_send **\n src %s dst %s\n",
1732
                    ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst));
1733
#endif
1734
        ++pim6stat.pim6s_snd_registers;
1735
 
1736
        /* Make a copy of the packet to send to the user level process */
1737
        MGETHDR(mm, M_DONTWAIT, MT_HEADER);
1738
        if (mm == NULL)
1739
                return ENOBUFS;
1740
        mm->m_pkthdr.rcvif = NULL;
1741
        mm->m_data += max_linkhdr;
1742
        mm->m_len = sizeof(struct ip6_hdr);
1743
 
1744
        if ((mm->m_next = m_copy(m, 0, M_COPYALL)) == NULL) {
1745
                m_freem(mm);
1746
                return ENOBUFS;
1747
        }
1748
        i = MHLEN - M_LEADINGSPACE(mm);
1749
        if (i > len)
1750
                i = len;
1751
        mm = m_pullup(mm, i);
1752
        if (mm == NULL){
1753
                m_freem(mm);
1754
                return ENOBUFS;
1755
        }
1756
/* TODO: check it! */
1757
        mm->m_pkthdr.len = len + sizeof(struct ip6_hdr);
1758
 
1759
        /*
1760
         * Send message to routing daemon
1761
         */
1762
        sin6.sin6_addr = ip6->ip6_src;
1763
 
1764
        im6 = mtod(mm, struct mrt6msg *);
1765
        im6->im6_msgtype      = MRT6MSG_WHOLEPKT;
1766
        im6->im6_mbz          = 0;
1767
 
1768
        im6->im6_mif = mif - mif6table;
1769
 
1770
        /* iif info is not given for reg. encap.n */
1771
        mrt6stat.mrt6s_upcalls++;
1772
 
1773
        if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1774
#ifdef MRT6DEBUG
1775
                if (mrt6debug)
1776
                        log(LOG_WARNING,
1777
                            "register_send: ip6_mrouter socket queue full\n");
1778
#endif
1779
                ++mrt6stat.mrt6s_upq_sockfull;
1780
                return ENOBUFS;
1781
        }
1782
        return 0;
1783
}
1784
 
1785
/*
1786
 * PIM sparse mode hook
1787
 * Receives the pim control messages, and passes them up to the listening
1788
 * socket, using rip6_input.
1789
 * The only message processed is the REGISTER pim message; the pim header
1790
 * is stripped off, and the inner packet is passed to register_mforward.
1791
 */
1792
int
1793
pim6_input(mp, offp, proto)
1794
        struct mbuf **mp;
1795
        int *offp, proto;
1796
{
1797
        struct pim *pim; /* pointer to a pim struct */
1798
        struct ip6_hdr *ip6;
1799
        int pimlen;
1800
        struct mbuf *m = *mp;
1801
        int minlen;
1802
        int off = *offp;
1803
 
1804
        ++pim6stat.pim6s_rcv_total;
1805
 
1806
        ip6 = mtod(m, struct ip6_hdr *);
1807
        pimlen = m->m_pkthdr.len - *offp;
1808
 
1809
        /*
1810
         * Validate lengths
1811
         */
1812
        if (pimlen < PIM_MINLEN) {
1813
                ++pim6stat.pim6s_rcv_tooshort;
1814
#ifdef MRT6DEBUG
1815
                if (mrt6debug & DEBUG_PIM)
1816
                        log(LOG_DEBUG,"pim6_input: PIM packet too short\n");
1817
#endif
1818
                m_freem(m);
1819
                return(IPPROTO_DONE);
1820
        }
1821
 
1822
        /*
1823
         * if the packet is at least as big as a REGISTER, go ahead
1824
         * and grab the PIM REGISTER header size, to avoid another
1825
         * possible m_pullup() later.
1826
         *
1827
         * PIM_MINLEN       == pimhdr + u_int32 == 8
1828
         * PIM6_REG_MINLEN   == pimhdr + reghdr + eip6hdr == 4 + 4 + 40
1829
         */
1830
        minlen = (pimlen >= PIM6_REG_MINLEN) ? PIM6_REG_MINLEN : PIM_MINLEN;
1831
 
1832
        /*
1833
         * Make sure that the IP6 and PIM headers in contiguous memory, and
1834
         * possibly the PIM REGISTER header
1835
         */
1836
#ifndef PULLDOWN_TEST
1837
        IP6_EXTHDR_CHECK(m, off, minlen, IPPROTO_DONE);
1838
        /* adjust pointer */
1839
        ip6 = mtod(m, struct ip6_hdr *);
1840
 
1841
        /* adjust mbuf to point to the PIM header */
1842
        pim = (struct pim *)((caddr_t)ip6 + off);
1843
#else
1844
        IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen);
1845
        if (pim == NULL) {
1846
                pim6stat.pim6s_rcv_tooshort++;
1847
                return IPPROTO_DONE;
1848
        }
1849
#endif
1850
 
1851
#define PIM6_CHECKSUM
1852
#ifdef PIM6_CHECKSUM
1853
        {
1854
                int cksumlen;
1855
 
1856
                /*
1857
                 * Validate checksum.
1858
                 * If PIM REGISTER, exclude the data packet
1859
                 */
1860
                if (pim->pim_type == PIM_REGISTER)
1861
                        cksumlen = PIM_MINLEN;
1862
                else
1863
                        cksumlen = pimlen;
1864
 
1865
                if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) {
1866
                        ++pim6stat.pim6s_rcv_badsum;
1867
#ifdef MRT6DEBUG
1868
                        if (mrt6debug & DEBUG_PIM)
1869
                                log(LOG_DEBUG,
1870
                                    "pim6_input: invalid checksum\n");
1871
#endif
1872
                        m_freem(m);
1873
                        return(IPPROTO_DONE);
1874
                }
1875
        }
1876
#endif /* PIM_CHECKSUM */
1877
 
1878
        /* PIM version check */
1879
        if (pim->pim_ver != PIM_VERSION) {
1880
                ++pim6stat.pim6s_rcv_badversion;
1881
#ifdef MRT6DEBUG
1882
                log(LOG_ERR,
1883
                    "pim6_input: incorrect version %d, expecting %d\n",
1884
                    pim->pim_ver, PIM_VERSION);
1885
#endif
1886
                m_freem(m);
1887
                return(IPPROTO_DONE);
1888
        }
1889
 
1890
        if (pim->pim_type == PIM_REGISTER) {
1891
                /*
1892
                 * since this is a REGISTER, we'll make a copy of the register
1893
                 * headers ip6+pim+u_int32_t+encap_ip6, to be passed up to the
1894
                 * routing daemon.
1895
                 */
1896
                static struct sockaddr_in6 dst = { sizeof(dst), AF_INET6 };
1897
 
1898
                struct mbuf *mcp;
1899
                struct ip6_hdr *eip6;
1900
                u_int32_t *reghdr;
1901
                int rc;
1902
 
1903
                ++pim6stat.pim6s_rcv_registers;
1904
 
1905
                if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {
1906
#ifdef MRT6DEBUG
1907
                        if (mrt6debug & DEBUG_PIM)
1908
                                log(LOG_DEBUG,
1909
                                    "pim6_input: register mif not set: %d\n",
1910
                                    reg_mif_num);
1911
#endif
1912
                        m_freem(m);
1913
                        return(IPPROTO_DONE);
1914
                }
1915
 
1916
                reghdr = (u_int32_t *)(pim + 1);
1917
 
1918
                if ((ntohl(*reghdr) & PIM_NULL_REGISTER))
1919
                        goto pim6_input_to_daemon;
1920
 
1921
                /*
1922
                 * Validate length
1923
                 */
1924
                if (pimlen < PIM6_REG_MINLEN) {
1925
                        ++pim6stat.pim6s_rcv_tooshort;
1926
                        ++pim6stat.pim6s_rcv_badregisters;
1927
#ifdef MRT6DEBUG
1928
                        log(LOG_ERR,
1929
                            "pim6_input: register packet size too "
1930
                            "small %d from %s\n",
1931
                            pimlen, ip6_sprintf(&ip6->ip6_src));
1932
#endif
1933
                        m_freem(m);
1934
                        return(IPPROTO_DONE);
1935
                }
1936
 
1937
                eip6 = (struct ip6_hdr *) (reghdr + 1);
1938
#ifdef MRT6DEBUG        
1939
                if (mrt6debug & DEBUG_PIM)
1940
                        log(LOG_DEBUG,
1941
                            "pim6_input[register], eip6: %s -> %s, "
1942
                            "eip6 plen %d\n",
1943
                            ip6_sprintf(&eip6->ip6_src),
1944
                            ip6_sprintf(&eip6->ip6_dst),
1945
                            ntohs(eip6->ip6_plen));
1946
#endif
1947
 
1948
                /* verify the version number of the inner packet */
1949
                if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
1950
                        ++pim6stat.pim6s_rcv_badregisters;
1951
#ifdef MRT6DEBUG
1952
                        log(LOG_DEBUG, "pim6_input: invalid IP version (%d) "
1953
                            "of the inner packet\n",
1954
                            (eip6->ip6_vfc & IPV6_VERSION));
1955
#endif
1956
                        m_freem(m);
1957
                        return(IPPROTO_NONE);
1958
                }
1959
 
1960
                /* verify the inner packet is destined to a mcast group */
1961
                if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {
1962
                        ++pim6stat.pim6s_rcv_badregisters;
1963
#ifdef MRT6DEBUG
1964
                        if (mrt6debug & DEBUG_PIM)
1965
                                log(LOG_DEBUG,
1966
                                    "pim6_input: inner packet of register "
1967
                                    "is not multicast %s\n",
1968
                                    ip6_sprintf(&eip6->ip6_dst));
1969
#endif
1970
                        m_freem(m);
1971
                        return(IPPROTO_DONE);
1972
                }
1973
 
1974
                /*
1975
                 * make a copy of the whole header to pass to the daemon later.
1976
                 */
1977
                mcp = m_copy(m, 0, off + PIM6_REG_MINLEN);
1978
                if (mcp == NULL) {
1979
#ifdef MRT6DEBUG
1980
                        log(LOG_ERR,
1981
                            "pim6_input: pim register: "
1982
                            "could not copy register head\n");
1983
#endif
1984
                        m_freem(m);
1985
                        return(IPPROTO_DONE);
1986
                }
1987
 
1988
                /*
1989
                 * forward the inner ip6 packet; point m_data at the inner ip6.
1990
                 */
1991
                m_adj(m, off + PIM_MINLEN);
1992
#ifdef MRT6DEBUG
1993
                if (mrt6debug & DEBUG_PIM) {
1994
                        log(LOG_DEBUG,
1995
                            "pim6_input: forwarding decapsulated register: "
1996
                            "src %s, dst %s, mif %d\n",
1997
                            ip6_sprintf(&eip6->ip6_src),
1998
                            ip6_sprintf(&eip6->ip6_dst),
1999
                            reg_mif_num);
2000
                }
2001
#endif
2002
 
2003
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
2004
#if (__FreeBSD_version >= 410000)
2005
                rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m,
2006
                                dst.sin6_family, (int)NULL);
2007
#else
2008
                rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m,
2009
                                (struct sockaddr *) &dst, NULL);
2010
 
2011
#endif
2012
#else
2013
                rc = looutput(mif6table[reg_mif_num].m6_ifp, m,
2014
                              (struct sockaddr *) &dst,
2015
                              (struct rtentry *) NULL);
2016
#endif
2017
 
2018
                /* prepare the register head to send to the mrouting daemon */
2019
                m = mcp;
2020
        }
2021
 
2022
        /*
2023
         * Pass the PIM message up to the daemon; if it is a register message
2024
         * pass the 'head' only up to the daemon. This includes the
2025
         * encapsulator ip6 header, pim header, register header and the
2026
         * encapsulated ip6 header.
2027
         */
2028
  pim6_input_to_daemon:
2029
        rip6_input(&m, offp, proto);
2030
        return(IPPROTO_DONE);
2031
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.