⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 igmp.c

📁 lwip-1.4.0
💻 C
📖 第 1 页 / 共 2 页
字号:
  LWIP_DEBUGF(IGMP_DEBUG, (" to address "));  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));  /* Now calculate and check the checksum */  igmp = (struct igmp_msg *)p->payload;  if (inet_chksum(igmp, p->len)) {    pbuf_free(p);    IGMP_STATS_INC(igmp.chkerr);    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));    return;  }  /* Packet is ok so find an existing group */  group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */    /* If group can be found or create... */  if (!group) {    pbuf_free(p);    IGMP_STATS_INC(igmp.drop);    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));    return;  }  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */  switch (igmp->igmp_msgtype) {   case IGMP_MEMB_QUERY: {     /* IGMP_MEMB_QUERY to the "all systems" address ? */     if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) {       /* THIS IS THE GENERAL QUERY */       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)));       if (igmp->igmp_maxresp == 0) {         IGMP_STATS_INC(igmp.rx_v1);         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));         igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;       } else {         IGMP_STATS_INC(igmp.rx_general);       }       groupref = igmp_group_list;       while (groupref) {         /* Do not send messages on the all systems group address! */         if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {           igmp_delaying_member(groupref, igmp->igmp_maxresp);         }         groupref = groupref->next;       }     } else {       /* IGMP_MEMB_QUERY to a specific group ? */       if (!ip_addr_isany(&igmp->igmp_group_address)) {         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));         ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);         if (ip_addr_cmp(dest, &allsystems)) {           ip_addr_t groupaddr;           LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));           /* we first need to re-look for the group since we used dest last time */           ip_addr_copy(groupaddr, igmp->igmp_group_address);           group = igmp_lookfor_group(inp, &groupaddr);         } else {           LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));         }         if (group != NULL) {           IGMP_STATS_INC(igmp.rx_group);           igmp_delaying_member(group, igmp->igmp_maxresp);         } else {           IGMP_STATS_INC(igmp.drop);         }       } else {         IGMP_STATS_INC(igmp.proterr);       }     }     break;   }   case IGMP_V2_MEMB_REPORT: {     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));     IGMP_STATS_INC(igmp.rx_report);     if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {       /* This is on a specific group we have already looked up */       group->timer = 0; /* stopped */       group->group_state = IGMP_GROUP_IDLE_MEMBER;       group->last_reporter_flag = 0;     }     break;   }   default: {     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",       igmp->igmp_msgtype, group->group_state, &group, group->netif));     IGMP_STATS_INC(igmp.proterr);     break;   }  }  pbuf_free(p);  return;}/** * Join a group on one network interface. * * @param ifaddr ip address of the network interface which should join a new group * @param groupaddr the ip address of the group which to join * @return ERR_OK if group was joined on the netif(s), an err_t otherwise */err_tigmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr){  err_t              err = ERR_VAL; /* no matching interface */  struct igmp_group *group;  struct netif      *netif;  /* make sure it is multicast address */  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);  /* loop through netif's */  netif = netif_list;  while (netif != NULL) {    /* Should we join this interface ? */    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {      /* find group or create a new one if not found */      group = igmp_lookup_group(netif, groupaddr);      if (group != NULL) {        /* This should create a new group, check the state to make sure */        if (group->group_state != IGMP_GROUP_NON_MEMBER) {          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));        } else {          /* OK - it was new group */          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));          ip_addr_debug_print(IGMP_DEBUG, groupaddr);          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));          /* If first use of the group, allow the group at the MAC level */          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));            ip_addr_debug_print(IGMP_DEBUG, groupaddr);            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);          }          IGMP_STATS_INC(igmp.tx_join);          igmp_send(group, IGMP_V2_MEMB_REPORT);          igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);          /* Need to work out where this timer comes from */          group->group_state = IGMP_GROUP_DELAYING_MEMBER;        }        /* Increment group use */        group->use++;        /* Join on this interface */        err = ERR_OK;      } else {        /* Return an error even if some network interfaces are joined */        /** @todo undo any other netif already joined */        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));        return ERR_MEM;      }    }    /* proceed to next network interface */    netif = netif->next;  }  return err;}/** * Leave a group on one network interface. * * @param ifaddr ip address of the network interface which should leave a group * @param groupaddr the ip address of the group which to leave * @return ERR_OK if group was left on the netif(s), an err_t otherwise */err_tigmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr){  err_t              err = ERR_VAL; /* no matching interface */  struct igmp_group *group;  struct netif      *netif;  /* make sure it is multicast address */  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);  /* loop through netif's */  netif = netif_list;  while (netif != NULL) {    /* Should we leave this interface ? */    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {      /* find group */      group = igmp_lookfor_group(netif, groupaddr);      if (group != NULL) {        /* Only send a leave if the flag is set according to the state diagram */        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));        ip_addr_debug_print(IGMP_DEBUG, groupaddr);        LWIP_DEBUGF(IGMP_DEBUG, ("\n"));        /* If there is no other use of the group */        if (group->use <= 1) {          /* If we are the last reporter for this group */          if (group->last_reporter_flag) {            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));            IGMP_STATS_INC(igmp.tx_leave);            igmp_send(group, IGMP_LEAVE_GROUP);          }                    /* Disable the group at the MAC level */          if (netif->igmp_mac_filter != NULL) {            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));            ip_addr_debug_print(IGMP_DEBUG, groupaddr);            LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));            netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);          }                    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));          ip_addr_debug_print(IGMP_DEBUG, groupaddr);          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));                              /* Free the group */          igmp_remove_group(group);        } else {          /* Decrement group use */          group->use--;        }        /* Leave on this interface */        err = ERR_OK;      } else {        /* It's not a fatal error on "leavegroup" */        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));      }    }    /* proceed to next network interface */    netif = netif->next;  }  return err;}/** * The igmp timer function (both for NO_SYS=1 and =0) * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). */voidigmp_tmr(void){  struct igmp_group *group = igmp_group_list;  while (group != NULL) {    if (group->timer > 0) {      group->timer--;      if (group->timer == 0) {        igmp_timeout(group);      }    }    group = group->next;  }}/** * Called if a timeout for one group is reached. * Sends a report for this group. * * @param group an igmp_group for which a timeout is reached */static voidigmp_timeout(struct igmp_group *group){  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));    ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));    LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));    IGMP_STATS_INC(igmp.tx_report);    igmp_send(group, IGMP_V2_MEMB_REPORT);  }}/** * Start a timer for an igmp group * * @param group the igmp_group for which to start a timer * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with *        every call to igmp_tmr()) */static voidigmp_start_timer(struct igmp_group *group, u8_t max_time){  /* ensure the input value is > 0 */  if (max_time == 0) {    max_time = 1;  }  /* ensure the random value is > 0 */  group->timer = (LWIP_RAND() % (max_time - 1)) + 1;}/** * Stop a timer for an igmp_group * * @param group the igmp_group for which to stop the timer */static voidigmp_stop_timer(struct igmp_group *group){  group->timer = 0;}/** * Delaying membership report for a group if necessary * * @param group the igmp_group for which "delaying" membership report * @param maxresp query delay */static voidigmp_delaying_member(struct igmp_group *group, u8_t maxresp){  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||     ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) &&      ((group->timer == 0) || (maxresp < group->timer)))) {    igmp_start_timer(group, maxresp);    group->group_state = IGMP_GROUP_DELAYING_MEMBER;  }}/** * Sends an IP packet on a network interface. This function constructs the IP header * and calculates the IP header checksum. If the source IP address is NULL, * the IP address of the outgoing network interface is filled in as source address. * * @param p the packet to send (p->payload points to the data, e.g. next            protocol header; if dest == IP_HDRINCL, p already includes an IP            header and p->payload points to that IP header) * @param src the source IP address to send from (if src == IP_ADDR_ANY, the *         IP  address of the netif used to send is used as source address) * @param dest the destination IP address to send the packet to * @param ttl the TTL value to be set in the IP header * @param proto the PROTOCOL to be set in the IP header * @param netif the netif on which to send this packet * @return ERR_OK if the packet was sent OK *         ERR_BUF if p doesn't have enough space for IP/LINK headers *         returns errors returned by netif->output */static err_tigmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif){  /* This is the "router alert" option */  u16_t ra[2];  ra[0] = PP_HTONS(ROUTER_ALERT);  ra[1] = 0x0000; /* Router shall examine packet */  IGMP_STATS_INC(igmp.xmit);  return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);}/** * Send an igmp packet to a specific group. * * @param group the group to which to send the packet * @param type the type of igmp packet to send */static voidigmp_send(struct igmp_group *group, u8_t type){  struct pbuf*     p    = NULL;  struct igmp_msg* igmp = NULL;  ip_addr_t   src  = *IP_ADDR_ANY;  ip_addr_t*  dest = NULL;  /* IP header + "router alert" option + IGMP header */  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);    if (p) {    igmp = (struct igmp_msg *)p->payload;    LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",               (p->len >= sizeof(struct igmp_msg)));    ip_addr_copy(src, group->netif->ip_addr);         if (type == IGMP_V2_MEMB_REPORT) {      dest = &(group->group_address);      ip_addr_copy(igmp->igmp_group_address, group->group_address);      group->last_reporter_flag = 1; /* Remember we were the last to report */    } else {      if (type == IGMP_LEAVE_GROUP) {        dest = &allrouters;        ip_addr_copy(igmp->igmp_group_address, group->group_address);      }    }    if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {      igmp->igmp_msgtype  = type;      igmp->igmp_maxresp  = 0;      igmp->igmp_checksum = 0;      igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN);      igmp_ip_output_if(p, &src, dest, group->netif);    }    pbuf_free(p);  } else {    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));    IGMP_STATS_INC(igmp.memerr);  }}#endif /* LWIP_IGMP */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -