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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [ethernet/] [lwIP_132/] [src/] [core/] [ipv4/] [igmp.c] - Blame information for rev 606

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 606 jeremybenn
/**
2
 * @file
3
 * IGMP - Internet Group Management Protocol
4
 *
5
 */
6
 
7
/*
8
 * Copyright (c) 2002 CITEL Technologies Ltd.
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
20
 *    may be used to endorse or promote products derived from this software
21
 *    without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
24
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 *
35
 * This file is a contribution to the lwIP TCP/IP stack.
36
 * The Swedish Institute of Computer Science and Adam Dunkels
37
 * are specifically granted permission to redistribute this
38
 * source code.
39
*/
40
 
41
/*-------------------------------------------------------------
42
Note 1)
43
Although the rfc requires V1 AND V2 capability
44
we will only support v2 since now V1 is very old (August 1989)
45
V1 can be added if required
46
 
47
a debug print and statistic have been implemented to
48
show this up.
49
-------------------------------------------------------------
50
-------------------------------------------------------------
51
Note 2)
52
A query for a specific group address (as opposed to ALLHOSTS)
53
has now been implemented as I am unsure if it is required
54
 
55
a debug print and statistic have been implemented to
56
show this up.
57
-------------------------------------------------------------
58
-------------------------------------------------------------
59
Note 3)
60
The router alert rfc 2113 is implemented in outgoing packets
61
but not checked rigorously incoming
62
-------------------------------------------------------------
63
Steve Reynolds
64
------------------------------------------------------------*/
65
 
66
/*-----------------------------------------------------------------------------
67
 * RFC 988  - Host extensions for IP multicasting                         - V0
68
 * RFC 1054 - Host extensions for IP multicasting                         -
69
 * RFC 1112 - Host extensions for IP multicasting                         - V1
70
 * RFC 2236 - Internet Group Management Protocol, Version 2               - V2  <- this code is based on this RFC (it's the "de facto" standard)
71
 * RFC 3376 - Internet Group Management Protocol, Version 3               - V3
72
 * RFC 4604 - Using Internet Group Management Protocol Version 3...       - V3+
73
 * RFC 2113 - IP Router Alert Option                                      -
74
 *----------------------------------------------------------------------------*/
75
 
76
/*-----------------------------------------------------------------------------
77
 * Includes
78
 *----------------------------------------------------------------------------*/
79
 
80
#include "lwip/opt.h"
81
 
82
#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
83
 
84
#include "lwip/igmp.h"
85
#include "lwip/debug.h"
86
#include "lwip/def.h"
87
#include "lwip/mem.h"
88
#include "lwip/ip.h"
89
#include "lwip/inet.h"
90
#include "lwip/inet_chksum.h"
91
#include "lwip/netif.h"
92
#include "lwip/icmp.h"
93
#include "lwip/udp.h"
94
#include "lwip/tcp.h"
95
#include "lwip/stats.h"
96
 
97
#include "string.h"
98
 
99
/*-----------------------------------------------------------------------------
100
 * Globales
101
 *----------------------------------------------------------------------------*/
102
 
103
static struct igmp_group* igmp_group_list;
104
static struct ip_addr     allsystems;
105
static struct ip_addr     allrouters;
106
 
107
/**
108
 * Initialize the IGMP module
109
 */
110
void
111
igmp_init(void)
112
{
113
  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
114
 
115
  IP4_ADDR(&allsystems, 224, 0, 0, 1);
116
  IP4_ADDR(&allrouters, 224, 0, 0, 2);
117
}
118
 
119
#ifdef LWIP_DEBUG
120
/**
121
 * Dump global IGMP groups list
122
 */
123
void
124
igmp_dump_group_list()
125
{
126
  struct igmp_group *group = igmp_group_list;
127
 
128
  while (group != NULL) {
129
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
130
    ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
131
    LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
132
    group = group->next;
133
  }
134
  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
135
}
136
#else
137
#define igmp_dump_group_list()
138
#endif /* LWIP_DEBUG */
139
 
140
/**
141
 * Start IGMP processing on interface
142
 *
143
 * @param netif network interface on which start IGMP processing
144
 */
