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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [ethernet/] [lwIP_130/] [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 %x\n", (int) 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 %x\n", (int) 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 %x\n", (int) 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 %x\n", (int) 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 %x\n", (int) 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 %x\n", (int) 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 %x\n", (int) 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 %x in state %x on group %x on if %x\n", (int) igmp->igmp_msgtype, (int) group->group_state, (int) &group, (int) group->interface));
443
     break;
444
   }
445
  }
446
 
447
  pbuf_free(p);
448
  return;
449
}
450
 
451
/**
452
 * Join a group on one network interface.
453
 *
454
 * @param ifaddr ip address of the network interface which should join a new group
455
 * @param groupaddr the ip address of the group which to join
456
 * @return ERR_OK if group was joined on the netif(s), an err_t otherwise
457
 */
458
err_t
459
igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
460
{
461
  err_t              err = ERR_VAL; /* no matching interface */
462
  struct igmp_group *group;
463
  struct netif      *netif;
464
 
465
  /* make sure it is multicast address */
466
  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
467
  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
468
 
469
  /* loop through netif's */
470
  netif = netif_list;
471
  while (netif != NULL) {
472
    /* Should we join this interface ? */
473
    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
474
      /* find group or create a new one if not found */
475
      group = igmp_lookup_group(netif, groupaddr);
476
 
477
      if (group != NULL) {
478
        /* This should create a new group, check the state to make sure */
479
        if (group->group_state != IGMP_GROUP_NON_MEMBER) {
480
          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
481
        } else {
482
          /* OK - it was new group */
483
          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
484
          ip_addr_debug_print(IGMP_DEBUG, groupaddr);
485
          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
486
 
487
          /* If first use of the group, allow the group at the MAC level */
488
          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
489
            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
490
            ip_addr_debug_print(IGMP_DEBUG, groupaddr);
491
            LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
492
            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
493
          }
494
 
495
          IGMP_STATS_INC(igmp.join_sent);
496
          igmp_send(group, IGMP_V2_MEMB_REPORT);
497
 
498
          igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
499
 
500
          /* Need to work out where this timer comes from */
501
          group->group_state = IGMP_GROUP_DELAYING_MEMBER;
502
        }
503
        /* Increment group use */
504
        group->use++;
505
        /* Join on this interface */
506
        err = ERR_OK;
507
      } else {
508
        /* Return an error even if some network interfaces are joined */
509
        /** @todo undo any other netif already joined */
510
        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
511
        return ERR_MEM;
512
      }
513
    }
514
    /* proceed to next network interface */
515
    netif = netif->next;
516
  }
517
 
518
  return err;
519
}
520
 
521
/**
522
 * Leave a group on one network interface.
523
 *
524
 * @param ifaddr ip address of the network interface which should leave a group
525
 * @param groupaddr the ip address of the group which to leave
526
 * @return ERR_OK if group was left on the netif(s), an err_t otherwise
527
 */
528
err_t
529
igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
530
{
531
  err_t              err = ERR_VAL; /* no matching interface */
532
  struct igmp_group *group;
533
  struct netif      *netif;
534
 
535
  /* make sure it is multicast address */
536
  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
537
  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
538
 
539
  /* loop through netif's */
540
  netif = netif_list;
541
  while (netif != NULL) {
542
    /* Should we leave this interface ? */
543
    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
544
      /* find group */
545
      group = igmp_lookfor_group(netif, groupaddr);
546
 
547
      if (group != NULL) {
548
        /* Only send a leave if the flag is set according to the state diagram */
549
        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
550
        ip_addr_debug_print(IGMP_DEBUG, groupaddr);
551
        LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
552
 
553
        /* If there is no other use of the group */
554
        if (group->use <= 1) {
555
          /* If we are the last reporter for this group */
556
          if (group->last_reporter_flag) {
557
            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
558
            IGMP_STATS_INC(igmp.leave_sent);
559
            igmp_send(group, IGMP_LEAVE_GROUP);
560
          }
561
 
562
          /* Disable the group at the MAC level */
563
          if (netif->igmp_mac_filter != NULL) {
564
            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
565
            ip_addr_debug_print(IGMP_DEBUG, groupaddr);
566
            LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
567
            netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
568
          }
569
 
570
          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
571
          ip_addr_debug_print(IGMP_DEBUG, groupaddr);
572
          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
573
 
574
          /* Free the group */
575
          igmp_remove_group(group);
576
        } else {
577
          /* Decrement group use */
578
          group->use--;
579
        }
580
        /* Leave on this interface */
581
        err = ERR_OK;
582
      } else {
583
        /* It's not a fatal error on "leavegroup" */
584
        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
585
      }
586
    }
587
    /* proceed to next network interface */
588
    netif = netif->next;
589
  }
