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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [bsd_tcpip/] [current/] [src/] [sys/] [netinet6/] [ip6_mroute.c] - Blame information for rev 786

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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