Пример #1
0
/************************************************************************
* NAME: fnet_netbuf_del_chain
*
* DESCRIPTION: Deletes chain nb_chain, which is in the queue pointed by
*              nb_ptr
*              
*************************************************************************/
void fnet_netbuf_del_chain( fnet_netbuf_t ** nb_ptr, fnet_netbuf_t *nb_chain )
{
    fnet_netbuf_t *nb_current, *nb;
    
    if(!((nb_ptr == 0) || ((fnet_netbuf_t *) *nb_ptr == 0)))
    {
        nb_current = (fnet_netbuf_t *) *nb_ptr;

        if(nb_current == nb_chain)
        {
            nb = nb_current->next_chain;
            fnet_netbuf_free_chain(nb_current);
            *nb_ptr = nb;
            return;
        }

        while((nb_current->next_chain != nb_chain) && (nb_current != 0))
        {
            nb_current = nb_current->next_chain;
        }

        nb = nb_current->next_chain->next_chain;

        fnet_netbuf_free_chain(nb_current->next_chain);

        nb_current->next_chain = nb;
    }
}
Пример #2
0
/************************************************************************
* DESCRIPTION: Deletes chain nb_chain, which is in the queue pointed by nb_ptr
*************************************************************************/
void fnet_netbuf_del_chain( fnet_netbuf_t **nb_ptr, fnet_netbuf_t *nb_chain )
{
    fnet_netbuf_t *nb_current, *nb;

    if(!((nb_ptr == 0) || ((fnet_netbuf_t *) *nb_ptr == 0)))
    {
        nb_current = (fnet_netbuf_t *) *nb_ptr;

        if(nb_current == nb_chain)
        {
            nb = nb_current->next_chain;
            fnet_netbuf_free_chain(nb_current);
            *nb_ptr = nb;
        }
        else
        {
            while(nb_current && (nb_current->next_chain != nb_chain))
            {
                nb_current = nb_current->next_chain;
            }

            if(nb_current)
            {
                nb = nb_current->next_chain->next_chain;

                fnet_netbuf_free_chain(nb_current->next_chain);

                nb_current->next_chain = nb;
            }
            /* else not found -> assert?*/
        }
    }
}
Пример #3
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);
}
Пример #4
0
void fnet_loop_output_ip4(fnet_netif_t *netif, fnet_ip4_addr_t dest_ip_addr, fnet_netbuf_t* nb)
{
    FNET_COMP_UNUSED_ARG(dest_ip_addr);
    
    /* MTU check */
    if (nb->total_length <= netif->mtu)
        fnet_ip_input(netif, nb);
    else
        fnet_netbuf_free_chain(nb);
}
Пример #5
0
void fnet_loop_output_ip6(struct fnet_netif *netif, fnet_ip6_addr_t *src_ip_addr,  fnet_ip6_addr_t *dest_ip_addr, fnet_netbuf_t* nb)
{
    FNET_COMP_UNUSED_ARG(dest_ip_addr);
    FNET_COMP_UNUSED_ARG(src_ip_addr);
    
    fnet_isr_lock();
 
    /* MTU check */
    if (nb->total_length <= netif->mtu)
        fnet_ip6_input(netif, nb);
    else
        fnet_netbuf_free_chain(nb);
        
    fnet_isr_unlock();
}
Пример #6
0
/************************************************************************
* NAME: fnet_icmp_notify_protocol
*
* DESCRIPTION: Upper protocol notification..
*************************************************************************/
static void fnet_icmp_notify_protocol(fnet_prot_notify_t prot_cmd, fnet_netbuf_t *nb)
{
    fnet_icmp_err_header_t  *hdr_err = (fnet_icmp_err_header_t *)nb->data_ptr;
    fnet_ip_header_t        *ip_header = &hdr_err->ip;
    fnet_size_t             hdr_err_length = sizeof(fnet_icmp_err_header_t) /*+ ((FNET_IP_HEADER_GET_HEADER_LENGTH(ip_header) << 2) - sizeof(fnet_ip_header_t))*/; 
    fnet_size_t             hdr_err_data_length = hdr_err_length+8u; /* 8 bytes is enough for transport protocol (port numbers).*/
    fnet_prot_if_t          *protocol;

    if(nb->total_length < hdr_err_data_length) 
    {
        goto DISCARD;
    }

    if(nb->total_length > hdr_err_data_length)
    {
        fnet_netbuf_trim(&nb, (fnet_int32_t)(hdr_err_data_length - nb->total_length));
    }

    if(fnet_netbuf_pullup(&nb, nb->total_length) == FNET_ERR) /* The header must reside in contiguous area of memory.*/
    {
        goto DISCARD;
    }

    hdr_err = (fnet_icmp_err_header_t *)nb->data_ptr;
    ip_header = &hdr_err->ip;

    if((protocol = fnet_prot_find(AF_INET, SOCK_UNSPEC, (fnet_uint32_t)hdr_err->ip.protocol)) != 0)
    {
        if(protocol->prot_control_input)
        {
            struct sockaddr     err_src_addr;
            struct sockaddr     err_dest_addr;

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

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

            protocol->prot_control_input(prot_cmd, &err_src_addr, &err_dest_addr, nb);
        }
    }

DISCARD:
     fnet_netbuf_free_chain(nb);
}
Пример #7
0
static void fnet_arp_timer(fnet_uint32_t cookie)
{
    fnet_arp_if_t *arpif = (fnet_arp_if_t *)cookie;
    fnet_index_t i;

    for (i = 0U; i < FNET_CFG_ARP_TABLE_SIZE; i++)
    {
        if ((arpif->arp_table[i].prot_addr) && (((fnet_timer_ticks() - arpif->arp_table[i].cr_time)) > (fnet_time_t)((FNET_CFG_ARP_EXPIRE_TIMEOUT * 1000U) / FNET_TIMER_PERIOD_MS)))
        {
            if (arpif->arp_table[i].hold)
            {
                fnet_netbuf_free_chain(arpif->arp_table[i].hold);
            }

            fnet_memset_zero(&(arpif->arp_table[i]), sizeof(fnet_arp_entry_t));
        }
    }
}
Пример #8
0
/************************************************************************
* NAME: fnet_arp_timer
*
* DESCRIPTION: ARP timer.
*************************************************************************/
static void fnet_arp_timer( void *cookie )
{
    fnet_arp_if_t *arpif =  (fnet_arp_if_t *)cookie;
    int i;

    for (i = 0; i < FNET_ARP_TABLE_SIZE; i++)
    {
        if((arpif->arp_table[i].prot_addr)
             && ((fnet_timer_ticks() - arpif->arp_table[i].cr_time))
                              > (unsigned long)(FNET_ARP_TIMEOUT / FNET_TIMER_PERIOD_MS))
        {
            if(arpif->arp_table[i].hold)
                fnet_netbuf_free_chain(arpif->arp_table[i].hold);

            fnet_memset_zero(&(arpif->arp_table[i]), sizeof(fnet_arp_entry_t));
        }
    }

}
Пример #9
0
/************************************************************************
* NAME: fnet_arp_resolve
*
* DESCRIPTION: This function finds the first unused or the oldest
*              ARP table entry and makes a new entry
*              to prepare it for an ARP reply.
*************************************************************************/
void fnet_arp_resolve(fnet_netif_t *netif, fnet_ip4_addr_t ipaddr, fnet_netbuf_t *nb)
{
    fnet_arp_if_t       *arpif = netif->arp_if_ptr;
    fnet_index_t        i;
    fnet_arp_entry_t    *entry;

    fnet_isr_lock();
    for (i = 0U; i < FNET_CFG_ARP_TABLE_SIZE; i++)
    {
        if (ipaddr == arpif->arp_table[i].prot_addr)
        {
            break;
        }
    }

    /* If no unused entry is found, create it. */
    if (i == FNET_CFG_ARP_TABLE_SIZE)
    {
        entry = fnet_arp_add_entry(netif, ipaddr, fnet_eth_null_addr);
    }
    else
    {
        entry = &arpif->arp_table[i];
    }

    if (entry->hold)
    {
        fnet_netbuf_free_chain(entry->hold);
        entry->hold = NULL;
    }

    if ((i == FNET_CFG_ARP_TABLE_SIZE) || ((entry->hold) && (((fnet_timer_ticks() - entry->hold_time) * FNET_TIMER_PERIOD_MS) > 1000U)) || (!entry->hold))
    {
        entry->hold_time = fnet_timer_ticks();
        entry->hold = nb;
        fnet_arp_request(netif, ipaddr);
    }
    else
    {
        entry->hold = nb;
    }
    fnet_isr_unlock();
}
Пример #10
0
/************************************************************************
* NAME: fnet_arp_drain
*
* DESCRIPTION: This function tries to free not critical parts
*              of memory used by ARP protocol.
*************************************************************************/
void fnet_arp_drain(fnet_netif_t *netif)
{
    fnet_index_t    i;
    fnet_arp_if_t   *arpif = netif->arp_if_ptr;

    fnet_isr_lock();

    /* ARP table drain.*/
    for (i = 0U; i < FNET_CFG_ARP_TABLE_SIZE; i++)
    {
        if (arpif->arp_table[i].hold)
        {
            fnet_netbuf_free_chain(arpif->arp_table[i].hold);
            arpif->arp_table[i].hold      = 0;
            arpif->arp_table[i].hold_time = 0U;
        }
    }

    fnet_isr_unlock();
}
Пример #11
0
/************************************************************************
* NAME: fnet_arp_drain
*
* DESCRIPTION: This function tries to free not critical parts 
*              of memory used by ARP protocol.
*************************************************************************/
void fnet_arp_drain(fnet_netif_t *netif)
{
   int i;
   fnet_arp_if_t * arpif = &(((fnet_eth_if_t *)(netif->if_ptr))->arp_if); //PFI
     
   fnet_isr_lock();
   
   /* ARP table drain.*/
   for(i=0;i<FNET_ARP_TABLE_SIZE;i++)
   {
      if(arpif->arp_table[i].hold)
      {
         fnet_netbuf_free_chain(arpif->arp_table[i].hold);
         arpif->arp_table[i].hold=0;
         arpif->arp_table[i].hold_time=0;
      }
   }
  
   fnet_isr_unlock();
}
Пример #12
0
/************************************************************************
* NAME: fnet_eth_prot_input
*
* DESCRIPTION: Eth. network-layer input function.
*************************************************************************/
void fnet_eth_prot_input( fnet_netif_t *netif, fnet_netbuf_t *nb, fnet_uint16_t protocol )
{
    fnet_index_t i;

    if(netif && nb)
    {
        /* Find Network-layer protocol.*/
        for(i = 0U; i < FNET_ETH_PROT_IF_LIST_SIZE; i++)
        {
            if( protocol == fnet_eth_prot_if_list[i].protocol)
            {
                /* Call the protocol-input function.*/
                fnet_eth_prot_if_list[i].input(netif, nb);
                break;
            }
        }

        if(i == FNET_ETH_PROT_IF_LIST_SIZE)
        {
            /* No procol found */
            fnet_netbuf_free_chain(nb);
        }
    }
}
Пример #13
0
/************************************************************************
* NAME: fnet_arp_resolve
*
* DESCRIPTION: This function finds the first unused or the oldest
*              ARP table entry and makes a new entry
*              to prepare it for an ARP reply.
*************************************************************************/
void fnet_arp_resolve( fnet_netif_t *netif, fnet_ip4_addr_t ipaddr, fnet_netbuf_t *nb )
{
    fnet_arp_if_t *arpif = &(((fnet_eth_if_t *)(netif->if_ptr))->arp_if); //PFI
    int i;
    fnet_arp_entry_t *entry;

    for (i = 0; i < FNET_ARP_TABLE_SIZE; i++)
    {
        if(ipaddr == arpif->arp_table[i].prot_addr)
        {
            break;
        }
    }

    /* If no unused entry is found, create it. */
    if(i == FNET_ARP_TABLE_SIZE)
        entry = fnet_arp_add_entry(netif, ipaddr, fnet_eth_null_addr);
    else
        entry = &arpif->arp_table[i];

    if(entry->hold)
    {
        fnet_netbuf_free_chain(entry->hold);
    }

    if((i == FNET_ARP_TABLE_SIZE)||
        ((entry->hold)&&(((fnet_timer_ticks()-entry->hold_time)*FNET_TIMER_PERIOD_MS)>1000))||
        (!entry->hold))
    {
        entry->hold_time = fnet_timer_ticks();
        entry->hold = nb;
        fnet_arp_request(netif, ipaddr);
    }
    else
        entry->hold = nb;
}
Пример #14
0
/************************************************************************
* NAME: fnet_udp_input
*
* DESCRIPTION: UDP input function.
*************************************************************************/
static void fnet_udp_input(fnet_netif_t *netif, struct sockaddr *foreign_addr,  struct sockaddr *local_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip_nb)
{
    fnet_udp_header_t   *udp_header = (fnet_udp_header_t *)nb->data_ptr;
    fnet_socket_if_t       *sock;
    fnet_socket_if_t       *last;
    fnet_size_t         udp_length;
    fnet_netbuf_t       *nb_tmp;

    if((netif != 0) && (nb != 0))
    {
        /* The header must reside in contiguous area of memory.*/
        if(fnet_netbuf_pullup(&nb, sizeof(fnet_udp_header_t)) == FNET_ERR) 
        {
            goto BAD;
        }
        
        udp_length = fnet_ntohs(udp_header->length);

        if(nb->total_length >= udp_length)  /* Check the amount of data.*/
        {
            if(nb->total_length > udp_length)
            {
                /* Logical size and the physical size of the packet should be the same.*/
                fnet_netbuf_trim(&nb, (fnet_int32_t)(udp_length - nb->total_length)); 
            }

#if FNET_CFG_UDP_CHECKSUM
            if((udp_header->checksum != 0u)
        #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_uint16_t sum;
                
                sum = fnet_checksum_pseudo_start( nb, FNET_HTONS((fnet_uint16_t)FNET_IP_PROTOCOL_UDP), (fnet_uint16_t)udp_length );
                sum = fnet_checksum_pseudo_end( sum, &foreign_addr->sa_data[0], &local_addr->sa_data[0], 
                            (fnet_size_t)((local_addr->sa_family == AF_INET) ? sizeof(fnet_ip4_addr_t) : sizeof(fnet_ip6_addr_t)));

                if(sum)
                {
                    goto BAD;
                }
            }
#endif
            fnet_udp_trace("RX", udp_header); /* Trace UDP header.*/

            local_addr->sa_port = udp_header->destination_port;
            foreign_addr->sa_port = udp_header->source_port;

            fnet_netbuf_trim(&nb, (fnet_int32_t)sizeof(fnet_udp_header_t));

            /* Demultiplex broadcast & multicast datagrams.*/
            if((fnet_socket_addr_is_broadcast(local_addr, netif)) || (fnet_socket_addr_is_multicast(local_addr))) 
            {
                last = 0;

                for (sock = fnet_udp_prot_if.head; sock != 0; sock = sock->next)
                {
                    /* Compare local port number.*/
                    if(sock->local_addr.sa_port != local_addr->sa_port)
                    {
                        continue; /* => ignore.*/
                    }

                #if FNET_CFG_MULTICAST
                    if(fnet_socket_addr_is_multicast(local_addr)) 
                    {
                        fnet_index_t        m;
                        fnet_bool_t         for_us = FNET_FALSE;
                        
                    #if FNET_CFG_IP4                        
                        if(local_addr->sa_family == AF_INET)
                        {
                            for(m = 0u; m < FNET_CFG_MULTICAST_SOCKET_MAX; m++)
                            {
                                if(sock->ip4_multicast_entry[m])
                                {
                                    if((sock->ip4_multicast_entry[m]->group_addr == ((struct sockaddr_in *)(local_addr))->sin_addr.s_addr) &&  (sock->ip4_multicast_entry[m]->netif == netif )) 
                                    {
                                        for_us = FNET_TRUE;       
                                    }
                                }
                            }
                        }
                        else
                     #endif    
                     #if FNET_CFG_IP6
                        if(local_addr->sa_family == AF_INET6) 
                        {  
                            for(m=0u; m < FNET_CFG_MULTICAST_SOCKET_MAX; m++)
                            {
                                if(sock->ip6_multicast_entry[m])
                                {
                                   
                                    if(FNET_IP6_ADDR_EQUAL(&sock->ip6_multicast_entry[m]->group_addr, &((struct sockaddr_in6 *)(local_addr))->sin6_addr.s6_addr) && (sock->ip6_multicast_entry[m]->netif == netif))
                                    {
                                        for_us = FNET_TRUE;       
                                    }
                                }
                            }
                        }
                        else
                     #endif   
                        {}

                        if(for_us == FNET_FALSE)
                        {
                            continue;
                        }
                    }
                    else
                #endif /* FNET_CFG_MULTICAST */                   
                    {
                        /* Compare local address.*/
                        if(!fnet_socket_addr_is_unspecified(&sock->local_addr))
                        {
                            if(!fnet_socket_addr_are_equal(&sock->local_addr, local_addr))
                            {
                                continue;
                            }    
                        }

                        /* Compare foreign address and port number.*/
                        if(!fnet_socket_addr_is_unspecified(&sock->foreign_addr))
                        {
                            if((!fnet_socket_addr_are_equal(&sock->foreign_addr, foreign_addr)) || (sock->foreign_addr.sa_port != foreign_addr->sa_port))
                            {
                                continue;
                            }
                        }
                    }

                    if((last != 0) && (last->receive_buffer.is_shutdown == FNET_FALSE))
                    {
                        if((nb_tmp = fnet_netbuf_copy(nb, 0u, FNET_NETBUF_COPYALL, FNET_FALSE)) != 0)
                        {
                            if(fnet_socket_buffer_append_address(&(last->receive_buffer), nb_tmp, foreign_addr) == FNET_ERR)
                            {
                                fnet_netbuf_free_chain(nb_tmp);
                            }
                        }
                    }
                    last = sock;
                }

                if(last == 0)
                {
                    goto BAD;
                }

                if(last->receive_buffer.is_shutdown) /* Is shutdown.*/
                {
                    goto BAD;
                }

                if(fnet_socket_buffer_append_address(&(last->receive_buffer), nb, foreign_addr) == FNET_ERR)
                {
                    goto BAD;
                }
                
                fnet_netbuf_free_chain(ip_nb);                  
            }
            else /* For unicast datagram.*/
            {
                sock = fnet_socket_lookup(fnet_udp_prot_if.head, local_addr, foreign_addr, FNET_IP_PROTOCOL_UDP);

                if(sock)
                {
                    if(sock->receive_buffer.is_shutdown) /* Is shutdown.*/
                    {
                        goto BAD;
                    }
                    if(fnet_socket_buffer_append_address(&(sock->receive_buffer), nb, foreign_addr) == FNET_ERR)
                    {
                        goto BAD;
                    }
                    
                    fnet_netbuf_free_chain(ip_nb);
                }
                else
                {
                    fnet_netbuf_free_chain(nb); /* No match was found, send ICMP destination port unreachable.*/
                #if FNET_CFG_IP4                    
                    if(local_addr->sa_family == AF_INET)
                    {
                        fnet_icmp_error(netif, FNET_ICMP_UNREACHABLE, FNET_ICMP_UNREACHABLE_PORT, ip_nb);
                    }else
                #endif
                #if FNET_CFG_IP6                        
                    if(local_addr->sa_family == AF_INET6)
                    {
                        fnet_icmp6_error(netif, FNET_ICMP6_TYPE_DEST_UNREACH, FNET_ICMP6_CODE_DU_PORT_UNREACH, 0u, ip_nb );
                    }else
                #endif
                    {}                
                }
            }
        }
        else
        {
            goto BAD;
        }
    }
    else
    {
BAD:
        fnet_netbuf_free_chain(ip_nb);
        fnet_netbuf_free_chain(nb);
    }
}
Пример #15
0
/************************************************************************
* NAME: fnet_mld_send
*
* DESCRIPTION: Sends MLD message defined by type:
*        FNET_ICMP6_TYPE_MULTICAST_LISTENER_REPORT or FNET_ICMP6_TYPE_MULTICAST_LISTENER_DONE
*************************************************************************/
static void fnet_mld_send(fnet_netif_t *netif, fnet_ip6_addr_t *group_addr, fnet_uint8_t type)
{
    fnet_netbuf_t                       *nb;
    fnet_netbuf_t                       *nb_option;
    fnet_mld_header_t                   *mld_header;
    fnet_mld_ra_option_header_t         *ra_option_header;
    FNET_COMP_PACKED_VAR fnet_uint16_t  *checksum_p;
    fnet_ip6_addr_t                     *ip_src;
    fnet_ip6_addr_t                     *ip_dst;

    /* [RFC2710] EXCLUDING the link-scope all-nodes address and any multicast
     * addresses of scope 0 (reserved) or 1(node-local).*/
    if((FNET_IP6_ADDR_MULTICAST_SCOPE(group_addr) > FNET_IP6_ADDR_SCOPE_INTERFACELOCAL)
            && !FNET_IP6_ADDR_EQUAL(&fnet_ip6_addr_linklocal_allnodes, group_addr))
    {
        /* Construct Router Alert option + MLD meassage */
        if((nb = fnet_netbuf_new(sizeof(fnet_mld_header_t), FNET_FALSE)) != 0)
        {
            if((nb_option = fnet_netbuf_new(sizeof(fnet_mld_ra_option_header_t), FNET_FALSE)) != 0)
            {
                /* Fill Hop-by_Hop Options header.*/
                ra_option_header = (fnet_mld_ra_option_header_t  *)(nb_option->data_ptr);
                fnet_memcpy ((void *)ra_option_header, (void *)(&mld_ra_option), sizeof(mld_ra_option));

                /* Fill MLD message. */
                mld_header = (fnet_mld_header_t  *)(nb->data_ptr);
                fnet_memset_zero(mld_header, sizeof(fnet_mld_header_t));
                mld_header->icmp6_header.type = type;
                FNET_IP6_ADDR_COPY(group_addr, &mld_header->multicast_addr);

                /* Checksum calculation.*/
                mld_header->icmp6_header.checksum = 0;
                mld_header->icmp6_header.checksum = fnet_checksum_pseudo_start(nb, FNET_HTONS((fnet_uint16_t)FNET_IP_PROTOCOL_ICMP6), (fnet_uint16_t)nb->total_length);
                checksum_p = &mld_header->icmp6_header.checksum;

                /* Concatanate Hop-by_Hop Options with MLD header. */
                nb = fnet_netbuf_concat(nb_option, nb);

                /* Source Address Selection for MLD, by RFC3590.*/

                /* [RFC3590] MLD Report and Done messages are sent with a link-local address as
                 * the IPv6 source address, if a valid address is available on the interface.*/
                ip_src = fnet_netif_get_ip6_addr_valid_link_local(netif);

                /* [RFC3590] If a valid link-local address is not available (e.g., one has not been configured),
                 * the message is sent with the unspecified address. */
                if(ip_src == FNET_NULL)
                {
                    ip_src = (fnet_ip6_addr_t *)&fnet_ip6_addr_any;
                    netif->mld_invalid = FNET_TRUE;
                }
                else
                {
                    netif->mld_invalid = FNET_FALSE;
                }

                /* When a node ceases to listen to a multicast address on an interface,
                 * it SHOULD send a single Done message to the link-scope all-routers
                 * multicast address (FF02::2)*/
                if(type == FNET_ICMP6_TYPE_MULTICAST_LISTENER_DONE)
                {
                    ip_dst =(fnet_ip6_addr_t *)&fnet_ip6_addr_linklocal_allrouters;
                }
                else
                {
                    ip_dst = group_addr;
                }

                /* Send via IPv6*/
                fnet_ip6_output(netif, ip_src, ip_dst, FNET_IP6_TYPE_HOP_BY_HOP_OPTIONS, FNET_MLD_HOP_LIMIT, nb, checksum_p);
            }
            else
            {
                fnet_netbuf_free_chain(nb);
            }
        }
    }
}
Пример #16
0
/************************************************************************
* 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);
    }
}
Пример #17
0
/************************************************************************
* NAME: fnet_raw_input
*
* DESCRIPTION: RAW input function.
*************************************************************************/
void fnet_raw_input(fnet_netif_t *netif, struct sockaddr *foreign_addr,  struct sockaddr *local_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip_nb)
{
    fnet_socket_t       *sock;
    fnet_socket_t       *last;
    fnet_netbuf_t       *nb_tmp;
    int                 protocol_number;

    if(netif && nb && nb->total_length)
    {
    #if FNET_CFG_IP4
        if(foreign_addr->sa_family == AF_INET)
        {
            protocol_number = ((fnet_ip_header_t *)(ip_nb->data_ptr))->protocol;
        }
        else
    #endif
    #if FNET_CFG_IP6
        if(foreign_addr->sa_family == AF_INET6)
        {
            protocol_number = ((fnet_ip6_header_t *)(ip_nb->data_ptr))->next_header;
        }
        else
    #endif
        {protocol_number = 0;}

        /* Demultiplex broadcast & multicast datagrams.*/
        if(fnet_socket_addr_is_broadcast(local_addr, netif) || fnet_socket_addr_is_multicast(local_addr)) 
        {
            last = 0;

            for (sock = fnet_raw_prot_if.head; sock != 0; sock = sock->next)
            {
                /* Ignore local port number.*/

                /* Check protocol number.*/
                if(sock->protocol_number != protocol_number)
                    continue; /* => ignore.*/
#if FNET_CFG_MULTICAST
                if(fnet_socket_addr_is_multicast(local_addr))
                {
                    int m;
                    int for_us = FNET_FALSE;
                        
                #if FNET_CFG_IP4                        
                    if(local_addr->sa_family == AF_INET)
                    {
                        
                        for(m=0; m < FNET_CFG_MULTICAST_SOCKET_MAX; m++)
                        {
                            if(sock->ip4_multicast_entry[m])
                            {
                                if((sock->ip4_multicast_entry[m]->group_addr == ((struct sockaddr_in *)(local_addr))->sin_addr.s_addr) &&  (sock->ip4_multicast_entry[m]->netif == netif )) 
                                    for_us = FNET_TRUE;       
                            }
                        }
                    }
                #endif    
                #if FNET_CFG_IP6
                    if(local_addr->sa_family == AF_INET6) 
                    {  
                        for(m=0; m < FNET_CFG_MULTICAST_SOCKET_MAX; m++)
                        {
                            if(sock->ip6_multicast_entry[m])
                            {
                                if(FNET_IP6_ADDR_EQUAL(&sock->ip6_multicast_entry[m]->group_addr, &((struct sockaddr_in6 *)(local_addr))->sin6_addr.s6_addr) && (sock->ip6_multicast_entry[m]->netif == netif))
                                    for_us = FNET_TRUE;       
                            }
                        }
                    }
                #endif   
                    
                        
                    if(for_us == FNET_FALSE)
                        continue;
                }
                else
#endif /* FNET_CFG_MULTICAST */                   
                {
                    /* Compare local address.*/
                    if(!fnet_socket_addr_is_unspecified(&sock->local_addr))
                    {
                        if(!fnet_socket_addr_are_equal(&sock->local_addr, local_addr))
                            continue;
                    }

                    /* Compare foreign address and port number.*/
                    if(!fnet_socket_addr_is_unspecified(&sock->foreign_addr))
                    {
                        if((!fnet_socket_addr_are_equal(&sock->foreign_addr, foreign_addr)) ) 
                            continue;
                    }
                    
                }

                if((last != 0) && (last->receive_buffer.is_shutdown == 0))
                {
                    if((nb_tmp = fnet_netbuf_copy(nb, 0, FNET_NETBUF_COPYALL, 0)) != 0)
                    {
                        if(fnet_socket_buffer_append_address(&(last->receive_buffer), nb_tmp, foreign_addr) == FNET_ERR)
                        {
                            fnet_netbuf_free_chain(nb_tmp);
                        }
                    }
                }
                last = sock;
            }

            if(last == 0)
                goto BAD;

            if(last->receive_buffer.is_shutdown) /* Is shutdown.*/
                goto BAD;
                
            /* Copy buffer.*/
            if((nb_tmp = fnet_netbuf_copy(nb, 0, FNET_NETBUF_COPYALL, 0)) != 0)
            {
                if(fnet_socket_buffer_append_address(&(last->receive_buffer), nb_tmp, foreign_addr) == FNET_ERR)
                {
                    fnet_netbuf_free_chain(nb_tmp);
                    goto BAD;
                }
            }
            else
                goto BAD;
        }
        else /* For unicast datagram.*/
        {
            sock = fnet_socket_lookup(fnet_raw_prot_if.head, local_addr, foreign_addr, protocol_number);

            if(sock)
            {
                if(sock->receive_buffer.is_shutdown) /* Is shutdown.*/
                    goto BAD;
                    
                /* Copy buffer.*/
                if((nb_tmp = fnet_netbuf_copy(nb, 0, FNET_NETBUF_COPYALL, 0)) != 0)
                {
                    if(fnet_socket_buffer_append_address(&(sock->receive_buffer), nb_tmp, foreign_addr) == FNET_ERR)
                    {
                        fnet_netbuf_free_chain(nb_tmp);
                        goto BAD;
                    }
                }
                else
                    goto BAD;
            }
        }
    }
BAD:
    return;
}
Пример #18
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);        
    
    }

}
Пример #19
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);
    }
}
Пример #20
0
/************************************************************************
* NAME: fnet_igmp_input
*
* DESCRIPTION: IGMP input function.
*************************************************************************/
static void fnet_igmp_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_igmp_header_t *hdr;
    fnet_netbuf_t *tmp_nb;
    int i;
    
    FNET_COMP_UNUSED_ARG(dest_ip);
    FNET_COMP_UNUSED_ARG(src_ip);
    
    fnet_netbuf_free_chain(ip4_nb);

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

        nb = tmp_nb;

        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, (int)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=0; 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=0; 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 */                
            /* esle wrong */
        }
        /************************
         * Ignore others
         ************************/
    }