145
err_t
146
igmp_start(struct netif *netif)
147
{
148
  struct igmp_group* group;
149
 
150
  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
151
 
152
  group = igmp_lookup_group(netif, &allsystems);
153
 
154
  if (group != NULL) {
155
    group->group_state = IGMP_GROUP_IDLE_MEMBER;
156
    group->use++;
157
 
158
    /* Allow the igmp messages at the MAC level */
159
    if (netif->igmp_mac_filter != NULL) {
160
      LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
161
      ip_addr_debug_print(IGMP_DEBUG, &allsystems);
162
      LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
163
      netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);
164
    }
165
 
166
    return ERR_OK;
167
  }
168
 
169
  return ERR_MEM;
170
}
171
 
172
/**
173
 * Stop IGMP processing on interface
174
 *
175
 * @param netif network interface on which stop IGMP processing
176
 */
177
err_t
178
igmp_stop(struct netif *netif)
179
{
180
  struct igmp_group *group = igmp_group_list;
181
  struct igmp_group *prev  = NULL;
182
  struct igmp_group *next;
183
 
184
  /* look for groups joined on this interface further down the list */
185
  while (group != NULL) {
186
    next = group->next;
187
    /* is it a group joined on this interface? */
188
    if (group->interface == netif) {
189
      /* is it the first group of the list? */
190
      if (group == igmp_group_list) {
191
        igmp_group_list = next;
192
      }
193
      /* is there a "previous" group defined? */
194
      if (prev != NULL) {
195
        prev->next = next;
196
      }
197
      /* disable the group at the MAC level */
198
      if (netif->igmp_mac_filter != NULL) {
199
        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
200
        ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
201
        LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
202
        netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
203
      }
204
      /* free group */
205
      memp_free(MEMP_IGMP_GROUP, group);
206
    } else {
207
      /* change the "previous" */
208
      prev = group;
209
    }
210
    /* move to "next" */
211
    group = next;
212
  }
213
  return ERR_OK;
214
}
215
 
216
/**
217
 * Report IGMP memberships for this interface
218
 *
219
 * @param netif network interface on which report IGMP memberships
220
 */
221
void
222
igmp_report_groups( struct netif *netif)
223
{
224
  struct igmp_group *group = igmp_group_list;
225
 
226
  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
227
 
228
  while (group != NULL) {
229
    if (group->interface == netif) {
230
      igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR);
231
    }
232
    group = group->next;
233
  }
234
}
235
 
236
/**
237
 * Search for a group in the global igmp_group_list
238
 *
239
 * @param ifp the network interface for which to look
240
 * @param addr the group ip address to search for
241
 * @return a struct igmp_group* if the group has been found,
242
 *         NULL if the group wasn't found.
243
 */
244
struct igmp_group *
245
igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)
246
{
247
  struct igmp_group *group = igmp_group_list;
248
 
249
  while (group != NULL) {
250
    if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
251
      return group;
252
    }
253
    group = group->next;
254
  }
255
 
256
  /* to be clearer, we return NULL here instead of
257
   * 'group' (which is also NULL at this point).
258
   */
259
  return NULL;
260
}
261
 
262
/**
263
 * Search for a specific igmp group and create a new one if not found-
264
 *
265
 * @param ifp the network interface for which to look
266
 * @param addr the group ip address to search
267
 * @return a struct igmp_group*,
268
 *         NULL on memory error.
269
 */
270
struct igmp_group *
271
igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
272
{
273
  struct igmp_group *group = igmp_group_list;
274
 
275
  /* Search if the group already exists */
276
  group = igmp_lookfor_group(ifp, addr);
277
  if (group != NULL) {
278
    /* Group already exists. */
279
    return group;
280
  }
281
 
282
  /* Group doesn't exist yet, create a new one */
283
  group = memp_malloc(MEMP_IGMP_GROUP);
284
  if (group != NULL) {
285
    group->interface          = ifp;
286
    ip_addr_set(&(group->group_address), addr);
287
    group->timer              = 0; /* Not running */
288
    group->group_state        = IGMP_GROUP_NON_MEMBER;
289
    group->last_reporter_flag = 0;
290
    group->use                = 0;
291
    group->next               = igmp_group_list;
292
 
293
    igmp_group_list = group;
294
  }
295
 
296
  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
297
  ip_addr_debug_print(IGMP_DEBUG, addr);
298
  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
299
 
300
  return group;
301
}
302
 
303
/**
304
 * Remove a group in the global igmp_group_list
305
 *
306
 * @param group the group to remove from the global igmp_group_list
307
 * @return ERR_OK if group was removed from the list, an err_t otherwise
308
 */
