/* * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * FNET porting to Nanostack environment */ #include "fnet.h" #include "fnet_netif.h" #include "fnet_netif_prv.h" #include "fnet_timer.h" #include "fnet_serial.h" #include "fnet_socket.h" #include "ns_types.h" #include "ns_list.h" #include "common_functions.h" // common_write #include "ns_trace.h" #include "socket_api.h" #include "net_interface.h" #include "nsdynmemLIB.h" #include "Core/include/ns_address_internal.h" #include "ns_fnet_events.h" #define TRACE_GROUP "mDNS" fnet_time_t fnet_timer_get_ms(void) { return ns_fnet_time_in_ms_get(); } fnet_scope_id_t fnet_netif_get_scope_id(fnet_netif_desc_t netif_desc) { fnet_netif_t *netif = (fnet_netif_t *)netif_desc; FNET_DEBUG("fnet_netif_get_scope_id() scope_id=%d", (int)netif->scope_id); return netif->scope_id; } fnet_ip4_addr_t fnet_netif_get_ip4_addr(fnet_netif_desc_t netif_desc) { (void)netif_desc; return 0u; } fnet_bool_t fnet_netif_get_ip6_addr(fnet_netif_desc_t netif_desc, fnet_index_t n, fnet_netif_ip6_addr_info_t *addr_info) { fnet_bool_t result = FNET_FALSE; fnet_netif_t *netif = (fnet_netif_t *)netif_desc; uint8_t global_address[16] = {0}; (void)n; if (netif && addr_info) { if (0 == arm_net_address_get((int8_t)netif->scope_id, ADDR_IPV6_GP, global_address)) { memcpy(&addr_info->address.addr, global_address, 16); /* IPv6 address.*/ addr_info->state = FNET_NETIF_IP6_ADDR_STATE_PREFERRED; /* Address current state.*/ addr_info->type = FNET_NETIF_IP_ADDR_TYPE_AUTOCONFIGURABLE; /* How the address was acquired.*/ result = FNET_TRUE; } FNET_DEBUG("fnet_netif_get_ip6_addr(), if=%d: %s", (int8_t)netif->scope_id, trace_ipv6(addr_info->address.addr)); } return result; } fnet_bool_t fnet_netif_is_my_ip6_addr(fnet_netif_t *netif, const fnet_ip6_addr_t *ip_addr) { int i = 0; uint8_t address_buffer[16]; int8_t interface_id = (int8_t)netif->scope_id; int8_t addr_available = 0; do { addr_available = arm_net_address_list_get_next(interface_id, &i, address_buffer); if (addr_available < 0) { return FNET_FALSE; } if (addr_ipv6_equal(address_buffer, ip_addr->addr)) { return FNET_TRUE; } } while (addr_available); return FNET_FALSE; } static void fnet_nanostack_port_ns_socket_recv(void *socket_cb) { (void)socket_cb; // socket event received, run service again to achieve faster response time ns_fnet_events_fast_poll(); } fnet_socket_t fnet_socket(fnet_address_family_t family, fnet_socket_type_t type, fnet_uint32_t protocol) { int8_t socket_id = 0; (void)protocol; if (type != SOCK_DGRAM || family != AF_INET6) { return FNET_NULL; } socket_id = socket_open(SOCKET_UDP, 0, fnet_nanostack_port_ns_socket_recv); if (socket_id < 0) { return FNET_NULL; } // Socket contains buffer for the received data, enable the feature using socket options static const int32_t rcvbuf_size = 1024 * 4; socket_setsockopt(socket_id, SOCKET_SOL_SOCKET, SOCKET_SO_RCVBUF, &rcvbuf_size, sizeof rcvbuf_size); FNET_DEBUG("fnet_socket_open, socket:%d", socket_id); return (fnet_socket_t)(long)socket_id; } fnet_return_t fnet_socket_bind(fnet_socket_t s, const struct sockaddr *name, fnet_size_t namelen) { (void)namelen; ns_address_t ns_source_addr; int8_t socket_id = (int8_t)(long)s; fnet_return_t fnet_ret_val = FNET_ERR; const struct sockaddr_in6 *namein6 = (const struct sockaddr_in6 *) name; memcpy(ns_source_addr.address, &namein6->sin6_addr, 16); ns_source_addr.identifier = FNET_NTOHS(namein6->sin6_port); ns_source_addr.type = ADDRESS_IPV6; FNET_DEBUG("fnet_socket_bind socket:%d to port %d address %s", socket_id, (int)ns_source_addr.identifier, trace_ipv6(ns_source_addr.address)); int8_t status = socket_bind(socket_id, &ns_source_addr); if (status == 0) { fnet_ret_val = FNET_OK; } return fnet_ret_val; } fnet_return_t fnet_socket_setopt(fnet_socket_t s, fnet_protocol_t level, fnet_socket_options_t optname, const void *optval, fnet_size_t optvallen) { (void) level; (void) optvallen; int8_t socket_id; int8_t ret_val = -1; socket_id = (int8_t)(long)s; if (optname == IPV6_JOIN_GROUP) { const struct ipv6_mreq *mreq6 = optval; /* Multicast group information.*/ int8_t interface_id = (int8_t)mreq6->ipv6imr_interface; // scope_id holds interface_id ret_val = socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, SOCKET_INTERFACE_SELECT, &interface_id, sizeof(interface_id)); if (ret_val == 0) { ns_ipv6_mreq_t ns_ipv6_mreq; ns_ipv6_mreq.ipv6mr_interface = interface_id; memcpy(ns_ipv6_mreq.ipv6mr_multiaddr, ADDR_LINK_LOCAL_MDNS, 16); // Join multicast group ret_val = socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_JOIN_GROUP, &ns_ipv6_mreq, sizeof(ns_ipv6_mreq)); } if (ret_val == 0) { bool loopback = false; // Ignore loopback from own multicasts ret_val = socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_MULTICAST_LOOP, &loopback, sizeof(loopback)); } } else if (optname == IPV6_MULTICAST_HOPS) { // Both FNET and Nanostack use int16_t, so can pass straight through ret_val = socket_setsockopt(socket_id, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_MULTICAST_HOPS, optval, optvallen); } if (ret_val == 0) { return FNET_OK; } return FNET_ERR; } fnet_int32_t fnet_socket_sendto(fnet_socket_t s, fnet_uint8_t *buf, fnet_size_t len, fnet_flag_t flags, const struct sockaddr *to, fnet_size_t tolen) { (void)tolen; // ipv6 address expected (void)flags; // int8_t socket_id = (int8_t)(long)s; ns_address_t ns_address; ns_address.type = ADDRESS_IPV6; memcpy(ns_address.address, &((struct sockaddr_in6 *)to)->sin6_addr.s6_addr, 16); // Note! Port is already in network byte order, transfer it back as nanostack will convert it again to network byte order ns_address.identifier = FNET_NTOHS(to->sa_port); FNET_DEBUG("fnet_socket_sendto, %d bytes, port:%d, socket:%d", (int)len, (int)ns_address.identifier, socket_id); return (fnet_int32_t)socket_sendto(socket_id, &ns_address, buf, len); } fnet_int32_t fnet_socket_recvfrom(fnet_socket_t s, fnet_uint8_t *buf, fnet_size_t len, fnet_flag_t flags, struct sockaddr *from, fnet_size_t *fromlen) { (void)flags; // mdns does not use flags (void)fromlen; // address is ipv6 int8_t socket_id = (int8_t)(long)s; int16_t data_len; ns_address_t source_address; data_len = socket_read(socket_id, &source_address, buf, len); if (data_len >= 0) { if (from) { struct sockaddr_in6 *fromin6 = (struct sockaddr_in6 *) from; memcpy(&fromin6->sin6_addr.s6_addr, source_address.address, 16); //addrin6.sin6_scope_id = interface_id; where to get interface_id here? fromin6->sin6_family = AF_INET6; // port is in native byte order,, convert to network byte order fromin6->sin6_port = FNET_HTONS(source_address.identifier); *fromlen = sizeof(struct sockaddr_in6); } } else { tr_error("Socket recv failed: socket:%d, err:%d", socket_id, data_len); data_len = (int16_t) FNET_ERR; } return data_len; } fnet_return_t fnet_socket_close(fnet_socket_t s) { int8_t socket_id = (int8_t)(long)s; FNET_DEBUG("fnet_socket_close, socket:%d", socket_id); socket_close(socket_id); return FNET_OK; }