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/] [netinet/] [igmp.c] - Blame information for rev 838

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

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      src/sys/netinet/igmp.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
/*
21
 * Copyright (c) 1988 Stephen Deering.
22
 * Copyright (c) 1992, 1993
23
 *      The Regents of the University of California.  All rights reserved.
24
 *
25
 * This code is derived from software contributed to Berkeley by
26
 * Stephen Deering of Stanford University.
27
 *
28
 * Redistribution and use in source and binary forms, with or without
29
 * modification, are permitted provided that the following conditions
30
 * are met:
31
 * 1. Redistributions of source code must retain the above copyright
32
 *    notice, this list of conditions and the following disclaimer.
33
 * 2. Redistributions in binary form must reproduce the above copyright
34
 *    notice, this list of conditions and the following disclaimer in the
35
 *    documentation and/or other materials provided with the distribution.
36
 * 3. All advertising materials mentioning features or use of this software
37
 *    must display the following acknowledgement:
38
 *      This product includes software developed by the University of
39
 *      California, Berkeley and its contributors.
40
 * 4. Neither the name of the University nor the names of its contributors
41
 *    may be used to endorse or promote products derived from this software
42
 *    without specific prior written permission.
43
 *
44
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54
 * SUCH DAMAGE.
55
 *
56
 *      @(#)igmp.c      8.1 (Berkeley) 7/19/93
57
 * $FreeBSD: src/sys/netinet/igmp.c,v 1.29 1999/12/22 19:13:17 shin Exp $
58
 */
59
 
60
/*
61
 * Internet Group Management Protocol (IGMP) routines.
62
 *
63
 * Written by Steve Deering, Stanford, May 1988.
64
 * Modified by Rosen Sharma, Stanford, Aug 1994.
65
 * Modified by Bill Fenner, Xerox PARC, Feb 1995.
66
 * Modified to fully comply to IGMPv2 by Bill Fenner, Oct 1995.
67
 *
68
 * MULTICAST Revision: 3.5.1.4
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/protosw.h>
76
#include <sys/sysctl.h>
77
 
78
#include <net/if.h>
79
#include <net/route.h>
80
 
81
#include <netinet/in.h>
82
#include <netinet/in_var.h>
83
#include <netinet/in_systm.h>
84
#include <netinet/ip.h>
85
#include <netinet/ip_var.h>
86
#include <netinet/igmp.h>
87
#include <netinet/igmp_var.h>
88
 
89
static struct router_info *
90
                find_rti __P((struct ifnet *ifp));
91
 
92
static struct igmpstat igmpstat;
93
 
94
SYSCTL_STRUCT(_net_inet_igmp, IGMPCTL_STATS, stats, CTLFLAG_RD,
95
        &igmpstat, igmpstat, "");
96
 
97
static int igmp_timers_are_running;
98
static u_long igmp_all_hosts_group;
99
static u_long igmp_all_rtrs_group;
100
static struct mbuf *router_alert;
101
static struct router_info *Head;
102
 
103
static void igmp_sendpkt __P((struct in_multi *, int, unsigned long));
104
 
105
void
106
igmp_init()
107
{
108
        struct ipoption *ra;
109
 
110
        /*
111
         * To avoid byte-swapping the same value over and over again.
112
         */
113
        igmp_all_hosts_group = htonl(INADDR_ALLHOSTS_GROUP);
114
        igmp_all_rtrs_group = htonl(INADDR_ALLRTRS_GROUP);
115
 
116
        igmp_timers_are_running = 0;
117
 
118
        /*
119
         * Construct a Router Alert option to use in outgoing packets
120
         */
121
        MGET(router_alert, M_DONTWAIT, MT_DATA);
122
        ra = mtod(router_alert, struct ipoption *);
123
        ra->ipopt_dst.s_addr = 0;
124
        ra->ipopt_list[0] = IPOPT_RA;    /* Router Alert Option */
125
        ra->ipopt_list[1] = 0x04;       /* 4 bytes long */
126
        ra->ipopt_list[2] = 0x00;
127
        ra->ipopt_list[3] = 0x00;
128
        router_alert->m_len = sizeof(ra->ipopt_dst) + ra->ipopt_list[1];
129
 
130
        Head = (struct router_info *) 0;
131
}
132
 
133
static struct router_info *
134
find_rti(ifp)
135
        struct ifnet *ifp;
