Esempio n. 1
0
/************************************************************************
* 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);
    }
}