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

Subversion Repositories openrisc_me

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

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

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

powered by: WebSVN 2.1.0

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