Ejemplo n.º 1
0
/************************************************************************
* NAME: fnet_netif_get_ip6_addr
*
* DESCRIPTION: This function is used to retrieve all IP addresses registerred 
*              with the given interface.
*              Returns FNET_TRUE if successful and data structure filled 
*              and FNET_FALSE in case of error.
*              It returns FNET_FALSE if n-th address is not available.
*************************************************************************/
int fnet_netif_get_ip6_addr (fnet_netif_desc_t netif_desc, unsigned int n, fnet_netif_ip6_addr_info_t *addr_info)
{

    int             result = FNET_FALSE;

    int             i;
    fnet_netif_t    *netif = (fnet_netif_t *)netif_desc;

    if(netif && addr_info)
    {
        for(i=0; i<FNET_NETIF_IP6_ADDR_MAX; i++)
        {
            /* Skip NOT_USED addresses. */
            if(netif->ip6_addr[i].state != FNET_NETIF_IP6_ADDR_STATE_NOT_USED)
            {    
                if(n == 0)
                {
                    FNET_IP6_ADDR_COPY(&netif->ip6_addr[i].address, &addr_info->address);    /* IPv6 address.*/
                    addr_info->state = netif->ip6_addr[i].state;                            /* Address current state.*/
                    addr_info->type = netif->ip6_addr[i].type;                              /* How the address was acquired.*/
                    
                    result = FNET_TRUE;
                    break;     
                }
                n--;
            }    
        } 
    }
    
    return result;
}
Ejemplo n.º 2
0
void fnet_raw_input_ip6(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)
{
    struct sockaddr     src_addr;
    struct sockaddr     dest_addr;
    fnet_ip6_header_t   *hdr = ip6_nb->data_ptr;
    
    fnet_memset_zero(&src_addr, sizeof(struct sockaddr));
    src_addr.sa_family = AF_INET6;
    FNET_IP6_ADDR_COPY(src_ip, &((struct sockaddr_in6 *)(&src_addr))->sin6_addr.s6_addr);
    ((struct sockaddr_in6 *)(&src_addr))->sin6_scope_id = netif->scope_id;
    
    
    fnet_memset_zero(&dest_addr, sizeof(struct sockaddr));
    dest_addr.sa_family = AF_INET6;
    FNET_IP6_ADDR_COPY(dest_ip, &((struct sockaddr_in6 *)(&dest_addr))->sin6_addr.s6_addr);
    ((struct sockaddr_in6 *)(&dest_addr))->sin6_scope_id = netif->scope_id;

    fnet_raw_input(netif, &src_addr,  &dest_addr, nb, hdr->next_header);    
}
Ejemplo n.º 3
0
/************************************************************************
* NAME: fapp_bench_udp_rx
*
* DESCRIPTION: Start Benchmark UDP server. 
************************************************************************/
static void fapp_bench_udp_rx (fnet_shell_desc_t desc, fnet_address_family_t family, struct sockaddr *multicast_address /* optional, set to 0*/)
{
	struct sockaddr         local_addr;
	const unsigned long     bufsize_option = FAPP_BENCH_SOCKET_BUF_SIZE;
	int                     received;
	char                    ip_str[FNET_IP_ADDR_STR_SIZE];
	struct sockaddr         addr;
    unsigned int            addr_len;
	int                     is_first = 1;
	int                     exit_flag = 0;
	

	/* Create listen socket */
    if((fapp_bench.socket_listen = socket(family, SOCK_DGRAM, 0)) == SOCKET_INVALID)
    {
        FNET_DEBUG("BENCH: Socket creation error.\n");
        goto ERROR_1;
    }
    
    /*Bind.*/
    fnet_memset_zero(&local_addr, sizeof(local_addr));
    
    local_addr.sa_port = FAPP_BENCH_PORT;    
    local_addr.sa_family = family;
    
    if(bind(fapp_bench.socket_listen, &local_addr, sizeof(local_addr)) == SOCKET_ERROR)
    {
        FNET_DEBUG("BENCH: Socket bind error.\n");
        goto ERROR_2;
    }


	/* Set socket options. */    
	if( 
		/* Set socket buffer size. */
		(setsockopt(fapp_bench.socket_listen, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize_option, sizeof(bufsize_option))== SOCKET_ERROR) ||
		(setsockopt(fapp_bench.socket_listen, SOL_SOCKET, SO_SNDBUF, (char *) &bufsize_option, sizeof(bufsize_option))== SOCKET_ERROR) 
	)
	{
    	FNET_DEBUG("BENCH: Socket setsockopt error.\n");
        goto ERROR_2;		
	}
    
    /* Join multicast group, if set. */
    if(multicast_address)
    {
    
    #if FNET_CFG_IP4
        if(multicast_address->sa_family == AF_INET)
        {
            struct ip_mreq mreq; /* Multicast group information.*/
            
            mreq.imr_multiaddr.s_addr = ((struct sockaddr_in*)multicast_address)->sin_addr.s_addr;
            mreq.imr_interface.s_addr = FNET_HTONL(INADDR_ANY); /* Default Interface.*/
            
            /* Join multicast group. */
            if(setsockopt(fapp_bench.socket_listen, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) == SOCKET_ERROR) 
    	    {
            	FNET_DEBUG("BENCH: Joining to multicast group is failed.\n");
                goto ERROR_2;		
        	}
    	}
    #endif
    #if FNET_CFG_IP6
        if(multicast_address->sa_family == AF_INET6)
        {
            struct ipv6_mreq mreq6; /* Multicast group information.*/
            
            FNET_IP6_ADDR_COPY(&((struct sockaddr_in6*)multicast_address)->sin6_addr.s6_addr, &mreq6.ipv6imr_multiaddr.s6_addr);
            mreq6.ipv6imr_interface = ((struct sockaddr_in6*)multicast_address)->sin6_scope_id;
            
            /* Join multicast group. */
            if(setsockopt(fapp_bench.socket_listen, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)) == SOCKET_ERROR) 
    	    {
            	FNET_DEBUG("BENCH: Joining to multicast group is failed.\n");
                goto ERROR_2;		
        	}
        }
    #endif    	
        
    }
    
     /* ------ Start test.----------- */
    fnet_shell_println(desc, FAPP_DELIMITER_STR);
    fnet_shell_println(desc, " UDP RX Test" );
    fnet_shell_println(desc, FAPP_DELIMITER_STR);
    fapp_netif_addr_print(desc, family, fapp_default_netif, FNET_FALSE);
    if(multicast_address)
    {
        fnet_shell_println(desc, FAPP_SHELL_INFO_FORMAT_S, "Multicast Group", fnet_inet_ntop(multicast_address->sa_family, (char*)(multicast_address->sa_data), ip_str, sizeof(ip_str)) );
    }       
    fnet_shell_println(desc, FAPP_SHELL_INFO_FORMAT_D, "Local Port", FNET_NTOHS(FAPP_BENCH_PORT));
    fnet_shell_println(desc, FAPP_TOCANCEL_STR);
    fnet_shell_println(desc, FAPP_DELIMITER_STR);
  
    
    while(exit_flag == 0) /* Main loop */
    {
        fnet_shell_println(desc, "Waiting.");
        
        fapp_bench.bytes = 0;
        fapp_bench.remote_bytes = 0;
        addr_len = sizeof(addr);
        is_first = 1;
        
        while(exit_flag == 0) /* Test loop. */
        {

    		/* Receive data */
            received = recvfrom  (fapp_bench.socket_listen, (char*)(&fapp_bench.buffer[0]), FAPP_BENCH_BUFFER_SIZE, 0,
                                &addr, &addr_len );

            if(received >= FAPP_BENCH_UDP_END_BUFFER_LENGTH)
            {   
      
                /* Reset timeout. */
                fapp_bench.last_time = fnet_timer_ticks();
                
                if(is_first)
                {
                    if( received > FAPP_BENCH_UDP_END_BUFFER_LENGTH )
                    {
                        fnet_shell_println(desc,"Receiving from %s:%d",  fnet_inet_ntop(addr.sa_family, (char*)(addr.sa_data), ip_str, sizeof(ip_str)), fnet_ntohs(addr.sa_port));
                        fapp_bench.first_time = fnet_timer_ticks();
                        is_first = 0;
                    }
                }
                else
                {
                    if(received == FAPP_BENCH_UDP_END_BUFFER_LENGTH ) /* End of transfer. */
                    {
                        /* Send ACK containing amount of received data.*/
                        unsigned long ack_bytes = fnet_htonl(fapp_bench.bytes);
                        
                        /* Send several times, just to be sure that it is received/not lost.*/
                        sendto(fapp_bench.socket_listen, (char*)(&ack_bytes), sizeof(ack_bytes), 0, (struct sockaddr*)&addr, sizeof(addr));
                        sendto(fapp_bench.socket_listen, (char*)(&ack_bytes), sizeof(ack_bytes), 0, (struct sockaddr*)&addr, sizeof(addr));
                        sendto(fapp_bench.socket_listen, (char*)(&ack_bytes), sizeof(ack_bytes), 0, (struct sockaddr*)&addr, sizeof(addr));
                        
                        
                        /* Print benchmark results.*/
                        fapp_bench_print_results (desc);           		
    					
                        break;    	
                    }
                    else
                        fapp_bench.bytes += received; 
                }
            }
            else
            {
                /* Check error. Check timeout */
                if(received == SOCKET_ERROR)
                {
                    fnet_shell_println(desc, "BENCH: Error (%d).", fnet_error_get());                   
                    break;
                }
                /* Check timeout. */
                if((is_first == 0) &&
                    (fnet_timer_get_interval(fapp_bench.last_time, fnet_timer_ticks()) > (FAPP_UDP_TIMEOUT_MS/FNET_TIMER_PERIOD_MS)))
                {
                    fnet_shell_println(desc, "BENCH: Exit on timeout.");
                    fapp_bench_print_results (desc);            
                    break;
                }
            }
            
            exit_flag = fnet_shell_ctrlc (desc);
        }
    }