309
err_t
310
igmp_remove_group(struct igmp_group *group)
311
{
312
  err_t err = ERR_OK;
313
 
314
  /* Is it the first group? */
315
  if (igmp_group_list == group) {
316
    igmp_group_list = group->next;
317
  } else {
318
    /* look for group further down the list */
319
    struct igmp_group *tmpGroup;
320
    for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
321
      if (tmpGroup->next == group) {
322
        tmpGroup->next = group->next;
323
        break;
324
      }
325
    }
326
    /* Group not found in the global igmp_group_list */
327
    if (tmpGroup == NULL)
328
      err = ERR_ARG;
329
  }
330
  /* free group */
331
  memp_free(MEMP_IGMP_GROUP, group);
332
 
333
  return err;
334
}
335
 
336
/**
337
 * Called from ip_input() if a new IGMP packet is received.
338
 *
339
 * @param p received igmp packet, p->payload pointing to the ip header
340
 * @param inp network interface on which the packet was received
341
 * @param dest destination ip address of the igmp packet
342
 */
343
void
344
igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
345
{
346
  struct ip_hdr *    iphdr;
347
  struct igmp_msg*   igmp;
348
  struct igmp_group* group;
349
  struct igmp_group* groupref;
350
 
351
  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
352
  iphdr = p->payload;
353
  if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
354
    pbuf_free(p);
355
    IGMP_STATS_INC(igmp.lenerr);
356
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
357
    return;
358
  }
359
 
360
  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
361
  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
362
  LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
363
  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
364
  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
365
 
366
  /* Now calculate and check the checksum */
367
  igmp = (struct igmp_msg *)p->payload;
368
  if (inet_chksum(igmp, p->len)) {
369
    pbuf_free(p);
370
    IGMP_STATS_INC(igmp.chkerr);
371
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
372
    return;
373
  }
374
 
375
  /* Packet is ok so find an existing group */
376
  group = igmp_lookfor_group(inp, dest); /* use the incoming IP address! */
377
 
378
  /* If group can be found or create... */
379
  if (!group) {
380
    pbuf_free(p);
381
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
382
    return;
383
  }
384
 
385
  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
386
  switch (igmp->igmp_msgtype) {
387
   case IGMP_MEMB_QUERY: {
388
     /* IGMP_MEMB_QUERY to the "all systems" address ? */
389
     if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) {
390
       /* THIS IS THE GENERAL QUERY */
391
       LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
392
 
393
       if (igmp->igmp_maxresp == 0) {
394
         IGMP_STATS_INC(igmp.v1_rxed);
395
         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
396
         igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
397
       }
398
 
399
       IGMP_STATS_INC(igmp.group_query_rxed);
400
       groupref = igmp_group_list;
401
       while (groupref) {
402
         /* Do not send messages on the all systems group address! */
403
         if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
404
           igmp_delaying_member( groupref, igmp->igmp_maxresp);
405
         }
406
         groupref = groupref->next;
407
       }
408
     } else {
409
       /* IGMP_MEMB_QUERY to a specific group ? */
410
       if (group->group_address.addr != 0) {
411
         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
412
         ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
413
         if (ip_addr_cmp (dest, &allsystems)) {
414
           LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
415
           /* we first need to re-lookfor the group since we used dest last time */
416
           group = igmp_lookfor_group(inp, &igmp->igmp_group_address);
417
         } else {
418
           LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
419
         }
420
 
421
         if (group != NULL) {
422
           IGMP_STATS_INC(igmp.unicast_query);
423
           igmp_delaying_member( group, igmp->igmp_maxresp);
424
         }
425
       }
426
     }
427
     break;
428
   }
429
   case IGMP_V2_MEMB_REPORT: {
430
     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
431
 
432
     IGMP_STATS_INC(igmp.report_rxed);
433
     if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
434
       /* This is on a specific group we have already looked up */
435
       group->timer = 0; /* stopped */
436
       group->group_state = IGMP_GROUP_IDLE_MEMBER;
437
       group->last_reporter_flag = 0;
438
     }
439
     break;
440
   }
441
   default: {
442
     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
443
       igmp->igmp_msgtype, group->group_state, &group, group->interface));
444
     break;
445
   }
446
  }
447
 
448
  pbuf_free(p);
449
  return;
450
}
451
 
452
/**
453
 * Join a group on one network interface.
454
 *
455
 * @param ifaddr ip address of the network interface which should join a new group
456
 * @param groupaddr the ip address of the group which to join
457
 * @return ERR_OK if group was joined on the netif(s), an err_t otherwise
458
 */