DISCARD:
    fnet_netbuf_free_chain(nb);
}
Пример #21
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;
}
Пример #22
0
/************************************************************************
* NAME: fnet_arp_add_entry
*
* DESCRIPTION: Adds entry to the ARP table.
*************************************************************************/
static fnet_arp_entry_t *fnet_arp_add_entry( fnet_netif_t *netif, fnet_ip4_addr_t ipaddr, 
                                        const fnet_mac_addr_t ethaddr )
{
    fnet_arp_if_t *arpif = &(((fnet_eth_if_t *)(netif->if_ptr))->arp_if);
    int i, j;
    unsigned long max_time;

    /* Find an entry to update. */
    for (i = 0; i < FNET_ARP_TABLE_SIZE; ++i)
    {
        /* Check if the source IP address of the incoming packet matches
         * the IP address in this ARP table entry.*/
        if(ipaddr == arpif->arp_table[i].prot_addr)
        {
            /* Update this and return. */
            fnet_memcpy(arpif->arp_table[i].hard_addr, ethaddr, sizeof(fnet_mac_addr_t));
            arpif->arp_table[i].cr_time = fnet_timer_ticks();
            goto ADDED;
        }
    }

    /* If we get here, no existing ARP table entry was found. */

    /* Find an unused entry in the ARP table. */
    for (i = 0; i < FNET_ARP_TABLE_SIZE; ++i)
    {
        if(arpif->arp_table[i].prot_addr == 0)
        {
            break;
        }
    }

    /* If no unused entry is found, we try to find the oldest entry and throw it away.*/
    if(i == FNET_ARP_TABLE_SIZE)
    {
        max_time = 0;
        j = 0;

        for (i = 0; i < FNET_ARP_TABLE_SIZE; ++i)
        {
            if((fnet_timer_ticks() - arpif->arp_table[i].cr_time) > max_time)
            {
                max_time = fnet_timer_ticks() - arpif->arp_table[i].cr_time;
                j = i;
            }
        }

        i = j;
    }

    /* Now, it is the ARP table entry which we will fill with the new information. */
    if(arpif->arp_table[i].hold)
    {
        fnet_netbuf_free_chain(arpif->arp_table[i].hold);
        arpif->arp_table[i].hold = 0;
        arpif->arp_table[i].hold_time = 0;
    }

    arpif->arp_table[i].prot_addr = ipaddr;
    fnet_memcpy(arpif->arp_table[i].hard_addr, ethaddr, sizeof(fnet_mac_addr_t));
    
    arpif->arp_table[i].cr_time = fnet_timer_ticks();
ADDED:
    return ( &arpif->arp_table[i]);
}
Пример #23
0
/************************************************************************
* NAME: fnet_icmp_error
*
* DESCRIPTION: Sends ICMP error message.
*************************************************************************/
void fnet_icmp_error( fnet_netif_t *netif, fnet_uint8_t type, fnet_uint8_t code, fnet_netbuf_t *nb )
{
    fnet_ip_header_t        *ipheader;
    fnet_netbuf_t           *nb_header;
    fnet_icmp_err_header_t  *icmpheader;
    fnet_ip4_addr_t          source_addr;
    fnet_ip4_addr_t          destination_addr;
    

    if(nb)
    {
        ipheader = (fnet_ip_header_t *)nb->data_ptr;
        
        source_addr = ipheader->source_addr;
        destination_addr = ipheader->desination_addr;

        /* Do not send error if not the first fragment of message (RFC1122)*/
        if((FNET_IP_HEADER_GET_OFFSET(ipheader) != 0u) ||
            /* Do not send error on ICMP error messages*/
            ((ipheader->protocol == FNET_IP_PROTOCOL_ICMP)
              && (!FNET_ICMP_IS_QUERY_TYPE(((fnet_icmp_header_t *)((fnet_uint8_t *)(nb->data_ptr) + (FNET_IP_HEADER_GET_HEADER_LENGTH(ipheader) << 2)))->type))) 
            /* Do not send error on a datagram whose source address does not define a single
             * host -- e.g., a zero address, a loopback address, a
             * broadcast address, a multicast address, or a Class E
             * address.*/
            || (fnet_ip_addr_is_broadcast(source_addr, netif))
            || FNET_IP4_ADDR_IS_MULTICAST(source_addr) 
            || FNET_IP4_CLASS_E(source_addr)
            /* Do not send error on a datagram destined to an IP broadcast or IP multicast address*/
            || (fnet_ip_addr_is_broadcast(destination_addr, netif))
            || FNET_IP4_ADDR_IS_MULTICAST(destination_addr)
             /* Do not send error on datagram sent as a link-layer broadcast or multicast.*/
            ||((nb->flags & FNET_NETBUF_FLAG_BROADCAST) != 0u) || ((nb->flags & FNET_NETBUF_FLAG_MULTICAST) != 0u)
        )
        {
            goto FREE_NB;
        }

        /* Construct ICMP error header*/
        if((nb_header = fnet_netbuf_new((sizeof(fnet_icmp_err_header_t) - sizeof(fnet_ip_header_t)), FNET_FALSE)) == 0)
        {
            goto FREE_NB;
        }

        icmpheader = (fnet_icmp_err_header_t *)nb_header->data_ptr;
        icmpheader->fields.unused = 0u;

        if(type == FNET_ICMP_PARAMPROB)
        {
            icmpheader->fields.ptr = fnet_htons((fnet_uint16_t)code);
            code = 0u;
        }
        else if((type == FNET_ICMP_PARAMPROB) && (code == FNET_ICMP_UNREACHABLE_NEEDFRAG) && netif)
        {    
            icmpheader->fields.mtu = fnet_htons((fnet_uint16_t)netif->mtu);
        }
        else
        {}

        icmpheader->header.type = type;
        icmpheader->header.code = code;

        if((fnet_size_t)((FNET_IP_HEADER_GET_HEADER_LENGTH(ipheader) << 2) + 8u) < nb->total_length)
        {
            fnet_netbuf_trim(&nb, (fnet_int32_t)((fnet_size_t)((FNET_IP_HEADER_GET_HEADER_LENGTH(ipheader) << 2) + 8u) - nb->total_length));
        }

        nb = fnet_netbuf_concat(nb_header, nb);

        fnet_icmp_output(netif, destination_addr, source_addr, nb);

        return;

FREE_NB:
        fnet_netbuf_free_chain(nb);
    }
}
Пример #24
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);
}
Пример #25
0
/************************************************************************
* NAME: fnet_icmp_input
*
* DESCRIPTION: ICMP input function.
*************************************************************************/
static void fnet_icmp_input(fnet_netif_t *netif, struct sockaddr *src_addr,  struct sockaddr *dest_addr, fnet_netbuf_t *nb, fnet_netbuf_t *ip4_nb)
{
    fnet_icmp_header_t      *hdr;
    fnet_prot_notify_t      prot_cmd;
    fnet_ip4_addr_t         src_ip;
    fnet_ip4_addr_t         dest_ip;
    
    fnet_netbuf_free_chain(ip4_nb); /* Not used.*/
    
    if((netif != 0) && (nb != 0) )
    {
        if(fnet_netbuf_pullup(&nb, sizeof(fnet_icmp_header_t)) == FNET_ERR) /* The header must reside in contiguous area of memory. */
        {
            goto DISCARD;
        }

        hdr = (fnet_icmp_header_t *)nb->data_ptr;

        src_ip = ((struct sockaddr_in*)(src_addr))->sin_addr.s_addr;
        dest_ip = ((struct sockaddr_in*)(dest_addr))->sin_addr.s_addr;

        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, 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(fnet_netbuf_pullup(&nb, sizeof(fnet_icmp_timestamp_header_t)) == FNET_ERR)
                {
                    goto DISCARD;
                }

                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(fnet_netbuf_pullup(&nb, sizeof(fnet_icmp_mask_header_t)) == FNET_ERR) 
                {
                    goto DISCARD;
                }

                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;
                }
                fnet_icmp_notify_protocol(prot_cmd, nb);  /* Protocol notification.*/
                break;
            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;
                }

                fnet_icmp_notify_protocol(prot_cmd, nb);  /* Protocol notification.*/
                break;
            case FNET_ICMP_PARAMPROB:                       /* Parameter Problem Message.*/
                if(hdr->code > 1u)
                {
                    goto DISCARD;
                }

                prot_cmd = FNET_PROT_NOTIFY_PARAMPROB;
                fnet_icmp_notify_protocol(prot_cmd, nb);  /* Protocol notification.*/
                break;
            case FNET_ICMP_SOURCEQUENCH:                    /* Source Quench Message; packet lost, slow down.*/
                if(hdr->code)
                {
                    goto DISCARD;
                }

                prot_cmd = FNET_PROT_NOTIFY_QUENCH;
                fnet_icmp_notify_protocol(prot_cmd, nb);  /* Protocol notification.*/
                break;
            /************************
             * 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);
    }
}
Пример #26
0
/************************************************************************
* NAME: fnet_arp_input
*
* DESCRIPTION: ARP input function.
*************************************************************************/
void fnet_arp_input( fnet_netif_t *netif, fnet_netbuf_t *nb )
{
	fnet_arp_if_t       *arpif = &(((fnet_eth_if_t *)(netif->if_ptr))->arp_if);
    fnet_arp_header_t   *arp_hdr = nb->data_ptr;
    fnet_mac_addr_t     local_addr;
    fnet_arp_entry_t    *entry;

    if(!((nb == 0) /* The packet is wrong. */
    || (nb->total_length < sizeof(fnet_arp_header_t)) || (arp_hdr->hard_type != FNET_HTONS(FNET_ARP_HARD_TYPE))
             || (arp_hdr->hard_size != FNET_ARP_HARD_SIZE) || (arp_hdr->prot_type != FNET_HTONS(FNET_ETH_TYPE_IP4))
             || (arp_hdr->prot_size != FNET_ARP_PROT_SIZE)))
    {

        if(nb->total_length > sizeof(fnet_arp_header_t)) 
        {
            /* Logical size and the physical size of the packet should be the same.*/
            fnet_netbuf_trim(&nb, (int)(sizeof(fnet_arp_header_t) - nb->total_length)); 
        }
        
        fnet_arp_trace("RX", arp_hdr); /* Print ARP header. */
        
        fnet_netif_get_hw_addr(netif, local_addr, sizeof(fnet_mac_addr_t));

        if(!(!fnet_memcmp(arp_hdr->sender_hard_addr, local_addr, sizeof(fnet_mac_addr_t)) /* It's from me => ignore it.*/
        || !fnet_memcmp(arp_hdr->sender_hard_addr, fnet_eth_broadcast, sizeof(fnet_mac_addr_t)))  /* It's broadcast=> error. */
        )
        {
            fnet_ip4_addr_t sender_prot_addr = arp_hdr->sender_prot_addr;
            fnet_ip4_addr_t targer_prot_addr = arp_hdr->targer_prot_addr;
           
            if(sender_prot_addr != netif->ip4_addr.address)     /* Check Duplicate IP address.*/
            {
                if(targer_prot_addr == netif->ip4_addr.address) /* It's for me.*/
                {
                    entry = fnet_arp_add_entry(netif, sender_prot_addr, arp_hdr->sender_hard_addr);
                }
                else
                {
                    entry = fnet_arp_update_entry(netif, sender_prot_addr, arp_hdr->sender_hard_addr);
                }

                if(entry && entry->hold)
                {
                    /* Send waiting data.*/
                    ((fnet_eth_if_t *)(netif->if_ptr))->output(netif, FNET_ETH_TYPE_IP4, entry->hard_addr, entry->hold);

                    entry->hold = 0;
                    entry->hold_time = 0;
                }
            }
            else
            {
                /* IP is duplicated. */
                fnet_event_raise(arpif->arp_event);
            }

            /* ARP request. If it asked for our address, we send out a reply.*/
            if((arp_hdr->op == FNET_HTONS(FNET_ARP_OP_REQUEST)) && (targer_prot_addr == netif->ip4_addr.address))
            {
                arp_hdr->op = FNET_HTONS(FNET_ARP_OP_REPLY); /* Opcode */

                fnet_memcpy(arp_hdr->target_hard_addr, arp_hdr->sender_hard_addr, sizeof(fnet_mac_addr_t));
                fnet_memcpy(arp_hdr->sender_hard_addr, local_addr, sizeof(fnet_mac_addr_t));

                arp_hdr->targer_prot_addr = arp_hdr->sender_prot_addr;
                arp_hdr->sender_prot_addr = netif->ip4_addr.address;
                
                fnet_arp_trace("TX Reply", arp_hdr); /* Print ARP header. */
                
                ((fnet_eth_if_t *)(netif->if_ptr))->output(netif, FNET_ETH_TYPE_ARP, fnet_eth_broadcast, nb);
                return;
            }
        }
    }

    fnet_netbuf_free_chain(nb);
}