ERROR_2:
    closesocket(fapp_bench.socket_listen);

ERROR_1:
 
    fnet_shell_println(desc, FAPP_BENCH_COMPLETED_STR);
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
/************************************************************************
* NAME: fnet_dns_state_machine
*
* DESCRIPTION: DNS-client state machine.
************************************************************************/
static void fnet_dns_state_machine( void *fnet_dns_if_p )
{
    int                     sent_size;
    int                     received;    
    unsigned int            i;
    fnet_dns_header_t       *header;
    fnet_dns_rr_header_t    *rr_header;
    fnet_dns_if_t           *dns_if = (fnet_dns_if_t *)fnet_dns_if_p;

    switch(dns_if->state)
    {
        /*---- TX --------------------------------------------*/
        case FNET_DNS_STATE_TX:

            FNET_DEBUG_DNS("Sending query...");
            sent_size = send(dns_if->socket_cln, dns_if->message, dns_if->message_size, 0U);
            
            if (sent_size != (int)dns_if->message_size)
        	{
        		dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */
        	}	
            else
            {
                dns_if->last_time = fnet_timer_ticks();
                dns_if->state = FNET_DNS_STATE_RX;
            }		
            break; 
        /*---- RX -----------------------------------------------*/
        case  FNET_DNS_STATE_RX:
            /* Receive data */
            
            received = recv(dns_if->socket_cln, dns_if->message, sizeof(dns_if->message), 0U);
            
            if(received > 0 )
            {
                header = (fnet_dns_header_t *)fnet_dns_if.message;
                
                if((header->id == dns_if->id) && /* Check the ID.*/
                   ((header->flags & FNET_DNS_HEADER_FLAGS_QR)==FNET_DNS_HEADER_FLAGS_QR)) /* Is response.*/
                {
                    for (i=(sizeof(fnet_dns_header_t)-1U); i < (unsigned int)received; i++)
                    {
                        /* [RFC1035 4.1.4.] In order to reduce the size of messages, the domain system utilizes a
                        * compression scheme which eliminates the repetition of domain names in a
                        * message. In this scheme, an entire domain name or a list of labels at
                        * the end of a domain name is replaced with a pointer to a prior occurance
                        * of the same name.
                        * The pointer takes the form of a two octet sequence:
                        * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
                        * | 1  1|                OFFSET                   |
                        * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
                        */
                        /* => Check for 0xC0. */
                        if ((unsigned char)dns_if->message[i] == FNET_DNS_NAME_COMPRESSED_MASK) /* look for the beginnig of the response (Question Name == 192 (label compression))*/
                        {
                            rr_header = (fnet_dns_rr_header_t *)&dns_if->message[i]; 


                            /* Check Question Type, Class and Resource Data Length. */
                            if ( (rr_header->type ==  dns_if->dns_type) && 
                                 (rr_header->rr_class == FNET_HTONS(FNET_DNS_HEADER_CLASS_IN))) 
                            {
                                /* Resolved.*/
                                if(rr_header->type == FNET_HTONS(FNET_DNS_TYPE_A))
                                {
                                	dns_if->resolved_ip4_addr[dns_if->addr_number].ip4_addr = *((fnet_ip4_addr_t*)(&rr_header->rdata));
                                    dns_if->resolved_ip4_addr[dns_if->addr_number].ttl = rr_header->ttl;
                                }
                                else /* AF_INET6 */
                                {
                                    FNET_IP6_ADDR_COPY( (fnet_ip6_addr_t*)(&rr_header->rdata), &dns_if->resolved_ip6_addr[dns_if->addr_number].ip6_addr );
                                    dns_if->resolved_ip6_addr[dns_if->addr_number].ttl = rr_header->ttl;
                                }
                                dns_if->addr_number++;
                            }
                            i+=(unsigned int)(sizeof(fnet_dns_rr_header_t)+fnet_ntohs(rr_header->rdlength)-4U-1U);
                        }
                    }
                }
                /* else = wrong message.*/
                
                dns_if->state = FNET_DNS_STATE_RELEASE;
            }
            else if(received == SOCKET_ERROR) /* Check error.*/
            {
                dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */
            }
            else /* No data. Check timeout */
            if(fnet_timer_get_interval(dns_if->last_time, fnet_timer_ticks()) > ((FNET_CFG_DNS_RETRANSMISSION_TIMEOUT*1000U)/FNET_TIMER_PERIOD_MS))
            {
                dns_if->iteration++;
                
                if(dns_if->iteration > FNET_CFG_DNS_RETRANSMISSION_MAX)
                {
                    dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */
                }
                else
                {
                    dns_if->state = FNET_DNS_STATE_TX;
                }
            }
            else
            {}
            break;
         /*---- RELEASE -------------------------------------------------*/    
        case FNET_DNS_STATE_RELEASE:
            {
                struct fnet_dns_resolved_addr   *addr_list = FNET_NULL;

                fnet_dns_release(); 

                /* Fill fnet_dns_resolved_addr */
                if(dns_if->addr_number > 0)
                {
                    if(dns_if->addr_family  == AF_INET)
                    {
                        for(i=0; i<dns_if->addr_number; i++)
                        {
                            fnet_memset_zero(&dns_if->resolved_ip4_addr_sock[i].resolved_addr, sizeof(dns_if->resolved_ip4_addr_sock[i].resolved_addr));

                            dns_if->resolved_ip4_addr_sock[i].resolved_addr.sa_family = AF_INET;
                            ((struct sockaddr_in*)(&dns_if->resolved_ip4_addr_sock[i].resolved_addr))->sin_addr.s_addr = dns_if->resolved_ip4_addr[i].ip4_addr;
                            dns_if->resolved_ip4_addr_sock[i].resolved_addr_ttl = dns_if->resolved_ip4_addr[i].ttl;
                        }
                        addr_list = dns_if->resolved_ip4_addr_sock;
                    }
                    else if(dns_if->addr_family == AF_INET6)
                    {
                        for(i=0; i<dns_if->addr_number; i++)
                        {
                            fnet_memset_zero(&dns_if->resolved_ip6_addr_sock[i].resolved_addr, sizeof(dns_if->resolved_ip4_addr_sock[i].resolved_addr));

                            dns_if->resolved_ip6_addr_sock[i].resolved_addr.sa_family = AF_INET6;
                            FNET_IP6_ADDR_COPY(&dns_if->resolved_ip6_addr[i].ip6_addr, &((struct sockaddr_in6*)(&dns_if->resolved_ip6_addr_sock[i].resolved_addr))->sin6_addr.s6_addr);
                            dns_if->resolved_ip6_addr_sock[i].resolved_addr_ttl = dns_if->resolved_ip6_addr[i].ttl;
                        }
                        addr_list = dns_if->resolved_ip6_addr_sock;
                    }
                    else
                    {}
                }

                dns_if->handler(addr_list, dns_if->addr_number, dns_if->handler_cookie); /* User Callback.*/
            }
            break;
        default:
            break;            
    }

}
Ejemplo n.º 6
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);
            }
        }
    }
}
Ejemplo n.º 7
0
/************************************************************************
* 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;
}