590
 
591
  return err;
592
}
593
 
594
/**
595
 * The igmp timer function (both for NO_SYS=1 and =0)
596
 * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
597
 */
598
void
599
igmp_tmr(void)
600
{
601
  struct igmp_group *group = igmp_group_list;
602
 
603
  while (group != NULL) {
604
    if (group->timer != 0) {
605
      group->timer -= 1;
606
      if (group->timer == 0) {
607
        igmp_timeout(group);
608
      }
609
    }
610
    group = group->next;
611
  }
612
}
613
 
614
/**
615
 * Called if a timeout for one group is reached.
616
 * Sends a report for this group.
617
 *
618
 * @param group an igmp_group for which a timeout is reached
619
 */
620
void
621
igmp_timeout(struct igmp_group *group)
622
{
623
  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
624
  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
625
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
626
    ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
627
    LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));
628
 
629
    igmp_send(group, IGMP_V2_MEMB_REPORT);
630
  }
631
}
632
 
633
/**
634
 * Start a timer for an igmp group
635
 *
636
 * @param group the igmp_group for which to start a timer
637
 * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
638
 *        every call to igmp_tmr())
639
 */
640
void
641
igmp_start_timer(struct igmp_group *group, u8_t max_time)
642
{
643
  /**
644
   * @todo Important !! this should be random 0 -> max_time. Find out how to do this
645
   */
646
  group->timer = max_time;
647
}
648
 
649
/**
650
 * Stop a timer for an igmp_group
651
 *
652
 * @param group the igmp_group for which to stop the timer
653
 */
654
void
655
igmp_stop_timer(struct igmp_group *group)
656
{
657
  group->timer = 0;
658
}
659
 
660
/**
661
 * Delaying membership report for a group if necessary
662
 *
663
 * @param group the igmp_group for which "delaying" membership report
664
 * @param maxresp query delay
665
 */
666
void
667
igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
668
{
669
  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
670
    igmp_start_timer(group, (maxresp)/2);
671
    group->group_state = IGMP_GROUP_DELAYING_MEMBER;
672
  }
673
}
674
 
675
 
676
/**
677
 * Sends an IP packet on a network interface. This function constructs the IP header
678
 * and calculates the IP header checksum. If the source IP address is NULL,
679
 * the IP address of the outgoing network interface is filled in as source address.
680
 *
681
 * @param p the packet to send (p->payload points to the data, e.g. next
682
            protocol header; if dest == IP_HDRINCL, p already includes an IP
683
            header and p->payload points to that IP header)
684
 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
685
 *         IP  address of the netif used to send is used as source address)
686
 * @param dest the destination IP address to send the packet to
687
 * @param ttl the TTL value to be set in the IP header
688
 * @param proto the PROTOCOL to be set in the IP header
689
 * @param netif the netif on which to send this packet
690
 * @return ERR_OK if the packet was sent OK
691
 *         ERR_BUF if p doesn't have enough space for IP/LINK headers
692
 *         returns errors returned by netif->output
693
 */
694
err_t
695
igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
696
                  u8_t ttl, u8_t proto, struct netif *netif)