459
err_t
460
igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
461
{
462
  err_t              err = ERR_VAL; /* no matching interface */
463
  struct igmp_group *group;
464
  struct netif      *netif;
465
 
466
  /* make sure it is multicast address */
467
  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
468
  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
469
 
470
  /* loop through netif's */
471
  netif = netif_list;
472
  while (netif != NULL) {
473
    /* Should we join this interface ? */
474
    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
475
      /* find group or create a new one if not found */
476
      group = igmp_lookup_group(netif, groupaddr);
477
 
478
      if (group != NULL) {
479
        /* This should create a new group, check the state to make sure */
480
        if (group->group_state != IGMP_GROUP_NON_MEMBER) {
481
          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
482
        } else {
483
          /* OK - it was new group */
484
          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
485
          ip_addr_debug_print(IGMP_DEBUG, groupaddr);
486
          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
487
 
488
          /* If first use of the group, allow the group at the MAC level */
489
          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
490
            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
491
            ip_addr_debug_print(IGMP_DEBUG, groupaddr);
492
            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
493
            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
494
          }
495
 
496
          IGMP_STATS_INC(igmp.join_sent);
497
          igmp_send(group, IGMP_V2_MEMB_REPORT);
498
 
499
          igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
500
 
501
          /* Need to work out where this timer comes from */
502
          group->group_state = IGMP_GROUP_DELAYING_MEMBER;
503
        }
504
        /* Increment group use */
505
        group->use++;
506
        /* Join on this interface */
507
        err = ERR_OK;
508
      } else {
509
        /* Return an error even if some network interfaces are joined */
510
        /** @todo undo any other netif already joined */
511
        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
512
        return ERR_MEM;
513
      }
514
    }
515
    /* proceed to next network interface */
516
    netif = netif->next;
517
  }
518
 
519
  return err;
520
}
521
 
522
/**
523
 * Leave a group on one network interface.
524
 *
525
 * @param ifaddr ip address of the network interface which should leave a group
526
 * @param groupaddr the ip address of the group which to leave
527
 * @return ERR_OK if group was left on the netif(s), an err_t otherwise
528
 */
529
err_t
530
igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
531
{
532
  err_t              err = ERR_VAL; /* no matching interface */
533
  struct igmp_group *group;
534
  struct netif      *netif;
535
 
536
  /* make sure it is multicast address */
537
  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
538
  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
539
 
540
  /* loop through netif's */
541
  netif = netif_list;
542
  while (netif != NULL) {
543
    /* Should we leave this interface ? */
544
    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
545
      /* find group */
546
      group = igmp_lookfor_group(netif, groupaddr);
547
 
548
      if (group != NULL) {
549
        /* Only send a leave if the flag is set according to the state diagram */
550
        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
551
        ip_addr_debug_print(IGMP_DEBUG, groupaddr);
552
        LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
553
 
554
        /* If there is no other use of the group */
555
        if (group->use <= 1) {
556
          /* If we are the last reporter for this group */
557
          if (group->last_reporter_flag) {
558
            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
559
            IGMP_STATS_INC(igmp.leave_sent);
560
            igmp_send(group, IGMP_LEAVE_GROUP);
561
          }
562
 
563
          /* Disable the group at the MAC level */
564
          if (netif->igmp_mac_filter != NULL) {
565
            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
566
            ip_addr_debug_print(IGMP_DEBUG, groupaddr);
567
            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
568
            netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
569
          }
570
 
571
          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
572
          ip_addr_debug_print(IGMP_DEBUG, groupaddr);
573
          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
574
 
575
          /* Free the group */
576
          igmp_remove_group(group);
577
        } else {
578
          /* Decrement group use */
579
          group->use--;
580
        }
581
        /* Leave on this interface */
582
        err = ERR_OK;
583
      } else {
584
        /* It's not a fatal error on "leavegroup" */
585
        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
586
      }
587
    }
588
    /* proceed to next network interface */
589
    netif = netif->next;
590
  }
591
 
592
  return err;
593
}
594
 
595
/**
596
 * The igmp timer function (both for NO_SYS=1 and =0)
597
 * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
598
 */
599
void
600
igmp_tmr(void)
601
{
602
  struct igmp_group *group = igmp_group_list;
603
 
604
  while (group != NULL) {
605
    if (group->timer != 0) {
606
      group->timer -= 1;
607
      if (group->timer == 0) {
608
        igmp_timeout(group);
609
      }
610
    }
611
    group = group->next;
612
  }
613
}
614
 
