/************************************************************************ * NAME: fnet_igmp_input * * DESCRIPTION: IGMP input function. *************************************************************************/ static void fnet_igmp_input(fnet_netif_t *netif, struct sockaddr *src_addr, struct sockaddr *dest_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip4_nb) { fnet_igmp_header_t *hdr; fnet_index_t i; FNET_COMP_UNUSED_ARG(src_addr); FNET_COMP_UNUSED_ARG(dest_addr); fnet_netbuf_free_chain(ip4_nb); /* Not used*/ if((netif != 0) && (nb != 0) ) { /* The header must reside in contiguous area of memory. */ if(fnet_netbuf_pullup(&nb, sizeof(fnet_igmp_header_t)) == FNET_ERR) { goto DISCARD; } hdr = nb->data_ptr; /* RFC2236 To be valid, the Query message * must be at least 8 octets long, have a correct IGMP * checksum. */ if(fnet_checksum(nb, nb->total_length) ) { goto DISCARD; } fnet_igmp_trace("RX", hdr); /************************** * IGMP QUERY Processing **************************/ if(hdr->type == IGMP_HEADER_TYPE_QUERY) { /* RFC2236: The group address in the IGMP header must either be zero (a General * Query) or a valid multicast group address (a Group-Specific Query). * A General Query applies to all memberships on the interface from * which the Query is received. A Group-Specific Query applies to * membership in a single group on the interface from which the Query * is received. Queries are ignored for memberships in the Non-Member * state. */ if(hdr->group_addr == 0) /* General Query */ { /* Find all joined-groups for this interface.*/ for(i=0u; i < FNET_CFG_MULTICAST_MAX; i++) { if((fnet_ip_multicast_list[i].user_counter > 0) && (fnet_ip_multicast_list[i].netif == netif)) { /* Send report.*/ fnet_igmp_join(netif, fnet_ip_multicast_list[i].group_addr ); } } } #if FNET_CFG_IGMP_VERSION == 2 else if(FNET_IP4_ADDR_IS_MULTICAST(hdr->group_addr)) /* A Group-Specific Query.*/ { /* Find specific group.*/ for(i=0u; i < FNET_CFG_MULTICAST_MAX; i++) { if((fnet_ip_multicast_list[i].user_counter > 0) && (fnet_ip_multicast_list[i].netif == netif) && (fnet_ip_multicast_list[i].group_addr == hdr->group_addr)) { /* Send report.*/ fnet_igmp_join(netif, fnet_ip_multicast_list[i].group_addr ); break; } } } #endif /* FNET_CFG_IGMP_VERSION */ else {} /* wrong */ } /************************ * Ignore others ************************/ } DISCARD: fnet_netbuf_free_chain(nb); }
/************************************************************************ * NAME: fnet_icmp_input * * DESCRIPTION: ICMP input function. *************************************************************************/ static void fnet_icmp_input( fnet_netif_t *netif, fnet_ip4_addr_t src_ip, fnet_ip4_addr_t dest_ip, fnet_netbuf_t *nb, fnet_netbuf_t *ip4_nb ) { fnet_icmp_header_t *hdr; fnet_icmp_err_header_t *hdr_err; fnet_prot_notify_t prot_cmd; fnet_prot_if_t *protocol; fnet_netbuf_t *tmp_nb; fnet_netbuf_free_chain(ip4_nb); if((netif != 0) && (nb != 0) ) { if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp_header_t))) == 0) /* The header must reside in contiguous area of memory. */ { goto DISCARD; } nb = tmp_nb; hdr = nb->data_ptr; if( #if FNET_CFG_CPU_ETH_HW_RX_PROTOCOL_CHECKSUM || FNET_CFG_CPU_ETH_HW_TX_PROTOCOL_CHECKSUM ((nb->flags & FNET_NETBUF_FLAG_HW_PROTOCOL_CHECKSUM) == 0) && #endif fnet_checksum(nb, (int)nb->total_length) || fnet_ip_addr_is_broadcast(src_ip, netif) || FNET_IP4_ADDR_IS_MULTICAST(src_ip)) { goto DISCARD; } fnet_icmp_trace("RX", hdr); switch(hdr->type) { /************************** * ICMP Request Processing **************************/ case FNET_ICMP_ECHO: if((nb->total_length < sizeof(fnet_icmp_echo_header_t)) || /* An ICMP Echo Request destined to an IP broadcast or IP * multicast address MAY be silently discarded.(RFC1122)*/ fnet_ip_addr_is_broadcast(dest_ip, netif) || FNET_IP4_ADDR_IS_MULTICAST(dest_ip)) { goto DISCARD; } hdr->type = FNET_ICMP_ECHOREPLY; fnet_icmp_output(netif, dest_ip, src_ip, nb); break; #if 0 /* Optional functionality.*/ /************************ * Time Stamp Query ************************/ case FNET_ICMP_TSTAMP: /* The header must reside in contiguous area of memory. */ if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp_timestamp_header_t))) == 0) { goto DISCARD; } nb = tmp_nb; hdr = nb->data_ptr; hdr->type = FNET_ICMP_TSTAMPREPLY; /* All times are in milliseconds since the stack timer start modulo 1 day. * The high-order bit is set as the time value is recorded in nonstandard units. */ ((fnet_icmp_timestamp_header_t *)hdr)->receive_timestamp = fnet_htonl(((fnet_timer_ticks() * FNET_TIMER_PERIOD_MS) % (24 * 60 * 60 * 1000)) | (0x80000000)); dest_ip = netif->ip4_addr.address; fnet_icmp_output(netif, dest_ip, src_ip, nb); break; /************************ * Address Mask Query ************************/ case FNET_ICMP_MASKREQ: /* The header must reside in contiguous area of memory*/ if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp_mask_header_t))) == 0) { goto DISCARD; } nb = tmp_nb; hdr = nb->data_ptr; hdr->type = FNET_ICMP_MASKREPLY; ((fnet_icmp_mask_header_t *)hdr)->mask = netif->ip4_addr.subnetmask; dest_ip = netif->ip4_addr.address; fnet_icmp_output(netif, dest_ip, src_ip, nb); break; #endif /************************** * ICMP Error Processing **************************/ case FNET_ICMP_UNREACHABLE: switch(hdr->code) { case FNET_ICMP_UNREACHABLE_NET: /* net unreachable */ case FNET_ICMP_UNREACHABLE_NET_UNKNOWN: /* unknown net */ case FNET_ICMP_UNREACHABLE_NET_PROHIB: /* prohibited access */ case FNET_ICMP_UNREACHABLE_TOSNET: /* bad tos for net */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_NET; break; case FNET_ICMP_UNREACHABLE_HOST: /* host unreachable */ case FNET_ICMP_UNREACHABLE_HOST_UNKNOWN: /* unknown host */ case FNET_ICMP_UNREACHABLE_ISOLATED: /* src host isolated */ case FNET_ICMP_UNREACHABLE_HOST_PROHIB: /* ditto */ case FNET_ICMP_UNREACHABLE_TOSHOST: /* bad tos for host */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_HOST; break; case FNET_ICMP_UNREACHABLE_PROTOCOL: /* protocol unreachable */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_PROTOCOL; break; case FNET_ICMP_UNREACHABLE_PORT: /* port unreachable */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_PORT; break; case FNET_ICMP_UNREACHABLE_SRCFAIL: /* source route failed */ prot_cmd = FNET_PROT_NOTIFY_UNREACH_SRCFAIL; break; case FNET_ICMP_UNREACHABLE_NEEDFRAG: /* fragmentation needed and DF set*/ prot_cmd = FNET_PROT_NOTIFY_MSGSIZE; break; default: goto DISCARD; } goto NOTIFY_PROT; case FNET_ICMP_TIMXCEED: switch(hdr->code) { case FNET_ICMP_TIMXCEED_INTRANS: /* time to live exceeded in transit (ttl==0)*/ prot_cmd = FNET_PROT_NOTIFY_TIMXCEED_INTRANS; break; case FNET_ICMP_TIMXCEED_REASS: /* fragment reassembly time exceeded (ttl==0)*/ prot_cmd = FNET_PROT_NOTIFY_TIMXCEED_REASS; break; default: goto DISCARD; } goto NOTIFY_PROT; case FNET_ICMP_PARAMPROB: /* Parameter Problem Message.*/ if(hdr->code > 1) goto DISCARD; prot_cmd = FNET_PROT_NOTIFY_PARAMPROB; goto NOTIFY_PROT; case FNET_ICMP_SOURCEQUENCH: /* Source Quench Message; packet lost, slow down.*/ if(hdr->code) goto DISCARD; prot_cmd = FNET_PROT_NOTIFY_QUENCH; NOTIFY_PROT: /* Protocol notification.*/ if(nb->total_length < (sizeof(fnet_icmp_err_header_t) + 8)) goto DISCARD; if(nb->total_length > (sizeof(fnet_icmp_err_header_t) + 8)) fnet_netbuf_trim(&nb, (int)((sizeof(fnet_icmp_err_header_t) + 8) - nb->total_length)); if((tmp_nb = fnet_netbuf_pullup(nb, (int)nb->total_length)) == 0) /* The header must reside in contiguous area of memory.*/ { goto DISCARD; } nb = tmp_nb; hdr_err = (fnet_icmp_err_header_t *)nb->data_ptr; if((protocol = fnet_prot_find(AF_INET, SOCK_UNSPEC, hdr_err->ip.protocol)) != 0) { if(protocol->prot_control_input) protocol->prot_control_input(prot_cmd, (void *)(&hdr_err->ip)); } goto DISCARD; /************************ * Ignore others ************************/ /* case FNET_ICMP_REDIRECT: case FNET_ICMP_ECHOREPLY: case FNET_ICMP_ROUTERADVERT: case FNET_ICMP_ROUTERSOLICIT: case FNET_ICMP_TSTAMPREPLY: case FNET_ICMP_IREQREPLY: case FNET_ICMP_MASKREPLY:*/ default: goto DISCARD; }/* switch(hdr->type) */ } else { DISCARD: fnet_netbuf_free_chain(nb); } }