136
{
137
        register struct router_info *rti = Head;
138
 
139
#ifdef IGMP_DEBUG
140
        printf("[igmp.c, _find_rti] --> entering \n");
141
#endif
142
        while (rti) {
143
                if (rti->rti_ifp == ifp) {
144
#ifdef IGMP_DEBUG
145
                        printf("[igmp.c, _find_rti] --> found old entry \n");
146
#endif
147
                        return rti;
148
                }
149
                rti = rti->rti_next;
150
        }
151
        MALLOC(rti, struct router_info *, sizeof *rti, M_IGMP, M_NOWAIT);
152
        rti->rti_ifp = ifp;
153
        rti->rti_type = IGMP_V2_ROUTER;
154
        rti->rti_time = 0;
155
        rti->rti_next = Head;
156
        Head = rti;
157
#ifdef IGMP_DEBUG
158
        printf("[igmp.c, _find_rti] --> created an entry \n");
159
#endif
160
        return rti;
161
}
162
 
163
void
164
igmp_input(m, off)
165
        register struct mbuf *m;
166
        int off;
167
{
168
        register int iphlen = off;
169
        register struct igmp *igmp;
170
        register struct ip *ip;
171
        register int igmplen;
172
        register struct ifnet *ifp = m->m_pkthdr.rcvif;
173
        register int minlen;
174
        register struct in_multi *inm;
175
        register struct in_ifaddr *ia;
176
        struct in_multistep step;
177
        struct router_info *rti;
178
 
179
        int timer; /** timer value in the igmp query header **/
180
 
181
        ++igmpstat.igps_rcv_total;
182
 
183
        ip = mtod(m, struct ip *);
184
        igmplen = ip->ip_len;
185
 
186
        /*
187
         * Validate lengths
188
         */
189
        if (igmplen < IGMP_MINLEN) {
190
                ++igmpstat.igps_rcv_tooshort;
191
                m_freem(m);
192
                return;
193
        }
194
        minlen = iphlen + IGMP_MINLEN;
195
        if ((m->m_flags & M_EXT || m->m_len < minlen) &&
196
            (m = m_pullup(m, minlen)) == 0) {
197
                ++igmpstat.igps_rcv_tooshort;
198
                return;
199
        }
200
 
201
        /*
202
         * Validate checksum
203
         */
204
        m->m_data += iphlen;
205
        m->m_len -= iphlen;
206
        igmp = mtod(m, struct igmp *);
207
        if (in_cksum(m, igmplen)) {
208
                ++igmpstat.igps_rcv_badsum;
209
                m_freem(m);
210
                return;
211
        }
212
        m->m_data -= iphlen;
213
        m->m_len += iphlen;
214
 
215
        ip = mtod(m, struct ip *);
216
        timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
217
        if (timer == 0)
218
                timer = 1;
219
        rti = find_rti(ifp);
220
 
221
        /*
222
         * In the IGMPv2 specification, there are 3 states and a flag.
223
         *
224
         * In Non-Member state, we simply don't have a membership record.
225
         * In Delaying Member state, our timer is running (inm->inm_timer)
226
         * In Idle Member state, our timer is not running (inm->inm_timer==0)
227
         *
228
         * The flag is inm->inm_state, it is set to IGMP_OTHERMEMBER if
229
         * we have heard a report from another member, or IGMP_IREPORTEDLAST
230
         * if I sent the last report.
231
         */
232
        switch (igmp->igmp_type) {
233
 
234
        case IGMP_MEMBERSHIP_QUERY:
235
                ++igmpstat.igps_rcv_queries;
236
 
237
                if (ifp->if_flags & IFF_LOOPBACK)
238
                        break;
239
 
240
                if (igmp->igmp_code == 0) {
241
                        /*
242
                         * Old router.  Remember that the querier on this
243
                         * interface is old, and set the timer to the
244
                         * value in RFC 1112.
245
                         */
246
 
247
                        rti->rti_type = IGMP_V1_ROUTER;
248
                        rti->rti_time = 0;
249
 
250
                        timer = IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ;
251
 
252
                        if (ip->ip_dst.s_addr != igmp_all_hosts_group ||
253
                            igmp->igmp_group.s_addr != 0) {
254
                                ++igmpstat.igps_rcv_badqueries;
255
                                m_freem(m);
256
                                return;
257
                        }
258
                } else {
259
                        /*
260
                         * New router.  Simply do the new validity check.
261
                         */
262
 
263
                        if (igmp->igmp_group.s_addr != 0 &&
264
                            !IN_MULTICAST(ntohl(igmp->igmp_group.s_addr))) {
265
                                ++igmpstat.igps_rcv_badqueries;
266
                                m_freem(m);
267
                                return;
268
                        }
269
                }
270
 
271
                /*
272
                 * - Start the timers in all of our membership records
273
                 *   that the query applies to for the interface on
274
                 *   which the query arrived excl. those that belong
275
                 *   to the "all-hosts" group (224.0.0.1).
276
                 * - Restart any timer that is already running but has
277
                 *   a value longer than the requested timeout.
278
                 * - Use the value specified in the query message as
279
                 *   the maximum timeout.
280
                 */
281
                IN_FIRST_MULTI(step, inm);
282
                while (inm != NULL) {
283
                        if (inm->inm_ifp == ifp &&
284
                            inm->inm_addr.s_addr != igmp_all_hosts_group &&
285
                            (igmp->igmp_group.s_addr == 0 ||
286
                             igmp->igmp_group.s_addr == inm->inm_addr.s_addr)) {
287
                                if (inm->inm_timer == 0 ||
288
                                    inm->inm_timer > timer) {
289
                                        inm->inm_timer =
290
                                                IGMP_RANDOM_DELAY(timer);
291
                                        igmp_timers_are_running = 1;
292
                                }
293
                        }
294
                        IN_NEXT_MULTI(step, inm);
295
                }
296
 
297
                break;
298
 
299
        case IGMP_V1_MEMBERSHIP_REPORT:
300
        case IGMP_V2_MEMBERSHIP_REPORT:
301
                /*
302
                 * For fast leave to work, we have to know that we are the
303
                 * last person to send a report for this group.  Reports
304
                 * can potentially get looped back if we are a multicast
305
                 * router, so discard reports sourced by me.
306
                 */
307
                IFP_TO_IA(ifp, ia);
308
                if (ia && ip->ip_src.s_addr == IA_SIN(ia)->sin_addr.s_addr)
309
                        break;
310
 
311
                ++igmpstat.igps_rcv_reports;
312
 
313
                if (ifp->if_flags & IFF_LOOPBACK)
314
                        break;
315
 
316
                if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr))) {
317
                        ++igmpstat.igps_rcv_badreports;
318
                        m_freem(m);
319
                        return;
320
                }
321
 
322
                /*
323
                 * KLUDGE: if the IP source address of the report has an
324
                 * unspecified (i.e., zero) subnet number, as is allowed for
325
                 * a booting host, replace it with the correct subnet number
326
                 * so that a process-level multicast routing demon can
327
                 * determine which subnet it arrived from.  This is necessary
328
                 * to compensate for the lack of any way for a process to
329
                 * determine the arrival interface of an incoming packet.
330
                 */
331
                if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0)
332
                        if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet);
333
 
334
                /*
335
                 * If we belong to the group being reported, stop
336
                 * our timer for that group.
337
                 */
338
                IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
339
 
340
                if (inm != NULL) {
341
                        inm->inm_timer = 0;
342
                        ++igmpstat.igps_rcv_ourreports;
343
 
344
                        inm->inm_state = IGMP_OTHERMEMBER;
345
                }
346
 
347
                break;
348
        }
349
 
350
        /*
351
         * Pass all valid IGMP packets up to any process(es) listening
352
         * on a raw IGMP socket.
353
         */
354
        rip_input(m, off);
355
}
356
 
357
void
358
igmp_joingroup(inm)
359
        struct in_multi *inm;
360
{
361
        int s = splnet();
362
 
363
        if (inm->inm_addr.s_addr == igmp_all_hosts_group
364
            || inm->inm_ifp->if_flags & IFF_LOOPBACK) {
365
                inm->inm_timer = 0;
366
                inm->inm_state = IGMP_OTHERMEMBER;
367
        } else {
368
                inm->inm_rti = find_rti(inm->inm_ifp);
369
                igmp_sendpkt(inm, inm->inm_rti->rti_type, 0);
370
                inm->inm_timer = IGMP_RANDOM_DELAY(
371
                                        IGMP_MAX_HOST_REPORT_DELAY*PR_FASTHZ);
372
                inm->inm_state = IGMP_IREPORTEDLAST;
373
                igmp_timers_are_running = 1;
374
        }
375
        splx(s);
376
}
377
 
378
void
379
igmp_leavegroup(inm)
380
        struct in_multi *inm;
381
{
382
        if (inm->inm_state == IGMP_IREPORTEDLAST &&
383
            inm->inm_addr.s_addr != igmp_all_hosts_group &&
384
            !(inm->inm_ifp->if_flags & IFF_LOOPBACK) &&
385
            inm->inm_rti->rti_type != IGMP_V1_ROUTER)
386
                igmp_sendpkt(inm, IGMP_V2_LEAVE_GROUP, igmp_all_rtrs_group);
387
}
388
 
389
void
390
igmp_fasttimo()
391
{
392
        register struct in_multi *inm;
393
        struct in_multistep step;
394
        int s;
395
 
396
        /*
397
         * Quick check to see if any work needs to be done, in order
398
         * to minimize the overhead of fasttimo processing.
399
         */
400
 
401
        if (!igmp_timers_are_running)
402
                return;
403
 
404
        s = splnet();
405
        igmp_timers_are_running = 0;
406
        IN_FIRST_MULTI(step, inm);
407
        while (inm != NULL) {
408
                if (inm->inm_timer == 0) {
409
                        /* do nothing */
410
                } else if (--inm->inm_timer == 0) {
411
                        igmp_sendpkt(inm, inm->inm_rti->rti_type, 0);
412
                        inm->inm_state = IGMP_IREPORTEDLAST;
413
                } else {
414
                        igmp_timers_are_running = 1;
415
                }
416
                IN_NEXT_MULTI(step, inm);
417
        }
418
        splx(s);
419
}
420
 
421
void
422
igmp_slowtimo()
423
{
424
        int s = splnet();
425
        register struct router_info *rti =  Head;
426
 
427
#ifdef IGMP_DEBUG
428
        printf("[igmp.c,_slowtimo] -- > entering \n");
429
#endif
430
        while (rti) {
431
            if (rti->rti_type == IGMP_V1_ROUTER) {
432
                rti->rti_time++;
433
                if (rti->rti_time >= IGMP_AGE_THRESHOLD) {
434
                        rti->rti_type = IGMP_V2_ROUTER;
435
                }
436
            }
437
            rti = rti->rti_next;
438
        }
439
#ifdef IGMP_DEBUG       
440
        printf("[igmp.c,_slowtimo] -- > exiting \n");
441
#endif
442
        splx(s);
443
}
444
 
445
static struct route igmprt;
446
 
447
static void
448
igmp_sendpkt(inm, type, addr)
449
        struct in_multi *inm;
450
        int type;
451
        unsigned long addr;
452
{
453
        struct mbuf *m;
454
        struct igmp *igmp;
455
        struct ip *ip;
456
        struct ip_moptions imo;
457
 
458
        MGETHDR(m, M_DONTWAIT, MT_HEADER);
459
        if (m == NULL)
460
                return;
461
 
462
        m->m_pkthdr.rcvif = loif;
463
        m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
464
        MH_ALIGN(m, IGMP_MINLEN + sizeof(struct ip));
465
        m->m_data += sizeof(struct ip);
466
        m->m_len = IGMP_MINLEN;
467
        igmp = mtod(m, struct igmp *);
468
        igmp->igmp_type   = type;
469
        igmp->igmp_code   = 0;
470
        igmp->igmp_group  = inm->inm_addr;
471
        igmp->igmp_cksum  = 0;
472
        igmp->igmp_cksum  = in_cksum(m, IGMP_MINLEN);
473
 
474
        m->m_data -= sizeof(struct ip);
475
        m->m_len += sizeof(struct ip);
476
        ip = mtod(m, struct ip *);
477
        ip->ip_tos        = 0;
478
        ip->ip_len        = sizeof(struct ip) + IGMP_MINLEN;
479
        ip->ip_off        = 0;
480
        ip->ip_p          = IPPROTO_IGMP;
481
        ip->ip_src.s_addr = INADDR_ANY;
482
        ip->ip_dst.s_addr = addr ? addr : igmp->igmp_group.s_addr;
483
 
484
        imo.imo_multicast_ifp  = inm->inm_ifp;
485
        imo.imo_multicast_ttl  = 1;
486
        imo.imo_multicast_vif  = -1;
487
        /*
488
         * Request loopback of the report if we are acting as a multicast
489
         * router, so that the process-level routing demon can hear it.
490
         */
491
        imo.imo_multicast_loop = (ip_mrouter != NULL);
492
 
493
        /*
494
         * XXX
495
         * Do we have to worry about reentrancy here?  Don't think so.
496
         */
497
        ip_output(m, router_alert, &igmprt, 0, &imo);
498
 
499
        ++igmpstat.igps_snd_reports;
500
}

powered by: WebSVN 2.1.0

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