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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [tcpip/] [v2_0/] [src/] [sys/] [netinet/] [igmp.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      sys/netinet/igmp.c
4
//
5
//     
6
//
7
//==========================================================================
8
//####BSDCOPYRIGHTBEGIN####
9
//
10
// -------------------------------------------
11
//
12
// Portions of this software may have been derived from OpenBSD or other sources,
13
// and are covered by the appropriate copyright disclaimers included herein.
14
//
15
// -------------------------------------------
16
//
17
//####BSDCOPYRIGHTEND####
18
//==========================================================================
19
//#####DESCRIPTIONBEGIN####
20
//
21
// Author(s):    gthomas
22
// Contributors: gthomas
23
// Date:         2000-01-10
24
// Purpose:      
25
// Description:  
26
//              
27
//
28
//####DESCRIPTIONEND####
29
//
30
//==========================================================================
31
 
32
 
33
/*      $OpenBSD: igmp.c,v 1.6 1999/12/08 06:50:19 itojun Exp $ */
34
/*      $NetBSD: igmp.c,v 1.15 1996/02/13 23:41:25 christos Exp $       */
35
 
36
/*
37
 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
38
 * All rights reserved.
39
 *
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in the
47
 *    documentation and/or other materials provided with the distribution.
48
 * 3. Neither the name of the project nor the names of its contributors
49
 *    may be used to endorse or promote products derived from this software
50
 *    without specific prior written permission.
51
 *
52
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
53
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
56
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62
 * SUCH DAMAGE.
63
 */
64
 
65
/*
66
 * Internet Group Management Protocol (IGMP) routines.
67
 *
68
 * Written by Steve Deering, Stanford, May 1988.
69
 * Modified by Rosen Sharma, Stanford, Aug 1994.
70
 * Modified by Bill Fenner, Xerox PARC, Feb 1995.
71
 *
72
 * MULTICAST Revision: 1.3
73
 */
74
 
75
#include <sys/param.h>
76
#include <sys/mbuf.h>
77
#include <sys/socket.h>
78
#include <sys/protosw.h>
79
#ifndef __ECOS
80
#include <sys/systm.h>
81
#endif
82
 
83
#include <net/if.h>
84
#include <net/route.h>
85
 
86
#include <netinet/in.h>
87
#include <netinet/in_var.h>
88
#include <netinet/in_systm.h>
89
#include <netinet/ip.h>
90
#include <netinet/ip_var.h>
91
#include <netinet/igmp.h>
92
#include <netinet/igmp_var.h>
93
#ifndef __ECOS
94
#include <dev/rndvar.h>
95
#endif
96
 
97
#include <machine/stdarg.h>
98
 
99
#define IP_MULTICASTOPTS        0
100
 
101
int             igmp_timers_are_running;
102
static struct router_info *rti_head;
103
 
104
void igmp_sendpkt __P((struct in_multi *, int));
105
static int rti_fill __P((struct in_multi *));
106
static struct router_info * rti_find __P((struct ifnet *));
107
 
108
void
109
igmp_init()
110
{
111
 
112
        /*
113
         * To avoid byte-swapping the same value over and over again.
114
         */
115
        igmp_timers_are_running = 0;
116
        rti_head = 0;
117
}
118
 
119
static int
120
rti_fill(inm)
121
        struct in_multi *inm;
122
{
123
        register struct router_info *rti;
124
 
125
        for (rti = rti_head; rti != 0; rti = rti->rti_next) {
126
                if (rti->rti_ifp == inm->inm_ifp) {
127
                        inm->inm_rti = rti;
128
                        if (rti->rti_type == IGMP_v1_ROUTER)
129
                                return (IGMP_v1_HOST_MEMBERSHIP_REPORT);
130
                        else
131
                                return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
132
                }
133
        }
134
 
135
        rti = (struct router_info *)malloc(sizeof(struct router_info),
136
                                           M_MRTABLE, M_NOWAIT);
137
        rti->rti_ifp = inm->inm_ifp;
138
        rti->rti_type = IGMP_v2_ROUTER;
139
        rti->rti_next = rti_head;
140
        rti_head = rti;
141
        inm->inm_rti = rti;
142
        return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
143
}
144
 
145
static struct router_info *
146
rti_find(ifp)
147
        struct ifnet *ifp;
148
{
149
        register struct router_info *rti;
150
 
151
        for (rti = rti_head; rti != 0; rti = rti->rti_next) {
152
                if (rti->rti_ifp == ifp)
153
                        return (rti);
154
        }
155
 
156
        rti = (struct router_info *)malloc(sizeof(struct router_info),
157
                                           M_MRTABLE, M_NOWAIT);
158
        rti->rti_ifp = ifp;
159
        rti->rti_type = IGMP_v2_ROUTER;
160
        rti->rti_next = rti_head;
161
        rti_head = rti;
162
        return (rti);
163
}
164
 
165
void
166
rti_delete(ifp)
167
        struct ifnet *ifp;
168
{
169
        struct router_info *rti, **prti = &rti_head;
170
 
171
        for (rti = rti_head; rti != 0; rti = rti->rti_next) {
172
                if (rti->rti_ifp == ifp) {
173
                        *prti = rti->rti_next;
174
                        free(rti, M_MRTABLE);
175
                        break;
176
                }
177
                prti = &rti->rti_next;
178
        }
179
}
180
 
181
void
182
#if __STDC__
183
igmp_input(struct mbuf *m, ...)
184
#else
185
igmp_input(m, va_alist)
186
        struct mbuf *m;
187
        va_dcl
188
#endif
189
{
190
        int proto;
191
        register int iphlen;
192
        register struct ifnet *ifp = m->m_pkthdr.rcvif;
193
        register struct ip *ip = mtod(m, struct ip *);
194
        register struct igmp *igmp;
195
        register int igmplen;
196
        register int minlen;
197
        struct in_multi *inm;
198
        struct in_multistep step;
199
        struct router_info *rti;
200
        register struct in_ifaddr *ia;
201
        int timer;
202
        va_list ap;
203
 
204
        va_start(ap, m);
205
        iphlen = va_arg(ap, int);
206
        proto = va_arg(ap, int);
207
        va_end(ap);
208
 
209
        ++igmpstat.igps_rcv_total;
210
 
211
        igmplen = ip->ip_len;
212
 
213
        /*
214
         * Validate lengths
215
         */
216
        if (igmplen < IGMP_MINLEN) {
217
                ++igmpstat.igps_rcv_tooshort;
218
                m_freem(m);
219
                return;
220
        }
221
        minlen = iphlen + IGMP_MINLEN;
222
        if ((m->m_flags & M_EXT || m->m_len < minlen) &&
223
            (m = m_pullup(m, minlen)) == 0) {
224
                ++igmpstat.igps_rcv_tooshort;
225
                return;
226
        }
227
 
228
        /*
229
         * Validate checksum
230
         */
231
        m->m_data += iphlen;
232
        m->m_len -= iphlen;
233
        igmp = mtod(m, struct igmp *);
234
        if (in_cksum(m, igmplen)) {
235
                ++igmpstat.igps_rcv_badsum;
236
                m_freem(m);
237
                return;
238
        }
239
        m->m_data -= iphlen;
240
        m->m_len += iphlen;
241
        ip = mtod(m, struct ip *);
242
 
243
        switch (igmp->igmp_type) {
244
 
245
        case IGMP_HOST_MEMBERSHIP_QUERY:
246
                ++igmpstat.igps_rcv_queries;
247
 
248
                if (ifp->if_flags & IFF_LOOPBACK)
249
                        break;
250
 
251
                if (igmp->igmp_code == 0) {
252
                        rti = rti_find(ifp);
253
                        rti->rti_type = IGMP_v1_ROUTER;
254
                        rti->rti_age = 0;
255
 
256
                        if (ip->ip_dst.s_addr != INADDR_ALLHOSTS_GROUP) {
257
                                ++igmpstat.igps_rcv_badqueries;
258
                                m_freem(m);
259
                                return;
260
                        }
261
 
262
                        /*
263
                         * Start the timers in all of our membership records
264
                         * for the interface on which the query arrived,
265
                         * except those that are already running and those
266
                         * that belong to a "local" group (224.0.0.X).
267
                         */
268
                        IN_FIRST_MULTI(step, inm);
269
                        while (inm != NULL) {
270
                                if (inm->inm_ifp == ifp &&
271
                                    inm->inm_timer == 0 &&
272
                                    !IN_LOCAL_GROUP(inm->inm_addr.s_addr)) {
273
                                        inm->inm_state = IGMP_DELAYING_MEMBER;
274
                                        inm->inm_timer = IGMP_RANDOM_DELAY(
275
                                            IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
276
                                        igmp_timers_are_running = 1;
277
                                }
278
                                IN_NEXT_MULTI(step, inm);
279
                        }
280
                } else {
281
                        if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
282
                                ++igmpstat.igps_rcv_badqueries;
283
                                m_freem(m);
284
                                return;
285
                        }
286
 
287
                        timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
288
 
289
                        /*
290
                         * Start the timers in all of our membership records
291
                         * for the interface on which the query arrived,
292
                         * except those that are already running and those
293
                         * that belong to a "local" group (224.0.0.X).  For
294
                         * timers already running, check if they need to be
295
                         * reset.
296
                         */
297
                        IN_FIRST_MULTI(step, inm);
298
                        while (inm != NULL) {
299
                                if (inm->inm_ifp == ifp &&
300
                                    !IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
301
                                    (ip->ip_dst.s_addr == INADDR_ALLHOSTS_GROUP ||
302
                                     ip->ip_dst.s_addr == inm->inm_addr.s_addr)) {
303
                                        switch (inm->inm_state) {
304
                                        case IGMP_DELAYING_MEMBER:
305
                                                if (inm->inm_timer <= timer)
306
                                                        break;
307
                                                /* FALLTHROUGH */
308
                                        case IGMP_IDLE_MEMBER:
309
                                        case IGMP_LAZY_MEMBER:
310
                                        case IGMP_AWAKENING_MEMBER:
311
                                                inm->inm_state =
312
                                                    IGMP_DELAYING_MEMBER;
313
                                                inm->inm_timer =
314
                                                    IGMP_RANDOM_DELAY(timer);
315
                                                igmp_timers_are_running = 1;
316
                                                break;
317
                                        case IGMP_SLEEPING_MEMBER:
318
                                                inm->inm_state =
319
                                                    IGMP_AWAKENING_MEMBER;
320
                                                break;
321
                                        }
322
                                }
323
                                IN_NEXT_MULTI(step, inm);
324
                        }
325
                }
326
 
327
                break;
328
 
329
        case IGMP_v1_HOST_MEMBERSHIP_REPORT:
330
                ++igmpstat.igps_rcv_reports;
331
 
332
                if (ifp->if_flags & IFF_LOOPBACK)
333
                        break;
334
 
335
                if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
336
                    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
337
                        ++igmpstat.igps_rcv_badreports;
338
                        m_freem(m);
339
                        return;
340
                }
341
 
342
                /*
343
                 * KLUDGE: if the IP source address of the report has an
344
                 * unspecified (i.e., zero) subnet number, as is allowed for
345
                 * a booting host, replace it with the correct subnet number
346
                 * so that a process-level multicast routing daemon can
347
                 * determine which subnet it arrived from.  This is necessary
348
                 * to compensate for the lack of any way for a process to
349
                 * determine the arrival interface of an incoming packet.
350
                 */
351
                if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
352
                        IFP_TO_IA(ifp, ia);
353
                        if (ia)
354
                                ip->ip_src.s_addr = ia->ia_subnet;
355
                }
356
 
357
                /*
358
                 * If we belong to the group being reported, stop
359
                 * our timer for that group.
360
                 */
361
                IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
362
                if (inm != NULL) {
363
                        inm->inm_timer = 0;
364
                        ++igmpstat.igps_rcv_ourreports;
365
 
366
                        switch (inm->inm_state) {
367
                        case IGMP_IDLE_MEMBER:
368
                        case IGMP_LAZY_MEMBER:
369
                        case IGMP_AWAKENING_MEMBER:
370
                        case IGMP_SLEEPING_MEMBER:
371
                                inm->inm_state = IGMP_SLEEPING_MEMBER;
372
                                break;
373
                        case IGMP_DELAYING_MEMBER:
374
                                if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
375
                                        inm->inm_state = IGMP_LAZY_MEMBER;
376
                                else
377
                                        inm->inm_state = IGMP_SLEEPING_MEMBER;
378
                                break;
379
                        }
380
                }
381
 
382
                break;
383
 
384
        case IGMP_v2_HOST_MEMBERSHIP_REPORT:
385
#ifdef MROUTING
386
                /*
387
                 * Make sure we don't hear our own membership report.  Fast
388
                 * leave requires knowing that we are the only member of a
389
                 * group.
390
                 */
391
                IFP_TO_IA(ifp, ia);
392
                if (ia && ip->ip_src.s_addr == ia->ia_addr.sin_addr.s_addr)
393
                        break;
394
#endif
395
 
396
                ++igmpstat.igps_rcv_reports;
397
 
398
                if (ifp->if_flags & IFF_LOOPBACK)
399
                        break;
400
 
401
                if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
402
                    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
403
                        ++igmpstat.igps_rcv_badreports;
404
                        m_freem(m);
405
                        return;
406
                }
