/************************************************************************ * 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; }
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); }
/************************************************************************ * 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); }
/************************************************************************ * NAME: fnet_eth_output_ip6 * * DESCRIPTION: Ethernet IPv6 output function. *************************************************************************/ void fnet_eth_output_ip6(fnet_netif_t *netif, const fnet_ip6_addr_t *src_ip_addr, const fnet_ip6_addr_t *dest_ip_addr, fnet_netbuf_t *nb) { fnet_mac_addr_t dest_mac_addr; /* 48-bit destination address */ fnet_uint8_t *dest_mac_addr_ptr; /******************************************** * Multicast. ********************************************/ if (FNET_IP6_ADDR_IS_MULTICAST(dest_ip_addr)) { FNET_ETH_MULTICAST_IP6_TO_MAC(dest_ip_addr, dest_mac_addr); dest_mac_addr_ptr = (fnet_uint8_t *)dest_mac_addr; } /******************************************** * Unicast. ********************************************/ else { fnet_nd6_neighbor_entry_t *neighbor; /* Possible redirection.*/ fnet_nd6_redirect_addr(netif, &dest_ip_addr); /* Check Neigbor cache.*/ neighbor = fnet_nd6_neighbor_cache_get(netif, dest_ip_addr); /* RFC4861 7.2.2: When a node has a unicast packet to send to a neighbor, but does not * know the neighbor’s link-layer address, it performs address resolution. * For multicast-capable interfaces, this entails creating a * Neighbor Cache entry in the INCOMPLETE state and transmitting a * Neighbor Solicitation message targeted at the neighbor. The * solicitation is sent to the solicited-node multicast address * corresponding to the target address. */ if(neighbor == FNET_NULL) { /* RFC4861 7.2.Address resolution is performed only on addresses that are determined to be * on-link and for which the sender does not know the corresponding link-layer address. * Address resolution is never performed on multicast addresses.*/ if(fnet_nd6_addr_is_onlink(netif, dest_ip_addr) == FNET_TRUE) /* Destimnation is ON local-link.*/ { /* Creating a Neighbor Cache entry in the INCOMPLETE state. */ neighbor = fnet_nd6_neighbor_cache_add(netif, dest_ip_addr, FNET_NULL, FNET_ND6_NEIGHBOR_STATE_INCOMPLETE); neighbor->state_time = fnet_timer_ms(); neighbor->solicitation_send_counter = 0u; FNET_IP6_ADDR_COPY(src_ip_addr, &neighbor->solicitation_src_ip_addr); /* Save src address for later usage.*/ /* AR: Transmitting a Neighbor Solicitation message targeted at the neighbor.*/ fnet_nd6_neighbor_solicitation_send(netif, src_ip_addr, FNET_NULL /* NULL for AR */, dest_ip_addr); } /* Destination is OFF local-link.*/ else { /* Try to use the router, if exists.*/ neighbor = fnet_nd6_default_router_get(netif); if(neighbor == FNET_NULL) /* No Router exists.*/ { fnet_netbuf_free_chain(nb); /* Discard datagram */ goto EXIT; } dest_ip_addr = &neighbor->ip_addr; /* Chage destination address to the router one */ } } /* Link -layer address is not initialized.*/ if((neighbor->state != FNET_ND6_NEIGHBOR_STATE_INCOMPLETE) && (neighbor->ll_addr[0] == 0U) && (neighbor->ll_addr[1] == 0U) && (neighbor->ll_addr[2] == 0U) && (neighbor->ll_addr[3] == 0U) && (neighbor->ll_addr[4] == 0U) && (neighbor->ll_addr[5] == 0U) ) { neighbor->state = FNET_ND6_NEIGHBOR_STATE_INCOMPLETE; neighbor->state_time = fnet_timer_ms(); neighbor->solicitation_send_counter = 0u; FNET_IP6_ADDR_COPY(src_ip_addr, &neighbor->solicitation_src_ip_addr); /* Save src address for later usage.*/ /* AR: Transmitting a Neighbor Solicitation message targeted at the neighbor.*/ fnet_nd6_neighbor_solicitation_send(netif, src_ip_addr, FNET_NULL /* NULL for AR */, dest_ip_addr); } if(neighbor->state == FNET_ND6_NEIGHBOR_STATE_INCOMPLETE) /* Queue packet for later transmit. */ { fnet_nd6_neighbor_enqueue_waiting_netbuf(neighbor, nb); goto EXIT; } if(neighbor->state == FNET_ND6_NEIGHBOR_STATE_STALE) /* RFC4861 7.3.3: The first time a node sends a packet to a neighbor whose entry is * STALE, the sender changes the state to DELAY and sets a timer to * expire in DELAY_FIRST_PROBE_TIME seconds. */ { neighbor->state = FNET_ND6_NEIGHBOR_STATE_DELAY; neighbor->state_time = fnet_timer_ms(); } /* Get destination MAC/HW address.*/ dest_mac_addr_ptr = (fnet_uint8_t *)(&neighbor->ll_addr[0]); } /* Send Ethernet frame. */ fnet_eth_output(netif, FNET_ETH_TYPE_IP6, dest_mac_addr_ptr, nb); EXIT: return; }
/************************************************************************ * NAME: fnet_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; } }
/************************************************************************ * 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); } } } }
/************************************************************************ * 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; }