示例#1
0
/************************************************************************
* NAME: fnet_icmp6_error
*
* DESCRIPTION: Sends ICMPv6 error message.
*************************************************************************/
void fnet_icmp6_error( fnet_netif_t *netif, unsigned char type, unsigned char code, unsigned long param, fnet_netbuf_t *origin_nb )
{
    fnet_ip6_header_t       *ip6_header;
    fnet_icmp6_err_header_t *icmp6_err_header;
    fnet_ip6_addr_t         *src_ip; 
    const fnet_ip6_addr_t   *dest_ip; 
    fnet_netbuf_t           *nb_header;   
    
    if(origin_nb)
    {
        /* Limit to FNET_IP6_DEFAULT_MTU. */
        if(origin_nb->total_length > (FNET_IP6_DEFAULT_MTU - (sizeof(fnet_icmp6_err_header_t) + sizeof(fnet_ip6_header_t))  ))
            fnet_netbuf_trim(&origin_nb, (int)(FNET_IP6_DEFAULT_MTU - (sizeof(fnet_icmp6_err_header_t) + sizeof(fnet_ip6_header_t)) - origin_nb->total_length));
        
        ip6_header = origin_nb->data_ptr;
        
        src_ip = &ip6_header->source_addr;
        dest_ip = &ip6_header->destination_addr;
        
        /*******************************************************************
         * RFC 4443:
         * (e) An ICMPv6 error message MUST NOT be originated as a result of
         * receiving the following:
         *******************************************************************/
        /* (e.1) An ICMPv6 error message. */ 
        /* (e.2) An ICMPv6 REDIRECT message [IPv6-DISC].*/
        if (ip6_header->next_header == FNET_IP_PROTOCOL_ICMP6) /* TBD Extension header case.*/
        {
            /* Make sure the packet has at least a 'TYPE' field */
            if (ip6_header->length == 0)
            {
                goto FREE_NB;
            }
            
            icmp6_err_header = (fnet_icmp6_err_header_t *)((unsigned char *)ip6_header + sizeof(fnet_ip6_header_t));
            if (FNET_ICMP6_TYPE_IS_ERROR(icmp6_err_header->icmp6_header.type) || (icmp6_err_header->icmp6_header.type == FNET_ICMP6_TYPE_REDIRECT ) )
            {
                goto FREE_NB;
            }
        }

        /*
         * (e.3) A packet destined to an IPv6 multicast address. (There are
         * two exceptions to this rule: (1) the Packet Too Big Message
         * (Section 3.2) to allow Path MTU discovery to work for IPv6
         * multicast, and (2) the Parameter Problem Message, Code 2
         * (Section 3.4) reporting an unrecognized IPv6 option (see
         * Section 4.2 of [IPv6]) that has the Option Type highestorder
         * two bits set to 10).
         * (e.4) A packet sent as a link-layer multicast (the exceptions
         * from e.3 apply to this case, too).     
         */
         if(FNET_IP6_ADDR_IS_MULTICAST(dest_ip)  
            && !( (type == FNET_ICMP6_TYPE_PACKET_TOOBIG) 
                || ((type == FNET_ICMP6_TYPE_PARAM_PROB) && (code == FNET_ICMP6_CODE_PP_OPTION))) )
         {
            goto FREE_NB;
         }
         else
         {
            if(FNET_IP6_ADDR_IS_MULTICAST(dest_ip))
            {
                /* We may not use multicast address as source. Get real source address. */
                dest_ip = fnet_ip6_select_src_addr(netif, src_ip /*dest*/); 
            }
         }    
             
        /*
         * (e.5) A packet sent as a link-layer broadcast (the exceptions
         *  from e.3 apply to this case, too). TBD
         */
      

        /*
         * (e.6) A packet whose source address does not uniquely identify a
         * single node -- e.g., the IPv6 Unspecified Address, an IPv6
         * multicast address, or an address known by the ICMP message
         * originator to be an IPv6 anycast address.
         */
        if(FNET_IP6_ADDR_IS_MULTICAST(src_ip) || FNET_IP6_ADDR_EQUAL(&fnet_ip6_addr_any, src_ip))
        {
            goto FREE_NB;
        }
     
        /* Construct ICMPv6 error header.*/
        if((nb_header = fnet_netbuf_new((sizeof(fnet_icmp6_err_header_t)), FNET_FALSE)) == 0)
            goto FREE_NB;     
        
        icmp6_err_header = nb_header->data_ptr;
        
        icmp6_err_header->icmp6_header.type = type;
        icmp6_err_header->icmp6_header.code = code;        
        icmp6_err_header->data = fnet_htonl(param); 
        
        origin_nb = fnet_netbuf_concat(nb_header, origin_nb);
        
        fnet_icmp6_output( netif, dest_ip/*ipsrc*/, src_ip/*ipdest*/, 0, origin_nb);        
            
        return;

FREE_NB:
        fnet_netbuf_free_chain(origin_nb);        
    
    }

}
示例#2
0
文件: fnet_ping.c 项目: rschuck/K64f
/************************************************************************
* NAME: fnet_ping_state_machine
*
* DESCRIPTION: PING service state machine.
************************************************************************/
static void fnet_ping_state_machine(void *fnet_ping_if_p)
{
    fnet_int32_t            received;    
    fnet_icmp_echo_header_t *hdr;
    fnet_ping_if_t          *ping_if = (fnet_ping_if_t *)fnet_ping_if_p;
    struct sockaddr         addr;
    fnet_size_t             addr_len = sizeof(addr);

    switch(ping_if->state)
    {
        /*===================================*/ 
        case FNET_PING_STATE_SENDING_REQUEST:
            /* Build message.*/
            hdr = (fnet_icmp_echo_header_t *)&fnet_ping_if.buffer[0];

            /* Fill ICMP Echo request header.*/
            fnet_memset_zero(hdr, sizeof(*hdr));
            hdr->header.type = (fnet_uint8_t)((fnet_ping_if.family == AF_INET) ? FNET_ICMP_ECHO: FNET_ICMP6_TYPE_ECHO_REQ);
            hdr->identifier = FNET_CFG_PING_IDENTIFIER;
            fnet_ping_if.sequence_number++;
            hdr->sequence_number = fnet_htons(fnet_ping_if.sequence_number);
            
            /* Fill payload data by pattern.*/
            fnet_memset(&fnet_ping_if.buffer[sizeof(*hdr)], ping_if->pattern, ping_if->packet_size);
                
            /* Checksum.*/
#if FNET_CFG_IP4
            if(ping_if->family == AF_INET)
            {
                hdr->header.checksum = fnet_checksum_buf(&fnet_ping_if.buffer[0], (sizeof(*hdr) + ping_if->packet_size));
            }
            else
#endif  
#if FNET_CFG_IP6
            if(ping_if->family == AF_INET6)
            {
                const fnet_ip6_addr_t   *src_ip = fnet_ip6_select_src_addr(FNET_NULL, (fnet_ip6_addr_t *)ping_if->target_addr.sa_data); /*TBD  Check result.*/

                hdr->header.checksum = fnet_checksum_pseudo_buf(&fnet_ping_if.buffer[0], 
                                                                (fnet_uint16_t)(sizeof(*hdr) + ping_if->packet_size), 
                                                                FNET_HTONS((fnet_uint16_t)IPPROTO_ICMPV6), 
                                                                (const fnet_uint8_t *)src_ip,
                                                                ping_if->target_addr.sa_data, 
                                                                sizeof(fnet_ip6_addr_t));
            }
            else
#endif 
            {}
            
            /* Send request.*/    
            fnet_socket_sendto(fnet_ping_if.socket_foreign, (fnet_uint8_t*)(&fnet_ping_if.buffer[0]), (sizeof(*hdr) + ping_if->packet_size), 0u,  &ping_if->target_addr, sizeof(ping_if->target_addr));
            ping_if->packet_count--;
           
            fnet_ping_if.send_time = fnet_timer_ticks();        
            
            ping_if->state = FNET_PING_STATE_WAITING_REPLY;
            break;
        /*===================================*/    
        case  FNET_PING_STATE_WAITING_REPLY:
            /* Receive data */
            
            received = fnet_socket_recvfrom(ping_if->socket_foreign, (fnet_uint8_t*)(&ping_if->buffer[0]), FNET_PING_BUFFER_SIZE, 0u, &addr, &addr_len );
            
            if(received > 0 )
            {
                fnet_uint16_t  checksum = 0u;
                
                hdr = (fnet_icmp_echo_header_t *)(ping_if->buffer);
                
                
                /* Check checksum.*/
#if FNET_CFG_IP4
                if(ping_if->family == AF_INET)
                {
                    checksum = fnet_checksum_buf(&fnet_ping_if.buffer[0], (fnet_size_t)received);
                }
                else
#endif  
#if 0 /* #if FNET_CFG_IP6  */ /* TBD case to receive from multicast address ff02::1*/
                if(ping_if->family == AF_INET6)
                {
                     checksum = fnet_checksum_pseudo_buf(&fnet_ping_if.buffer[0], 
                                                                (fnet_uint16_t)(received), 
                                                                IPPROTO_ICMPV6, 
                                                                ping_if->local_addr.sa_data,
                                                                ping_if->target_addr.sa_data, 
                                                                sizeof(fnet_ip6_addr_t));
                }
                else    
#endif                               
                {}
 
                /* Check header.*/
                if( checksum
                    ||(hdr->header.type != ((addr.sa_family == AF_INET) ? FNET_ICMP_ECHOREPLY: FNET_ICMP6_TYPE_ECHO_REPLY))
                    ||(hdr->identifier != FNET_CFG_PING_IDENTIFIER)
                    ||(hdr->sequence_number != fnet_htons(ping_if->sequence_number)) )
                {
                    goto NO_DATA;
                }     
                
                /* Call handler.*/
                if(ping_if->handler)   
                {
                    ping_if->handler(FNET_ERR_OK, ping_if->packet_count, &addr, ping_if->handler_cookie);
                }
                    
                if(ping_if->packet_count)
                {
                    ping_if->state = FNET_PING_STATE_WAITING_TIMEOUT;
                }
                else
                {
                    fnet_ping_release();              
                }
            }
            else if(received == FNET_ERR)
            {
                /* Call handler.*/
                if(ping_if->handler)
                {
                    fnet_error_t    sock_err ;
                    fnet_size_t     option_len;
                    
                    /* Get socket error.*/
                    option_len = sizeof(sock_err); 
                    fnet_socket_getopt(ping_if->socket_foreign, SOL_SOCKET, SO_ERROR, (fnet_uint8_t*)&sock_err, &option_len);
                                 
                    ping_if->handler(sock_err, ping_if->packet_count, FNET_NULL, ping_if->handler_cookie);
                }
               
                if(ping_if->packet_count)
                {
                    ping_if->state = FNET_PING_STATE_WAITING_TIMEOUT;
                }
                else
                {
                    fnet_ping_release();    
                }
            }
            else /* No data. Check timeout */
            {
NO_DATA:            
                if(fnet_timer_get_interval(fnet_ping_if.send_time, fnet_timer_ticks()) > fnet_ping_if.timeout_clk)
                {
                    /* Call handler.*/
                    if(ping_if->handler)   
                    {
                        ping_if->handler(FNET_ERR_TIMEDOUT, ping_if->packet_count, FNET_NULL, ping_if->handler_cookie);
                    }
                        
                    if(ping_if->packet_count)
                    {
                        ping_if->state = FNET_PING_STATE_SENDING_REQUEST;
                    }
                    else
                    {
                        fnet_ping_release();    
                    }
                }
            }
            break;
        /*===================================*/             
        case FNET_PING_STATE_WAITING_TIMEOUT:
            if(fnet_timer_get_interval(fnet_ping_if.send_time, fnet_timer_ticks()) > fnet_ping_if.timeout_clk)
            {
                ping_if->state = FNET_PING_STATE_SENDING_REQUEST;
            }
            break;

        default:
            break;  /* do nothing, avoid compiler warning "enumeration value not handled in switch" */
    }
}