407
 
408
                /*
409
                 * KLUDGE: if the IP source address of the report has an
410
                 * unspecified (i.e., zero) subnet number, as is allowed for
411
                 * a booting host, replace it with the correct subnet number
412
                 * so that a process-level multicast routing daemon can
413
                 * determine which subnet it arrived from.  This is necessary
414
                 * to compensate for the lack of any way for a process to
415
                 * determine the arrival interface of an incoming packet.
416
                 */
417
                if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
418
#ifndef MROUTING
419
                        IFP_TO_IA(ifp, ia);
420
#endif
421
                        if (ia)
422
                                ip->ip_src.s_addr = ia->ia_subnet;
423
                }
424
 
425
                /*
426
                 * If we belong to the group being reported, stop
427
                 * our timer for that group.
428
                 */
429
                IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
430
                if (inm != NULL) {
431
                        inm->inm_timer = 0;
432
                        ++igmpstat.igps_rcv_ourreports;
433
 
434
                        switch (inm->inm_state) {
435
                        case IGMP_DELAYING_MEMBER:
436
                        case IGMP_IDLE_MEMBER:
437
                        case IGMP_AWAKENING_MEMBER:
438
                                inm->inm_state = IGMP_LAZY_MEMBER;
439
                                break;
440
                        case IGMP_LAZY_MEMBER:
441
                        case IGMP_SLEEPING_MEMBER:
442
                                break;
443
                        }
444
                }