697
{
698
  static u16_t    ip_id = 0;
699
  struct ip_hdr * iphdr = NULL;
700
  u16_t *         ra    = NULL;
701
 
702
  /* First write in the "router alert" */
703
  if (pbuf_header(p, ROUTER_ALERTLEN)) {
704
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));
705
    return ERR_BUF;
706
  }
707
 
708
  /* This is the "router alert" option */
709
  ra    = p->payload;
710
  ra[0] = htons (ROUTER_ALERT);
711
  ra[1] = 0x0000; /* Router shall examine packet */
712
 
713
  /* now the normal ip header */
714
  if (pbuf_header(p, IP_HLEN)) {
715
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));
716
    return ERR_BUF;
717
  }
718
 
719
  iphdr = p->payload;
720
 
721
  /* Should the IP header be generated or is it already included in p? */
722
  if (dest != IP_HDRINCL) {
723
    /** @todo should be shared with ip.c - ip_output_if */
724
    IPH_TTL_SET(iphdr, ttl);
725
    IPH_PROTO_SET(iphdr, proto);
726
 
727
    ip_addr_set(&(iphdr->dest), dest);
728
 
729
    IPH_VHLTOS_SET(iphdr, 4, ((IP_HLEN + ROUTER_ALERTLEN) / 4), 0/*tos*/);
730
    IPH_LEN_SET(iphdr, htons(p->tot_len));
731
    IPH_OFFSET_SET(iphdr, 0);
732
    IPH_ID_SET(iphdr, htons(ip_id));
733
    ++ip_id;
734
 
735
    if (ip_addr_isany(src)) {
736
      ip_addr_set(&(iphdr->src), &(netif->ip_addr));
737
    } else {
738
      ip_addr_set(&(iphdr->src), src);
739
    }
740
 
741
    IPH_CHKSUM_SET(iphdr, 0);
742
#if CHECKSUM_GEN_IP
743
    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, (IP_HLEN + ROUTER_ALERTLEN)));
744
#endif
745
  } else {
746
    dest = &(iphdr->dest);
747
  }
748
 
749
#if IP_DEBUG
750
  ip_debug_print(p);
751
#endif
752
 
753
  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: sending to if %x\n", (int) netif));
754
 
755
  return netif->output(netif, p, dest);
756
}
757
 
758
/**
759
 * Send an igmp packet to a specific group.
760
 *
761
 * @param group the group to which to send the packet
762
 * @param type the type of igmp packet to send
763
 */
764
void
765
igmp_send(struct igmp_group *group, u8_t type)
766
{
767
  struct pbuf*     p    = NULL;
768
  struct igmp_msg* igmp = NULL;
769
  struct ip_addr   src  = {0};
770
  struct ip_addr*  dest = NULL;
771
 
772
  /* IP header + "router alert" option + IGMP header */
773
  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
774
 
775
  if (p) {
776
    igmp = p->payload;
777
    LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
778
               (p->len >= sizeof(struct igmp_msg)));
779
    ip_addr_set(&src, &((group->interface)->ip_addr));
780
 
781
    if (type == IGMP_V2_MEMB_REPORT) {
782
      dest = &(group->group_address);
783
      IGMP_STATS_INC(igmp.report_sent);
784
      ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
785
      group->last_reporter_flag = 1; /* Remember we were the last to report */
786
    } else {
787
      if (type == IGMP_LEAVE_GROUP) {
788
        dest = &allrouters;
789
        ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
790
      }
791
    }
792
 
793
    if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
794
      igmp->igmp_msgtype  = type;
795
      igmp->igmp_maxresp  = 0;
796
      igmp->igmp_checksum = 0;
797
      igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);
798
 
799
      igmp_ip_output_if( p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);
800
    }
801
 
802
    pbuf_free (p);
803
  } else {
804
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
805
  }
806
}
807
 
808
#endif /* LWIP_IGMP */

powered by: WebSVN 2.1.0

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