Exemple #1
0
/************************************************************************
* NAME: fnet_mld_query_receive
*
* DESCRIPTION: Handles received Multicast Listener Query message.
*************************************************************************/
void fnet_mld_query_receive(fnet_netif_t *netif, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t *nb, fnet_netbuf_t *ip6_nb)
{

    fnet_mld_header_t               *mld_packet = nb->data_ptr;
    fnet_size_t                     mld_packet_size = nb->total_length;
    fnet_ip6_header_t               *ip6_packet = (fnet_ip6_header_t *)ip6_nb->data_ptr;

    FNET_COMP_UNUSED_ARG(dest_ip);

    /************************************************************
    * Validation of MLD Query Message.
    *************************************************************/
    if(
        (mld_packet_size < sizeof(fnet_mld_header_t))
        /* Validation RFC2710.*/
        ||(ip6_packet->hop_limit != FNET_MLD_HOP_LIMIT)     /* The IP Hop Limit field has a value of 1.*/
        || !FNET_IP6_ADDR_IS_LINKLOCAL(src_ip)              /* MUST be the link-local address.*/
    )
    {
        goto DROP;
    }

    /* [RFC2710] The Multicast Address field in the MLD
     * message must contain either zero (a General Query) or a valid
     * multicast address (a Multicast- Address-Specific Query).*/
    if(FNET_IP6_ADDR_IS_MULTICAST(&mld_packet->multicast_addr))
    {
        /* [RFC2710] A Multicast-Address-Specific
         * Query applies to a single multicast address on the interface from
         * which the Query is received. */
        if(fnet_ip6_multicast_find_entry(netif, &mld_packet->multicast_addr))
            fnet_mld_join(netif, &mld_packet->multicast_addr);
    }
    else if(FNET_IP6_ADDR_EQUAL(&fnet_ip6_addr_any, &mld_packet->multicast_addr))
    {
        /* [RFC2710] General Query applies to all multicast addresses on the interface
         * from which the Query is received. */
        fnet_mld_report_all(netif);
    }
    else
    {}

DROP:
    fnet_netbuf_free_chain(ip6_nb);
    fnet_netbuf_free_chain(nb);
}
Exemple #2
0
/************************************************************************
* NAME: fnet_raw_output
*
* DESCRIPTION: RAW output function
*************************************************************************/
static int fnet_raw_output(  struct sockaddr *src_addr, const struct sockaddr *dest_addr, unsigned char protocol_number,
                             fnet_socket_option_t *sockoption, fnet_netbuf_t *nb )                            
{
    int error =  FNET_OK;
    
    fnet_netif_t *netif = FNET_NULL;


#if FNET_CFG_IP4
    if(dest_addr->sa_family == AF_INET)
    {
        error = fnet_ip_output(netif, ((struct sockaddr_in *)(src_addr))->sin_addr.s_addr, 
                                        ((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr, 
                                        protocol_number, 
                                        sockoption->ip_opt.tos,
                                #if FNET_CFG_MULTICAST
                                    (unsigned char)((FNET_IP4_ADDR_IS_MULTICAST(((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr)?sockoption->ip_opt.ttl_multicast:sockoption->ip_opt.ttl)),                               
                                #else
                                    sockoption->ip_opt.ttl, 
                                #endif /* FNET_CFG_MULTICAST */                               
                                   nb, 0, ((sockoption->flags & SO_DONTROUTE) > 0),
                                   0
                                   );
    }
#endif
   
#if FNET_CFG_IP6    
    if(dest_addr->sa_family == AF_INET6)
    {
        /* Check Scope ID.*/
        netif = fnet_netif_get_by_scope_id( ((const struct sockaddr_in6 *)dest_addr)->sin6_scope_id );
        
        error = fnet_ip6_output( netif, 
                                fnet_socket_addr_is_unspecified(src_addr)? FNET_NULL : &((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr, 
                                &((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr, 
                                protocol_number, 
                                FNET_IP6_ADDR_IS_MULTICAST(&((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr)?sockoption->ip6_opt.hops_multicast:sockoption->ip6_opt.hops_unicast,
                                nb,0);
    }
#endif                               

    return (error);
}
Exemple #3
0
/************************************************************************
* DESCRIPTION: RAW output function
*************************************************************************/
static fnet_error_t fnet_raw_output(  struct sockaddr *src_addr, const struct sockaddr *dest_addr, fnet_uint8_t protocol_number,
                                      fnet_socket_option_t *sockoption, fnet_netbuf_t *nb )
{
    fnet_error_t error =  FNET_ERR_OK;

    fnet_netif_t *netif =  (fnet_netif_t *)fnet_netif_get_by_scope_id( dest_addr->sa_scope_id );

#if FNET_CFG_IP4
    if(dest_addr->sa_family == AF_INET)
    {
        error = fnet_ip_output(netif, ((struct sockaddr_in *)(src_addr))->sin_addr.s_addr,
                               ((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr,
                               protocol_number,
                               sockoption->ip_opt.tos,
#if FNET_CFG_MULTICAST
                               (fnet_uint8_t)((FNET_IP4_ADDR_IS_MULTICAST(((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr) ? sockoption->ip_opt.ttl_multicast : sockoption->ip_opt.ttl)),
#else
                               sockoption->ip_opt.ttl,
#endif /* FNET_CFG_MULTICAST */
                               nb, FNET_FALSE, sockoption->so_dontroute,
                               0
                              );
    }
#endif

#if FNET_CFG_IP6
    if(dest_addr->sa_family == AF_INET6)
    {
        error = fnet_ip6_output( netif,
                                 fnet_socket_addr_is_unspecified(src_addr) ? FNET_NULL : & ((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr,
                                 &((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr,
                                 protocol_number,
                                 FNET_IP6_ADDR_IS_MULTICAST(&((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr) ? sockoption->ip6_opt.hops_multicast : sockoption->ip6_opt.hops_unicast,
                                 nb, 0);
    }
#endif

    return (error);
}
Exemple #4
0
/************************************************************************
* NAME: fnet_icmp6_input
*
* DESCRIPTION: ICMPv6 input function.
*************************************************************************/
static void fnet_icmp6_input(fnet_netif_t *netif, struct sockaddr *src_addr,  struct sockaddr *dest_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip6_nb)
{
    fnet_icmp6_header_t     *hdr;
    fnet_netbuf_t           *tmp_nb;
    unsigned short          sum;
    fnet_ip6_addr_t         *src_ip;
    fnet_ip6_addr_t         *dest_ip;
    fnet_prot_notify_t      prot_cmd;

    if((netif != 0) && (nb != 0))
    {
        /* The header must reside in contiguous area of memory. */
        if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp6_header_t))) == 0) 
        {
            goto DISCARD;
        }

        nb = tmp_nb;

        hdr = nb->data_ptr;

        dest_ip = &((struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr;
        src_ip = &((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr;

    /* Drop Multicast loopback.*/
    #if FNET_CFG_LOOPBACK     
        if ((netif == FNET_LOOP_IF) && FNET_IP6_ADDR_IS_MULTICAST(dest_ip))
        {
            goto DISCARD;
        }
    #endif /* FNET_CFG_LOOPBACK */
   
        /* Verify the checksum. */
        sum = fnet_checksum_pseudo_start( nb, FNET_HTONS((unsigned short)FNET_IP_PROTOCOL_ICMP6), (unsigned short)nb->total_length );
        sum = fnet_checksum_pseudo_end( sum, (char *)src_ip, (char *)dest_ip, sizeof(fnet_ip6_addr_t) );
        if(sum)
            goto DISCARD;

    	/************************************************************
    	* Process incoming ICMPv6 packets.
    	*************************************************************/
    	switch (hdr->type) 
    	{
            /**************************
             * Neighbor Solicitation.
             **************************/
            case FNET_ICMP6_TYPE_NEIGHBOR_SOLICITATION:
                fnet_nd6_neighbor_solicitation_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break;
            /**************************
             * Neighbor Advertisemnt.
             **************************/            
            case FNET_ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT:
                fnet_nd6_neighbor_advertisement_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break;                
            /**************************
             * Router Advertisemnt.
             **************************/
            case FNET_ICMP6_TYPE_ROUTER_ADVERTISEMENT:
                fnet_nd6_router_advertisement_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break; 
            /**************************
             * Router Advertisemnt.
             **************************/
            case FNET_ICMP6_TYPE_REDIRECT:
                fnet_nd6_redirect_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break;
        #if FNET_CFG_MLD 
            /**************************
             * Multicast Listener Query.
             **************************/
            case FNET_ICMP6_TYPE_MULTICAST_LISTENER_QUERY:
                fnet_mld_query_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break;
        #endif                                
            /**************************
             * Echo Request.
             * RFC4443 4.1: Every node MUST implement an ICMPv6 Echo responder function that
             * receives Echo Requests and originates corresponding Echo Replies.             
             **************************/
            case FNET_ICMP6_TYPE_ECHO_REQ:
                hdr->type = FNET_ICMP6_TYPE_ECHO_REPLY;
                
                /* RFC4443: the source address of the reply MUST be a unicast 
                 * address belonging to the interface on which 
                 * the Echo Request message was received.*/
                if(FNET_IP6_ADDR_IS_MULTICAST(dest_ip))
                     dest_ip = FNET_NULL;
                
                fnet_icmp6_output(netif, dest_ip/*ipsrc*/, src_ip/*ipdest*/, 0, nb);
                fnet_netbuf_free_chain(ip6_nb);
                break;   
        #if FNET_CFG_IP6_PMTU_DISCOVERY 
           /**************************
            * Packet Too Big Message.
            **************************/
            case FNET_ICMP6_TYPE_PACKET_TOOBIG:     
                if(netif->pmtu) /* If PMTU is enabled for the interface.*/
                {
                    unsigned long           pmtu;
                    fnet_icmp6_err_header_t *icmp6_err = nb->data_ptr;
                    
                    /* The header must reside in contiguous area of memory. */
                    if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp6_err_header_t))) == 0) 
                    {
                        goto DISCARD;
                    }

                    nb = tmp_nb;
                    
                    /* RFC 1981.Upon receipt of such a
                     * message, the source node reduces its assumed PMTU for the path based
                     * on the MTU of the constricting hop as reported in the Packet Too Big
                     * message.*/
                    pmtu = fnet_ntohl(icmp6_err->data); 

                    /* A node MUST NOT increase its estimate of the Path MTU in response to
                     * the contents of a Packet Too Big message. */
                    if(netif->pmtu > pmtu)        
                    {
                        fnet_netif_set_pmtu(netif, pmtu);
                    }                
                }
                goto DISCARD;
        #endif   
           /**************************
            * Destination Unreachable. 
            **************************/
            case FNET_ICMP6_TYPE_DEST_UNREACH:
                switch(hdr->code)
                {
                    case FNET_ICMP6_CODE_DU_NO_ROUTE:           /* No route to destination. */
                    case FNET_ICMP6_CODE_DU_BEYOND_SCOPE:       /* Beyond scope of source address.*/
                        prot_cmd = FNET_PROT_NOTIFY_UNREACH_NET;
                        break;
                    case FNET_ICMP6_CODE_DU_ADMIN_PROHIBITED:   /* Communication with destination administratively prohibited. */
                    case FNET_ICMP6_CODE_DU_ADDR_UNREACH:       /* Address unreachable.*/
                        prot_cmd = FNET_PROT_NOTIFY_UNREACH_HOST;
                        break;
                    case FNET_ICMP6_CODE_DU_PORT_UNREACH:       /* Port unreachable.*/
                        prot_cmd = FNET_PROT_NOTIFY_UNREACH_PORT;
                        break;
                    default:
                        goto DISCARD;
                }

                /* Protocol notification.*/
                {
                    fnet_ip6_header_t       *ip_header;
                    fnet_prot_if_t          *protocol;
                    unsigned int            hdr_err_length = sizeof(fnet_icmp6_err_header_t) + sizeof(fnet_ip6_header_t); 
                    unsigned int            hdr_err_data_length = hdr_err_length + 8; /* 8 bytes is enough for transport protocol (port numbers).*/


                    if(nb->total_length < hdr_err_data_length) 
                    {
                        goto DISCARD;
                    }
                    if(nb->total_length > hdr_err_data_length)
                    {
                        fnet_netbuf_trim(&nb, (int)(hdr_err_data_length - 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;

                    ip_header = (fnet_ip6_header_t *)((char *)nb->data_ptr  + sizeof(fnet_icmp6_err_header_t));

                    if((protocol = fnet_prot_find(AF_INET6, SOCK_UNSPEC, ip_header->next_header)) != 0)
                    {
                        if(protocol->prot_control_input)
                        {
                            struct sockaddr     err_src_addr;
                            struct sockaddr     err_dest_addr;

                            /* Prepare addreses for upper protocol.*/
                            fnet_ip6_set_socket_addr(netif, ip_header, &err_src_addr, &err_dest_addr );

                            fnet_netbuf_trim(&nb, (int)(hdr_err_length)); /* Cut the ICMP error header.*/

                            protocol->prot_control_input(prot_cmd, &err_src_addr, &err_dest_addr, nb);
                        }
                    }
                }
                goto DISCARD;                                                
            default:
                goto DISCARD;
        }                
    }
    else
    {
DISCARD:
        fnet_netbuf_free_chain(ip6_nb);
        fnet_netbuf_free_chain(nb);
    }
}
Exemple #5
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);        
    
    }

}
Exemple #6
0
/************************************************************************
* NAME: fnet_eth_output_ip6
*
* DESCRIPTION: Ethernet IPv6 output function.
*************************************************************************/
void fnet_eth_output_ip6(fnet_netif_t *netif, const fnet_ip6_addr_t *src_ip_addr,  const fnet_ip6_addr_t *dest_ip_addr, fnet_netbuf_t *nb)
{
    fnet_mac_addr_t dest_mac_addr; /* 48-bit destination address */
    fnet_uint8_t *dest_mac_addr_ptr;

    /********************************************
    * Multicast.
    ********************************************/
    if (FNET_IP6_ADDR_IS_MULTICAST(dest_ip_addr))
    {
        FNET_ETH_MULTICAST_IP6_TO_MAC(dest_ip_addr, dest_mac_addr);

        dest_mac_addr_ptr = (fnet_uint8_t *)dest_mac_addr;
    }
    /********************************************
    * Unicast.
    ********************************************/
    else
    {
        fnet_nd6_neighbor_entry_t *neighbor;

        /* Possible redirection.*/
        fnet_nd6_redirect_addr(netif, &dest_ip_addr);

        /* Check Neigbor cache.*/
        neighbor = fnet_nd6_neighbor_cache_get(netif, dest_ip_addr);

        /* RFC4861 7.2.2: When a node has a unicast packet to send to a neighbor, but does not
         * know the neighbor’s link-layer address, it performs address resolution.
         * For multicast-capable interfaces, this entails creating a
         * Neighbor Cache entry in the INCOMPLETE state and transmitting a
         * Neighbor Solicitation message targeted at the neighbor. The
         * solicitation is sent to the solicited-node multicast address
         * corresponding to the target address.
         */
        if(neighbor == FNET_NULL)
        {
            /* RFC4861 7.2.Address resolution is performed only on addresses that are determined to be
             * on-link and for which the sender does not know the corresponding link-layer address.
             * Address resolution is never performed on multicast addresses.*/

            if(fnet_nd6_addr_is_onlink(netif, dest_ip_addr) == FNET_TRUE)
                /* Destimnation is ON local-link.*/
            {
                /* Creating a Neighbor Cache entry in the INCOMPLETE state. */
                neighbor = fnet_nd6_neighbor_cache_add(netif, dest_ip_addr, FNET_NULL, FNET_ND6_NEIGHBOR_STATE_INCOMPLETE);

                neighbor->state_time = fnet_timer_ms();
                neighbor->solicitation_send_counter = 0u;
                FNET_IP6_ADDR_COPY(src_ip_addr, &neighbor->solicitation_src_ip_addr); /* Save src address for later usage.*/

                /* AR: Transmitting a Neighbor Solicitation message targeted at the neighbor.*/
                fnet_nd6_neighbor_solicitation_send(netif, src_ip_addr, FNET_NULL /* NULL for AR */, dest_ip_addr);
            }
            /* Destination is OFF local-link.*/
            else
            {
                /* Try to use the router, if exists.*/
                neighbor = fnet_nd6_default_router_get(netif);

                if(neighbor == FNET_NULL)
                    /* No Router exists.*/
                {
                    fnet_netbuf_free_chain(nb); /* Discard datagram */
                    goto EXIT;
                }

                dest_ip_addr = &neighbor->ip_addr;   /* Chage destination address to the router one */
            }
        }

        /* Link -layer address is not initialized.*/
        if((neighbor->state != FNET_ND6_NEIGHBOR_STATE_INCOMPLETE)
           && (neighbor->ll_addr[0] == 0U) && (neighbor->ll_addr[1] == 0U) && (neighbor->ll_addr[2] == 0U)
           && (neighbor->ll_addr[3] == 0U) && (neighbor->ll_addr[4] == 0U) && (neighbor->ll_addr[5] == 0U) )
        {
            neighbor->state = FNET_ND6_NEIGHBOR_STATE_INCOMPLETE;
            neighbor->state_time = fnet_timer_ms();
            neighbor->solicitation_send_counter = 0u;
            FNET_IP6_ADDR_COPY(src_ip_addr, &neighbor->solicitation_src_ip_addr); /* Save src address for later usage.*/
            /* AR: Transmitting a Neighbor Solicitation message targeted at the neighbor.*/
            fnet_nd6_neighbor_solicitation_send(netif, src_ip_addr, FNET_NULL /* NULL for AR */, dest_ip_addr);
        }

        if(neighbor->state == FNET_ND6_NEIGHBOR_STATE_INCOMPLETE)
            /* Queue packet for later transmit.
             */
        {
            fnet_nd6_neighbor_enqueue_waiting_netbuf(neighbor, nb);
            goto EXIT;
        }

        if(neighbor->state == FNET_ND6_NEIGHBOR_STATE_STALE)
            /* RFC4861 7.3.3: The first time a node sends a packet to a neighbor whose entry is
             * STALE, the sender changes the state to DELAY and sets a timer to
             * expire in DELAY_FIRST_PROBE_TIME seconds.
             */
        {
            neighbor->state = FNET_ND6_NEIGHBOR_STATE_DELAY;
            neighbor->state_time = fnet_timer_ms();
        }

        /* Get destination MAC/HW address.*/
        dest_mac_addr_ptr = (fnet_uint8_t *)(&neighbor->ll_addr[0]);
    }

    /* Send Ethernet frame. */
    fnet_eth_output(netif, FNET_ETH_TYPE_IP6, dest_mac_addr_ptr, nb);

EXIT:
    return;
}
/************************************************************************
* NAME: fnet_icmp6_input
*
* DESCRIPTION: ICMPv6 input function.
*************************************************************************/
static void fnet_icmp6_input(fnet_netif_t *netif, fnet_ip6_addr_t *src_ip, fnet_ip6_addr_t *dest_ip, fnet_netbuf_t *nb, fnet_netbuf_t *ip6_nb)
{
    fnet_icmp6_header_t     *hdr;
    fnet_netbuf_t           *tmp_nb;
    unsigned short          sum;


    if((netif != 0) && (nb != 0))
    {
        /* The header must reside in contiguous area of memory. */
        if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp6_header_t))) == 0) 
        {
            goto DISCARD;
        }

        nb = tmp_nb;

        hdr = nb->data_ptr;

    /* Drop Multicast loopback.*/
    #if FNET_CFG_LOOPBACK     
        if ((netif == FNET_LOOP_IF) && FNET_IP6_ADDR_IS_MULTICAST(dest_ip))
        {
            goto DISCARD;
        }
    #endif /* FNET_CFG_LOOPBACK */
   
        /* Verify the checksum. */
        sum = fnet_checksum_pseudo_start( nb, FNET_HTONS((unsigned short)FNET_IP_PROTOCOL_ICMP6), (unsigned short)nb->total_length );
        sum = fnet_checksum_pseudo_end( sum, (char *)src_ip, (char *)dest_ip, sizeof(fnet_ip6_addr_t) );
        if(sum)
            goto DISCARD;

    	/************************************************************
    	* Process incoming ICMPv6 packets.
    	*************************************************************/
    	switch (hdr->type) 
    	{
            /**************************
             * Neighbor Solicitation.
             **************************/
            case FNET_ICMP6_TYPE_NEIGHBOR_SOLICITATION:
                fnet_nd6_neighbor_solicitation_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break;
            /**************************
             * Neighbor Advertisemnt.
             **************************/            
            case FNET_ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT:
                fnet_nd6_neighbor_advertisement_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break;                
            /**************************
             * Router Advertisemnt.
             **************************/
            case FNET_ICMP6_TYPE_ROUTER_ADVERTISEMENT:
                fnet_nd6_router_advertisement_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break; 
            /**************************
             * Router Advertisemnt.
             **************************/
            case FNET_ICMP6_TYPE_REDIRECT:
                fnet_nd6_redirect_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break;
        #if FNET_CFG_MLD 
            /**************************
             * Multicast Listener Query.
             **************************/
            case FNET_ICMP6_TYPE_MULTICAST_LISTENER_QUERY:
                fnet_mld_query_receive(netif, src_ip, dest_ip, nb, ip6_nb);
                break;
        #endif                                
            /**************************
             * Echo Request.
             * RFC4443 4.1: Every node MUST implement an ICMPv6 Echo responder function that
             * receives Echo Requests and originates corresponding Echo Replies.             
             **************************/
            case FNET_ICMP6_TYPE_ECHO_REQ:
                hdr->type = FNET_ICMP6_TYPE_ECHO_REPLY;
                
                /* RFC4443: the source address of the reply MUST be a unicast 
                 * address belonging to the interface on which 
                 * the Echo Request message was received.*/
                if(FNET_IP6_ADDR_IS_MULTICAST(dest_ip))
                     dest_ip = FNET_NULL;
                
                fnet_icmp6_output(netif, dest_ip/*ipsrc*/, src_ip/*ipdest*/, 0, nb);   //MD
                fnet_netbuf_free_chain(ip6_nb);
                break;   
        #if FNET_CFG_IP6_PMTU_DISCOVERY 
           /**************************
            * Packet Too Big Message.
            **************************/
            case FNET_ICMP6_TYPE_PACKET_TOOBIG:     
                if(netif->pmtu) /* If PMTU is enabled for the interface.*/
                {
                    unsigned long           pmtu;
                    fnet_icmp6_err_header_t *icmp6_err = nb->data_ptr;
                    
                    /* The header must reside in contiguous area of memory. */
                    if((tmp_nb = fnet_netbuf_pullup(nb, sizeof(fnet_icmp6_err_header_t))) == 0) 
                    {
                        goto DISCARD;
                    }

                    nb = tmp_nb;
                    
                    /* RFC 1981.Upon receipt of such a
                     * message, the source node reduces its assumed PMTU for the path based
                     * on the MTU of the constricting hop as reported in the Packet Too Big
                     * message.*/
                    pmtu = fnet_ntohl(icmp6_err->data); 

                    /* A node MUST NOT increase its estimate of the Path MTU in response to
                     * the contents of a Packet Too Big message. */
                    if(netif->pmtu > pmtu)        
                    {
                        fnet_netif_set_pmtu(netif, pmtu);
                    }                
                }
                goto DISCARD;
        #endif                       
            default:
                goto DISCARD;
        }                
    }
    else
    {
DISCARD:
        fnet_netbuf_free_chain(ip6_nb);
        fnet_netbuf_free_chain(nb);
    }
}
/************************************************************************
* NAME: fnet_netif_bind_ip6_addr_prv
*
* DESCRIPTION: This function binds the IPv6 address to a hardware interface.
*************************************************************************/
int fnet_netif_bind_ip6_addr_prv(fnet_netif_t *netif, fnet_ip6_addr_t *addr, fnet_netif_ip6_addr_type_t addr_type, 
                                     unsigned long lifetime /*in seconds*/, unsigned long prefix_length /* bits */ )
{
    int                     result = FNET_ERR;
    fnet_netif_ip6_addr_t   *if_addr_ptr = FNET_NULL;
    int                     i;

    fnet_os_mutex_lock();
    
    /* Check input parameters. */
    if(netif && addr && !FNET_IP6_ADDR_IS_MULTICAST(addr))
    {
        /* Find free address entry. 
         */
        for(i = 0; i < FNET_NETIF_IP6_ADDR_MAX; i++)
        {
            if(netif->ip6_addr[i].state == FNET_NETIF_IP6_ADDR_STATE_NOT_USED)
            {
                if_addr_ptr = &netif->ip6_addr[i];
                break; /* Found free entry.*/
            }
        }
        
        if(if_addr_ptr)
        {
            /* Copying address. */
            FNET_IP6_ADDR_COPY(addr, &if_addr_ptr->address); 
            
            /* If the address is zero => make it link-local.*/
            if(FNET_IP6_ADDR_EQUAL(&if_addr_ptr->address, &fnet_ip6_addr_any))
            {
                /* Set link-local address. */
                if_addr_ptr->address.addr[0] = 0xFE;
                if_addr_ptr->address.addr[1] = 0x80;
            }
            
            if_addr_ptr->type = addr_type; /* Set type.*/
      
            /* If we are doing Autoconfiguration, the ip_addr points to prefix.*/ 
            if(addr_type == FNET_NETIF_IP6_ADDR_TYPE_AUTOCONFIGURABLE)
            {
                /* Construct address from prefix and interface id. */
                if((prefix_length != FNET_ND6_PREFIX_LENGTH_DEFAULT) 
                    || fnet_netif_set_ip6_addr_autoconf(netif, &if_addr_ptr->address) == FNET_ERR)
                {
                    goto COMPLETE;
                }
            }
    
            /* Check if addr already exists. Do it here to cover Autoconfiguration case.*/
            if(fnet_netif_get_ip6_addr_info(netif, &if_addr_ptr->address) != FNET_NULL)
            {
                /* The address is already bound.*/
                result = FNET_OK;
                goto COMPLETE;
            }    
                       
            /* Save creation time, in seconds.*/
            if_addr_ptr->creation_time = fnet_timer_seconds();
            
            /* Set lifetime, in seconds.*/
            if_addr_ptr->lifetime = lifetime;
            
            /* If supports ND6. */
            if(netif->nd6_if_ptr)
            {
                /* An address on which the Duplicate Address Detection procedure is
                 * applied is said to be tentative until the procedure has completed
                 * successfully.
                 */
                if_addr_ptr->state = FNET_NETIF_IP6_ADDR_STATE_TENTATIVE;     

                /* Get&Set the solicited-node multicast group-address for assigned ip_addr. */
                fnet_ip6_get_solicited_multicast_addr(&if_addr_ptr->address, &if_addr_ptr->solicited_multicast_addr);    
                
                /*************************************************************************
                * Join Multicast ADDRESSES.
                * When a multicast-capable interface becomes enabled, the node MUST
                * join the all-nodes multicast address on that interface, as well as
                * the solicited-node multicast address corresponding to each of the IP
                * addresses assigned to the interface.
                **************************************************************************/
                /* Join solicited multicast address group.*/
                fnet_netif_join_ip6_multicast ( (fnet_netif_desc_t)netif, &if_addr_ptr->solicited_multicast_addr );

                /* Start Duplicate Address Detection (DAD).
                 * RFC4862:  The Duplicate Address Detection algorithm is performed on all addresses,
                 * independently of whether they are obtained via stateless
                 * autoconfiguration or DHCPv6.
                 */
                fnet_nd6_dad_start(netif , if_addr_ptr);
            }
            else
            {
                if_addr_ptr->state = FNET_NETIF_IP6_ADDR_STATE_PREFERRED; 
            }           
            
            

        //Check by type
           
           //TBD if(netif->api->set_addr_notify)
           //     netif->api->set_addr_notify(netif);
        }
    }

COMPLETE: 
    fnet_os_mutex_unlock();
   
    return result;
}
Exemple #9
0
/************************************************************************
* NAME: fnet_udp_output
*
* DESCRIPTION: UDP output function
*************************************************************************/
static fnet_error_t fnet_udp_output(  struct sockaddr *src_addr, const struct sockaddr *dest_addr,
                             fnet_socket_option_t *sockoption, fnet_netbuf_t *nb )                            
{
    fnet_netbuf_t                           *nb_header;
    fnet_udp_header_t                       *udp_header;
    fnet_error_t                            error =  FNET_ERR_OK;
    FNET_COMP_PACKED_VAR fnet_uint16_t      *checksum_p;
    fnet_netif_t                            *netif = FNET_NULL;
    fnet_scope_id_t                         scope_id = 0u;

    /* Check Scope ID.*/
    if(dest_addr->sa_scope_id) /* Take scope id from destination address.*/
    {
        scope_id = dest_addr->sa_scope_id;
    }
    else  /* Take scope id from source address.*/
    {
        scope_id = src_addr->sa_scope_id;
    }
    netif = (fnet_netif_t *)fnet_netif_get_by_scope_id(scope_id); /* It can be FNET_NULL, in case scope_id is 0.*/

    /* Construct UDP header.*/
    if((nb_header = fnet_netbuf_new(sizeof(fnet_udp_header_t), FNET_TRUE)) == 0)
    {
        fnet_netbuf_free_chain(nb); 
        return (FNET_ERR_NOMEM);
    }

    udp_header = (fnet_udp_header_t *)nb_header->data_ptr;

    udp_header->source_port = src_addr->sa_port;             /* Source port number.*/
    udp_header->destination_port = dest_addr->sa_port;       /* Destination port number.*/
    nb = fnet_netbuf_concat(nb_header, nb);
    udp_header->length = fnet_htons((fnet_uint16_t)nb->total_length);  /* Length.*/

    /* Checksum calculation.*/
    udp_header->checksum = 0u;  

#if FNET_CFG_UDP_CHECKSUM

#if FNET_CFG_CPU_ETH_HW_TX_IP_CHECKSUM
    if( 0 
    #if FNET_CFG_IP4
        ||( (dest_addr->sa_family == AF_INET) 
        && ((netif = fnet_ip_route(((struct sockaddr_in *)(dest_addr))->sin_addr.s_addr))!= FNET_NULL)
        && (netif->features & FNET_NETIF_FEATURE_HW_TX_PROTOCOL_CHECKSUM)
        && (fnet_ip_will_fragment(netif, nb->total_length) == FNET_FALSE) /* Fragmented packets are not inspected.*/  ) 
    #endif
    #if FNET_CFG_IP6
        ||( (dest_addr->sa_family == AF_INET6) 
        && (netif || (((netif = fnet_ip6_route(&((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr, &((struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr)))!= FNET_NULL) )
        && (netif->features & FNET_NETIF_FEATURE_HW_TX_PROTOCOL_CHECKSUM)
        && (fnet_ip6_will_fragment(netif, nb->total_length) == FNET_FALSE) /* Fragmented packets are not inspected.*/  ) 
    #endif
    )
    {
        nb->flags |= FNET_NETBUF_FLAG_HW_PROTOCOL_CHECKSUM;
        checksum_p = 0;
    }
    else
#endif /* FNET_CFG_CPU_ETH_HW_TX_IP_CHECKSUM */
    {
        udp_header->checksum = fnet_checksum_pseudo_start( nb, FNET_HTONS((fnet_uint16_t)FNET_IP_PROTOCOL_UDP), (fnet_uint16_t)nb->total_length );
        checksum_p = &udp_header->checksum;
    }
#endif /* FNET_CFG_UDP_CHECKSUM */

#if FNET_CFG_IP4
    if(dest_addr->sa_family == AF_INET)
    {
        error = fnet_ip_output(netif, 
                                ((const struct sockaddr_in *)(src_addr))->sin_addr.s_addr, 
                                ((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr, 
                                FNET_IP_PROTOCOL_UDP, sockoption->ip_opt.tos,
                            #if FNET_CFG_MULTICAST
                                (fnet_uint8_t)((FNET_IP4_ADDR_IS_MULTICAST(((const struct sockaddr_in *)(dest_addr))->sin_addr.s_addr)?sockoption->ip_opt.ttl_multicast:sockoption->ip_opt.ttl)),                               
                            #else
                                sockoption->ip_opt.ttl, 
                            #endif /* FNET_CFG_MULTICAST */                               
                                nb, FNET_UDP_DF, sockoption->so_dontroute,
                                checksum_p
                                );
    }
    else
#endif
#if FNET_CFG_IP6    
    if(dest_addr->sa_family == AF_INET6)
    {
        error = fnet_ip6_output( netif, 
                                fnet_socket_addr_is_unspecified(src_addr)? FNET_NULL : &((struct sockaddr_in6 *)(src_addr))->sin6_addr.s6_addr, 
                                &((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr, 
                                FNET_IP_PROTOCOL_UDP, 
                                FNET_IP6_ADDR_IS_MULTICAST(&((const struct sockaddr_in6 *)(dest_addr))->sin6_addr.s6_addr)?sockoption->ip6_opt.hops_multicast:sockoption->ip6_opt.hops_unicast,
                                nb, 
                                checksum_p
                                );
    }
    else
#endif                               
    {}

    return (error);
}