445
 
446
                break;
447
 
448
        }
449
 
450
        /*
451
         * Pass all valid IGMP packets up to any process(es) listening
452
         * on a raw IGMP socket.
453
         */
454
        rip_input(m, iphlen, proto);
455
        return;
456
}
457
 
458
void
459
igmp_joingroup(inm)
460
        struct in_multi *inm;
461
{
462
        int s = splsoftnet();
463
 
464
        inm->inm_state = IGMP_IDLE_MEMBER;
465
 
466
        if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
467
            (inm->inm_ifp->if_flags & IFF_LOOPBACK) == 0) {
468
                igmp_sendpkt(inm, rti_fill(inm));
469
                inm->inm_state = IGMP_DELAYING_MEMBER;
470
                inm->inm_timer = IGMP_RANDOM_DELAY(
471
                    IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
472
                igmp_timers_are_running = 1;
473
        } else
474
                inm->inm_timer = 0;
475
        splx(s);
476
}
477
 
478
void
479
igmp_leavegroup(inm)
480
        struct in_multi *inm;
481
{
482
 
483
        switch (inm->inm_state) {
484
        case IGMP_DELAYING_MEMBER:
485
        case IGMP_IDLE_MEMBER:
486
                if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
487
                    (inm->inm_ifp->if_flags & IFF_LOOPBACK) == 0)
488
                        if (inm->inm_rti->rti_type != IGMP_v1_ROUTER)
489
                                igmp_sendpkt(inm, IGMP_HOST_LEAVE_MESSAGE);
490
                break;
491
        case IGMP_LAZY_MEMBER:
492
        case IGMP_AWAKENING_MEMBER:
493
        case IGMP_SLEEPING_MEMBER:
494
                break;
495
        }
