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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [libnetworking/] [netinet/] [igmp.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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