615
/**
616
 * Called if a timeout for one group is reached.
617
 * Sends a report for this group.
618
 *
619
 * @param group an igmp_group for which a timeout is reached
620
 */
621
void
622
igmp_timeout(struct igmp_group *group)
623
{
624
  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
625
  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
626
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
627
    ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
628
    LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
629
 
630
    igmp_send(group, IGMP_V2_MEMB_REPORT);
631
  }
632
}
633
 
634
/**
635
 * Start a timer for an igmp group
636
 *
637
 * @param group the igmp_group for which to start a timer
638
 * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
639
 *        every call to igmp_tmr())
640
 */
641
void
642
igmp_start_timer(struct igmp_group *group, u8_t max_time)
643
{
644
  /**
645
   * @todo Important !! this should be random 0 -> max_time. Find out how to do this
646
   */
647
  group->timer = max_time;
648
}
649
 
650
/**
651
 * Stop a timer for an igmp_group
652
 *
653
 * @param group the igmp_group for which to stop the timer
654
 */
655
void
656
igmp_stop_timer(struct igmp_group *group)
657
{
658
  group->timer = 0;
659
}
660
 
661
/**
662
 * Delaying membership report for a group if necessary
663
 *
664
 * @param group the igmp_group for which "delaying" membership report
665
 * @param maxresp query delay
666
 */
667
void
668
igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
669
{
670
  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
671
     ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
672
    igmp_start_timer(group, (maxresp)/2);
673
    group->group_state = IGMP_GROUP_DELAYING_MEMBER;
674
  }
675
}
676
 
677
 
678
/**
679
 * Sends an IP packet on a network interface. This function constructs the IP header
680
 * and calculates the IP header checksum. If the source IP address is NULL,
681
 * the IP address of the outgoing network interface is filled in as source address.
682
 *
683
 * @param p the packet to send (p->payload points to the data, e.g. next
684
            protocol header; if dest == IP_HDRINCL, p already includes an IP
685
            header and p->payload points to that IP header)
686
 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
687
 *         IP  address of the netif used to send is used as source address)
688
 * @param dest the destination IP address to send the packet to
689
 * @param ttl the TTL value to be set in the IP header
690
 * @param proto the PROTOCOL to be set in the IP header
691
 * @param netif the netif on which to send this packet
692
 * @return ERR_OK if the packet was sent OK
693
 *         ERR_BUF if p doesn't have enough space for IP/LINK headers
694
 *         returns errors returned by netif->output
695
 */
696
err_t
697
igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
698
                  u8_t ttl, u8_t proto, struct netif *netif)
699
{
700
  /* This is the "router alert" option */
701
  u16_t ra[2];
702
  ra[0] = htons (ROUTER_ALERT);
703
  ra[1] = 0x0000; /* Router shall examine packet */
704
  return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN);
705
}
706
 
707
/**
708
 * Send an igmp packet to a specific group.
709
 *
710
 * @param group the group to which to send the packet
711
 * @param type the type of igmp packet to send
712
 */
713
void
714
igmp_send(struct igmp_group *group, u8_t type)
715
{
716
  struct pbuf*     p    = NULL;
717
  struct igmp_msg* igmp = NULL;
718
  struct ip_addr   src  = {0};
719
  struct ip_addr*  dest = NULL;
720
 
721
  /* IP header + "router alert" option + IGMP header */
722
  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
723
 
724
  if (p) {
725
    igmp = p->payload;
726
    LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
727
               (p->len >= sizeof(struct igmp_msg)));
728
    ip_addr_set(&src, &((group->interface)->ip_addr));
729
 
730
    if (type == IGMP_V2_MEMB_REPORT) {
731
      dest = &(group->group_address);
732
      IGMP_STATS_INC(igmp.report_sent);
733
      ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
734
      group->last_reporter_flag = 1; /* Remember we were the last to report */
735
    } else {
736
      if (type == IGMP_LEAVE_GROUP) {
737
        dest = &allrouters;
738
        ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
739
      }
740
    }
741
 
742
    if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
743
      igmp->igmp_msgtype  = type;
744
      igmp->igmp_maxresp  = 0;
745
      igmp->igmp_checksum = 0;
746
      igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);
747
 
748
      igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);
749
    }
750
 
751
    pbuf_free(p);
752
  } else {
753
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
754
  }
755
}
756
 
757
#endif /* LWIP_IGMP */

powered by: WebSVN 2.1.0

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