496
}
497
 
498
void
499
igmp_fasttimo()
500
{
501
        register struct in_multi *inm;
502
        struct in_multistep step;
503
        int s;
504
 
505
        /*
506
         * Quick check to see if any work needs to be done, in order
507
         * to minimize the overhead of fasttimo processing.
508
         */
509
        if (!igmp_timers_are_running)
510
                return;
511
 
512
        s = splsoftnet();
513
        igmp_timers_are_running = 0;
514
        IN_FIRST_MULTI(step, inm);
515
        while (inm != NULL) {
516
                if (inm->inm_timer == 0) {
517
                        /* do nothing */
518
                } else if (--inm->inm_timer == 0) {
519
                        if (inm->inm_state == IGMP_DELAYING_MEMBER) {
520
                                if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
521
                                        igmp_sendpkt(inm,
522
                                            IGMP_v1_HOST_MEMBERSHIP_REPORT);
523
                                else
524
                                        igmp_sendpkt(inm,
525
                                            IGMP_v2_HOST_MEMBERSHIP_REPORT);
526
                                inm->inm_state = IGMP_IDLE_MEMBER;
527
                        }
528
                } else {
529
                        igmp_timers_are_running = 1;
530
                }
531
                IN_NEXT_MULTI(step, inm);
532
        }
533
        splx(s);
534
}
535
 
536
void
537
igmp_slowtimo()
538
{
539
        register struct router_info *rti;
540
        int s;
541
 
542
        s = splsoftnet();
543
        for (rti = rti_head; rti != 0; rti = rti->rti_next) {
544
                if (rti->rti_type == IGMP_v1_ROUTER &&
545
                    ++rti->rti_age >= IGMP_AGE_THRESHOLD) {
546
                        rti->rti_type = IGMP_v2_ROUTER;
547
                }
548
        }
549
        splx(s);
550
}
551
 
552
void
553
igmp_sendpkt(inm, type)
554
        struct in_multi *inm;
555
        int type;
556
{
557
        struct mbuf *m;
558
        struct igmp *igmp;
559
        struct ip *ip;
560
        struct ip_moptions imo;
561
#ifdef MROUTING
562
        extern struct socket *ip_mrouter;
563
#endif /* MROUTING */
564
 
565
        MGETHDR(m, M_DONTWAIT, MT_HEADER);
566
        if (m == NULL)
567
                return;
568
        /*
569
         * Assume max_linkhdr + sizeof(struct ip) + IGMP_MINLEN
570
         * is smaller than mbuf size returned by MGETHDR.
571
         */
572
        m->m_data += max_linkhdr;
573
        m->m_len = sizeof(struct ip) + IGMP_MINLEN;
574
        m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
575
 
576
        ip = mtod(m, struct ip *);
577
        ip->ip_tos = 0;
578
        ip->ip_len = sizeof(struct ip) + IGMP_MINLEN;
579
        ip->ip_off = 0;
580
        ip->ip_p = IPPROTO_IGMP;
581
        ip->ip_src.s_addr = INADDR_ANY;
582
        ip->ip_dst = inm->inm_addr;
583
 
584
        m->m_data += sizeof(struct ip);
585
        m->m_len -= sizeof(struct ip);
586
        igmp = mtod(m, struct igmp *);
587
        igmp->igmp_type = type;
588
        igmp->igmp_code = 0;
589
        igmp->igmp_group = inm->inm_addr;
590
        igmp->igmp_cksum = 0;
591
        igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN);
592
        m->m_data -= sizeof(struct ip);
593
        m->m_len += sizeof(struct ip);
594
 
595
        imo.imo_multicast_ifp = inm->inm_ifp;
596
        imo.imo_multicast_ttl = 1;
597
#ifdef RSVP_ISI
598
        imo.imo_multicast_vif = -1;
599
#endif
600
        /*
601
         * Request loopback of the report if we are acting as a multicast
602
         * router, so that the process-level routing demon can hear it.
603
         */
604
#ifdef MROUTING
605
        imo.imo_multicast_loop = (ip_mrouter != NULL);
606
#else
607
        imo.imo_multicast_loop = 0;
608
#endif /* MROUTING */
609
 
610
#if 0 /*KAME IPSEC*/
611
        m->m_pkthdr.rcvif = NULL;
612
#endif /*IPSEC*/
613
        ip_output(m, (struct mbuf *)0, (struct route *)0, IP_MULTICASTOPTS,
614
            &imo, NULL);
615
 
616
        ++igmpstat.igps_snd_reports;
617
}

powered by: WebSVN 2.1.0

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