From bce40f40849b4fd5cb56702125883b9ba7cd9463 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Tue, 15 Aug 2017 15:55:30 +0300 Subject: [PATCH 01/16] Networking update: general refactoring, unifying EMAC Initial work by Bartek Szatkowski in https://github.com/ARMmbed/mbed-os/pull/4079, reworked following review of https://github.com/ARMmbed/mbed-os/pull/5202 to transform the entire system into C++, retaining the basic functionality. Bartek's summary: * Porting ethernet to EMAC * Updating EMAC to enable multiple interfaces * Untangling networking classes, making the abstractions a bit clearer to follow, etc * General refactoring * Removal of DEVICE_EMAC flag and introducing DEVICE_ETH and DEVICE_WIFI Revisions since initial branch: * Remove lwip depencies * Correct doxygen warnings * Remove emac_api.h, replace with C++ EMAC abstract class. * Create OnboardNetworkInterface, and LWIP implementation. * Mappings since #4079 lwip-interface/nsapi_stack_lwip.c -> LWIPStack.cpp lwip-interface/ipstack_lwip.c -> LWIPInterface.cpp netsocket/mbed_ipstack.h -> OnboardNetworkStack.h hal/emac_api.h -> EMAC.h * Reinstate use of EthInterface abstraction * Correct and clarify HW address EMAC ops * Restore MBED_MAC_ADDR implementation * Integrate PPP support with LWIP::Interface. * Convert K64F lwIP driver to K64F_EMAC. To do: * Convert emac_stack_mem.h to follow this pattern. * Figure out DEVICE_ETH/EMAC * Update all drivers to use EMAC --- doxyfile_options | 1 + .../lwip-interface/LWIPInterface.cpp | 535 +++++++ .../lwip-interface/LWIPInterfaceEMAC.cpp | 182 +++ .../FEATURE_LWIP/lwip-interface/LWIPStack.cpp | 662 ++++++++ .../FEATURE_LWIP/lwip-interface/LWIPStack.h | 457 ++++++ .../FEATURE_LWIP/lwip-interface/emac_lwip.c | 88 -- ...c_stack_lwip.cpp => emac_stack_mem_lwip.c} | 28 +- .../FEATURE_LWIP/lwip-interface/eth_arch.h | 45 - .../arch/TARGET_Freescale/k64f_emac.c | 781 ---------- .../arch/TARGET_Freescale/k64f_emac.cpp | 595 +++++++ .../arch/TARGET_Freescale/k64f_emac.h | 140 ++ .../arch/TARGET_Freescale/k64f_emac_config.h | 11 +- .../arch/TARGET_Freescale/lwipopts_conf.h | 1 - .../FEATURE_LWIP/lwip-interface/lwip_stack.c | 1364 ----------------- .../FEATURE_LWIP/lwip-interface/lwip_stack.h | 47 - .../lwip-interface/lwip_tools.cpp | 191 +++ .../FEATURE_LWIP/lwip-interface/ppp_lwip.cpp | 32 +- .../FEATURE_LWIP/lwip-interface/ppp_lwip.h | 12 +- features/netsocket/EMAC.h | 156 ++ .../EthernetInterface.cpp | 31 +- .../EthernetInterface.h | 40 +- features/netsocket/NetworkStack.cpp | 6 +- features/netsocket/NetworkStack.h | 5 +- features/netsocket/OnboardNetworkStack.h | 121 ++ features/netsocket/emac_stack_mem.h | 47 +- features/netsocket/mbed_lib.json | 3 +- hal/emac_api.h | 160 -- targets/targets.json | 4 +- 28 files changed, 3168 insertions(+), 2577 deletions(-) create mode 100644 features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp create mode 100644 features/FEATURE_LWIP/lwip-interface/LWIPInterfaceEMAC.cpp create mode 100644 features/FEATURE_LWIP/lwip-interface/LWIPStack.cpp create mode 100644 features/FEATURE_LWIP/lwip-interface/LWIPStack.h delete mode 100644 features/FEATURE_LWIP/lwip-interface/emac_lwip.c rename features/FEATURE_LWIP/lwip-interface/{emac_stack_lwip.cpp => emac_stack_mem_lwip.c} (68%) delete mode 100644 features/FEATURE_LWIP/lwip-interface/eth_arch.h delete mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.c create mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.cpp create mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.h delete mode 100644 features/FEATURE_LWIP/lwip-interface/lwip_stack.c delete mode 100644 features/FEATURE_LWIP/lwip-interface/lwip_stack.h create mode 100644 features/FEATURE_LWIP/lwip-interface/lwip_tools.cpp create mode 100644 features/netsocket/EMAC.h rename features/{FEATURE_LWIP/lwip-interface => netsocket}/EthernetInterface.cpp (70%) rename features/{FEATURE_LWIP/lwip-interface => netsocket}/EthernetInterface.h (70%) create mode 100644 features/netsocket/OnboardNetworkStack.h delete mode 100644 hal/emac_api.h diff --git a/doxyfile_options b/doxyfile_options index c97e13de78d..e9d922fd6b2 100644 --- a/doxyfile_options +++ b/doxyfile_options @@ -2065,6 +2065,7 @@ PREDEFINED = DOXYGEN_ONLY \ DEVICE_CAN \ DEVICE_ETHERNET \ DEVICE_EMAC \ + DEVICE_ETH \ DEVICE_FLASH \ DEVICE_I2C \ DEVICE_I2CSLAVE \ diff --git a/features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp b/features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp new file mode 100644 index 00000000000..c6d7d7b7e55 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp @@ -0,0 +1,535 @@ +/* Copyright (c) 2017 ARM Limited + * + * 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. + */ + +#define __STDC_LIMIT_MACROS + +#include "nsapi.h" +#include "mbed_interface.h" +#include "mbed_assert.h" +#include +#include +#include +#include + +#include "lwip/opt.h" +#include "lwip/api.h" +#include "lwip/inet.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/tcpip.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "lwip/mld6.h" +#include "lwip/dns.h" +#include "lwip/udp.h" + +#include "ppp_lwip.h" + +#include "LWIPStack.h" + +static void add_dns_addr_to_dns_list_index(const u8_t addr_type, const u8_t index) +{ +#if LWIP_IPV6 + if (addr_type == IPADDR_TYPE_V6) { + /* 2001:4860:4860::8888 google */ + ip_addr_t ipv6_dns_addr = IPADDR6_INIT( + PP_HTONL(0x20014860UL), + PP_HTONL(0x48600000UL), + PP_HTONL(0x00000000UL), + PP_HTONL(0x00008888UL)); + dns_setserver(index, &ipv6_dns_addr); + } +#endif +#if LWIP_IPV4 + if (addr_type == IPADDR_TYPE_V4) { + /* 8.8.8.8 google */ + ip_addr_t ipv4_dns_addr = IPADDR4_INIT(0x08080808); + dns_setserver(index, &ipv4_dns_addr); + } +#endif +} + +static int get_ip_addr_type(const ip_addr_t *ip_addr) +{ +#if LWIP_IPV6 + if (IP_IS_V6(ip_addr)) { + return IPADDR_TYPE_V6; + } +#endif +#if LWIP_IPV4 + if (IP_IS_V4(ip_addr)) { + return IPADDR_TYPE_V4; + } +#endif +#if LWIP_IPV6 && LWIP_IPV4 + return IPADDR_TYPE_ANY; +#endif +} + +void LWIP::add_dns_addr(struct netif *lwip_netif) +{ + // Check for existing dns address + for (char numdns = 0; numdns < DNS_MAX_SERVERS; numdns++) { + const ip_addr_t *dns_ip_addr = dns_getserver(numdns); + if (!ip_addr_isany(dns_ip_addr)) { + return; + } + } + + // Get preferred ip version + const ip_addr_t *ip_addr = get_ip_addr(false, lwip_netif); + u8_t addr_type = IPADDR_TYPE_ANY; + + // Add preferred ip version dns address to index 0 + if (ip_addr) { + addr_type = get_ip_addr_type(ip_addr); + add_dns_addr_to_dns_list_index(addr_type, 0); + } + +#if LWIP_IPV4 && LWIP_IPV6 + if (!ip_addr) { + // Get address for any ip version + ip_addr = get_ip_addr(true, lwip_netif); + if (!ip_addr) { + return; + } + addr_type = get_ip_addr_type(ip_addr); + // Add the dns address to index 0 + add_dns_addr_to_dns_list_index(addr_type, 0); + } + + if (addr_type == IPADDR_TYPE_V4) { + // If ipv4 is preferred and ipv6 is available add ipv6 dns address to index 1 + ip_addr = get_ipv6_addr(lwip_netif); + } else if (addr_type == IPADDR_TYPE_V6) { + // If ipv6 is preferred and ipv4 is available add ipv4 dns address to index 1 + ip_addr = get_ipv4_addr(lwip_netif); + } else { + ip_addr = NULL; + } + + if (ip_addr) { + addr_type = get_ip_addr_type(ip_addr); + add_dns_addr_to_dns_list_index(addr_type, 1); + } +#endif +} + +void LWIP::Interface::netif_link_irq(struct netif *netif) +{ + LWIP::Interface *interface = static_cast(netif->state); + + if (netif_is_link_up(&interface->netif)) { + osSemaphoreRelease(interface->linked); + } else { + osSemaphoreRelease(interface->unlinked); + } +} + +void LWIP::Interface::netif_status_irq(struct netif *netif) +{ + LWIP::Interface *interface = static_cast(netif->state); + + if (netif_is_up(&interface->netif)) { + if (!(interface->has_addr_state & HAS_ANY_ADDR) && LWIP::get_ip_addr(true, netif)) { + osSemaphoreRelease(interface->has_any_addr); + interface->has_addr_state |= HAS_ANY_ADDR; + } +#if PREF_ADDR_TIMEOUT + if (!(interface->has_addr_state & HAS_PREF_ADDR) && LWIP::get_ip_addr(false, netif)) { + osSemaphoreRelease(interface->has_pref_addr); + interface->has_addr_state |= HAS_PREF_ADDR; + } +#endif +#if BOTH_ADDR_TIMEOUT + if (!(interface->has_addr_state & HAS_BOTH_ADDR) && LWIP::get_ipv4_addr(netif) && LWIP::get_ipv6_addr(netif)) { + osSemaphoreRelease(interface->has_both_addr); + interface->has_addr_state |= HAS_BOTH_ADDR; + } +#endif + } +} + +#if LWIP_IPV6 +static void mbed_lwip_clear_ipv6_addresses(struct netif *netif) +{ + for (u8_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); + } +} +#endif + +char *LWIP::Interface::get_mac_address(char *buf, nsapi_size_t buflen) +{ + (void) snprintf(buf, buflen, "%02x:%02x:%02x:%02x:%02x:%02x", + netif.hwaddr[0], netif.hwaddr[1], netif.hwaddr[2], + netif.hwaddr[3], netif.hwaddr[4], netif.hwaddr[5]); + return buf; +} + +char *LWIP::Interface::get_ip_address(char *buf, nsapi_size_t buflen) +{ + const ip_addr_t *addr = LWIP::get_ip_addr(true, &netif); + if (!addr) { + return NULL; + } +#if LWIP_IPV6 + if (IP_IS_V6(addr)) { + return ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen); + } +#endif +#if LWIP_IPV4 + if (IP_IS_V4(addr)) { + return ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen); + } +#endif +#if LWIP_IPV6 && LWIP_IPV4 + return NULL; +#endif +} + +char *LWIP::Interface::get_netmask(char *buf, nsapi_size_t buflen) +{ +#if LWIP_IPV4 + const ip4_addr_t *addr = netif_ip4_netmask(&netif); + if (!ip4_addr_isany(addr)) { + return ip4addr_ntoa_r(addr, buf, buflen); + } else { + return NULL; + } +#else + return NULL; +#endif +} + +char *LWIP::Interface::get_gateway(char *buf, nsapi_size_t buflen) +{ +#if LWIP_IPV4 + const ip4_addr_t *addr = netif_ip4_gw(&netif); + if (!ip4_addr_isany(addr)) { + return ip4addr_ntoa_r(addr, buf, buflen); + } else { + return NULL; + } +#else + return NULL; +#endif +} + +LWIP::Interface::Interface() : + hw(NULL), has_addr_state(0), + connected(false), dhcp(false), ppp(false) +{ + memset(&netif, 0, sizeof netif); + + osSemaphoreAttr_t attr; + attr.name = NULL; + attr.attr_bits = 0; + + attr.cb_mem = &linked_sem; + attr.cb_size = sizeof linked_sem; + linked = osSemaphoreNew(UINT16_MAX, 0, &attr); + + attr.cb_mem = &unlinked_sem; + attr.cb_size = sizeof unlinked_sem; + unlinked = osSemaphoreNew(UINT16_MAX, 0, &attr); + + attr.cb_mem = &has_any_addr_sem; + attr.cb_size = sizeof has_any_addr_sem; + has_any_addr = osSemaphoreNew(UINT16_MAX, 0, &attr); +#if PREF_ADDR_TIMEOUT + attr.cb_mem = &has_pref_addr_sem; + attr.cb_size = sizeof has_pref_addr_sem; + has_pref_addr = osSemaphoreNew(UINT16_MAX, 0, &attr); +#endif +#if BOTH_ADDR_TIMEOUT + attr.cb_mem = &has_both_addr_sem; + attr.cb_size = sizeof has_both_addr_sem; + has_both_addr = osSemaphoreNew(UINT16_MAX, 0, &attr); +#endif + + netif.state = this; +} + +nsapi_error_t LWIP::add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out) +{ +#if LWIP_ETHERNET + Interface *interface = new (std::nothrow) Interface(); + if (!interface) { + return NSAPI_ERROR_NO_MEMORY; + } + interface->emac = &emac; + interface->dhcp = true; + interface->ppp = false; + +#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) + netif->interface.hwaddr[0] = MBED_MAC_ADDR_0; + netif->interface.hwaddr[1] = MBED_MAC_ADDR_1; + netif->interface.hwaddr[2] = MBED_MAC_ADDR_2; + netif->interface.hwaddr[3] = MBED_MAC_ADDR_3; + netif->interface.hwaddr[4] = MBED_MAC_ADDR_4; + netif->interface.hwaddr[5] = MBED_MAC_ADDR_5; +#else + mbed_mac_address((char *) interface->netif.hwaddr); +#endif + + interface->netif.hwaddr_len = 6; + + if (!netif_add(&interface->netif, +#if LWIP_IPV4 + 0, 0, 0, +#endif + interface, &LWIP::Interface::emac_if_init, tcpip_input)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + if (default_if) { + netif_set_default(&interface->netif); + default_interface = interface; + } + + netif_set_link_callback(&interface->netif, &LWIP::Interface::netif_link_irq); + netif_set_status_callback(&interface->netif, &LWIP::Interface::netif_status_irq); + + *interface_out = interface; + + /* Use mac address as additional seed to random number generator */ + uint64_t seed = interface->netif.hwaddr[0]; + for (uint8_t i = 1; i < 8; i++) { + seed <<= 8; + seed |= interface->netif.hwaddr[i % 6]; + } + lwip_add_random_seed(seed); + + return NSAPI_ERROR_OK; +#else + return NSAPI_ERROR_UNSUPPORTED; +#endif //LWIP_ETHERNET +} + +/* Internal API to preserve existing PPP functionality - revise to better match mbed_ipstak_add_ethernet_interface later */ +nsapi_error_t LWIP::_add_ppp_interface(void *hw, bool default_if, LWIP::Interface **interface_out) +{ +#if LWIP_PPP + Interface *interface = new (nothrow) Interface(); + if (!interface) { + return NSAPI_ERROR_NO_MEMORY; + } + interface->hw = hw; + interface->dhcp = true; + interface->ppp = true; + + ret = ppp_lwip_if_init(hw, &interface->netif); + if (ret != NSAPI_ERROR_OK) { + free(interface); + return ret; + } + + if (default_if) + netif_set_default(&interface->netif); + + netif_set_link_callback(&interface->netif, mbed_lwip_netif_link_irq); + netif_set_status_callback(&interface->netif, mbed_lwip_netif_status_irq); + + *interface_out = interface; + +#else + return NSAPI_ERROR_UNSUPPORTED; +#endif //LWIP_PPP +} + +nsapi_error_t LWIP::Interface::bringup(bool dhcp, const char *ip, const char *netmask, const char *gw, const nsapi_ip_stack_t stack) +{ + // Check if we've already connected + if (connected) { + return NSAPI_ERROR_PARAMETER; + } + +#if LWIP_IPV6 + if (stack != IPV4_STACK) { + if (netif.hwaddr_len == 6) { + netif_create_ip6_linklocal_address(&netif, 1/*from MAC*/); + } +#if LWIP_IPV6_MLD + /* + * For hardware/netifs that implement MAC filtering. + * All-nodes link-local is handled by default, so we must let the hardware know + * to allow multicast packets in. + * Should set mld_mac_filter previously. */ + if (netif.mld_mac_filter != NULL) { + ip6_addr_t ip6_allnodes_ll; + ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); + netif.mld_mac_filter(&netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); + } +#endif /* LWIP_IPV6_MLD */ + +#if LWIP_IPV6_AUTOCONFIG + /* IPv6 address autoconfiguration not enabled by default */ + netif.ip6_autoconfig_enabled = 1; +#endif /* LWIP_IPV6_AUTOCONFIG */ + } else { + // Disable rourter solicitations + netif.rs_count = 0; + } +#endif /* LWIP_IPV6 */ + +#if LWIP_IPV4 + if (stack != IPV6_STACK) { + if (!dhcp && !ppp) { + ip4_addr_t ip_addr; + ip4_addr_t netmask_addr; + ip4_addr_t gw_addr; + + if (!inet_aton(ip, &ip_addr) || + !inet_aton(netmask, &netmask_addr) || + !inet_aton(gw, &gw_addr)) { + return NSAPI_ERROR_PARAMETER; + } + + netif_set_addr(&netif, &ip_addr, &netmask_addr, &gw_addr); + } + } +#endif + + netif_set_up(&netif); + if (ppp) { + err_t err = ppp_lwip_connect(hw); + if (err) { + return err_remap(err); + } + } + + if (!netif_is_link_up(&netif)) { + if (osSemaphoreAcquire(linked, 15000) != osOK) { + if (ppp) { + (void) ppp_lwip_disconnect(hw); + } + return NSAPI_ERROR_NO_CONNECTION; + } + } + + if (!ppp) { + netif_set_up(&netif); + } + +#if LWIP_DHCP + if (stack != IPV6_STACK) { + // Connect to the network + dhcp = dhcp; + + if (dhcp) { + err_t err = dhcp_start(&netif); + if (err) { + return NSAPI_ERROR_DHCP_FAILURE; + } + } + } +#endif + + // If doesn't have address + if (!LWIP::get_ip_addr(true, &netif)) { + if (osSemaphoreAcquire(has_any_addr, DHCP_TIMEOUT * 1000) != osOK) { + if (ppp) { + (void) ppp_lwip_disconnect(hw); + } + return NSAPI_ERROR_DHCP_FAILURE; + } + connected = true; + } + +#if PREF_ADDR_TIMEOUT + if (stack != IPV4_STACK && stack != IPV6_STACK) { + // If address is not for preferred stack waits a while to see + // if preferred stack address is acquired + if (!LWIP::get_ip_addr(false, &netif)) { + osSemaphoreAcquire(has_pref_addr, PREF_ADDR_TIMEOUT * 1000); + } + } +#endif +#if BOTH_ADDR_TIMEOUT + if (stack != IPV4_STACK && stack != IPV6_STACK) { + // If addresses for both stacks are not available waits a while to + // see if address for both stacks are acquired + if (!(LWIP::get_ipv4_addr(&netif) && LWIP::get_ipv6_addr(&netif))) { + osSemaphoreAcquire(has_both_addr, BOTH_ADDR_TIMEOUT * 1000); + } + } +#endif + + add_dns_addr(&netif); + + return 0; +} + +nsapi_error_t LWIP::Interface::bringdown() +{ + // Check if we've connected + if (!connected) { + return NSAPI_ERROR_PARAMETER; + } + +#if LWIP_DHCP + // Disconnect from the network + if (dhcp) { + dhcp_release(&netif); + dhcp_stop(&netif); + dhcp = false; + } +#endif + + if (ppp) { + /* this is a blocking call, returns when PPP is properly closed */ + err_t err = ppp_lwip_disconnect(hw); + if (err) { + return err_remap(err); + } + MBED_ASSERT(!netif_is_link_up(&netif)); + /*if (netif_is_link_up(&netif)) { + if (sys_arch_sem_wait(&unlinked, 15000) == SYS_ARCH_TIMEOUT) { + return NSAPI_ERROR_DEVICE_ERROR; + } + }*/ + } else { + netif_set_down(&netif); + } + +#if LWIP_IPV6 + mbed_lwip_clear_ipv6_addresses(&netif); +#endif + + osSemaphoreDelete(has_any_addr); + osSemaphoreAttr_t attr; + attr.name = NULL; + attr.attr_bits = 0; + attr.cb_mem = &has_any_addr_sem; + attr.cb_size = sizeof has_any_addr_sem; + has_any_addr = osSemaphoreNew(UINT16_MAX, 0, &attr); +#if PREF_ADDR_TIMEOUT + osSemaphoreDelete(has_pref_addr); + attr.cb_mem = &has_pref_addr_sem; + attr.cb_size = sizeof has_pref_addr_sem; + has_pref_addr = osSemaphoreNew(UINT16_MAX, 0, &attr); +#endif +#if BOTH_ADDR_TIMEOUT + osSemaphoreDelete(has_both_addr); + attr.cb_mem = &has_both_addr_sem; + attr.cb_size = sizeof has_both_addr_sem; + has_both_addr = osSemaphoreNew(UINT16_MAX, 0, &attr); +#endif + has_addr_state = 0; + + connected = false; + return 0; +} diff --git a/features/FEATURE_LWIP/lwip-interface/LWIPInterfaceEMAC.cpp b/features/FEATURE_LWIP/lwip-interface/LWIPInterfaceEMAC.cpp new file mode 100644 index 00000000000..f7fb2866a48 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/LWIPInterfaceEMAC.cpp @@ -0,0 +1,182 @@ +/* mbed Microcontroller Library + * Copyright (c) 2016 ARM Limited + * + * 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. + */ + +#include "emac_stack_mem.h" +#include "lwip/tcpip.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "netif/etharp.h" +#include "lwip/ethip6.h" +#include "netsocket/nsapi_types.h" +#include "netsocket/EMAC.h" + +#include "LWIPStack.h" + +#if LWIP_ETHERNET + +err_t LWIP::Interface::emac_low_level_output(struct netif *netif, struct pbuf *p) +{ + LWIP::Interface *mbed_if = static_cast(netif->state); + bool ret = mbed_if->emac->link_out(p); + return ret ? ERR_OK : ERR_IF; +} + +void LWIP::Interface::emac_input(emac_stack_mem_t *buf) +{ + struct pbuf *p = static_cast(buf); + + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif.input(p, &netif) != ERR_OK) { + LWIP_DEBUGF(NETIF_DEBUG, ("Emac LWIP: IP input error\n")); + + pbuf_free(p); + } +} + +void LWIP::Interface::emac_state_change(bool up) +{ + if (up) { + tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, &netif, 1); + } else { + tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, &netif, 1); + } +} + +#if LWIP_IGMP + +#include "lwip/igmp.h" +/** + * IPv4 address filtering setup. + * + * \param[in] netif the lwip network interface structure + * \param[in] group IPv4 group to modify + * \param[in] action + * \return ERR_OK or error code + */ +err_t LWIP::Interface::emac_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group, enum netif_mac_filter_action action) +{ + LWIP::Interface *mbed_if = static_cast(netif->state); + + switch (action) { + case NETIF_ADD_MAC_FILTER: + { + uint32_t group23 = ntohl(group->addr) & 0x007FFFFF; + uint8_t addr[6]; + addr[0] = LL_IP4_MULTICAST_ADDR_0; + addr[1] = LL_IP4_MULTICAST_ADDR_1; + addr[2] = LL_IP4_MULTICAST_ADDR_2; + addr[3] = group23 >> 16; + addr[4] = group23 >> 8; + addr[5] = group23; + mbed_if->emac->add_multicast_group(addr); + return ERR_OK; + } + case NETIF_DEL_MAC_FILTER: + /* As we don't reference count, silently ignore delete requests */ + return ERR_OK; + default: + return ERR_ARG; + } +} +#endif + +#if LWIP_IPV6_MLD + +#include "lwip/mld6.h" +/** + * IPv6 address filtering setup. + * + * \param[in] netif the lwip network interface structure + * \param[in] group IPv6 group to modify + * \param[in] action + * \return ERR_OK or error code + */ +err_t LWIP::Interface::emac_mld_mac_filter(struct netif *netif, const ip6_addr_t *group, enum netif_mac_filter_action action) +{ + LWIP::Interface *mbed_if = static_cast(netif->state); + + switch (action) { + case NETIF_ADD_MAC_FILTER: + { + uint32_t group32 = ntohl(group->addr[3]); + uint8_t addr[6]; + addr[0] = LL_IP6_MULTICAST_ADDR_0; + addr[1] = LL_IP6_MULTICAST_ADDR_1; + addr[2] = group32 >> 24; + addr[3] = group32 >> 16; + addr[4] = group32 >> 8; + addr[5] = group32; + mbed_if->emac->add_multicast_group(addr); + return ERR_OK; + } + case NETIF_DEL_MAC_FILTER: + /* As we don't reference count, silently ignore delete requests */ + return ERR_OK; + default: + return ERR_ARG; + } +} +#endif + +err_t LWIP::Interface::emac_if_init(struct netif *netif) +{ + int err = ERR_OK; + LWIP::Interface *mbed_if = static_cast(netif->state); + + mbed_if->emac->set_link_input_cb(mbed::callback(mbed_if, &LWIP::Interface::emac_input)); + mbed_if->emac->set_link_state_cb(mbed::callback(mbed_if, &LWIP::Interface::emac_state_change)); + + if (!mbed_if->emac->power_up()) { + err = ERR_IF; + } + + netif->mtu = mbed_if->emac->get_mtu_size(); + /* We have a default MAC address, so do don't force them to supply one */ + netif->hwaddr_len = mbed_if->emac->get_hwaddr_size(); + /* They may or may not update hwaddr with their address */ + mbed_if->emac->get_hwaddr(netif->hwaddr); + /* Then we write back either what they gave us, or our default */ + mbed_if->emac->set_hwaddr(netif->hwaddr); + /* Interface capabilities */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET; + + mbed_if->emac->get_ifname(netif->name, 2); + +#if LWIP_IPV4 + netif->output = etharp_output; +#if LWIP_IGMP + netif->igmp_mac_filter = &LWIP::Interface::emac_igmp_mac_filter; + netif->flags |= NETIF_FLAG_IGMP; +#endif /* LWIP_IGMP */ +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#if LWIP_IPV6_MLD + netif->mld_mac_filter = &LWIP::Interface::emac_mld_mac_filter; + netif->flags |= NETIF_FLAG_MLD6; +#else +// Would need to enable all multicasts here - no API in fsl_enet to do that +#error "IPv6 multicasts won't be received if LWIP_IPV6_MLD is disabled, breaking the system" +#endif +#endif + + netif->linkoutput = &LWIP::Interface::emac_low_level_output; + + return err; +} + +#endif + diff --git a/features/FEATURE_LWIP/lwip-interface/LWIPStack.cpp b/features/FEATURE_LWIP/lwip-interface/LWIPStack.cpp new file mode 100644 index 00000000000..0fbb073719b --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/LWIPStack.cpp @@ -0,0 +1,662 @@ +/* LWIP implementation of NSAPI NetworkStack + * Copyright (c) 2017 ARM Limited + * + * 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. + */ +#include "nsapi.h" +#include "mbed_interface.h" +#include "mbed_assert.h" +#include +#include +#include + +#include "lwip/opt.h" +#include "lwip/api.h" +#include "lwip/inet.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/tcpip.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "lwip/mld6.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/udp.h" +#include "lwip/lwip_errno.h" + +#include "LWIPStack.h" + +#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS + #define LWIP_SOCKET_MAX_MEMBERSHIPS 4 +#endif + +void LWIP::socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len) +{ + // Filter send minus events + if (eh == NETCONN_EVT_SENDMINUS && nc->state == NETCONN_WRITE) { + return; + } + + sys_prot_t prot = sys_arch_protect(); + + LWIP &lwip = LWIP::get_instance(); + + for (int i = 0; i < MEMP_NUM_NETCONN; i++) { + if (lwip.arena[i].in_use + && lwip.arena[i].conn == nc + && lwip.arena[i].cb) { + lwip.arena[i].cb(lwip.arena[i].data); + } + } + + sys_arch_unprotect(prot); +} + +#if !LWIP_IPV4 || !LWIP_IPV6 +static bool all_zeros(const uint8_t *p, int len) +{ + for (int i = 0; i < len; i++) { + if (p[i]) { + return false; + } + } + + return true; +} +#endif + +static bool convert_lwip_addr_to_mbed(nsapi_addr_t *out, const ip_addr_t *in) +{ +#if LWIP_IPV6 + if (IP_IS_V6(in)) { + out->version = NSAPI_IPv6; + SMEMCPY(out->bytes, ip_2_ip6(in), sizeof(ip6_addr_t)); + return true; + } +#endif +#if LWIP_IPV4 + if (IP_IS_V4(in)) { + out->version = NSAPI_IPv4; + SMEMCPY(out->bytes, ip_2_ip4(in), sizeof(ip4_addr_t)); + return true; + } +#endif +#if LWIP_IPV6 && LWIP_IPV4 + return false; +#endif +} + +static bool convert_mbed_addr_to_lwip(ip_addr_t *out, const nsapi_addr_t *in) +{ +#if LWIP_IPV6 + if (in->version == NSAPI_IPv6) { + IP_SET_TYPE(out, IPADDR_TYPE_V6); + SMEMCPY(ip_2_ip6(out), in->bytes, sizeof(ip6_addr_t)); + return true; + } +#if !LWIP_IPV4 + /* For bind() and other purposes, need to accept "null" of other type */ + /* (People use IPv4 0.0.0.0 as a general null) */ + if (in->version == NSAPI_UNSPEC || + (in->version == NSAPI_IPv4 && all_zeros(in->bytes, 4))) { + ip_addr_set_zero_ip6(out); + return true; + } +#endif +#endif + +#if LWIP_IPV4 + if (in->version == NSAPI_IPv4) { + IP_SET_TYPE(out, IPADDR_TYPE_V4); + SMEMCPY(ip_2_ip4(out), in->bytes, sizeof(ip4_addr_t)); + return true; + } +#if !LWIP_IPV6 + /* For symmetry with above, accept IPv6 :: as a general null */ + if (in->version == NSAPI_UNSPEC || + (in->version == NSAPI_IPv6 && all_zeros(in->bytes, 16))) { + ip_addr_set_zero_ip4(out); + return true; + } +#endif +#endif + +#if LWIP_IPV4 && LWIP_IPV6 + if (in->version == NSAPI_UNSPEC) { +#if IP_VERSION_PREF == PREF_IPV4 + ip_addr_set_zero_ip4(out); +#else + ip_addr_set_zero_ip6(out); +#endif + return true; + } +#endif + + return false; +} + +void LWIP::tcpip_init_irq(void *eh) +{ + LWIP *lwip = static_cast(eh); + lwip->tcpip_inited.release(); +} + +/* LWIP network stack implementation */ +LWIP::LWIP() +{ + default_interface = NULL; + + // Seed lwip random + lwip_seed_random(); + + // Initialise TCP sequence number + uint32_t tcp_isn_secret[4]; + for (int i = 0; i < 4; i++) { + tcp_isn_secret[i] = LWIP_RAND(); + } + lwip_init_tcp_isn(0, (u8_t *) &tcp_isn_secret); + + tcpip_init(&LWIP::tcpip_init_irq, this); + tcpip_inited.wait(0); + + // Zero out socket set + arena_init(); +} + +nsapi_error_t LWIP::gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version) +{ + ip_addr_t lwip_addr; + +#if LWIP_IPV4 && LWIP_IPV6 + u8_t addr_type; + if (version == NSAPI_UNSPEC) { + const ip_addr_t *ip_addr = NULL; + if (default_interface) { + ip_addr = get_ip_addr(true, &default_interface->netif); + } + // Prefer IPv6 + if (IP_IS_V6(ip_addr)) { + // If IPv4 is available use it as backup + if (get_ipv4_addr(&default_interface->netif)) { + addr_type = NETCONN_DNS_IPV6_IPV4; + } else { + addr_type = NETCONN_DNS_IPV6; + } + // Prefer IPv4 + } else { + // If IPv6 is available use it as backup + if (get_ipv6_addr(&default_interface->netif)) { + addr_type = NETCONN_DNS_IPV4_IPV6; + } else { + addr_type = NETCONN_DNS_IPV4; + } + } + } else if (version == NSAPI_IPv4) { + addr_type = NETCONN_DNS_IPV4; + } else if (version == NSAPI_IPv6) { + addr_type = NETCONN_DNS_IPV6; + } else { + return NSAPI_ERROR_DNS_FAILURE; + } + err_t err = netconn_gethostbyname_addrtype(host, &lwip_addr, addr_type); +#elif LWIP_IPV4 + if (version != NSAPI_IPv4 && version != NSAPI_UNSPEC) { + return NSAPI_ERROR_DNS_FAILURE; + } + err_t err = netconn_gethostbyname(host, &lwip_addr); +#elif LWIP_IPV6 + if (version != NSAPI_IPv6 && version != NSAPI_UNSPEC) { + return NSAPI_ERROR_DNS_FAILURE; + } + err_t err = netconn_gethostbyname(host, &lwip_addr); +#endif + + if (err != ERR_OK) { + return NSAPI_ERROR_DNS_FAILURE; + } + + nsapi_addr_t addr; + convert_lwip_addr_to_mbed(&addr, &lwip_addr); + address->set_addr(addr); + + return 0; +} + +nsapi_error_t LWIP::add_dns_server(const SocketAddress &address) +{ + // Shift all dns servers down to give precedence to new server + for (int i = DNS_MAX_SERVERS-1; i > 0; i--) { + dns_setserver(i, dns_getserver(i-1)); + } + + nsapi_addr_t addr = address.get_addr(); + ip_addr_t ip_addr; + if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) { + return NSAPI_ERROR_PARAMETER; + } + + dns_setserver(0, &ip_addr); + return 0; +} + +nsapi_error_t LWIP::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto) +{ + // check if network is connected +// if (!stack-> ->emac->connected) { +// return NSAPI_ERROR_NO_CONNECTION; +// } + + // allocate a socket + struct mbed_lwip_socket *s = arena_alloc(); + if (!s) { + return NSAPI_ERROR_NO_SOCKET; + } + + enum netconn_type lwip_proto = proto == NSAPI_TCP ? NETCONN_TCP : NETCONN_UDP; + +#if LWIP_IPV6 + // Enable IPv6 (or dual-stack) + lwip_proto = (enum netconn_type) (lwip_proto | NETCONN_TYPE_IPV6); +#endif + + s->conn = netconn_new_with_callback(lwip_proto, &LWIP::socket_callback); + + if (!s->conn) { + arena_dealloc(s); + return NSAPI_ERROR_NO_SOCKET; + } + + netconn_set_recvtimeout(s->conn, 1); + *(struct mbed_lwip_socket **)handle = s; + return 0; +} + +nsapi_error_t LWIP::socket_close(nsapi_socket_t handle) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + + netbuf_delete(s->buf); + err_t err = netconn_delete(s->conn); + arena_dealloc(s); + return err_remap(err); +} + +nsapi_error_t LWIP::socket_bind(nsapi_socket_t handle, const SocketAddress &address) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + ip_addr_t ip_addr; + + if ( +#if LWIP_TCP + (s->conn->type == NETCONN_TCP && s->conn->pcb.tcp->local_port != 0) || +#endif + (s->conn->type == NETCONN_UDP && s->conn->pcb.udp->local_port != 0)) { + return NSAPI_ERROR_PARAMETER; + } + + nsapi_addr_t addr = address.get_addr(); + if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) { + return NSAPI_ERROR_PARAMETER; + } + + if (!ip_addr_isany(&ip_addr) && !is_local_addr(&ip_addr)) { + return NSAPI_ERROR_PARAMETER; + } + + err_t err = netconn_bind(s->conn, &ip_addr, address.get_port()); + return err_remap(err); +} + +nsapi_error_t LWIP::socket_listen(nsapi_socket_t handle, int backlog) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + + if (s->conn->pcb.tcp->local_port == 0) { + return NSAPI_ERROR_PARAMETER; + } + + err_t err = netconn_listen_with_backlog(s->conn, backlog); + return err_remap(err); +} + +nsapi_error_t LWIP::socket_connect(nsapi_socket_t handle, const SocketAddress &address) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + ip_addr_t ip_addr; + + nsapi_addr_t addr = address.get_addr(); + if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) { + return NSAPI_ERROR_PARAMETER; + } + + netconn_set_nonblocking(s->conn, false); + err_t err = netconn_connect(s->conn, &ip_addr, address.get_port()); + netconn_set_nonblocking(s->conn, true); + + return err_remap(err); +} + +nsapi_error_t LWIP::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)server; + struct mbed_lwip_socket *ns = arena_alloc(); + if (!ns) { + return NSAPI_ERROR_NO_SOCKET; + } + + if (s->conn->pcb.tcp->state != LISTEN) { + return NSAPI_ERROR_PARAMETER; + } + + err_t err = netconn_accept(s->conn, &ns->conn); + if (err != ERR_OK) { + arena_dealloc(ns); + return err_remap(err); + } + + netconn_set_recvtimeout(ns->conn, 1); + *(struct mbed_lwip_socket **)handle = ns; + + ip_addr_t peer_addr; + nsapi_addr_t addr; + u16_t port; + (void) netconn_peer(ns->conn, &peer_addr, &port); + convert_lwip_addr_to_mbed(&addr, &peer_addr); + + if (address) { + address->set_addr(addr); + address->set_port(port); + } + + netconn_set_nonblocking(ns->conn, true); + + return 0; +} + +nsapi_size_or_error_t LWIP::socket_send(nsapi_socket_t handle, const void *data, nsapi_size_t size) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + size_t bytes_written = 0; + + err_t err = netconn_write_partly(s->conn, data, size, NETCONN_COPY, &bytes_written); + if (err != ERR_OK) { + return err_remap(err); + } + + return (nsapi_size_or_error_t)bytes_written; +} + +nsapi_size_or_error_t LWIP::socket_recv(nsapi_socket_t handle, void *data, nsapi_size_t size) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + + if (!s->buf) { + err_t err = netconn_recv(s->conn, &s->buf); + s->offset = 0; + + if (err != ERR_OK) { + return err_remap(err); + } + } + + u16_t recv = netbuf_copy_partial(s->buf, data, (u16_t)size, s->offset); + s->offset += recv; + + if (s->offset >= netbuf_len(s->buf)) { + netbuf_delete(s->buf); + s->buf = 0; + } + + return recv; +} + +nsapi_size_or_error_t LWIP::socket_sendto(nsapi_socket_t handle, const SocketAddress &address, const void *data, nsapi_size_t size) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + ip_addr_t ip_addr; + + nsapi_addr_t addr = address.get_addr(); + if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) { + return NSAPI_ERROR_PARAMETER; + } + + struct netbuf *buf = netbuf_new(); + err_t err = netbuf_ref(buf, data, (u16_t)size); + if (err != ERR_OK) { + netbuf_free(buf); + return err_remap(err); + } + + err = netconn_sendto(s->conn, buf, &ip_addr, address.get_port()); + netbuf_delete(buf); + if (err != ERR_OK) { + return err_remap(err); + } + + return size; +} + +nsapi_size_or_error_t LWIP::socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, void *data, nsapi_size_t size) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + struct netbuf *buf; + + err_t err = netconn_recv(s->conn, &buf); + if (err != ERR_OK) { + return err_remap(err); + } + + if (address) { + nsapi_addr_t addr; + convert_lwip_addr_to_mbed(&addr, netbuf_fromaddr(buf)); + address->set_addr(addr); + address->set_port(netbuf_fromport(buf)); + } + + u16_t recv = netbuf_copy(buf, data, (u16_t)size); + netbuf_delete(buf); + + return recv; +} + +int32_t LWIP::find_multicast_member(const struct mbed_lwip_socket *s, const nsapi_ip_mreq_t *imr) { + uint32_t count = 0; + uint32_t index = 0; + // Set upper limit on while loop, should break out when the membership pair is found + while (count < s->multicast_memberships_count) { + index = next_registered_multicast_member(s, index); + + if (memcmp(&s->multicast_memberships[index].imr_multiaddr, &imr->imr_multiaddr, sizeof(nsapi_addr_t)) == 0 && + memcmp(&s->multicast_memberships[index].imr_interface, &imr->imr_interface, sizeof(nsapi_addr_t)) == 0) { + return index; + } + count++; + index++; + } + + return -1; +} + +nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + + switch (optname) { +#if LWIP_TCP + case NSAPI_KEEPALIVE: + if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) { + return NSAPI_ERROR_UNSUPPORTED; + } + + s->conn->pcb.tcp->so_options |= SOF_KEEPALIVE; + return 0; + + case NSAPI_KEEPIDLE: + if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) { + return NSAPI_ERROR_UNSUPPORTED; + } + + s->conn->pcb.tcp->keep_idle = *(int*)optval; + return 0; + + case NSAPI_KEEPINTVL: + if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) { + return NSAPI_ERROR_UNSUPPORTED; + } + + s->conn->pcb.tcp->keep_intvl = *(int*)optval; + return 0; +#endif + + case NSAPI_REUSEADDR: + if (optlen != sizeof(int)) { + return NSAPI_ERROR_UNSUPPORTED; + } + + if (*(int *)optval) { + ip_set_option(s->conn->pcb.ip, SOF_REUSEADDR); + } else { + ip_reset_option(s->conn->pcb.ip, SOF_REUSEADDR); + } + return 0; + + case NSAPI_ADD_MEMBERSHIP: + case NSAPI_DROP_MEMBERSHIP: { + if (optlen != sizeof(nsapi_ip_mreq_t)) { + return NSAPI_ERROR_PARAMETER; + } + err_t igmp_err; + const nsapi_ip_mreq_t *imr = static_cast(optval); + + /* Check interface address type matches group, or is unspecified */ + if (imr->imr_interface.version != NSAPI_UNSPEC && imr->imr_interface.version != imr->imr_multiaddr.version) { + return NSAPI_ERROR_PARAMETER; + } + + ip_addr_t if_addr; + ip_addr_t multi_addr; + + /* Convert the group address */ + if (!convert_mbed_addr_to_lwip(&multi_addr, &imr->imr_multiaddr)) { + return NSAPI_ERROR_PARAMETER; + } + + /* Convert the interface address, or make sure it's the correct sort of "any" */ + if (imr->imr_interface.version != NSAPI_UNSPEC) { + if (!convert_mbed_addr_to_lwip(&if_addr, &imr->imr_interface)) { + return NSAPI_ERROR_PARAMETER; + } + } else { + ip_addr_set_any(IP_IS_V6(&if_addr), &if_addr); + } + + igmp_err = ERR_USE; // Maps to NSAPI_ERROR_UNSUPPORTED + int32_t member_pair_index = find_multicast_member(s, imr); + + if (optname == NSAPI_ADD_MEMBERSHIP) { + if (!s->multicast_memberships) { + // First multicast join on this socket, allocate space for membership tracking + s->multicast_memberships = (nsapi_ip_mreq_t*)malloc(sizeof(nsapi_ip_mreq_t) * LWIP_SOCKET_MAX_MEMBERSHIPS); + if (!s->multicast_memberships) { + return NSAPI_ERROR_NO_MEMORY; + } + } else if(s->multicast_memberships_count == LWIP_SOCKET_MAX_MEMBERSHIPS) { + return NSAPI_ERROR_NO_MEMORY; + } + + if (member_pair_index != -1) { + return NSAPI_ERROR_ADDRESS_IN_USE; + } + + member_pair_index = next_free_multicast_member(s, 0); + + sys_prot_t prot = sys_arch_protect(); + + #if LWIP_IPV4 + if (IP_IS_V4(&if_addr)) { + igmp_err = igmp_joingroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr)); + } + #endif + #if LWIP_IPV6 + if (IP_IS_V6(&if_addr)) { + igmp_err = mld6_joingroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr)); + } + #endif + + sys_arch_unprotect(prot); + + if (igmp_err == ERR_OK) { + set_multicast_member_registry_bit(s, member_pair_index); + s->multicast_memberships[member_pair_index] = *imr; + s->multicast_memberships_count++; + } + } else { + if (member_pair_index == -1) { + return NSAPI_ERROR_NO_ADDRESS; + } + + clear_multicast_member_registry_bit(s, member_pair_index); + s->multicast_memberships_count--; + + sys_prot_t prot = sys_arch_protect(); + + #if LWIP_IPV4 + if (IP_IS_V4(&if_addr)) { + igmp_err = igmp_leavegroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr)); + } + #endif + #if LWIP_IPV6 + if (IP_IS_V6(&if_addr)) { + igmp_err = mld6_leavegroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr)); + } + #endif + + sys_arch_unprotect(prot); + } + + return err_remap(igmp_err); + } + + default: + return NSAPI_ERROR_UNSUPPORTED; + } +} + +nsapi_error_t LWIP::getsockopt(nsapi_socket_t handle, int level, int optname, void *optval, unsigned *optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + + +void LWIP::socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data) +{ + struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; + + s->cb = callback; + s->data = data; +} + +LWIP &LWIP::get_instance() { + static LWIP lwip; + return lwip; +} + +// This works as long as it's not ever set to something which corresponds to +// a macro defined as a non-integer. Eg `#define Nanostack "Foo"` +#define LWIP 0x11991199 +#if MBED_CONF_NSAPI_DEFAULT_STACK == LWIP +#undef LWIP +OnboardNetworkStack &OnboardNetworkStack::get_default_instance() { + return LWIP::get_instance(); +} +#endif diff --git a/features/FEATURE_LWIP/lwip-interface/LWIPStack.h b/features/FEATURE_LWIP/lwip-interface/LWIPStack.h new file mode 100644 index 00000000000..fd2b6f0c038 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/LWIPStack.h @@ -0,0 +1,457 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * 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. + */ + +#ifndef LWIPSTACK_H_ +#define LWIPSTACK_H_ + +#include "emac_stack_mem.h" +#include "lwip/tcpip.h" +#include "lwip/tcp.h" +#include "lwip/ip.h" +#include "lwip/api.h" +#include "netif/etharp.h" +#include "lwip/ethip6.h" +#include "netsocket/nsapi_types.h" +#include "netsocket/EMAC.h" +#include "netsocket/OnboardNetworkStack.h" + + +class LWIP : public OnboardNetworkStack, private mbed::NonCopyable { +public: + + static LWIP &get_instance(); + + class Interface : public OnboardNetworkStack::Interface { + public: + /** Connect the interface to the network + * + * Sets up a connection on specified network interface, using DHCP or provided network details. If the @a dhcp is set to + * true all the remaining parameters are ignored. + * + * @param dhcp true if the network details should be acquired using DHCP + * @param ip IP address to be used for the interface as "W:X:Y:Z" or NULL + * @param netmask Net mask to be used for the interface as "W:X:Y:Z" or NULL + * @param gw Gateway address to be used for the interface as "W:X:Y:Z" or NULL + * @param stack Allow manual selection of IPv4 and/or IPv6. + * @return NSAPI_ERROR_OK on success, or error code + */ + virtual nsapi_error_t bringup(bool dhcp, const char *ip, + const char *netmask, const char *gw, + nsapi_ip_stack_t stack + #ifdef __cplusplus + = DEFAULT_STACK + #endif + ); + + /** Disconnect interface from the network + * + * After this call the network interface is inactive, to use it again user needs to call @a mbed_ipstack_bringup again. + * + * @return NSAPI_ERROR_OK on success, or error code + */ + virtual nsapi_error_t bringdown(); + + /** Return MAC address of the network interface + * + * @return MAC address as "V:W:X:Y:Z" + */ + virtual char *get_mac_address(char *buf, nsapi_size_t buflen); + + /** Copies IP address of the network interface to user supplied buffer + * + * @param emac EMAC HAL implementation for this network interface + * @param buf buffer to which IP address will be copied as "W:X:Y:Z" + * @param buflen size of supplied buffer + * @return Pointer to a buffer, or NULL if the buffer is too small + */ + virtual char *get_ip_address(char *buf, nsapi_size_t buflen); + + /** Copies netmask of the network interface to user supplied buffer + * + * @param buf buffer to which netmask will be copied as "W:X:Y:Z" + * @param buflen size of supplied buffer + * @return Pointer to a buffer, or NULL if the buffer is too small + */ + virtual char *get_netmask(char *buf, nsapi_size_t buflen); + + /** Copies gateway address of the network interface to user supplied buffer + * + * @param buf buffer to which gateway address will be copied as "W:X:Y:Z" + * @param buflen size of supplied buffer + * @return Pointer to a buffer, or NULL if the buffer is too small + */ + virtual char *get_gateway(char *buf, nsapi_size_t buflen); + + private: + friend LWIP; + + Interface(); + + static void netif_link_irq(struct netif *netif); + static void netif_status_irq(struct netif *netif); + + static err_t emac_low_level_output(struct netif *netif, struct pbuf *p); + void emac_input(emac_stack_mem_t *buf); + void emac_state_change(bool up); + #if LWIP_IGMP + static err_t emac_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group, enum netif_mac_filter_action action); + #endif + #if LWIP_IPV6_MLD + static err_t emac_mld_mac_filter(struct netif *netif, const ip6_addr_t *group, enum netif_mac_filter_action action); + #endif + + static err_t emac_if_init(struct netif *netif); + + union { + EMAC *emac; /**< HW specific emac implementation */ + void *hw; /**< alternative implementation pointer - used for PPP */ + }; + + os_semaphore_t linked_sem; + osSemaphoreId_t linked; + os_semaphore_t unlinked_sem; + osSemaphoreId_t unlinked; + os_semaphore_t has_any_addr_sem; + osSemaphoreId_t has_any_addr; + #define HAS_ANY_ADDR 1 + #if PREF_ADDR_TIMEOUT + os_semaphore_t has_pref_addr_sem; + osSemaphoreId_t has_pref_addr; + #define HAS_PREF_ADDR 2 + #endif + #if BOTH_ADDR_TIMEOUT + os_semaphore_t has_both_addr_sem; + osSemaphoreId_t has_both_addr; + #define HAS_BOTH_ADDR 4 + #endif + char has_addr_state; + bool connected; + bool dhcp; + bool ppp; + struct netif netif; + }; + + /** Register a network interface with the IP stack + * + * Connects EMAC layer with the IP stack and initializes all the required infrastructure. + * This function should be called only once for each available interface. + * + * @param emac EMAC HAL implementation for this network interface + * @param default_if true if the interface should be treated as the default one + * @param[out] interface_out pointer to stack interface object controlling the EMAC + * @return NSAPI_ERROR_OK on success, or error code + */ + nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out); + + /** Register a PPP interface with the IP stack + * + * Connects PPP layer with the IP stack and initializes all the required infrastructure. + * This function should be called only once for each available interface. + * + * This is an internal function that links ppp_lwip.cpp to mbed_ipstack_lwip.cpp, + * once a driver starts it via the nsapi_ppp.h API. + * + * Ultimately the nsapi_ppp.h API will be deprecated, and there will be a + * mbed_ipstack_add_ppp_interface() replacing nsapi_ppp_connect(). + * + * @param pcb PPP implementation specific user data; will be passed to PPP callbacks + * @param default_if true if the interface should be treated as the default one + * @param[out] interface_out set to interface handle that must be passed to subsequent mbed_stack calls + * @return NSAPI_ERROR_OK on success, or error code + */ + nsapi_error_t _add_ppp_interface(void *pcb, bool default_if, LWIP::Interface **interface_out); + + /** Translates a hostname to an IP address with specific version + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * + * @param host Hostname to resolve + * @param address Destination for the host SocketAddress + * @param version IP version of address to resolve, NSAPI_UNSPEC indicates + * version is chosen by the stack (defaults to NSAPI_UNSPEC) + * @return 0 on success, negative error code on failure + */ + nsapi_error_t gethostbyname(const char *host, + SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC); + + /** Add a domain name server to list of servers to query + * + * @param address Destination for the host address + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t add_dns_server(const SocketAddress &address); + +protected: + LWIP(); + virtual ~LWIP() {} + + /** Opens a socket + * + * Creates a network socket and stores it in the specified handle. + * The handle must be passed to following calls on the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * @param handle Destination for the handle to a newly created socket + * @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto); + + /** Close the socket + * + * Closes any open connection and deallocates any memory associated + * with the socket. + * + * @param handle Socket handle + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_close(nsapi_socket_t handle); + + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to recieve + * data. If the IP address is zeroed, only the port is bound. + * + * @param handle Socket handle + * @param address Local address to bind + * @return 0 on success, negative error code on failure. + */ + virtual nsapi_error_t socket_bind(nsapi_socket_t handle, const SocketAddress &address); + + /** Listen for connections on a TCP socket + * + * Marks the socket as a passive socket that can be used to accept + * incoming connections. + * + * @param handle Socket handle + * @param backlog Number of pending connections that can be queued + * simultaneously + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog); + + /** Connects TCP socket to a remote host + * + * Initiates a connection to a remote server specified by the + * indicated address. + * + * @param handle Socket handle + * @param address The SocketAddress of the remote host + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address); + + /** Accepts a connection on a TCP socket + * + * The server socket must be bound and set to listen for connections. + * On a new connection, creates a network socket and stores it in the + * specified handle. The handle must be passed to following calls on + * the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * This call is non-blocking. If accept would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param server Socket handle to server to accept from + * @param handle Destination for a handle to the newly created socket + * @param address Destination for the remote address or NULL + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t socket_accept(nsapi_socket_t server, + nsapi_socket_t *handle, SocketAddress *address=0); + + /** Send data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes sent from the buffer. + * + * This call is non-blocking. If send would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_send(nsapi_socket_t handle, + const void *data, nsapi_size_t size); + + /** Receive data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes received into the buffer. + * + * This call is non-blocking. If recv would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_recv(nsapi_socket_t handle, + void *data, nsapi_size_t size); + + /** Send a packet over a UDP socket + * + * Sends data to the specified address. Returns the number of bytes + * sent from the buffer. + * + * This call is non-blocking. If sendto would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param address The SocketAddress of the remote host + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, const SocketAddress &address, + const void *data, nsapi_size_t size); + + /** Receive a packet over a UDP socket + * + * Receives data and stores the source address in address if address + * is not NULL. Returns the number of bytes received into the buffer. + * + * This call is non-blocking. If recvfrom would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param handle Socket handle + * @param address Destination for the source address or NULL + * @param buffer Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, + void *buffer, nsapi_size_t size); + + /** Register a callback on state change of the socket + * + * The specified callback will be called on state changes such as when + * the socket can recv/send/accept successfully and on when an error + * occurs. The callback may also be called spuriously without reason. + * + * The callback may be called in an interrupt context and should not + * perform expensive operations such as recv/send calls. + * + * @param handle Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + */ + virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data); + + /* Set stack-specific socket options + * + * The setsockopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. + * + * @param handle Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t setsockopt(nsapi_socket_t handle, int level, + int optname, const void *optval, unsigned optlen); + + /* Get stack-specific socket options + * + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * + * @param handle Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Destination for option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t getsockopt(nsapi_socket_t handle, int level, + int optname, void *optval, unsigned *optlen); +private: + struct mbed_lwip_socket { + bool in_use; + + struct netconn *conn; + struct netbuf *buf; + u16_t offset; + + void (*cb)(void *); + void *data; + + // Track multicast addresses subscribed to by this socket + nsapi_ip_mreq_t *multicast_memberships; + uint32_t multicast_memberships_count; + uint32_t multicast_memberships_registry; + }; + + static nsapi_error_t err_remap(err_t err); + static bool is_local_addr(const ip_addr_t *ip_addr); + static const ip_addr_t *get_ip_addr(bool any_addr, const struct netif *netif); + static const ip_addr_t *get_ipv4_addr(const struct netif *netif); + static const ip_addr_t *get_ipv6_addr(const struct netif *netif); + + static void add_dns_addr(struct netif *lwip_netif); + + /* Static arena of sockets */ + struct mbed_lwip_socket arena[MEMP_NUM_NETCONN]; + void arena_init(void); + struct mbed_lwip_socket *arena_alloc(); + void arena_dealloc(struct mbed_lwip_socket *s); + + static uint32_t next_registered_multicast_member(const struct mbed_lwip_socket *s, uint32_t index) { + while (!(s->multicast_memberships_registry & (0x0001 << index))) { index++; } + return index; + } + + static uint32_t next_free_multicast_member(const struct mbed_lwip_socket *s, uint32_t index) { + while ((s->multicast_memberships_registry & (0x0001 << index))) { index++; } + return index; + } + + static void set_multicast_member_registry_bit(struct mbed_lwip_socket *s, uint32_t index) { + s->multicast_memberships_registry |= (0x0001 << index); + } + + static void clear_multicast_member_registry_bit(struct mbed_lwip_socket *s, uint32_t index) { + s->multicast_memberships_registry &= ~(0x0001 << index); + } + static int32_t find_multicast_member(const struct mbed_lwip_socket *s, const nsapi_ip_mreq_t *imr); + + static void socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len); + + static void tcpip_init_irq(void *handle); + rtos::Semaphore tcpip_inited; + Interface *default_interface; +}; + +#endif /* LWIPSTACK_H_ */ diff --git a/features/FEATURE_LWIP/lwip-interface/emac_lwip.c b/features/FEATURE_LWIP/lwip-interface/emac_lwip.c deleted file mode 100644 index f189bb2a988..00000000000 --- a/features/FEATURE_LWIP/lwip-interface/emac_lwip.c +++ /dev/null @@ -1,88 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2016 ARM Limited - * - * 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. - */ - -#if DEVICE_EMAC - -#include "emac_api.h" -#include "emac_stack_mem.h" -#include "lwip/tcpip.h" -#include "lwip/tcp.h" -#include "lwip/ip.h" -#include "netif/etharp.h" - -static err_t emac_lwip_low_level_output(struct netif *netif, struct pbuf *p) -{ - emac_interface_t *mac = (emac_interface_t *)netif->state; - bool ret = mac->ops.link_out(mac, (emac_stack_mem_t *)p); - - return ret ? ERR_OK : ERR_IF; -} - -static void emac_lwip_input(void *data, emac_stack_t *buf) -{ - struct pbuf *p = (struct pbuf *)buf; - struct netif *netif = (struct netif *)data; - - /* pass all packets to ethernet_input, which decides what packets it supports */ - if (netif->input(p, netif) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("Emac LWIP: IP input error\n")); - - pbuf_free(p); - } -} - -static void emac_lwip_state_change(void *data, bool up) -{ - struct netif *netif = (struct netif *)data; - - if (up) { - tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, netif, 1); - } else { - tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, netif, 1); - } -} - -err_t emac_lwip_if_init(struct netif *netif) -{ - int err = ERR_OK; - emac_interface_t *mac = (emac_interface_t *)netif->state; - - mac->ops.set_link_input_cb(mac, emac_lwip_input, netif); - mac->ops.set_link_state_cb(mac, emac_lwip_state_change, netif); - - if (!mac->ops.power_up(mac)) { - err = ERR_IF; - } - - netif->mtu = mac->ops.get_mtu_size(mac); - netif->hwaddr_len = mac->ops.get_hwaddr_size(mac); - mac->ops.get_hwaddr(mac, netif->hwaddr); - - /* Interface capabilities */ - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; - - mac->ops.get_ifname(mac, netif->name, 2); - -#if LWIP_IPV4 - netif->output = etharp_output; -#endif /* LWIP_IPV4 */ - - netif->linkoutput = emac_lwip_low_level_output; - - return err; -} - -#endif /* DEVICE_EMAC */ diff --git a/features/FEATURE_LWIP/lwip-interface/emac_stack_lwip.cpp b/features/FEATURE_LWIP/lwip-interface/emac_stack_mem_lwip.c similarity index 68% rename from features/FEATURE_LWIP/lwip-interface/emac_stack_lwip.cpp rename to features/FEATURE_LWIP/lwip-interface/emac_stack_mem_lwip.c index 42ec7ff82a8..d84427802cc 100644 --- a/features/FEATURE_LWIP/lwip-interface/emac_stack_lwip.cpp +++ b/features/FEATURE_LWIP/lwip-interface/emac_stack_mem_lwip.c @@ -14,12 +14,10 @@ * limitations under the License. */ -#if DEVICE_EMAC - #include "emac_stack_mem.h" #include "pbuf.h" -emac_stack_mem_t *emac_stack_mem_alloc(emac_stack_t* stack, uint32_t size, uint32_t align) +emac_stack_mem_t *emac_stack_mem_alloc(uint32_t size, uint32_t align) { struct pbuf *pbuf = pbuf_alloc(PBUF_RAW, size + align, PBUF_RAM); @@ -42,34 +40,34 @@ emac_stack_mem_t *emac_stack_mem_alloc(emac_stack_t* stack, uint32_t size, uint3 return (emac_stack_mem_t*)pbuf; } -void emac_stack_mem_free(emac_stack_t* stack, emac_stack_mem_t *mem) +void emac_stack_mem_free(emac_stack_mem_t *mem) { pbuf_free((struct pbuf*)mem); } -void emac_stack_mem_copy(emac_stack_t* stack, emac_stack_mem_t *to, emac_stack_mem_t *from) +void emac_stack_mem_copy(emac_stack_mem_t *to, emac_stack_mem_t *from) { pbuf_copy((struct pbuf*)to, (struct pbuf*)from); } -void *emac_stack_mem_ptr(emac_stack_t* stack, emac_stack_mem_t *mem) +void *emac_stack_mem_ptr(emac_stack_mem_t *mem) { return ((struct pbuf*)mem)->payload; } -uint32_t emac_stack_mem_len(emac_stack_t* stack, emac_stack_mem_t *mem) +uint32_t emac_stack_mem_len(emac_stack_mem_t *mem) { return ((struct pbuf*)mem)->len; } -void emac_stack_mem_set_len(emac_stack_t* stack, emac_stack_mem_t *mem, uint32_t len) +void emac_stack_mem_set_len(emac_stack_mem_t *mem, uint32_t len) { struct pbuf *pbuf = (struct pbuf*)mem; pbuf->len = len; } -emac_stack_mem_t *emac_stack_mem_chain_dequeue(emac_stack_t* stack, emac_stack_mem_chain_t **chain) +emac_stack_mem_t *emac_stack_mem_chain_dequeue(emac_stack_mem_chain_t **chain) { struct pbuf **list = (struct pbuf**)chain; struct pbuf *head = *list; @@ -78,14 +76,18 @@ emac_stack_mem_t *emac_stack_mem_chain_dequeue(emac_stack_t* stack, emac_stack_m return (emac_stack_mem_t *)head; } -uint32_t emac_stack_mem_chain_len(emac_stack_t* stack, emac_stack_mem_chain_t *chain) +uint32_t emac_stack_mem_chain_len(emac_stack_mem_chain_t *chain) { return ((struct pbuf*)chain)->tot_len; } -void emac_stack_mem_ref(emac_stack_t* stack, emac_stack_mem_t *mem) +void emac_stack_mem_set_chain_len(emac_stack_mem_chain_t *chain, uint32_t len) + { + struct pbuf *pbuf = (struct pbuf*)chain; + pbuf->tot_len = len; +} + +void emac_stack_mem_ref(emac_stack_mem_t *mem) { pbuf_ref((struct pbuf*)mem); } - -#endif /* DEVICE_EMAC */ diff --git a/features/FEATURE_LWIP/lwip-interface/eth_arch.h b/features/FEATURE_LWIP/lwip-interface/eth_arch.h deleted file mode 100644 index 25bdde38dda..00000000000 --- a/features/FEATURE_LWIP/lwip-interface/eth_arch.h +++ /dev/null @@ -1,45 +0,0 @@ -/* EthernetInterface.h */ -/* Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -// Architecture specific Ethernet interface -// Must be implemented by each target - -#ifndef ETHARCH_H_ -#define ETHARCH_H_ - -#include "lwip/netif.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#if DEVICE_EMAC -err_t emac_lwip_if_init(struct netif *netif); - -#else /* DEVICE_EMAC */ -void eth_arch_enable_interrupts(void); -void eth_arch_disable_interrupts(void); -err_t eth_arch_enetif_init(struct netif *netif); -#endif - -#ifdef __cplusplus -} -#endif - -#endif // #ifndef ETHARCHINTERFACE_H_ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.c b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.c deleted file mode 100644 index e07e700b153..00000000000 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.c +++ /dev/null @@ -1,781 +0,0 @@ -#include "lwip/opt.h" -#include "lwip/sys.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/tcpip.h" -#include "lwip/ethip6.h" -#include "lwip/igmp.h" -#include "lwip/mld6.h" -#include "netif/etharp.h" -#include "netif/ppp/pppoe.h" - -#include "eth_arch.h" -#include "sys_arch.h" - -#include "fsl_phy.h" -#include "k64f_emac_config.h" -#include -#include -#include -#include - -#include "mbed_interface.h" - -enet_handle_t g_handle; -// TX Buffer descriptors -uint8_t *tx_desc_start_addr; -// RX Buffer descriptors -uint8_t *rx_desc_start_addr; -// RX packet buffer pointers -struct pbuf *rx_buff[ENET_RX_RING_LEN]; -// TX packet buffer pointers -struct pbuf *tx_buff[ENET_RX_RING_LEN]; -// RX packet payload pointers -uint32_t *rx_ptr[ENET_RX_RING_LEN]; - -/******************************************************************************** - * Internal data - ********************************************************************************/ -#define ENET_BuffSizeAlign(n) ENET_ALIGN(n, ENET_BUFF_ALIGNMENT) -#define ENET_ALIGN(x,align) ((unsigned int)((x) + ((align)-1)) & (unsigned int)(~(unsigned int)((align)- 1))) -#if (defined(TARGET_K64F) && (defined(TARGET_FRDM))) -extern void k64f_init_eth_hardware(void); -#endif - -#if (defined(TARGET_K66F) && (defined(TARGET_FRDM))) -extern void k66f_init_eth_hardware(void); -#endif - -/* K64F EMAC driver data structure */ -struct k64f_enetdata { - struct netif *netif; /**< Reference back to LWIP parent netif */ - osThreadId_t thread; /**< Processing thread */ - sys_mutex_t TXLockMutex; /**< TX critical section mutex */ - sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */ - uint8_t tx_consume_index, tx_produce_index; /**< TX buffers ring */ -}; - -static struct k64f_enetdata k64f_enetdata; - -/* \brief Flags for worker thread */ -#define FLAG_TX 1 -#define FLAG_RX 2 - -/** \brief Driver thread priority */ -#define THREAD_PRIORITY (osPriorityNormal) - -#ifdef LWIP_DEBUG -#define THREAD_STACKSIZE (DEFAULT_THREAD_STACKSIZE * 5) -#else -#define THREAD_STACKSIZE DEFAULT_THREAD_STACKSIZE -#endif - -static void k64f_phy_task(void *data); -static void packet_rx(struct k64f_enetdata *k64f_enet); -static void packet_tx(struct k64f_enetdata *k64f_enet); - -#define PHY_TASK_PERIOD_MS 200 - -/******************************************************************************** - * Buffer management - ********************************************************************************/ -/* - * This function will queue a new receive buffer - */ -static void update_read_buffer(uint8_t *buf) -{ - if (buf != NULL) { - g_handle.rxBdCurrent->buffer = buf; - } - - /* Clears status. */ - g_handle.rxBdCurrent->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; - - /* Sets the receive buffer descriptor with the empty flag. */ - g_handle.rxBdCurrent->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; - - /* Increases the buffer descriptor to the next one. */ - if (g_handle.rxBdCurrent->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK) { - g_handle.rxBdCurrent = g_handle.rxBdBase; - } else { - g_handle.rxBdCurrent++; - } - - /* Actives the receive buffer descriptor. */ - ENET->RDAR = ENET_RDAR_RDAR_MASK; -} - -/** \brief Free TX buffers that are complete - * - * \param[in] k64f_enet Pointer to driver data structure - */ -static void k64f_tx_reclaim(struct k64f_enetdata *k64f_enet) -{ - /* Get exclusive access */ - sys_mutex_lock(&k64f_enet->TXLockMutex); - - // Traverse all descriptors, looking for the ones modified by the uDMA - while((k64f_enet->tx_consume_index != k64f_enet->tx_produce_index) && - (!(g_handle.txBdDirty->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))) { - pbuf_free(tx_buff[k64f_enet->tx_consume_index % ENET_TX_RING_LEN]); - if (g_handle.txBdDirty->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) - g_handle.txBdDirty = g_handle.txBdBase; - else - g_handle.txBdDirty++; - - k64f_enet->tx_consume_index += 1; - osSemaphoreRelease(k64f_enet->xTXDCountSem.id); - } - - /* Restore access */ - sys_mutex_unlock(&k64f_enet->TXLockMutex); -} - -/** \brief Ethernet receive interrupt handler - * - * This function handles the receive interrupt of K64F. - */ -void enet_mac_rx_isr() -{ - if (k64f_enetdata.thread) { - osThreadFlagsSet(k64f_enetdata.thread, FLAG_RX); - } -} - -void enet_mac_tx_isr() -{ - osThreadFlagsSet(k64f_enetdata.thread, FLAG_TX); -} - -void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param) -{ - switch (event) - { - case kENET_RxEvent: - enet_mac_rx_isr(); - break; - case kENET_TxEvent: - enet_mac_tx_isr(); - break; - default: - break; - } -} - -/** \brief Low level init of the MAC and PHY. - * - * \param[in] netif Pointer to LWIP netif structure - */ -static err_t low_level_init(struct netif *netif) -{ - struct k64f_enetdata *k64f_enet = netif->state; - uint8_t i; - uint32_t sysClock; - phy_speed_t phy_speed; - phy_duplex_t phy_duplex; - uint32_t phyAddr = 0; - bool link = false; - enet_config_t config; - - // Allocate RX descriptors - rx_desc_start_addr = (uint8_t *)calloc(1, sizeof(enet_rx_bd_struct_t) * ENET_RX_RING_LEN + ENET_BUFF_ALIGNMENT); - if(!rx_desc_start_addr) - return ERR_MEM; - - // Allocate TX descriptors - tx_desc_start_addr = (uint8_t *)calloc(1, sizeof(enet_tx_bd_struct_t) * ENET_TX_RING_LEN + ENET_BUFF_ALIGNMENT); - if(!tx_desc_start_addr) - return ERR_MEM; - - rx_desc_start_addr = (uint8_t *)ENET_ALIGN(rx_desc_start_addr, ENET_BUFF_ALIGNMENT); - tx_desc_start_addr = (uint8_t *)ENET_ALIGN(tx_desc_start_addr, ENET_BUFF_ALIGNMENT); - - /* Create buffers for each receive BD */ - for (i = 0; i < ENET_RX_RING_LEN; i++) { - rx_buff[i] = pbuf_alloc(PBUF_RAW, ENET_ETH_MAX_FLEN + ENET_BUFF_ALIGNMENT, PBUF_RAM); - if (NULL == rx_buff[i]) - return ERR_MEM; - - /* K64F note: the next line ensures that the RX buffer is properly aligned for the K64F - RX descriptors (16 bytes alignment). However, by doing so, we're effectively changing - a data structure which is internal to lwIP. This might not prove to be a good idea - in the long run, but a better fix would probably involve modifying lwIP itself */ - rx_buff[i]->payload = (void*)ENET_ALIGN((uint32_t)rx_buff[i]->payload, ENET_BUFF_ALIGNMENT); - rx_ptr[i] = rx_buff[i]->payload; - } - - k64f_enet->tx_consume_index = k64f_enet->tx_produce_index = 0; - - /* prepare the buffer configuration. */ - enet_buffer_config_t buffCfg = { - ENET_RX_RING_LEN, - ENET_TX_RING_LEN, - ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT), - 0, - (volatile enet_rx_bd_struct_t *)rx_desc_start_addr, - (volatile enet_tx_bd_struct_t *)tx_desc_start_addr, - (uint8_t *)&rx_ptr, - NULL, - }; -#if (defined(TARGET_K64F) && (defined(TARGET_FRDM))) - k64f_init_eth_hardware(); -#endif - -#if (defined(TARGET_K66F) && (defined(TARGET_FRDM))) - k66f_init_eth_hardware(); -#endif - - sysClock = CLOCK_GetFreq(kCLOCK_CoreSysClk); - - ENET_GetDefaultConfig(&config); - - PHY_Init(ENET, 0, sysClock); - PHY_GetLinkStatus(ENET, phyAddr, &link); - if (link) - { - /* Get link information from PHY */ - PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex); - /* Change the MII speed and duplex for actual link status. */ - config.miiSpeed = (enet_mii_speed_t)phy_speed; - config.miiDuplex = (enet_mii_duplex_t)phy_duplex; - config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt; - } - config.rxMaxFrameLen = ENET_ETH_MAX_FLEN; - config.macSpecialConfig = kENET_ControlFlowControlEnable; - config.txAccelerConfig = kENET_TxAccelIsShift16Enabled; - config.rxAccelerConfig = kENET_RxAccelisShift16Enabled | kENET_RxAccelMacCheckEnabled; - ENET_Init(ENET, &g_handle, &config, &buffCfg, netif->hwaddr, sysClock); - -#if defined(TOOLCHAIN_ARM) -#if defined(__OPTIMISE_TIME) && (__ARMCC_VERSION < 5060750) - /* Add multicast groups - work around for https://github.com/ARMmbed/mbed-os/issues/4372 */ - ENET->GAUR = 0xFFFFFFFFu; - ENET->GALR = 0xFFFFFFFFu; -#endif -#endif - - ENET_SetCallback(&g_handle, ethernet_callback, netif); - ENET_ActiveRead(ENET); - - return ERR_OK; -} - - -/** - * This function is the ipv4 ethernet packet send function. It calls - * etharp_output after checking link status. - * - * \param[in] netif the lwip network interface structure for this enetif - * \param[in] q Pointer to pbug to send - * \param[in] ipaddr IP address - * \return ERR_OK or error code - */ -#if LWIP_IPV4 -err_t k64f_etharp_output_ipv4(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) -{ - /* Only send packet is link is up */ - if (netif->flags & NETIF_FLAG_LINK_UP) { - return etharp_output(netif, q, ipaddr); - } - - return ERR_CONN; -} -#endif - -/** - * This function is the ipv6 ethernet packet send function. It calls - * ethip6_output after checking link status. - * - * \param[in] netif the lwip network interface structure for this enetif - * \param[in] q Pointer to pbug to send - * \param[in] ipaddr IP address - * \return ERR_OK or error code - */ -#if LWIP_IPV6 -err_t k64f_etharp_output_ipv6(struct netif *netif, struct pbuf *q, const ip6_addr_t *ipaddr) -{ - /* Only send packet is link is up */ - if (netif->flags & NETIF_FLAG_LINK_UP) { - return ethip6_output(netif, q, ipaddr); - } - - return ERR_CONN; -} -#endif - -#if LWIP_IGMP -/** - * IPv4 address filtering setup. - * - * \param[in] netif the lwip network interface structure for this enetif - * \param[in] group IPv4 group to modify - * \param[in] action - * \return ERR_OK or error code - */ -err_t igmp_mac_filter(struct netif *netif, const ip4_addr_t *group, enum netif_mac_filter_action action) -{ - switch (action) { - case NETIF_ADD_MAC_FILTER: - { - uint32_t group23 = ntohl(group->addr) & 0x007FFFFF; - uint8_t addr[6]; - addr[0] = LL_IP4_MULTICAST_ADDR_0; - addr[1] = LL_IP4_MULTICAST_ADDR_1; - addr[2] = LL_IP4_MULTICAST_ADDR_2; - addr[3] = group23 >> 16; - addr[4] = group23 >> 8; - addr[5] = group23; - ENET_AddMulticastGroup(ENET, addr); - return ERR_OK; - } - case NETIF_DEL_MAC_FILTER: - /* As we don't reference count, silently ignore delete requests */ - return ERR_OK; - default: - return ERR_ARG; - } -} -#endif - -#if LWIP_IPV6_MLD -/** - * IPv6 address filtering setup. - * - * \param[in] netif the lwip network interface structure for this enetif - * \param[in] group IPv6 group to modify - * \param[in] action - * \return ERR_OK or error code - */ -err_t mld_mac_filter(struct netif *netif, const ip6_addr_t *group, enum netif_mac_filter_action action) -{ - switch (action) { - case NETIF_ADD_MAC_FILTER: - { - uint32_t group32 = ntohl(group->addr[3]); - uint8_t addr[6]; - addr[0] = LL_IP6_MULTICAST_ADDR_0; - addr[1] = LL_IP6_MULTICAST_ADDR_1; - addr[2] = group32 >> 24; - addr[3] = group32 >> 16; - addr[4] = group32 >> 8; - addr[5] = group32; - ENET_AddMulticastGroup(ENET, addr); - return ERR_OK; - } - case NETIF_DEL_MAC_FILTER: - /* As we don't reference count, silently ignore delete requests */ - return ERR_OK; - default: - return ERR_ARG; - } -} -#endif - -/** \brief Allocates a pbuf and returns the data from the incoming packet. - * - * \param[in] netif the lwip network interface structure - * \param[in] idx index of packet to be read - * \return a pbuf filled with the received packet (including MAC header) - */ -static struct pbuf *k64f_low_level_input(struct netif *netif, int idx) -{ - volatile enet_rx_bd_struct_t *bdPtr = g_handle.rxBdCurrent; - struct pbuf *p = NULL; - struct pbuf *temp_rxbuf = NULL; - u32_t length = 0; - const u16_t err_mask = ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK | ENET_BUFFDESCRIPTOR_RX_CRC_MASK | - ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK | ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK; - - -#ifdef LOCK_RX_THREAD - /* Get exclusive access */ - sys_mutex_lock(&k64f_enet->TXLockMutex); -#endif - - /* Determine if a frame has been received */ - if ((bdPtr->control & err_mask) != 0) { -#if LINK_STATS - if ((bdPtr->control & ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK) != 0) - LINK_STATS_INC(link.lenerr); - else - LINK_STATS_INC(link.chkerr); -#endif - LINK_STATS_INC(link.drop); - /* Re-use the same buffer in case of error */ - update_read_buffer(NULL); - } else { - /* A packet is waiting, get length */ - length = bdPtr->length; - - /* Zero-copy */ - p = rx_buff[idx]; - p->len = length; - - /* Attempt to queue new buffer */ - temp_rxbuf = pbuf_alloc(PBUF_RAW, ENET_ETH_MAX_FLEN + ENET_BUFF_ALIGNMENT, PBUF_RAM); - if (NULL == temp_rxbuf) { - /* Drop frame (out of memory) */ - LINK_STATS_INC(link.drop); - - /* Re-queue the same buffer */ - update_read_buffer(NULL); - - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("k64f_low_level_input: Packet index %d dropped for OOM\n", - idx)); -#ifdef LOCK_RX_THREAD - sys_mutex_unlock(&k64f_enet->TXLockMutex); -#endif - - return NULL; - } - - rx_buff[idx] = temp_rxbuf; - /* K64F note: the next line ensures that the RX buffer is properly aligned for the K64F - RX descriptors (16 bytes alignment). However, by doing so, we're effectively changing - a data structure which is internal to lwIP. This might not prove to be a good idea - in the long run, but a better fix would probably involve modifying lwIP itself */ - rx_buff[idx]->payload = (void*)ENET_ALIGN((uint32_t)rx_buff[idx]->payload, ENET_BUFF_ALIGNMENT); - rx_ptr[idx] = rx_buff[idx]->payload; - - update_read_buffer(rx_buff[idx]->payload); - LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, - ("k64f_low_level_input: Packet received: %p, size %"PRIu32" (index=%d)\n", - p, length, idx)); - - /* Save size */ - p->tot_len = (u16_t) length; - LINK_STATS_INC(link.recv); - } - -#ifdef LOCK_RX_THREAD - sys_mutex_unlock(&k64f_enet->TXLockMutex); -#endif - - return p; -} - -/** \brief Attempt to read a packet from the EMAC interface. - * - * \param[in] netif the lwip network interface structure - * \param[in] idx index of packet to be read - */ -void k64f_enetif_input(struct netif *netif, int idx) -{ - struct pbuf *p; - - /* move received packet into a new pbuf */ - p = k64f_low_level_input(netif, idx); - if (p == NULL) - return; - - /* pass all packets to ethernet_input, which decides what packets it supports */ - if (netif->input(p, netif) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("k64f_enetif_input: input error\n")); - /* Free buffer */ - pbuf_free(p); - } -} - -/** \brief Worker thread. - * - * Woken by thread flags to receive packets or clean up transmit - * - * \param[in] pvParameters pointer to the interface data - */ -static void emac_thread(void* pvParameters) -{ - struct k64f_enetdata *k64f_enet = pvParameters; - - for (;;) { - uint32_t flags = osThreadFlagsWait(FLAG_RX|FLAG_TX, osFlagsWaitAny, PHY_TASK_PERIOD_MS); - if (flags == osFlagsErrorTimeout) { - // Rather than calling strictly every period, we call when idle - // for that period - hopefully good enough. We run this task - // from lwIP's thread rather than our RX/TX thread, as PHY reads can - // be slow, and we don't want them to interfere with data pumping. - // This is analogous to the way the PHY polling works in the Nanostack - // version of the driver - tcpip_callback_with_block(k64f_phy_task, k64f_enet->netif, 0); - continue; - } - - LWIP_ASSERT("osThreadFlagsWait error", !(flags & osFlagsError)); - - if (flags & FLAG_RX) { - packet_rx(k64f_enet); - } - - if (flags & FLAG_TX) { - packet_tx(k64f_enet); - } - } -} - -/** \brief Packet reception task - * - * This task is called when a packet is received. It will - * pass the packet to the LWIP core. - * - * \param[in] k64f_enet pointer to the interface data - */ -static void packet_rx(struct k64f_enetdata *k64f_enet) -{ - static int idx = 0; - - while ((g_handle.rxBdCurrent->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK) == 0) { - k64f_enetif_input(k64f_enet->netif, idx); - idx = (idx + 1) % ENET_RX_RING_LEN; - } -} - -/** \brief Transmit cleanup task - * - * This task is called when a transmit interrupt occurs and - * reclaims the pbuf and descriptor used for the packet once - * the packet has been transferred. - * - * \param[in] k64f_enet pointer to the interface data - */ -static void packet_tx(struct k64f_enetdata *k64f_enet) -{ - k64f_tx_reclaim(k64f_enet); -} - -/** \brief Low level output of a packet. Never call this from an - * interrupt context, as it may block until TX descriptors - * become available. - * - * \param[in] netif the lwip network interface structure for this netif - * \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type) - * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent - */ -static err_t k64f_low_level_output(struct netif *netif, struct pbuf *p) -{ - struct k64f_enetdata *k64f_enet = netif->state; - struct pbuf *q; - struct pbuf *temp_pbuf; - uint8_t *psend = NULL, *dst; - - temp_pbuf = pbuf_alloc(PBUF_RAW, p->tot_len + ENET_BUFF_ALIGNMENT, PBUF_RAM); - if (NULL == temp_pbuf) - return ERR_MEM; - - /* K64F note: the next line ensures that the RX buffer is properly aligned for the K64F - RX descriptors (16 bytes alignment). However, by doing so, we're effectively changing - a data structure which is internal to lwIP. This might not prove to be a good idea - in the long run, but a better fix would probably involve modifying lwIP itself */ - psend = (uint8_t *)ENET_ALIGN((uint32_t)temp_pbuf->payload, ENET_BUFF_ALIGNMENT); - - for (q = p, dst = psend; q != NULL; q = q->next) { - MEMCPY(dst, q->payload, q->len); - dst += q->len; - } - - /* Check if a descriptor is available for the transfer. */ - osStatus_t stat = osSemaphoreAcquire(k64f_enet->xTXDCountSem.id, 0); - if (stat != osOK) - return ERR_BUF; - - /* Get exclusive access */ - sys_mutex_lock(&k64f_enet->TXLockMutex); - - /* Save the buffer so that it can be freed when transmit is done */ - tx_buff[k64f_enet->tx_produce_index % ENET_TX_RING_LEN] = temp_pbuf; - k64f_enet->tx_produce_index += 1; - - /* Setup transfers */ - g_handle.txBdCurrent->buffer = psend; - g_handle.txBdCurrent->length = p->tot_len; - g_handle.txBdCurrent->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK); - - /* Increase the buffer descriptor address. */ - if (g_handle.txBdCurrent->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) - g_handle.txBdCurrent = g_handle.txBdBase; - else - g_handle.txBdCurrent++; - - /* Active the transmit buffer descriptor. */ - ENET->TDAR = ENET_TDAR_TDAR_MASK; - - LINK_STATS_INC(link.xmit); - - /* Restore access */ - sys_mutex_unlock(&k64f_enet->TXLockMutex); - - return ERR_OK; -} - -/******************************************************************************* - * PHY task: monitor link -*******************************************************************************/ - -#define STATE_UNKNOWN (-1) - -typedef struct { - int connected; - phy_speed_t speed; - phy_duplex_t duplex; -} PHY_STATE; - -int phy_link_status(void) { - bool connection_status; - uint32_t phyAddr = 0; - - PHY_GetLinkStatus(ENET, phyAddr, &connection_status); - return (int)connection_status; -} - -static void k64f_phy_task(void *data) -{ - struct netif *netif = data; - - static PHY_STATE prev_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN}; - - uint32_t phyAddr = 0; - - // Get current status - PHY_STATE crt_state; - bool connection_status; - PHY_GetLinkStatus(ENET, phyAddr, &connection_status); - crt_state.connected = connection_status; - // Get the actual PHY link speed - PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex); - - // Compare with previous state - if (crt_state.connected != prev_state.connected) { - // We're called from lwIP's tcpip thread, so can call link functions directly - if (crt_state.connected) { - netif_set_link_up(netif); - } else { - netif_set_link_down(netif); - } - } - - if (crt_state.speed != prev_state.speed) { - uint32_t rcr = ENET->RCR; - rcr &= ~ENET_RCR_RMII_10T_MASK; - rcr |= ENET_RCR_RMII_10T(!crt_state.speed); - ENET->RCR = rcr; - } - - prev_state = crt_state; -} - -/** - * Should be called at the beginning of the program to set up the - * network interface. - * - * This function should be passed as a parameter to netif_add(). - * - * @param[in] netif the lwip network interface structure for this netif - * @return ERR_OK if the loopif is initialized - * ERR_MEM if private data couldn't be allocated - * any other err_t on error - */ -err_t eth_arch_enetif_init(struct netif *netif) -{ - err_t err; - - LWIP_ASSERT("netif != NULL", (netif != NULL)); - - k64f_enetdata.netif = netif; - - /* set MAC hardware address */ -#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) - netif->hwaddr[0] = MBED_MAC_ADDR_0; - netif->hwaddr[1] = MBED_MAC_ADDR_1; - netif->hwaddr[2] = MBED_MAC_ADDR_2; - netif->hwaddr[3] = MBED_MAC_ADDR_3; - netif->hwaddr[4] = MBED_MAC_ADDR_4; - netif->hwaddr[5] = MBED_MAC_ADDR_5; -#else - mbed_mac_address((char *)netif->hwaddr); -#endif - - /* Ethernet address length */ - netif->hwaddr_len = ETH_HWADDR_LEN; - - /* maximum transfer unit */ - netif->mtu = 1500; - - /* device capabilities */ - // TODOETH: check if the flags are correct below - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET; - - /* Initialize the hardware */ - netif->state = &k64f_enetdata; - err = low_level_init(netif); - if (err != ERR_OK) - return err; - -#if LWIP_NETIF_HOSTNAME - /* Initialize interface hostname */ - netif->hostname = "lwipk64f"; -#endif /* LWIP_NETIF_HOSTNAME */ - - netif->name[0] = 'e'; - netif->name[1] = 'n'; - -#if LWIP_IPV4 - netif->output = k64f_etharp_output_ipv4; -#if LWIP_IGMP - netif->igmp_mac_filter = igmp_mac_filter; - netif->flags |= NETIF_FLAG_IGMP; -#endif -#endif -#if LWIP_IPV6 - netif->output_ip6 = k64f_etharp_output_ipv6; -#if LWIP_IPV6_MLD - netif->mld_mac_filter = mld_mac_filter; - netif->flags |= NETIF_FLAG_MLD6; -#else - // Would need to enable all multicasts here - no API in fsl_enet to do that - #error "IPv6 multicasts won't be received if LWIP_IPV6_MLD is disabled, breaking the system" -#endif -#endif - netif->linkoutput = k64f_low_level_output; - - /* CMSIS-RTOS, start tasks */ - memset(&k64f_enetdata.xTXDCountSem.data, 0, sizeof(k64f_enetdata.xTXDCountSem.data)); - k64f_enetdata.xTXDCountSem.attr.cb_mem = &k64f_enetdata.xTXDCountSem.data; - k64f_enetdata.xTXDCountSem.attr.cb_size = sizeof(k64f_enetdata.xTXDCountSem.data); - k64f_enetdata.xTXDCountSem.id = osSemaphoreNew(ENET_TX_RING_LEN, ENET_TX_RING_LEN, &k64f_enetdata.xTXDCountSem.attr); - - LWIP_ASSERT("xTXDCountSem creation error", (k64f_enetdata.xTXDCountSem.id != NULL)); - - err = sys_mutex_new(&k64f_enetdata.TXLockMutex); - LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK)); - - /* Allow the PHY task to detect the initial link state and set up the proper flags */ - tcpip_callback_with_block(k64f_phy_task, netif, 1); - osDelay(10); - - /* Worker thread */ - k64f_enetdata.thread = sys_thread_new("k64f_emac_thread", emac_thread, netif->state, THREAD_STACKSIZE, THREAD_PRIORITY)->id; - - /* Trigger thread to deal with any RX packets that arrived before thread was started */ - enet_mac_rx_isr(); - - return ERR_OK; -} - -void eth_arch_enable_interrupts(void) { - //NVIC_SetPriority(ENET_Receive_IRQn, 6U); - //NVIC_SetPriority(ENET_Transmit_IRQn, 6U); -} - -void eth_arch_disable_interrupts(void) { - -} - -/** - * @} - */ - -/* --------------------------------- End Of File ------------------------------ */ - diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.cpp b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.cpp new file mode 100644 index 00000000000..0fddbd3283c --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.cpp @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc. + * Copyright (c) 2017 ARM Limited + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "cmsis_os.h" + +#include "mbed_interface.h" +#include "emac_stack_mem.h" +#include "mbed_assert.h" +#include "netsocket/nsapi_types.h" +#include "mbed_shared_queues.h" + +#if DEVICE_EMAC + +#include "fsl_phy.h" + +#include "k64f_emac_config.h" +#include "k64f_emac.h" + +enet_handle_t g_handle; +// TX Buffer descriptors +uint8_t *tx_desc_start_addr; +// RX Buffer descriptors +uint8_t *rx_desc_start_addr; +// RX packet buffer pointers +emac_stack_mem_t *rx_buff[ENET_RX_RING_LEN]; +// TX packet buffer pointers +emac_stack_mem_t *tx_buff[ENET_RX_RING_LEN]; +// RX packet payload pointers +uint32_t *rx_ptr[ENET_RX_RING_LEN]; + +/******************************************************************************** + * Internal data + ********************************************************************************/ +#define ENET_BuffSizeAlign(n) ENET_ALIGN(n, ENET_BUFF_ALIGNMENT) +#define ENET_ALIGN(x,align) ((unsigned int)((x) + ((align)-1)) & (unsigned int)(~(unsigned int)((align)- 1))) +#if (defined(TARGET_K64F) && (defined(TARGET_FRDM))) +extern "C" void k64f_init_eth_hardware(void); +#endif + +#if (defined(TARGET_K66F) && (defined(TARGET_FRDM))) +extern "C" void k66f_init_eth_hardware(void); +#endif + +/* \brief Flags for worker thread */ +#define FLAG_TX 1 +#define FLAG_RX 2 + +/** \brief Driver thread priority */ +#define THREAD_PRIORITY (osPriorityNormal) + +#define PHY_TASK_PERIOD_MS 200 + +K64F_EMAC::K64F_EMAC() : xTXDCountSem(ENET_TX_RING_LEN, ENET_TX_RING_LEN), hwaddr() +{ +} + +static osThreadId_t create_new_thread(const char *threadName, void (*thread)(void *arg), void *arg, int stacksize, osPriority_t priority, os_thread_t *thread_cb) +{ + osThreadAttr_t attr = {0}; + attr.name = threadName; + attr.stack_mem = malloc(stacksize); + attr.cb_mem = thread_cb; + attr.stack_size = stacksize; + attr.cb_size = sizeof(os_thread_t); + attr.priority = priority; + return osThreadNew(thread, arg, &attr); +} +/******************************************************************************** + * Buffer management + ********************************************************************************/ +/* + * This function will queue a new receive buffer + */ +static void update_read_buffer(uint8_t *buf) +{ + if (buf != NULL) { + g_handle.rxBdCurrent->buffer = buf; + } + + /* Clears status. */ + g_handle.rxBdCurrent->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + + /* Sets the receive buffer descriptor with the empty flag. */ + g_handle.rxBdCurrent->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + + /* Increases the buffer descriptor to the next one. */ + if (g_handle.rxBdCurrent->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK) { + g_handle.rxBdCurrent = g_handle.rxBdBase; + } else { + g_handle.rxBdCurrent++; + } + + /* Actives the receive buffer descriptor. */ + ENET->RDAR = ENET_RDAR_RDAR_MASK; +} + +/** \brief Free TX buffers that are complete + */ +void K64F_EMAC::tx_reclaim() +{ + /* Get exclusive access */ + TXLockMutex.lock(); + + // Traverse all descriptors, looking for the ones modified by the uDMA + while((tx_consume_index != tx_produce_index) && + (!(g_handle.txBdDirty->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))) { + emac_stack_mem_free(tx_buff[tx_consume_index % ENET_TX_RING_LEN]); + if (g_handle.txBdDirty->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + g_handle.txBdDirty = g_handle.txBdBase; + else + g_handle.txBdDirty++; + + tx_consume_index += 1; + xTXDCountSem.release(); + } + + /* Restore access */ + TXLockMutex.unlock(); +} + +/** \brief Ethernet receive interrupt handler + * + * This function handles the receive interrupt of K64F. + */ +void K64F_EMAC::rx_isr() +{ + if (thread) { + osThreadFlagsSet(thread, FLAG_RX); + } +} + +void K64F_EMAC::tx_isr() +{ + osThreadFlagsSet(thread, FLAG_TX); +} + +void K64F_EMAC::ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param) +{ + K64F_EMAC *enet = static_cast(param); + switch (event) + { + case kENET_RxEvent: + enet->rx_isr(); + break; + case kENET_TxEvent: + enet->tx_isr(); + break; + default: + break; + } +} + + +/** \brief Low level init of the MAC and PHY. + */ +bool K64F_EMAC::low_level_init_successful() +{ + uint8_t i; + uint32_t sysClock; + phy_speed_t phy_speed; + phy_duplex_t phy_duplex; + uint32_t phyAddr = 0; + bool link = false; + enet_config_t config; + + // Allocate RX descriptors + rx_desc_start_addr = (uint8_t *)calloc(1, sizeof(enet_rx_bd_struct_t) * ENET_RX_RING_LEN + ENET_BUFF_ALIGNMENT); + if(!rx_desc_start_addr) + return false; + + // Allocate TX descriptors + tx_desc_start_addr = (uint8_t *)calloc(1, sizeof(enet_tx_bd_struct_t) * ENET_TX_RING_LEN + ENET_BUFF_ALIGNMENT); + if(!tx_desc_start_addr) + return false; + + rx_desc_start_addr = (uint8_t *)ENET_ALIGN(rx_desc_start_addr, ENET_BUFF_ALIGNMENT); + tx_desc_start_addr = (uint8_t *)ENET_ALIGN(tx_desc_start_addr, ENET_BUFF_ALIGNMENT); + + /* Create buffers for each receive BD */ + for (i = 0; i < ENET_RX_RING_LEN; i++) { + rx_buff[i] = emac_stack_mem_alloc(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT); + if (NULL == rx_buff[i]) + return false; + + rx_ptr[i] = (uint32_t*)emac_stack_mem_ptr(rx_buff[i]); + } + + tx_consume_index = tx_produce_index = 0; + + /* prepare the buffer configuration. */ + enet_buffer_config_t buffCfg = { + ENET_RX_RING_LEN, + ENET_TX_RING_LEN, + ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT), + 0, + (volatile enet_rx_bd_struct_t *)rx_desc_start_addr, + (volatile enet_tx_bd_struct_t *)tx_desc_start_addr, + (uint8_t *)&rx_ptr, + NULL, + }; +#if (defined(TARGET_K64F) && (defined(TARGET_FRDM))) + k64f_init_eth_hardware(); +#endif + +#if (defined(TARGET_K66F) && (defined(TARGET_FRDM))) + k66f_init_eth_hardware(); +#endif + + sysClock = CLOCK_GetFreq(kCLOCK_CoreSysClk); + + ENET_GetDefaultConfig(&config); + + PHY_Init(ENET, 0, sysClock); + PHY_GetLinkStatus(ENET, phyAddr, &link); + if (link) + { + /* Get link information from PHY */ + PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex); + /* Change the MII speed and duplex for actual link status. */ + config.miiSpeed = (enet_mii_speed_t)phy_speed; + config.miiDuplex = (enet_mii_duplex_t)phy_duplex; + config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt; + } + config.rxMaxFrameLen = ENET_ETH_MAX_FLEN; + config.macSpecialConfig = kENET_ControlFlowControlEnable; + config.txAccelerConfig = 0; + config.rxAccelerConfig = kENET_RxAccelMacCheckEnabled; + ENET_Init(ENET, &g_handle, &config, &buffCfg, hwaddr, sysClock); + +#if defined(TOOLCHAIN_ARM) +#if defined(__OPTIMISE_TIME) && (__ARMCC_VERSION < 5060750) + /* Add multicast groups + work around for https://github.com/ARMmbed/mbed-os/issues/4372 */ + ENET->GAUR = 0xFFFFFFFFu; + ENET->GALR = 0xFFFFFFFFu; +#endif +#endif + + ENET_SetCallback(&g_handle, &K64F_EMAC::ethernet_callback, this); + ENET_ActiveRead(ENET); + + return true; +} + + +/** \brief Allocates a emac_stack_mem_t and returns the data from the incoming packet. + * + * \param[in] idx index of packet to be read + * \return a emac_stack_mem_t filled with the received packet (including MAC header) + */ +emac_stack_mem_t *K64F_EMAC::low_level_input(int idx) +{ + volatile enet_rx_bd_struct_t *bdPtr = g_handle.rxBdCurrent; + emac_stack_mem_t *p = NULL; + emac_stack_mem_t *temp_rxbuf = NULL; + uint32_t length = 0; + const uint16_t err_mask = ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK | ENET_BUFFDESCRIPTOR_RX_CRC_MASK | + ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK | ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK; + +#ifdef LOCK_RX_THREAD + /* Get exclusive access */ + TXLockMutex.lock(); +#endif + + /* Determine if a frame has been received */ + if ((bdPtr->control & err_mask) != 0) { + /* Re-use the same buffer in case of error */ + update_read_buffer(NULL); + } else { + /* A packet is waiting, get length */ + length = bdPtr->length; + + /* Zero-copy */ + p = rx_buff[idx]; + emac_stack_mem_set_len(p, length); + + /* Attempt to queue new buffer */ + temp_rxbuf = emac_stack_mem_alloc(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT); + if (NULL == temp_rxbuf) { + /* Re-queue the same buffer */ + update_read_buffer(NULL); + +#ifdef LOCK_RX_THREAD + TXLockMutex.unlock(); +#endif + + return NULL; + } + + rx_buff[idx] = temp_rxbuf; + rx_ptr[idx] = (uint32_t*)emac_stack_mem_ptr(rx_buff[idx]); + + update_read_buffer((uint8_t*)rx_ptr[idx]); + + /* Save size */ + emac_stack_mem_set_chain_len(p, length); + } + +#ifdef LOCK_RX_THREAD + osMutexRelease(TXLockMutex); +#endif + + return p; +} + +/** \brief Attempt to read a packet from the EMAC interface. + * + * \param[in] idx index of packet to be read + */ +void K64F_EMAC::input(int idx) +{ + emac_stack_mem_t *p; + + /* move received packet into a new buf */ + p = low_level_input(idx); + if (p == NULL) + return; + + emac_link_input_cb(p); + +} + +/** \brief Worker thread. + * + * Woken by thread flags to receive packets or clean up transmit + * + * \param[in] pvParameters pointer to the interface data + */ +void K64F_EMAC::thread_function(void* pvParameters) +{ + struct K64F_EMAC *k64f_enet = static_cast(pvParameters); + + for (;;) { + uint32_t flags = osThreadFlagsWait(FLAG_RX|FLAG_TX, osFlagsWaitAny, osWaitForever); + + MBED_ASSERT(!(flags & osFlagsError)); + + if (flags & FLAG_RX) { + k64f_enet->packet_rx(); + } + + if (flags & FLAG_TX) { + k64f_enet->packet_tx(); + } + } +} + +/** \brief Packet reception task + * + * This task is called when a packet is received. It will + * pass the packet to the LWIP core. + */ +void K64F_EMAC::packet_rx() +{ + static int idx = 0; + + while ((g_handle.rxBdCurrent->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK) == 0) { + input(idx); + idx = (idx + 1) % ENET_RX_RING_LEN; + } +} + +/** \brief Transmit cleanup task + * + * This task is called when a transmit interrupt occurs and + * reclaims the buffer and descriptor used for the packet once + * the packet has been transferred. + */ +void K64F_EMAC::packet_tx() +{ + tx_reclaim(); +} + +/** \brief Low level output of a packet. Never call this from an + * interrupt context, as it may block until TX descriptors + * become available. + * + * \param[in] buf the MAC packet to send (e.g. IP packet including MAC addresses and type) + * \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent + */ +bool K64F_EMAC::link_out(emac_stack_mem_chain_t *chain) +{ + emac_stack_mem_t *q; + emac_stack_mem_t *temp_pbuf; + uint8_t *psend = NULL, *dst; + + temp_pbuf = emac_stack_mem_alloc(emac_stack_mem_chain_len(chain), ENET_BUFF_ALIGNMENT); + if (NULL == temp_pbuf) + return false; + + psend = (uint8_t*)emac_stack_mem_ptr(temp_pbuf); + for (q = emac_stack_mem_chain_dequeue(&chain), dst = psend; q != NULL; q = emac_stack_mem_chain_dequeue(&chain)) { + memcpy(dst, emac_stack_mem_ptr(q), emac_stack_mem_len(q)); + dst += emac_stack_mem_len(q); + } + + /* Check if a descriptor is available for the transfer. */ + if (xTXDCountSem.wait(0) == 0) + return false; + + /* Get exclusive access */ + TXLockMutex.lock(); + + /* Save the buffer so that it can be freed when transmit is done */ + tx_buff[tx_produce_index % ENET_TX_RING_LEN] = temp_pbuf; + tx_produce_index += 1; + + /* Setup transfers */ + g_handle.txBdCurrent->buffer = psend; + g_handle.txBdCurrent->length = emac_stack_mem_len(temp_pbuf); + g_handle.txBdCurrent->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK); + + /* Increase the buffer descriptor address. */ + if (g_handle.txBdCurrent->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + g_handle.txBdCurrent = g_handle.txBdBase; + else + g_handle.txBdCurrent++; + + /* Active the transmit buffer descriptor. */ + ENET->TDAR = ENET_TDAR_TDAR_MASK; + + /* Restore access */ + TXLockMutex.unlock(); + + return true; +} + +/******************************************************************************* + * PHY task: monitor link +*******************************************************************************/ + +#define STATE_UNKNOWN (-1) + +int phy_link_status(void) { + bool connection_status; + uint32_t phyAddr = 0; + + PHY_GetLinkStatus(ENET, phyAddr, &connection_status); + return (int)connection_status; +} + +void K64F_EMAC::phy_task() +{ + static PHY_STATE prev_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN}; + + uint32_t phyAddr = 0; + + // Get current status + PHY_STATE crt_state; + bool connection_status; + PHY_GetLinkStatus(ENET, phyAddr, &connection_status); + crt_state.connected = connection_status; + // Get the actual PHY link speed + PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex); + + // Compare with previous state + if (crt_state.connected != prev_state.connected) { + emac_link_state_cb(crt_state.connected); + } + + if (crt_state.speed != prev_state.speed) { + uint32_t rcr = ENET->RCR; + rcr &= ~ENET_RCR_RMII_10T_MASK; + rcr |= ENET_RCR_RMII_10T(!crt_state.speed); + ENET->RCR = rcr; + } + + prev_state = crt_state; +} + +bool K64F_EMAC::power_up() +{ + /* Initialize the hardware */ + if (!low_level_init_successful()) + return false; + + /* Worker thread */ + thread = create_new_thread("k64f_emac_thread", &K64F_EMAC::thread_function, this, THREAD_STACKSIZE, THREAD_PRIORITY, &thread_cb); + + /* Trigger thread to deal with any RX packets that arrived before thread was started */ + rx_isr(); + + /* PHY monitoring task */ + prev_state.connected = STATE_UNKNOWN; + prev_state.speed = (phy_speed_t)STATE_UNKNOWN; + prev_state.duplex = (phy_duplex_t)STATE_UNKNOWN; + + phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &K64F_EMAC::phy_task)); + + /* Allow the PHY task to detect the initial link state and set up the proper flags */ + osDelay(10); + + return true; +} + + +uint32_t K64F_EMAC::get_mtu_size() const +{ + return K64_ETH_MTU_SIZE; +} + +void K64F_EMAC::get_ifname(char *name, uint8_t size) const +{ + memcpy(name, K64_ETH_IF_NAME, (size < sizeof(K64_ETH_IF_NAME)) ? size : sizeof(K64_ETH_IF_NAME)); +} + +uint8_t K64F_EMAC::get_hwaddr_size() const +{ + return K64F_HWADDR_SIZE; +} + +bool K64F_EMAC::get_hwaddr(uint8_t *addr) const +{ + return false; +} + +void K64F_EMAC::set_hwaddr(const uint8_t *addr) +{ + memcpy(hwaddr, addr, sizeof hwaddr); + ENET_SetMacAddr(ENET, const_cast(addr)); +} + +void K64F_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb) +{ + emac_link_input_cb = input_cb; +} + +void K64F_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb) +{ + emac_link_state_cb = state_cb; +} + +void K64F_EMAC::add_multicast_group(uint8_t *addr) +{ + ENET_AddMulticastGroup(ENET, addr); +} + +void K64F_EMAC::power_down() +{ + /* No-op at this stage */ +} + + +K64F_EMAC &K64F_EMAC::get_instance() { + static K64F_EMAC emac; + return emac; +} + +// Weak so a module can override +MBED_WEAK EMAC &EMAC::get_default_instance() { + return K64F_EMAC::get_instance(); +} + +/** + * @} + */ + +#endif // DEVICE_EMAC + +/* --------------------------------- End Of File ------------------------------ */ + diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.h new file mode 100644 index 00000000000..67ed406759f --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2017 ARM Limited. All rights reserved. + */ + +#ifndef K64F_EMAC_H_ +#define K64F_EMAC_H_ + +#include "EMAC.h" +#include "rtos/Semaphore.h" +#include "rtos/Mutex.h" + +class K64F_EMAC : public EMAC { +public: + K64F_EMAC(); + + static K64F_EMAC &get_instance(); + + /** + * Return maximum transmission unit + * + * @return MTU in bytes + */ + virtual uint32_t get_mtu_size() const; + + /** + * Return interface name + * + * @param name Pointer to where the name should be written + * @param size Maximum number of character to copy + */ + virtual void get_ifname(char *name, uint8_t size) const; + + /** + * Returns size of the underlying interface HW address size. + * + * @return HW address size in bytes + */ + virtual uint8_t get_hwaddr_size() const; + + /** + * Return interface-supplied HW address + * + * Copies HW address to provided memory, @param addr has to be of correct size see @a get_hwaddr_size + * + * HW address need not be provided if this interface does not have its own HW + * address configuration; stack will choose address from central system + * configuration if the function returns false and does not write to addr. + * + * @param addr HW address for underlying interface + * @return true if HW address is available + */ + virtual bool get_hwaddr(uint8_t *addr) const; + + /** + * Set HW address for interface + * + * Provided address has to be of correct size, see @a get_hwaddr_size + * + * Called to set the MAC address to actually use - if @a get_hwaddr is provided + * the stack would normally use that, but it could be overridden, eg for test + * purposes. + * + * @param addr Address to be set + */ + virtual void set_hwaddr(const uint8_t *addr); + + /** + * Sends the packet over the link + * + * That can not be called from an interrupt context. + * + * @param buf Packet to be send + * @return True if the packet was send successfully, False otherwise + */ + virtual bool link_out(emac_stack_mem_chain_t *buf); + + /** + * Initializes the HW + * + * @return True on success, False in case of an error. + */ + virtual bool power_up(); + + /** + * Deinitializes the HW + * + */ + virtual void power_down(); + + /** + * Sets a callback that needs to be called for packets received for that interface + * + * @param input_cb Function to be register as a callback + */ + virtual void set_link_input_cb(emac_link_input_cb_t input_cb); + + /** + * Sets a callback that needs to be called on link status changes for given interface + * + * @param state_cb Function to be register as a callback + */ + virtual void set_link_state_cb(emac_link_state_change_cb_t state_cb); + + /** Add device to a multicast group + * + * @param address A multicast group hardware address + */ + virtual void add_multicast_group(uint8_t *address); + +private: + bool low_level_init_successful(); + void rx_isr(); + void tx_isr(); + void packet_rx(); + void packet_tx(); + void tx_reclaim(); + void input(int idx); + emac_stack_mem_t *low_level_input(int idx); + static void thread_function(void* pvParameters); + void phy_task(); + static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param); + + os_thread_t thread_cb; + osThreadId_t thread; /**< Processing thread */ + rtos::Mutex TXLockMutex;/**< TX critical section mutex */ + rtos::Semaphore xTXDCountSem; /**< TX free buffer counting semaphore */ + uint8_t tx_consume_index, tx_produce_index; /**< TX buffers ring */ + emac_link_input_cb_t emac_link_input_cb; /**< Callback for incoming data */ + emac_link_state_change_cb_t emac_link_state_cb; /**< Link state change callback */ + int phy_task_handle; /**< Handle for phy task event */ + struct PHY_STATE { + int connected; + phy_speed_t speed; + phy_duplex_t duplex; + }; + PHY_STATE prev_state; + uint8_t hwaddr[K64F_HWADDR_SIZE]; +}; + +#endif /* K64F_EMAC_H_ */ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h index 8ec5f2ddaf3..99a4f0981de 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h @@ -37,15 +37,12 @@ #define ENET_ETH_MAX_FLEN (1522) // recommended size for a VLAN frame -#if defined(__cplusplus) -extern "C" { -#endif +#define K64F_HWADDR_SIZE (6) -int phy_link_status(void); +#define K64_ETH_MTU_SIZE 1500 +#define K64_ETH_IF_NAME "en" -#if defined(__cplusplus) -} -#endif +#define THREAD_STACKSIZE 512 #endif // #define K64F_EMAC_CONFIG_H__ diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h index 20d961abe5a..ca0c0f78de6 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h @@ -22,7 +22,6 @@ #include "k64f_emac_config.h" #define LWIP_TRANSPORT_ETHERNET 1 -#define ETH_PAD_SIZE 2 #define MEM_SIZE (ENET_RX_RING_LEN * (ENET_ETH_MAX_FLEN + ENET_BUFF_ALIGNMENT) + ENET_TX_RING_LEN * ENET_ETH_MAX_FLEN) diff --git a/features/FEATURE_LWIP/lwip-interface/lwip_stack.c b/features/FEATURE_LWIP/lwip-interface/lwip_stack.c deleted file mode 100644 index 23ffbc5317c..00000000000 --- a/features/FEATURE_LWIP/lwip-interface/lwip_stack.c +++ /dev/null @@ -1,1364 +0,0 @@ -/* LWIP implementation of NetworkInterfaceAPI - * Copyright (c) 2015 ARM Limited - * - * 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. - */ - -#include "nsapi.h" -#include "mbed_interface.h" -#include "mbed_assert.h" -#include -#include -#include -#include "lwip_stack.h" - -#include "eth_arch.h" -#include "lwip/opt.h" -#include "lwip/api.h" -#include "lwip/inet.h" -#include "lwip/netif.h" -#include "lwip/dhcp.h" -#include "lwip/tcpip.h" -#include "lwip/tcp.h" -#include "lwip/ip.h" -#include "lwip/mld6.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" -#include "lwip/udp.h" -#include "lwip_errno.h" -#include "netif/lwip_ethernet.h" -#include "emac_api.h" -#include "ppp_lwip.h" - -static nsapi_error_t mbed_lwip_err_remap(err_t err); - -#if DEVICE_EMAC - #define MBED_NETIF_INIT_FN emac_lwip_if_init -#else - #define MBED_NETIF_INIT_FN eth_arch_enetif_init -#endif - -#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS - #define LWIP_SOCKET_MAX_MEMBERSHIPS 4 -#endif - -/* Static arena of sockets */ -static struct lwip_socket { - bool in_use; - - struct netconn *conn; - struct netbuf *buf; - u16_t offset; - - void (*cb)(void *); - void *data; - - // Track multicast addresses subscribed to by this socket - nsapi_ip_mreq_t *multicast_memberships; - uint32_t multicast_memberships_count; - uint32_t multicast_memberships_registry; - -} lwip_arena[MEMP_NUM_NETCONN]; - -static bool lwip_inited = false; -static bool lwip_connected = false; -static bool netif_inited = false; -static bool netif_is_ppp = false; - -static nsapi_error_t mbed_lwip_setsockopt(nsapi_stack_t *stack, nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen); - -static inline uint32_t next_registered_multicast_member(const struct lwip_socket *s, uint32_t index) { - while (!(s->multicast_memberships_registry & (0x0001 << index))) { index++; } - return index; -} - -static inline uint32_t next_free_multicast_member(const struct lwip_socket *s, uint32_t index) { - while ((s->multicast_memberships_registry & (0x0001 << index))) { index++; } - return index; -} - -static inline void set_multicast_member_registry_bit(struct lwip_socket *s, uint32_t index) { - s->multicast_memberships_registry |= (0x0001 << index); -} - -static inline void clear_multicast_member_registry_bit(struct lwip_socket *s, uint32_t index) { - s->multicast_memberships_registry &= ~(0x0001 << index); -} - -static struct lwip_socket *mbed_lwip_arena_alloc(void) -{ - sys_prot_t prot = sys_arch_protect(); - - for (int i = 0; i < MEMP_NUM_NETCONN; i++) { - if (!lwip_arena[i].in_use) { - struct lwip_socket *s = &lwip_arena[i]; - memset(s, 0, sizeof *s); - s->in_use = true; - sys_arch_unprotect(prot); - return s; - } - } - - sys_arch_unprotect(prot); - return 0; -} - -static void mbed_lwip_arena_dealloc(struct lwip_socket *s) -{ - s->in_use = false; - - while (s->multicast_memberships_count > 0) { - uint32_t index = 0; - index = next_registered_multicast_member(s, index); - - mbed_lwip_setsockopt(NULL, s, NSAPI_SOCKET, NSAPI_DROP_MEMBERSHIP, &s->multicast_memberships[index], - sizeof(s->multicast_memberships[index])); - index++; - } - - free(s->multicast_memberships); - s->multicast_memberships = NULL; -} - -static void mbed_lwip_socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len) -{ - // Filter send minus events - if (eh == NETCONN_EVT_SENDMINUS && nc->state == NETCONN_WRITE) { - return; - } - - sys_prot_t prot = sys_arch_protect(); - - for (int i = 0; i < MEMP_NUM_NETCONN; i++) { - if (lwip_arena[i].in_use - && lwip_arena[i].conn == nc - && lwip_arena[i].cb) { - lwip_arena[i].cb(lwip_arena[i].data); - } - } - - sys_arch_unprotect(prot); -} - - -/* TCP/IP and Network Interface Initialisation */ -static struct netif lwip_netif; -#if LWIP_DHCP -static bool lwip_dhcp = false; -#endif -static char lwip_mac_address[NSAPI_MAC_SIZE]; - -#if !LWIP_IPV4 || !LWIP_IPV6 -static bool all_zeros(const uint8_t *p, int len) -{ - for (int i = 0; i < len; i++) { - if (p[i]) { - return false; - } - } - - return true; -} -#endif - -static bool convert_mbed_addr_to_lwip(ip_addr_t *out, const nsapi_addr_t *in) -{ -#if LWIP_IPV6 - if (in->version == NSAPI_IPv6) { - IP_SET_TYPE(out, IPADDR_TYPE_V6); - MEMCPY(ip_2_ip6(out), in->bytes, sizeof(ip6_addr_t)); - return true; - } -#if !LWIP_IPV4 - /* For bind() and other purposes, need to accept "null" of other type */ - /* (People use IPv4 0.0.0.0 as a general null) */ - if (in->version == NSAPI_UNSPEC || - (in->version == NSAPI_IPv4 && all_zeros(in->bytes, 4))) { - ip_addr_set_zero_ip6(out); - return true; - } -#endif -#endif - -#if LWIP_IPV4 - if (in->version == NSAPI_IPv4) { - IP_SET_TYPE(out, IPADDR_TYPE_V4); - MEMCPY(ip_2_ip4(out), in->bytes, sizeof(ip4_addr_t)); - return true; - } -#if !LWIP_IPV6 - /* For symmetry with above, accept IPv6 :: as a general null */ - if (in->version == NSAPI_UNSPEC || - (in->version == NSAPI_IPv6 && all_zeros(in->bytes, 16))) { - ip_addr_set_zero_ip4(out); - return true; - } -#endif -#endif - -#if LWIP_IPV4 && LWIP_IPV6 - if (in->version == NSAPI_UNSPEC) { -#if IP_VERSION_PREF == PREF_IPV4 - ip_addr_set_zero_ip4(out); -#else - ip_addr_set_zero_ip6(out); -#endif - return true; - } -#endif - - return false; -} - -static bool convert_lwip_addr_to_mbed(nsapi_addr_t *out, const ip_addr_t *in) -{ -#if LWIP_IPV6 - if (IP_IS_V6(in)) { - out->version = NSAPI_IPv6; - MEMCPY(out->bytes, ip_2_ip6(in), sizeof(ip6_addr_t)); - return true; - } -#endif -#if LWIP_IPV4 - if (IP_IS_V4(in)) { - out->version = NSAPI_IPv4; - MEMCPY(out->bytes, ip_2_ip4(in), sizeof(ip4_addr_t)); - return true; - } -#endif -#if LWIP_IPV6 && LWIP_IPV4 - return false; -#endif -} - -#if LWIP_IPV4 -static const ip_addr_t *mbed_lwip_get_ipv4_addr(const struct netif *netif) -{ - if (!netif_is_up(netif)) { - return NULL; - } - - if (!ip4_addr_isany(netif_ip4_addr(netif))) { - return netif_ip_addr4(netif); - } - - return NULL; -} -#endif - -#if LWIP_IPV6 -static const ip_addr_t *mbed_lwip_get_ipv6_addr(const struct netif *netif) -{ - - if (!netif_is_up(netif)) { - return NULL; - } - - for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - !ip6_addr_islinklocal(netif_ip6_addr(netif, i))) { - return netif_ip_addr6(netif, i); - } - } - - return NULL; -} -#endif - -static bool mbed_lwip_is_local_addr(const ip_addr_t *ip_addr) -{ - struct netif *netif; - - for (netif = netif_list; netif != NULL; netif = netif->next) { - if (!netif_is_up(netif)) { - continue; - } -#if LWIP_IPV6 - if (IP_IS_V6(ip_addr)) { - for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && - ip6_addr_cmp(netif_ip6_addr(netif, i), ip_2_ip6(ip_addr))) { - return true; - } - } - } -#endif - -#if LWIP_IPV4 - if (IP_IS_V4(ip_addr)) { - if (!ip4_addr_isany(netif_ip4_addr(netif)) && - ip4_addr_cmp(netif_ip4_addr(netif), ip_2_ip4(ip_addr))) { - return true; - } - } -#endif - } - return false; -} - -const ip_addr_t *mbed_lwip_get_ip_addr(bool any_addr, const struct netif *netif) -{ - const ip_addr_t *pref_ip_addr = 0; - const ip_addr_t *npref_ip_addr = 0; - -#if LWIP_IPV4 && LWIP_IPV6 -#if IP_VERSION_PREF == PREF_IPV4 - pref_ip_addr = mbed_lwip_get_ipv4_addr(netif); - npref_ip_addr = mbed_lwip_get_ipv6_addr(netif); -#else - pref_ip_addr = mbed_lwip_get_ipv6_addr(netif); - npref_ip_addr = mbed_lwip_get_ipv4_addr(netif); -#endif -#elif LWIP_IPV6 - pref_ip_addr = mbed_lwip_get_ipv6_addr(netif); -#elif LWIP_IPV4 - pref_ip_addr = mbed_lwip_get_ipv4_addr(netif); -#endif - - if (pref_ip_addr) { - return pref_ip_addr; - } else if (npref_ip_addr && any_addr) { - return npref_ip_addr; - } - - return NULL; -} - -static void add_dns_addr_to_dns_list_index(const u8_t addr_type, const u8_t index) -{ -#if LWIP_IPV6 - if (addr_type == IPADDR_TYPE_V6) { - /* 2001:4860:4860::8888 google */ - ip_addr_t ipv6_dns_addr = IPADDR6_INIT( - PP_HTONL(0x20014860UL), - PP_HTONL(0x48600000UL), - PP_HTONL(0x00000000UL), - PP_HTONL(0x00008888UL)); - dns_setserver(index, &ipv6_dns_addr); - } -#endif -#if LWIP_IPV4 - if (addr_type == IPADDR_TYPE_V4) { - /* 8.8.8.8 google */ - ip_addr_t ipv4_dns_addr = IPADDR4_INIT(0x08080808); - dns_setserver(index, &ipv4_dns_addr); - } -#endif -} - -static int get_ip_addr_type(const ip_addr_t *ip_addr) -{ -#if LWIP_IPV6 - if (IP_IS_V6(ip_addr)) { - return IPADDR_TYPE_V6; - } -#endif -#if LWIP_IPV4 - if (IP_IS_V4(ip_addr)) { - return IPADDR_TYPE_V4; - } -#endif -#if LWIP_IPV6 && LWIP_IPV4 - return IPADDR_TYPE_ANY; -#endif -} - -void add_dns_addr(struct netif *lwip_netif) -{ - // Check for existing dns address - for (char numdns = 0; numdns < DNS_MAX_SERVERS; numdns++) { - const ip_addr_t *dns_ip_addr = dns_getserver(numdns); - if (!ip_addr_isany(dns_ip_addr)) { - return; - } - } - - // Get preferred ip version - const ip_addr_t *ip_addr = mbed_lwip_get_ip_addr(false, lwip_netif); - u8_t addr_type = IPADDR_TYPE_ANY; - - // Add preferred ip version dns address to index 0 - if (ip_addr) { - addr_type = get_ip_addr_type(ip_addr); - add_dns_addr_to_dns_list_index(addr_type, 0); - } - -#if LWIP_IPV4 && LWIP_IPV6 - if (!ip_addr) { - // Get address for any ip version - ip_addr = mbed_lwip_get_ip_addr(true, lwip_netif); - if (!ip_addr) { - return; - } - addr_type = get_ip_addr_type(ip_addr); - // Add the dns address to index 0 - add_dns_addr_to_dns_list_index(addr_type, 0); - } - - if (addr_type == IPADDR_TYPE_V4) { - // If ipv4 is preferred and ipv6 is available add ipv6 dns address to index 1 - ip_addr = mbed_lwip_get_ipv6_addr(lwip_netif); - } else if (addr_type == IPADDR_TYPE_V6) { - // If ipv6 is preferred and ipv4 is available add ipv4 dns address to index 1 - ip_addr = mbed_lwip_get_ipv4_addr(lwip_netif); - } else { - ip_addr = NULL; - } - - if (ip_addr) { - addr_type = get_ip_addr_type(ip_addr); - add_dns_addr_to_dns_list_index(addr_type, 1); - } -#endif -} - -static sys_sem_t lwip_tcpip_inited; -static void mbed_lwip_tcpip_init_irq(void *eh) -{ - sys_sem_signal(&lwip_tcpip_inited); -} - -static sys_sem_t lwip_netif_linked; -static sys_sem_t lwip_netif_unlinked; -static void mbed_lwip_netif_link_irq(struct netif *lwip_netif) -{ - if (netif_is_link_up(lwip_netif)) { - sys_sem_signal(&lwip_netif_linked); - } else { - sys_sem_signal(&lwip_netif_unlinked); - } -} - -static char lwip_has_addr_state = 0; - -#define HAS_ANY_ADDR 1 -static sys_sem_t lwip_netif_has_any_addr; -#if PREF_ADDR_TIMEOUT -#define HAS_PREF_ADDR 2 -static sys_sem_t lwip_netif_has_pref_addr; -#endif -#if BOTH_ADDR_TIMEOUT -#define HAS_BOTH_ADDR 4 -static sys_sem_t lwip_netif_has_both_addr; -#endif - -static void mbed_lwip_netif_status_irq(struct netif *lwip_netif) -{ - if (netif_is_up(lwip_netif)) { - if (!(lwip_has_addr_state & HAS_ANY_ADDR) && mbed_lwip_get_ip_addr(true, lwip_netif)) { - sys_sem_signal(&lwip_netif_has_any_addr); - lwip_has_addr_state |= HAS_ANY_ADDR; - } -#if PREF_ADDR_TIMEOUT - if (!(lwip_has_addr_state & HAS_PREF_ADDR) && mbed_lwip_get_ip_addr(false, lwip_netif)) { - sys_sem_signal(&lwip_netif_has_pref_addr); - lwip_has_addr_state |= HAS_PREF_ADDR; - } -#endif -#if BOTH_ADDR_TIMEOUT - if (!(lwip_has_addr_state & HAS_BOTH_ADDR) && mbed_lwip_get_ipv4_addr(lwip_netif) && mbed_lwip_get_ipv6_addr(lwip_netif)) { - sys_sem_signal(&lwip_netif_has_both_addr); - lwip_has_addr_state |= HAS_BOTH_ADDR; - } -#endif - } -} - -#if LWIP_ETHERNET -static void mbed_lwip_set_mac_address(struct netif *netif) -{ -#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) - netif->hwaddr[0] = MBED_MAC_ADDR_0; - netif->hwaddr[1] = MBED_MAC_ADDR_1; - netif->hwaddr[2] = MBED_MAC_ADDR_2; - netif->hwaddr[3] = MBED_MAC_ADDR_3; - netif->hwaddr[4] = MBED_MAC_ADDR_4; - netif->hwaddr[5] = MBED_MAC_ADDR_5; -#else - mbed_mac_address((char *)netif->hwaddr); -#endif - - netif->hwaddr_len = ETH_HWADDR_LEN; - - /* Use mac address as additional seed to random number generator */ - uint64_t seed = netif->hwaddr[0]; - for (uint8_t i = 1; i < 8; i++) { - seed <<= 8; - seed |= netif->hwaddr[i % 6]; - } - lwip_add_random_seed(seed); -} - -static void mbed_lwip_record_mac_address(const struct netif *netif) -{ - const u8_t *mac = netif->hwaddr; - snprintf(lwip_mac_address, NSAPI_MAC_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); -} -#endif // LWIP_ETHERNET - -/* LWIP interface implementation */ -const char *mbed_lwip_get_mac_address(void) -{ - return lwip_mac_address[0] ? lwip_mac_address : NULL; -} - -char *mbed_lwip_get_ip_address(char *buf, nsapi_size_t buflen) -{ - const ip_addr_t *addr = mbed_lwip_get_ip_addr(true, &lwip_netif); - if (!addr) { - return NULL; - } -#if LWIP_IPV6 - if (IP_IS_V6(addr)) { - return ip6addr_ntoa_r(ip_2_ip6(addr), buf, buflen); - } -#endif -#if LWIP_IPV4 - if (IP_IS_V4(addr)) { - return ip4addr_ntoa_r(ip_2_ip4(addr), buf, buflen); - } -#endif -#if LWIP_IPV6 && LWIP_IPV4 - return NULL; -#endif -} - -char *mbed_lwip_get_netmask(char *buf, nsapi_size_t buflen) -{ -#if LWIP_IPV4 - const ip4_addr_t *addr = netif_ip4_netmask(&lwip_netif); - if (!ip4_addr_isany(addr)) { - return ip4addr_ntoa_r(addr, buf, buflen); - } else { - return NULL; - } -#else - return NULL; -#endif -} - -char *mbed_lwip_get_gateway(char *buf, nsapi_size_t buflen) -{ -#if LWIP_IPV4 - const ip4_addr_t *addr = netif_ip4_gw(&lwip_netif); - if (!ip4_addr_isany(addr)) { - return ip4addr_ntoa_r(addr, buf, buflen); - } else { - return NULL; - } -#else - return NULL; -#endif -} - -static void mbed_lwip_core_init(void) -{ - - // Check if we've already brought up lwip - if (!lwip_inited) { - // Seed lwip random - lwip_seed_random(); - - // Initialise TCP sequence number - uint32_t tcp_isn_secret[4]; - for (int i = 0; i < 4; i++) { - tcp_isn_secret[i] = LWIP_RAND(); - } - lwip_init_tcp_isn(0, (u8_t *) &tcp_isn_secret); - - sys_sem_new(&lwip_tcpip_inited, 0); - sys_sem_new(&lwip_netif_linked, 0); - sys_sem_new(&lwip_netif_unlinked, 0); - sys_sem_new(&lwip_netif_has_any_addr, 0); -#if PREF_ADDR_TIMEOUT - sys_sem_new(&lwip_netif_has_pref_addr, 0); -#endif -#if BOTH_ADDR_TIMEOUT - sys_sem_new(&lwip_netif_has_both_addr, 0); -#endif - tcpip_init(mbed_lwip_tcpip_init_irq, NULL); - sys_arch_sem_wait(&lwip_tcpip_inited, 0); - - lwip_inited = true; - } -} - -nsapi_error_t mbed_lwip_emac_init(emac_interface_t *emac) -{ -#if LWIP_ETHERNET - // Choose a MAC address - driver can override - mbed_lwip_set_mac_address(&lwip_netif); - - // Set up network - if (!netif_add(&lwip_netif, -#if LWIP_IPV4 - 0, 0, 0, -#endif - emac, MBED_NETIF_INIT_FN, tcpip_input)) { - return NSAPI_ERROR_DEVICE_ERROR; - } - - // Note the MAC address actually in use - mbed_lwip_record_mac_address(&lwip_netif); - -#if !DEVICE_EMAC - eth_arch_enable_interrupts(); -#endif - - return NSAPI_ERROR_OK; -#else - return NSAPI_ERROR_UNSUPPORTED; -#endif //LWIP_ETHERNET -} - -// Backwards compatibility with people using DEVICE_EMAC -nsapi_error_t mbed_lwip_init(emac_interface_t *emac) -{ - nsapi_error_t ret; - mbed_lwip_core_init(); - ret = mbed_lwip_emac_init(emac); - if (ret == NSAPI_ERROR_OK) { - netif_inited = true; - } - return ret; -} - -// Backwards compatibility with people using DEVICE_EMAC -nsapi_error_t mbed_lwip_bringup(bool dhcp, const char *ip, const char *netmask, const char *gw) -{ - return mbed_lwip_bringup_2(dhcp, false, ip, netmask, gw, DEFAULT_STACK); -} - -nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const char *netmask, const char *gw, const nsapi_ip_stack_t stack) -{ - // Check if we've already connected - if (lwip_connected) { - return NSAPI_ERROR_PARAMETER; - } - - mbed_lwip_core_init(); - - nsapi_error_t ret; - if (netif_inited) { - /* Can't cope with changing mode */ - if (netif_is_ppp == ppp) { - ret = NSAPI_ERROR_OK; - } else { - ret = NSAPI_ERROR_PARAMETER; - } - } else { - if (ppp) { - ret = ppp_lwip_if_init(&lwip_netif, stack); - } else { - ret = mbed_lwip_emac_init(NULL); - } - } - - if (ret != NSAPI_ERROR_OK) { - return ret; - } - - netif_inited = true; - if (ppp) { - netif_is_ppp = ppp; - } - - netif_set_default(&lwip_netif); - netif_set_link_callback(&lwip_netif, mbed_lwip_netif_link_irq); - netif_set_status_callback(&lwip_netif, mbed_lwip_netif_status_irq); - -#if LWIP_IPV6 - if (stack != IPV4_STACK) { - if (lwip_netif.hwaddr_len == ETH_HWADDR_LEN) { - netif_create_ip6_linklocal_address(&lwip_netif, 1/*from MAC*/); - } - -#if LWIP_IPV6_MLD - /* - * For hardware/netifs that implement MAC filtering. - * All-nodes link-local is handled by default, so we must let the hardware know - * to allow multicast packets in. - * Should set mld_mac_filter previously. */ - if (lwip_netif.mld_mac_filter != NULL) { - ip6_addr_t ip6_allnodes_ll; - ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); - lwip_netif.mld_mac_filter(&lwip_netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); - } -#endif /* LWIP_IPV6_MLD */ - -#if LWIP_IPV6_AUTOCONFIG - /* IPv6 address autoconfiguration not enabled by default */ - lwip_netif.ip6_autoconfig_enabled = 1; - } else { - // Disable router solidifications - lwip_netif.rs_count = 0; - } -#endif /* LWIP_IPV6_AUTOCONFIG */ -#endif // LWIP_IPV6 - -#if LWIP_IPV4 - if (stack != IPV6_STACK) { - if (!dhcp && !ppp) { - ip4_addr_t ip_addr; - ip4_addr_t netmask_addr; - ip4_addr_t gw_addr; - - if (!inet_aton(ip, &ip_addr) || - !inet_aton(netmask, &netmask_addr) || - !inet_aton(gw, &gw_addr)) { - return NSAPI_ERROR_PARAMETER; - } - - netif_set_addr(&lwip_netif, &ip_addr, &netmask_addr, &gw_addr); - } - } -#endif - - if (ppp) { - err_t err = ppp_lwip_connect(); - if (err) { - return mbed_lwip_err_remap(err); - } - } - - if (!netif_is_link_up(&lwip_netif)) { - if (sys_arch_sem_wait(&lwip_netif_linked, 15000) == SYS_ARCH_TIMEOUT) { - if (ppp) { - (void) ppp_lwip_disconnect(); - } - return NSAPI_ERROR_NO_CONNECTION; - } - } - - if (!ppp) { - netif_set_up(&lwip_netif); - } - -#if LWIP_DHCP - if (stack != IPV6_STACK) { - // Connect to the network - lwip_dhcp = dhcp; - - if (lwip_dhcp) { - err_t err = dhcp_start(&lwip_netif); - if (err) { - return NSAPI_ERROR_DHCP_FAILURE; - } - } - } -#endif - - // If doesn't have address - if (!mbed_lwip_get_ip_addr(true, &lwip_netif)) { - if (sys_arch_sem_wait(&lwip_netif_has_any_addr, DHCP_TIMEOUT * 1000) == SYS_ARCH_TIMEOUT) { - if (ppp) { - (void) ppp_lwip_disconnect(); - } - return NSAPI_ERROR_DHCP_FAILURE; - } - } - -#if PREF_ADDR_TIMEOUT - if (stack != IPV4_STACK && stack != IPV6_STACK) { - // If address is not for preferred stack waits a while to see - // if preferred stack address is acquired - if (!mbed_lwip_get_ip_addr(false, &lwip_netif)) { - sys_arch_sem_wait(&lwip_netif_has_pref_addr, PREF_ADDR_TIMEOUT * 1000); - } - } -#endif -#if BOTH_ADDR_TIMEOUT - if (stack != IPV4_STACK && stack != IPV6_STACK) { - // If addresses for both stacks are not available waits a while to - // see if address for both stacks are acquired - if (!(mbed_lwip_get_ipv4_addr(&lwip_netif) && mbed_lwip_get_ipv6_addr(&lwip_netif))) { - sys_arch_sem_wait(&lwip_netif_has_both_addr, BOTH_ADDR_TIMEOUT * 1000); - } - } -#endif - - add_dns_addr(&lwip_netif); - - lwip_connected = true; - return 0; -} - -#if LWIP_IPV6 -void mbed_lwip_clear_ipv6_addresses(struct netif *lwip_netif) -{ - for (u8_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { - netif_ip6_addr_set_state(lwip_netif, i, IP6_ADDR_INVALID); - } -} -#endif - -// Backwards compatibility with people using DEVICE_EMAC -nsapi_error_t mbed_lwip_bringdown(void) -{ - return mbed_lwip_bringdown_2(false); -} - -nsapi_error_t mbed_lwip_bringdown_2(bool ppp) -{ - // Check if we've connected - if (!lwip_connected) { - return NSAPI_ERROR_PARAMETER; - } - -#if LWIP_DHCP - // Disconnect from the network - if (lwip_dhcp) { - dhcp_release(&lwip_netif); - dhcp_stop(&lwip_netif); - lwip_dhcp = false; - } -#endif - - if (ppp) { - /* this is a blocking call, returns when PPP is properly closed */ - err_t err = ppp_lwip_disconnect(); - if (err) { - return mbed_lwip_err_remap(err); - } - MBED_ASSERT(!netif_is_link_up(&lwip_netif)); - /*if (netif_is_link_up(&lwip_netif)) { - if (sys_arch_sem_wait(&lwip_netif_unlinked, 15000) == SYS_ARCH_TIMEOUT) { - return NSAPI_ERROR_DEVICE_ERROR; - } - }*/ - } else { - netif_set_down(&lwip_netif); - } - -#if LWIP_IPV6 - mbed_lwip_clear_ipv6_addresses(&lwip_netif); -#endif - - sys_sem_free(&lwip_netif_has_any_addr); - sys_sem_new(&lwip_netif_has_any_addr, 0); -#if PREF_ADDR_TIMEOUT - sys_sem_free(&lwip_netif_has_pref_addr); - sys_sem_new(&lwip_netif_has_pref_addr, 0); -#endif -#if BOTH_ADDR_TIMEOUT - sys_sem_free(&lwip_netif_has_both_addr); - sys_sem_new(&lwip_netif_has_both_addr, 0); -#endif - lwip_has_addr_state = 0; - lwip_connected = false; - return 0; -} - -/* LWIP error remapping */ -static nsapi_error_t mbed_lwip_err_remap(err_t err) { - switch (err) { - case ERR_OK: - case ERR_CLSD: - return 0; - case ERR_MEM: - case ERR_BUF: - return NSAPI_ERROR_NO_MEMORY; - case ERR_CONN: - case ERR_RST: - case ERR_ABRT: - return NSAPI_ERROR_NO_CONNECTION; - case ERR_TIMEOUT: - case ERR_RTE: - case ERR_WOULDBLOCK: - return NSAPI_ERROR_WOULD_BLOCK; - case ERR_VAL: - case ERR_USE: - case ERR_ARG: - return NSAPI_ERROR_PARAMETER; - case ERR_INPROGRESS: - return NSAPI_ERROR_IN_PROGRESS; - case ERR_ALREADY: - return NSAPI_ERROR_ALREADY; - case ERR_ISCONN: - return NSAPI_ERROR_IS_CONNECTED; - default: - return NSAPI_ERROR_DEVICE_ERROR; - } -} - -/* LWIP network stack implementation */ -static nsapi_error_t mbed_lwip_gethostbyname(nsapi_stack_t *stack, const char *host, nsapi_addr_t *addr, nsapi_version_t version) -{ - ip_addr_t lwip_addr; - -#if LWIP_IPV4 && LWIP_IPV6 - u8_t addr_type; - if (version == NSAPI_UNSPEC) { - const ip_addr_t *ip_addr; - ip_addr = mbed_lwip_get_ip_addr(true, &lwip_netif); - // Prefer IPv6 - if (IP_IS_V6(ip_addr)) { - // If IPv4 is available use it as backup - if (mbed_lwip_get_ipv4_addr(&lwip_netif)) { - addr_type = NETCONN_DNS_IPV6_IPV4; - } else { - addr_type = NETCONN_DNS_IPV6; - } - // Prefer IPv4 - } else { - // If IPv6 is available use it as backup - if (mbed_lwip_get_ipv6_addr(&lwip_netif)) { - addr_type = NETCONN_DNS_IPV4_IPV6; - } else { - addr_type = NETCONN_DNS_IPV4; - } - } - } else if (version == NSAPI_IPv4) { - addr_type = NETCONN_DNS_IPV4; - } else if (version == NSAPI_IPv6) { - addr_type = NETCONN_DNS_IPV6; - } else { - return NSAPI_ERROR_DNS_FAILURE; - } - err_t err = netconn_gethostbyname_addrtype(host, &lwip_addr, addr_type); -#elif LWIP_IPV4 - if (version != NSAPI_IPv4 && version != NSAPI_UNSPEC) { - return NSAPI_ERROR_DNS_FAILURE; - } - err_t err = netconn_gethostbyname(host, &lwip_addr); -#elif LWIP_IPV6 - if (version != NSAPI_IPv6 && version != NSAPI_UNSPEC) { - return NSAPI_ERROR_DNS_FAILURE; - } - err_t err = netconn_gethostbyname(host, &lwip_addr); -#endif - - if (err != ERR_OK) { - return NSAPI_ERROR_DNS_FAILURE; - } - - convert_lwip_addr_to_mbed(addr, &lwip_addr); - - return 0; -} - -static nsapi_error_t mbed_lwip_add_dns_server(nsapi_stack_t *stack, nsapi_addr_t addr) -{ - // Shift all dns servers down to give precedence to new server - for (int i = DNS_MAX_SERVERS-1; i > 0; i--) { - dns_setserver(i, dns_getserver(i-1)); - } - - ip_addr_t ip_addr; - if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) { - return NSAPI_ERROR_PARAMETER; - } - - dns_setserver(0, &ip_addr); - return 0; -} - -static nsapi_error_t mbed_lwip_socket_open(nsapi_stack_t *stack, nsapi_socket_t *handle, nsapi_protocol_t proto) -{ - // check if network is connected - if (!lwip_connected) { - return NSAPI_ERROR_NO_CONNECTION; - } - - // allocate a socket - struct lwip_socket *s = mbed_lwip_arena_alloc(); - if (!s) { - return NSAPI_ERROR_NO_SOCKET; - } - - enum netconn_type lwip_proto = proto == NSAPI_TCP ? NETCONN_TCP : NETCONN_UDP; - -#if LWIP_IPV6 - // Enable IPv6 (or dual-stack) - lwip_proto |= NETCONN_TYPE_IPV6; -#endif - - s->conn = netconn_new_with_callback(lwip_proto, mbed_lwip_socket_callback); - - if (!s->conn) { - mbed_lwip_arena_dealloc(s); - return NSAPI_ERROR_NO_SOCKET; - } - - netconn_set_recvtimeout(s->conn, 1); - *(struct lwip_socket **)handle = s; - return 0; -} - -static nsapi_error_t mbed_lwip_socket_close(nsapi_stack_t *stack, nsapi_socket_t handle) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - - netbuf_delete(s->buf); - err_t err = netconn_delete(s->conn); - mbed_lwip_arena_dealloc(s); - return mbed_lwip_err_remap(err); -} - -static nsapi_error_t mbed_lwip_socket_bind(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - ip_addr_t ip_addr; - - if ( -#if LWIP_TCP - (s->conn->type == NETCONN_TCP && s->conn->pcb.tcp->local_port != 0) || -#endif - (s->conn->type == NETCONN_UDP && s->conn->pcb.udp->local_port != 0)) { - return NSAPI_ERROR_PARAMETER; - } - - if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) { - return NSAPI_ERROR_PARAMETER; - } - - if (!ip_addr_isany(&ip_addr) && !mbed_lwip_is_local_addr(&ip_addr)) { - return NSAPI_ERROR_PARAMETER; - } - - err_t err = netconn_bind(s->conn, &ip_addr, port); - return mbed_lwip_err_remap(err); -} - -static nsapi_error_t mbed_lwip_socket_listen(nsapi_stack_t *stack, nsapi_socket_t handle, int backlog) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - - if (s->conn->pcb.tcp->local_port == 0) { - return NSAPI_ERROR_PARAMETER; - } - - err_t err = netconn_listen_with_backlog(s->conn, backlog); - return mbed_lwip_err_remap(err); -} - -static nsapi_error_t mbed_lwip_socket_connect(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - ip_addr_t ip_addr; - - if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) { - return NSAPI_ERROR_PARAMETER; - } - - netconn_set_nonblocking(s->conn, false); - err_t err = netconn_connect(s->conn, &ip_addr, port); - netconn_set_nonblocking(s->conn, true); - - return mbed_lwip_err_remap(err); -} - -static nsapi_error_t mbed_lwip_socket_accept(nsapi_stack_t *stack, nsapi_socket_t server, nsapi_socket_t *handle, nsapi_addr_t *addr, uint16_t *port) -{ - struct lwip_socket *s = (struct lwip_socket *)server; - struct lwip_socket *ns = mbed_lwip_arena_alloc(); - if (!ns) { - return NSAPI_ERROR_NO_SOCKET; - } - - if (s->conn->pcb.tcp->state != LISTEN) { - return NSAPI_ERROR_PARAMETER; - } - - err_t err = netconn_accept(s->conn, &ns->conn); - if (err != ERR_OK) { - mbed_lwip_arena_dealloc(ns); - return mbed_lwip_err_remap(err); - } - - netconn_set_recvtimeout(ns->conn, 1); - *(struct lwip_socket **)handle = ns; - - ip_addr_t peer_addr; - (void) netconn_peer(ns->conn, &peer_addr, port); - convert_lwip_addr_to_mbed(addr, &peer_addr); - - netconn_set_nonblocking(ns->conn, true); - - return 0; -} - -static nsapi_size_or_error_t mbed_lwip_socket_send(nsapi_stack_t *stack, nsapi_socket_t handle, const void *data, nsapi_size_t size) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - size_t bytes_written = 0; - - err_t err = netconn_write_partly(s->conn, data, size, NETCONN_COPY, &bytes_written); - if (err != ERR_OK) { - return mbed_lwip_err_remap(err); - } - - return (nsapi_size_or_error_t)bytes_written; -} - -static nsapi_size_or_error_t mbed_lwip_socket_recv(nsapi_stack_t *stack, nsapi_socket_t handle, void *data, nsapi_size_t size) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - - if (!s->buf) { - err_t err = netconn_recv(s->conn, &s->buf); - s->offset = 0; - - if (err != ERR_OK) { - return mbed_lwip_err_remap(err); - } - } - - u16_t recv = netbuf_copy_partial(s->buf, data, (u16_t)size, s->offset); - s->offset += recv; - - if (s->offset >= netbuf_len(s->buf)) { - netbuf_delete(s->buf); - s->buf = 0; - } - - return recv; -} - -static nsapi_size_or_error_t mbed_lwip_socket_sendto(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t addr, uint16_t port, const void *data, nsapi_size_t size) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - ip_addr_t ip_addr; - - if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) { - return NSAPI_ERROR_PARAMETER; - } - - struct netbuf *buf = netbuf_new(); - err_t err = netbuf_ref(buf, data, (u16_t)size); - if (err != ERR_OK) { - netbuf_free(buf); - return mbed_lwip_err_remap(err); - } - - err = netconn_sendto(s->conn, buf, &ip_addr, port); - netbuf_delete(buf); - if (err != ERR_OK) { - return mbed_lwip_err_remap(err); - } - - return size; -} - -static nsapi_size_or_error_t mbed_lwip_socket_recvfrom(nsapi_stack_t *stack, nsapi_socket_t handle, nsapi_addr_t *addr, uint16_t *port, void *data, nsapi_size_t size) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - struct netbuf *buf; - - err_t err = netconn_recv(s->conn, &buf); - if (err != ERR_OK) { - return mbed_lwip_err_remap(err); - } - - convert_lwip_addr_to_mbed(addr, netbuf_fromaddr(buf)); - *port = netbuf_fromport(buf); - - u16_t recv = netbuf_copy(buf, data, (u16_t)size); - netbuf_delete(buf); - - return recv; -} - -static int32_t find_multicast_member(const struct lwip_socket *s, const nsapi_ip_mreq_t *imr) { - uint32_t count = 0; - uint32_t index = 0; - // Set upper limit on while loop, should break out when the membership pair is found - while (count < s->multicast_memberships_count) { - index = next_registered_multicast_member(s, index); - - if (memcmp(&s->multicast_memberships[index].imr_multiaddr, &imr->imr_multiaddr, sizeof(nsapi_addr_t)) == 0 && - memcmp(&s->multicast_memberships[index].imr_interface, &imr->imr_interface, sizeof(nsapi_addr_t)) == 0) { - return index; - } - count++; - index++; - } - - return -1; -} - -static nsapi_error_t mbed_lwip_setsockopt(nsapi_stack_t *stack, nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - - switch (optname) { -#if LWIP_TCP - case NSAPI_KEEPALIVE: - if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) { - return NSAPI_ERROR_UNSUPPORTED; - } - - s->conn->pcb.tcp->so_options |= SOF_KEEPALIVE; - return 0; - - case NSAPI_KEEPIDLE: - if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) { - return NSAPI_ERROR_UNSUPPORTED; - } - - s->conn->pcb.tcp->keep_idle = *(int*)optval; - return 0; - - case NSAPI_KEEPINTVL: - if (optlen != sizeof(int) || s->conn->type != NETCONN_TCP) { - return NSAPI_ERROR_UNSUPPORTED; - } - - s->conn->pcb.tcp->keep_intvl = *(int*)optval; - return 0; -#endif - - case NSAPI_REUSEADDR: - if (optlen != sizeof(int)) { - return NSAPI_ERROR_UNSUPPORTED; - } - - if (*(int *)optval) { - ip_set_option(s->conn->pcb.ip, SOF_REUSEADDR); - } else { - ip_reset_option(s->conn->pcb.ip, SOF_REUSEADDR); - } - return 0; - - case NSAPI_ADD_MEMBERSHIP: - case NSAPI_DROP_MEMBERSHIP: { - if (optlen != sizeof(nsapi_ip_mreq_t)) { - return NSAPI_ERROR_PARAMETER; - } - err_t igmp_err; - const nsapi_ip_mreq_t *imr = optval; - - /* Check interface address type matches group, or is unspecified */ - if (imr->imr_interface.version != NSAPI_UNSPEC && imr->imr_interface.version != imr->imr_multiaddr.version) { - return NSAPI_ERROR_PARAMETER; - } - - ip_addr_t if_addr; - ip_addr_t multi_addr; - - /* Convert the group address */ - if (!convert_mbed_addr_to_lwip(&multi_addr, &imr->imr_multiaddr)) { - return NSAPI_ERROR_PARAMETER; - } - - /* Convert the interface address, or make sure it's the correct sort of "any" */ - if (imr->imr_interface.version != NSAPI_UNSPEC) { - if (!convert_mbed_addr_to_lwip(&if_addr, &imr->imr_interface)) { - return NSAPI_ERROR_PARAMETER; - } - } else { - ip_addr_set_any(IP_IS_V6(&if_addr), &if_addr); - } - - igmp_err = ERR_USE; // Maps to NSAPI_ERROR_UNSUPPORTED - int32_t member_pair_index = find_multicast_member(s, imr); - - if (optname == NSAPI_ADD_MEMBERSHIP) { - if (!s->multicast_memberships) { - // First multicast join on this socket, allocate space for membership tracking - s->multicast_memberships = malloc(sizeof(nsapi_ip_mreq_t) * LWIP_SOCKET_MAX_MEMBERSHIPS); - if (!s->multicast_memberships) { - return NSAPI_ERROR_NO_MEMORY; - } - } else if(s->multicast_memberships_count == LWIP_SOCKET_MAX_MEMBERSHIPS) { - return NSAPI_ERROR_NO_MEMORY; - } - - if (member_pair_index != -1) { - return NSAPI_ERROR_ADDRESS_IN_USE; - } - - member_pair_index = next_free_multicast_member(s, 0); - - sys_prot_t prot = sys_arch_protect(); - - #if LWIP_IPV4 - if (IP_IS_V4(&if_addr)) { - igmp_err = igmp_joingroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr)); - } - #endif - #if LWIP_IPV6 - if (IP_IS_V6(&if_addr)) { - igmp_err = mld6_joingroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr)); - } - #endif - - sys_arch_unprotect(prot); - - if (igmp_err == ERR_OK) { - set_multicast_member_registry_bit(s, member_pair_index); - s->multicast_memberships[member_pair_index] = *imr; - s->multicast_memberships_count++; - } - } else { - if (member_pair_index == -1) { - return NSAPI_ERROR_NO_ADDRESS; - } - - clear_multicast_member_registry_bit(s, member_pair_index); - s->multicast_memberships_count--; - - sys_prot_t prot = sys_arch_protect(); - - #if LWIP_IPV4 - if (IP_IS_V4(&if_addr)) { - igmp_err = igmp_leavegroup(ip_2_ip4(&if_addr), ip_2_ip4(&multi_addr)); - } - #endif - #if LWIP_IPV6 - if (IP_IS_V6(&if_addr)) { - igmp_err = mld6_leavegroup(ip_2_ip6(&if_addr), ip_2_ip6(&multi_addr)); - } - #endif - - sys_arch_unprotect(prot); - } - - return mbed_lwip_err_remap(igmp_err); - } - - default: - return NSAPI_ERROR_UNSUPPORTED; - } -} - -static void mbed_lwip_socket_attach(nsapi_stack_t *stack, nsapi_socket_t handle, void (*callback)(void *), void *data) -{ - struct lwip_socket *s = (struct lwip_socket *)handle; - - s->cb = callback; - s->data = data; -} - -/* LWIP network stack */ -const nsapi_stack_api_t lwip_stack_api = { - .gethostbyname = mbed_lwip_gethostbyname, - .add_dns_server = mbed_lwip_add_dns_server, - .socket_open = mbed_lwip_socket_open, - .socket_close = mbed_lwip_socket_close, - .socket_bind = mbed_lwip_socket_bind, - .socket_listen = mbed_lwip_socket_listen, - .socket_connect = mbed_lwip_socket_connect, - .socket_accept = mbed_lwip_socket_accept, - .socket_send = mbed_lwip_socket_send, - .socket_recv = mbed_lwip_socket_recv, - .socket_sendto = mbed_lwip_socket_sendto, - .socket_recvfrom = mbed_lwip_socket_recvfrom, - .setsockopt = mbed_lwip_setsockopt, - .socket_attach = mbed_lwip_socket_attach, -}; - -nsapi_stack_t lwip_stack = { - .stack_api = &lwip_stack_api, -}; diff --git a/features/FEATURE_LWIP/lwip-interface/lwip_stack.h b/features/FEATURE_LWIP/lwip-interface/lwip_stack.h deleted file mode 100644 index 9fdb8ed7eb6..00000000000 --- a/features/FEATURE_LWIP/lwip-interface/lwip_stack.h +++ /dev/null @@ -1,47 +0,0 @@ -/* LWIP implementation of NetworkInterfaceAPI - * Copyright (c) 2015 ARM Limited - * - * 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. - */ - -#ifndef LWIP_STACK_H -#define LWIP_STACK_H - -#include "nsapi.h" -#include "emac_api.h" -#include "lwip/opt.h" -#ifdef __cplusplus -extern "C" { -#endif - -// Access to lwip through the nsapi - be wary of API changes as external 1st-generation EMAC -// drivers attach through these. -nsapi_error_t mbed_lwip_init(emac_interface_t *emac); -nsapi_error_t mbed_lwip_emac_init(emac_interface_t *emac); -nsapi_error_t mbed_lwip_bringup(bool dhcp, const char *ip, const char *netmask, const char *gw); -nsapi_error_t mbed_lwip_bringup_2(bool dhcp, bool ppp, const char *ip, const char *netmask, const char *gw, const nsapi_ip_stack_t stack); -nsapi_error_t mbed_lwip_bringdown(void); -nsapi_error_t mbed_lwip_bringdown_2(bool ppp); - -const char *mbed_lwip_get_mac_address(void); -char *mbed_lwip_get_ip_address(char *buf, nsapi_size_t buflen); -char *mbed_lwip_get_netmask(char *buf, nsapi_size_t buflen); -char *mbed_lwip_get_gateway(char *buf, nsapi_size_t buflen); - -extern nsapi_stack_t lwip_stack; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/features/FEATURE_LWIP/lwip-interface/lwip_tools.cpp b/features/FEATURE_LWIP/lwip-interface/lwip_tools.cpp new file mode 100644 index 00000000000..d7fdfc822be --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip_tools.cpp @@ -0,0 +1,191 @@ +/* LWIP common helpers + * Copyright (c) 2017 ARM Limited + * + * 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. + */ + +#include +#include + +#include "lwip/opt.h" +#include "lwip/netif.h" +#include "lwip/ip.h" +#include "lwip/api.h" + +#include "LWIPStack.h" + +#include "netsocket/nsapi_types.h" + +/* LWIP error remapping */ +nsapi_error_t LWIP::err_remap(err_t err) { + switch (err) { + case ERR_OK: + case ERR_CLSD: + return 0; + case ERR_MEM: + case ERR_BUF: + return NSAPI_ERROR_NO_MEMORY; + case ERR_CONN: + case ERR_RST: + case ERR_ABRT: + return NSAPI_ERROR_NO_CONNECTION; + case ERR_TIMEOUT: + case ERR_RTE: + case ERR_WOULDBLOCK: + return NSAPI_ERROR_WOULD_BLOCK; + case ERR_VAL: + case ERR_USE: + case ERR_ARG: + return NSAPI_ERROR_PARAMETER; + case ERR_INPROGRESS: + return NSAPI_ERROR_IN_PROGRESS; + case ERR_ALREADY: + return NSAPI_ERROR_ALREADY; + case ERR_ISCONN: + return NSAPI_ERROR_IS_CONNECTED; + default: + return NSAPI_ERROR_DEVICE_ERROR; + } +} + +#if LWIP_IPV4 +const ip_addr_t *LWIP::get_ipv4_addr(const struct netif *netif) +{ + if (!netif_is_up(netif)) { + return NULL; + } + + if (!ip4_addr_isany(netif_ip4_addr(netif))) { + return netif_ip_addr4(netif); + } + + return NULL; +} +#endif + +#if LWIP_IPV6 +const ip_addr_t *LWIP::get_ipv6_addr(const struct netif *netif) +{ + if (!netif_is_up(netif)) { + return NULL; + } + + for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + !ip6_addr_islinklocal(netif_ip6_addr(netif, i))) { + return netif_ip_addr6(netif, i); + } + } + + return NULL; +} +#endif + +bool LWIP::is_local_addr(const ip_addr_t *ip_addr) +{ + struct netif *netif; + + for (netif = netif_list; netif != NULL; netif = netif->next) { + if (!netif_is_up(netif)) { + continue; + } +#if LWIP_IPV6 + if (IP_IS_V6(ip_addr)) { + for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && + ip6_addr_cmp(netif_ip6_addr(netif, i), ip_2_ip6(ip_addr))) { + return true; + } + } + } +#endif + +#if LWIP_IPV4 + if (IP_IS_V4(ip_addr)) { + if (!ip4_addr_isany(netif_ip4_addr(netif)) && + ip4_addr_cmp(netif_ip4_addr(netif), ip_2_ip4(ip_addr))) { + return true; + } + } +#endif + } + return false; +} + +const ip_addr_t *LWIP::get_ip_addr(bool any_addr, const struct netif *netif) +{ + const ip_addr_t *pref_ip_addr = 0; + const ip_addr_t *npref_ip_addr = 0; + +#if LWIP_IPV4 && LWIP_IPV6 +#if IP_VERSION_PREF == PREF_IPV4 + pref_ip_addr = get_ipv4_addr(netif); + npref_ip_addr = get_ipv6_addr(netif); +#else + pref_ip_addr = get_ipv6_addr(netif); + npref_ip_addr = get_ipv4_addr(netif); +#endif +#elif LWIP_IPV6 + pref_ip_addr = get_ipv6_addr(netif); +#elif LWIP_IPV4 + pref_ip_addr = get_ipv4_addr(netif); +#endif + + if (pref_ip_addr) { + return pref_ip_addr; + } else if (npref_ip_addr && any_addr) { + return npref_ip_addr; + } + + return NULL; +} + +void LWIP::arena_init(void) +{ + memset(arena, 0, sizeof(arena)); +} + +struct LWIP::mbed_lwip_socket *LWIP::arena_alloc() +{ + sys_prot_t prot = sys_arch_protect(); + + for (int i = 0; i < MEMP_NUM_NETCONN; i++) { + if (!arena[i].in_use) { + struct mbed_lwip_socket *s = &arena[i]; + memset(s, 0, sizeof(*s)); + s->in_use = true; + sys_arch_unprotect(prot); + return s; + } + } + + sys_arch_unprotect(prot); + return 0; +} + +void LWIP::arena_dealloc(struct mbed_lwip_socket *s) +{ + s->in_use = false; + + while (s->multicast_memberships_count > 0) { + uint32_t index = 0; + index = next_registered_multicast_member(s, index); + + setsockopt(s, NSAPI_SOCKET, NSAPI_DROP_MEMBERSHIP, &s->multicast_memberships[index], + sizeof(s->multicast_memberships[index])); + index++; + } + + free(s->multicast_memberships); + s->multicast_memberships = NULL; +} diff --git a/features/FEATURE_LWIP/lwip-interface/ppp_lwip.cpp b/features/FEATURE_LWIP/lwip-interface/ppp_lwip.cpp index d1646540ba9..95e9be35e3a 100644 --- a/features/FEATURE_LWIP/lwip-interface/ppp_lwip.cpp +++ b/features/FEATURE_LWIP/lwip-interface/ppp_lwip.cpp @@ -38,7 +38,7 @@ extern "C" { // "pppos.h" is missing extern C #include "nsapi_ppp.h" #include "ppp_lwip.h" -#include "lwip_stack.h" +#include "LWIPStack.h" namespace mbed { @@ -54,6 +54,7 @@ static nsapi_error_t connect_error_code; // Just one interface for now static FileHandle *my_stream; +static LWIP::Interface *my_interface; static ppp_pcb *my_ppp_pcb; static bool ppp_active = false; static const char *login; @@ -279,7 +280,7 @@ static void stream_cb() { } } -extern "C" err_t ppp_lwip_connect() +extern "C" err_t ppp_lwip_connect(void *pcb) { #if PPP_AUTH_SUPPORT ppp_set_auth(my_ppp_pcb, PPPAUTHTYPE_ANY, login, pwd); @@ -295,7 +296,7 @@ extern "C" err_t ppp_lwip_connect() return ret; } -extern "C" err_t ppp_lwip_disconnect() +extern "C" err_t ppp_lwip_disconnect(void *pcb) { err_t ret = ppp_close(my_ppp_pcb, 0); if (ret != ERR_OK) { @@ -313,7 +314,7 @@ extern "C" err_t ppp_lwip_disconnect() return ret; } -extern "C" nsapi_error_t ppp_lwip_if_init(struct netif *netif, const nsapi_ip_stack_t stack) +extern "C" nsapi_error_t ppp_lwip_if_init(void *pcb, struct netif *netif, const nsapi_ip_stack_t stack) { if (!prepare_event_queue()) { return NSAPI_ERROR_NO_MEMORY; @@ -362,9 +363,20 @@ nsapi_error_t nsapi_ppp_connect(FileHandle *stream, Callbackbringup(false, NULL, NULL, NULL, stack); if (retcode != NSAPI_ERROR_OK && connect_error_code != NSAPI_ERROR_OK) { return connect_error_code; @@ -375,12 +387,12 @@ nsapi_error_t nsapi_ppp_connect(FileHandle *stream, Callbackbringdown(); } NetworkStack *nsapi_ppp_get_stack() { - return nsapi_create_stack(&lwip_stack); + return &LWIP::get_instance(); } const char *nsapi_ppp_get_ip_addr(FileHandle *stream) @@ -389,7 +401,7 @@ const char *nsapi_ppp_get_ip_addr(FileHandle *stream) if (stream == my_stream) { - if (mbed_lwip_get_ip_address(ip_addr, IPADDR_STRLEN_MAX)) { + if (my_interface->get_ip_address(ip_addr, IPADDR_STRLEN_MAX)) { return ip_addr; } } @@ -404,7 +416,7 @@ const char *nsapi_ppp_get_netmask(FileHandle *stream) static char netmask[IPADDR_STRLEN_MAX]; if (stream == my_stream) { - if (mbed_lwip_get_netmask(netmask, IPADDR_STRLEN_MAX)) { + if (my_interface->get_netmask(netmask, IPADDR_STRLEN_MAX)) { return netmask; } } @@ -419,7 +431,7 @@ const char *nsapi_ppp_get_gw_addr(FileHandle *stream) static char gwaddr[IPADDR_STRLEN_MAX]; if (stream == my_stream) { - if (mbed_lwip_get_gateway(gwaddr, IPADDR_STRLEN_MAX)) { + if (my_interface->get_netmask(gwaddr, IPADDR_STRLEN_MAX)) { return gwaddr; } } diff --git a/features/FEATURE_LWIP/lwip-interface/ppp_lwip.h b/features/FEATURE_LWIP/lwip-interface/ppp_lwip.h index 6536619426d..a568737c560 100644 --- a/features/FEATURE_LWIP/lwip-interface/ppp_lwip.h +++ b/features/FEATURE_LWIP/lwip-interface/ppp_lwip.h @@ -30,7 +30,7 @@ extern "C" { * * @return 0 for success and negative error codes for failure */ -nsapi_error_t ppp_lwip_if_init(struct netif *netif, const nsapi_ip_stack_t stack); +nsapi_error_t ppp_lwip_if_init(void *pcb, struct netif *netif, nsapi_ip_stack_t stack); /** Connects to a PPP pipe * @@ -38,7 +38,7 @@ nsapi_error_t ppp_lwip_if_init(struct netif *netif, const nsapi_ip_stack_t stack * * @return 0 for success and negative error codes for failure */ -err_t ppp_lwip_connect(void); +err_t ppp_lwip_connect(void *pcb); /** Disconnects from a PPP pipe * @@ -48,14 +48,14 @@ err_t ppp_lwip_connect(void); * * @return 0 for success and negative error codes for failure */ -err_t ppp_lwip_disconnect(void); +err_t ppp_lwip_disconnect(void *pcb); #else /** * Stubs in case LWIP PPP is not enabled */ -#define ppp_lwip_if_init(netif, stack) NSAPI_ERROR_UNSUPPORTED -#define ppp_lwip_connect() ERR_IF -#define ppp_lwip_disconnect() ERR_IF +#define ppp_lwip_if_init(pcb, netif, stack) NSAPI_ERROR_UNSUPPORTED +#define ppp_lwip_connect(pcb) ERR_IF +#define ppp_lwip_disconnect(pcb) ERR_IF #endif //LWIP_PPP_API #ifdef __cplusplus } diff --git a/features/netsocket/EMAC.h b/features/netsocket/EMAC.h new file mode 100644 index 00000000000..77d0e967387 --- /dev/null +++ b/features/netsocket/EMAC.h @@ -0,0 +1,156 @@ +/* mbed Microcontroller Library + * Copyright (c) 2016 ARM Limited + * + * 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. + */ + +#ifndef EMAC_H +#define EMAC_H + +#include +#include "Callback.h" +#include "emac_stack_mem.h" + +/** + * This interface should be used to abstract low level access to networking hardware + * All operations receive a `void *` hw pointer which an emac device provides when + * it is registered with a stack. + */ +class EMAC { +public: + + /** Return the default on-board EMAC + * + * Returns the default on-board EMAC - this will be target-specific, and + * may not be available on all targets. + */ + static EMAC &get_default_instance(); + + /** + * Callback to be register with Emac interface and to be called for received packets + * + * @param buf Received data + */ + //typedef void (*emac_link_input_fn)(void *data, emac_stack_mem_chain_t *buf); + typedef mbed::Callback emac_link_input_cb_t; + + /** + * Callback to be register with Emac interface and to be called for link status changes + * + * @param up Link status + */ + //typedef void (*emac_link_state_change_fn)(void *data, bool up); + typedef mbed::Callback emac_link_state_change_cb_t; + + /** + * Return maximum transmission unit + * + * @return MTU in bytes + */ + virtual uint32_t get_mtu_size() const = 0; + + /** + * Return interface name + * + * @param name Pointer to where the name should be written + * @param size Maximum number of character to copy + */ + virtual void get_ifname(char *name, uint8_t size) const = 0; + + /** + * Returns size of the underlying interface HW address size. + * + * @return HW address size in bytes + */ + virtual uint8_t get_hwaddr_size() const = 0; + + /** + * Return interface-supplied HW address + * + * Copies HW address to provided memory, @param addr has to be of correct size see @a get_hwaddr_size + * + * HW address need not be provided if this interface does not have its own HW + * address configuration; stack will choose address from central system + * configuration if the function returns false and does not write to addr. + * + * @param addr HW address for underlying interface + * @return true if HW address is available + */ + virtual bool get_hwaddr(uint8_t *addr) const = 0; + + /** + * Set HW address for interface + * + * Provided address has to be of correct size, see @a get_hwaddr_size + * + * Called to set the MAC address to actually use - if @a get_hwaddr is provided + * the stack would normally use that, but it could be overridden, eg for test + * purposes. + * + * @param addr Address to be set + */ + virtual void set_hwaddr(const uint8_t *addr) = 0; + + /** + * Sends the packet over the link + * + * That can not be called from an interrupt context. + * + * @param buf Packet to be send + * @return True if the packet was send successfully, False otherwise + */ + virtual bool link_out(emac_stack_mem_chain_t *buf) = 0; + + /** + * Initializes the HW + * + * @return True on success, False in case of an error. + */ + virtual bool power_up() = 0; + + /** + * Deinitializes the HW + * + */ + virtual void power_down() = 0; + + /** + * Sets a callback that needs to be called for packets received for that interface + * + * @param input_cb Function to be register as a callback + */ + virtual void set_link_input_cb(emac_link_input_cb_t input_cb) = 0; + + /** + * Sets a callback that needs to be called on link status changes for given interface + * + * @param state_cb Function to be register as a callback + */ + virtual void set_link_state_cb(emac_link_state_change_cb_t state_cb) = 0; + + /** Add device to a multicast group + * + * @param address A multicast group hardware address + */ + virtual void add_multicast_group(uint8_t *address) = 0; + +}; + + +/** These need to be defined by targets wishing to provide an Ethernet driver using EMAC interface. It will + * be used by the EthernetInterface class's default constructor to initialise the networking subsystem. + */ +//extern const emac_interface_ops_t mbed_emac_eth_ops_default; +//extern void *mbed_emac_eth_hw_default; + +#endif /* EMAC_H */ diff --git a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp b/features/netsocket/EthernetInterface.cpp similarity index 70% rename from features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp rename to features/netsocket/EthernetInterface.cpp index 7c69b48a4c6..931a76d5cd5 100644 --- a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp +++ b/features/netsocket/EthernetInterface.cpp @@ -15,12 +15,10 @@ */ #include "EthernetInterface.h" -#include "lwip_stack.h" - /* Interface implementation */ -EthernetInterface::EthernetInterface() - : _dhcp(true), _ip_address(), _netmask(), _gateway() +EthernetInterface::EthernetInterface(EMAC &emac, OnboardNetworkStack &stack) + : _emac(emac), _stack(stack), _interface(NULL), _dhcp(true), _mac_address(), _ip_address(), _netmask(), _gateway() { } @@ -46,7 +44,15 @@ nsapi_error_t EthernetInterface::set_dhcp(bool dhcp) nsapi_error_t EthernetInterface::connect() { - return mbed_lwip_bringup_2(_dhcp, false, + if (!_interface) { + nsapi_error_t err = _stack.add_ethernet_interface(_emac, true, &_interface); + if (err != NSAPI_ERROR_OK) { + _interface = NULL; + return err; + } + } + + return _interface->bringup(_dhcp, _ip_address[0] ? _ip_address : 0, _netmask[0] ? _netmask : 0, _gateway[0] ? _gateway : 0, @@ -55,17 +61,20 @@ nsapi_error_t EthernetInterface::connect() nsapi_error_t EthernetInterface::disconnect() { - return mbed_lwip_bringdown_2(false); + return _interface->bringdown(); } const char *EthernetInterface::get_mac_address() { - return mbed_lwip_get_mac_address(); + if (_interface->get_mac_address(_mac_address, sizeof(_mac_address))) { + return _mac_address; + } + return NULL; } const char *EthernetInterface::get_ip_address() { - if (mbed_lwip_get_ip_address(_ip_address, sizeof _ip_address)) { + if (_interface->get_ip_address(_ip_address, sizeof(_ip_address))) { return _ip_address; } @@ -74,7 +83,7 @@ const char *EthernetInterface::get_ip_address() const char *EthernetInterface::get_netmask() { - if (mbed_lwip_get_netmask(_netmask, sizeof _netmask)) { + if (_interface->get_netmask(_netmask, sizeof(_netmask))) { return _netmask; } @@ -83,7 +92,7 @@ const char *EthernetInterface::get_netmask() const char *EthernetInterface::get_gateway() { - if (mbed_lwip_get_gateway(_gateway, sizeof _gateway)) { + if (_interface->get_gateway(_gateway, sizeof(_gateway))) { return _gateway; } @@ -92,5 +101,5 @@ const char *EthernetInterface::get_gateway() NetworkStack *EthernetInterface::get_stack() { - return nsapi_create_stack(&lwip_stack); + return &_stack; } diff --git a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.h b/features/netsocket/EthernetInterface.h similarity index 70% rename from features/FEATURE_LWIP/lwip-interface/EthernetInterface.h rename to features/netsocket/EthernetInterface.h index f92f70e4ebf..c11c8d84358 100644 --- a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.h +++ b/features/netsocket/EthernetInterface.h @@ -19,21 +19,32 @@ #include "nsapi.h" #include "rtos.h" -#include "lwip/netif.h" - -// Forward declaration -class NetworkStack; +#include "EMAC.h" +#include "OnboardNetworkStack.h" /** EthernetInterface class - * Implementation of the NetworkStack for LWIP + * Implementation of the NetworkStack for an EMAC-based driver */ class EthernetInterface : public EthInterface { public: - /** EthernetInterface lifetime + /** Create an EMAC-based ethernet interface. + * + * The default arguments obtain the default EMAC, which will be target- + * dependent (and the target may have some JSON option to choose which + * is the default, if there are multiple). The default stack is configured + * by JSON option nsapi.default-stack. + * + * Due to inability to return errors from the constructor, no real + * work is done until the first call to connect(). + * + * @param emac Reference to EMAC to use + * @param stack Reference to onboard-network stack to use */ - EthernetInterface(); + EthernetInterface( + EMAC &emac = EMAC::get_default_instance(), + OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance()); /** Set a static IP address * @@ -41,10 +52,10 @@ class EthernetInterface : public EthInterface * Implicitly disables DHCP, which can be enabled in set_dhcp. * Requires that the network is disconnected. * - * @param address Null-terminated representation of the local IP address - * @param netmask Null-terminated representation of the local network mask - * @param gateway Null-terminated representation of the local gateway - * @return 0 on success, negative error code on failure + * @param ip_address Null-terminated representation of the local IP address + * @param netmask Null-terminated representation of the local network mask + * @param gateway Null-terminated representation of the local gateway + * @return 0 on success, negative error code on failure */ virtual nsapi_error_t set_network( const char *ip_address, const char *netmask, const char *gateway); @@ -107,11 +118,14 @@ class EthernetInterface : public EthInterface */ virtual NetworkStack *get_stack(); + EMAC &_emac; + OnboardNetworkStack &_stack; + OnboardNetworkStack::Interface *_interface; bool _dhcp; - char _ip_address[IPADDR_STRLEN_MAX]; + char _mac_address[NSAPI_MAC_SIZE]; + char _ip_address[NSAPI_IPv6_SIZE]; char _netmask[NSAPI_IPv4_SIZE]; char _gateway[NSAPI_IPv4_SIZE]; }; - #endif diff --git a/features/netsocket/NetworkStack.cpp b/features/netsocket/NetworkStack.cpp index cb02bbfce10..515aa082908 100644 --- a/features/netsocket/NetworkStack.cpp +++ b/features/netsocket/NetworkStack.cpp @@ -20,8 +20,12 @@ #include "stddef.h" #include - // Default NetworkStack operations +const char *NetworkStack::get_ip_address() +{ + return 0; + +} nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version) { // check for simple ip addresses diff --git a/features/netsocket/NetworkStack.h b/features/netsocket/NetworkStack.h index 27b9cc1f97c..cede3bbb8b1 100644 --- a/features/netsocket/NetworkStack.h +++ b/features/netsocket/NetworkStack.h @@ -37,11 +37,14 @@ class NetworkStack virtual ~NetworkStack() {}; /** Get the local IP address + * @deprecated * * @return Null-terminated representation of the local IP address * or null if not yet connected */ - virtual const char *get_ip_address() = 0; + MBED_DEPRECATED_SINCE("mbed-os-5.7", + "Use NetworkInterface::get_ip_address()") + virtual const char *get_ip_address(); /** Translates a hostname to an IP address with specific version * diff --git a/features/netsocket/OnboardNetworkStack.h b/features/netsocket/OnboardNetworkStack.h new file mode 100644 index 00000000000..f5346113103 --- /dev/null +++ b/features/netsocket/OnboardNetworkStack.h @@ -0,0 +1,121 @@ +/* mbed OS IP stack API + * Copyright (c) 2015-2017 ARM Limited + * + * 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. + */ + +#ifndef MBED_IPSTACK_H +#define MBED_IPSTACK_H + +#include "nsapi.h" + +#include "NetworkStack.h" + +class EMAC; + +/** + * mbed OS API for onboard IP stack abstraction + * + * This interface should be used by targets to initialize IP stack, create, bring up and bring down network interfaces. + * + * An onboard network stack has the potential ability to register interfaces + * such as through EMAC, and has its own interface identifiers. + */ +class OnboardNetworkStack : public NetworkStack { +public: + /** Return the default on-board network stack + * + * Returns the default on-board network stack, as configured by + * JSON option nsapi.default-stack. + */ + static OnboardNetworkStack &get_default_instance(); + + /** Representation of a stack's view of an interface. + * + * Provides facilities required by a driver to implement the application + * NetworkInterface API. + */ + class Interface { + public: + virtual ~Interface() {} + + /** Connect the interface to the network + * + * Sets up a connection on specified network interface, using DHCP or provided network details. If the @a dhcp is set to + * true all the remaining parameters are ignored. + * + * @param dhcp true if the network details should be acquired using DHCP + * @param ip IP address to be used for the interface as "W:X:Y:Z" or NULL + * @param netmask Net mask to be used for the interface as "W:X:Y:Z" or NULL + * @param gw Gateway address to be used for the interface as "W:X:Y:Z" or NULL + * @param stack Allow manual selection of IPv4 and/or IPv6. + * @return NSAPI_ERROR_OK on success, or error code + */ + virtual nsapi_error_t bringup(bool dhcp, const char *ip, + const char *netmask, const char *gw, + nsapi_ip_stack_t stack = DEFAULT_STACK) = 0; + + /** Disconnect interface from the network + * + * After this call the network interface is inactive, to use it again user needs to call @n bringup again. + * + * @return NSAPI_ERROR_OK on success, or error code + */ + virtual nsapi_error_t bringdown() = 0; + + /** Return MAC address of the network interface + * + * @return MAC address as "V:W:X:Y:Z" + */ + virtual char *get_mac_address(char *buf, nsapi_size_t buflen) = 0; + + /** Copies IP address of the network interface to user supplied buffer + * + * @param buf buffer to which IP address will be copied as "W:X:Y:Z" + * @param buflen size of supplied buffer + * @return Pointer to a buffer, or NULL if the buffer is too small + */ + virtual char *get_ip_address(char *buf, nsapi_size_t buflen) = 0; + + /** Copies netmask of the network interface to user supplied buffer + * + * @param buf buffer to which netmask will be copied as "W:X:Y:Z" + * @param buflen size of supplied buffer + * @return Pointer to a buffer, or NULL if the buffer is too small + */ + virtual char *get_netmask(char *buf, nsapi_size_t buflen) = 0; + + /** Copies gateway address of the network interface to user supplied buffer + * + * @param buf buffer to which gateway address will be copied as "W:X:Y:Z" + * @param buflen size of supplied buffer + * @return Pointer to a buffer, or NULL if the buffer is too small + */ + virtual char *get_gateway(char *buf, nsapi_size_t buflen) = 0; + }; + + + /** Register a network interface with the IP stack + * + * Connects EMAC layer with the IP stack and initializes all the required infrastructure. + * This function should be called only once for each available interface. + * + * @param emac EMAC HAL implementation for this network interface + * @param default_if true if the interface should be treated as the default one + * @param[out] interface_out pointer to stack interface object controlling the EMAC + * @return NSAPI_ERROR_OK on success, or error code + */ + virtual nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, Interface **interface_out) = 0; +}; + +#endif /* MBED_IPSTACK_H */ diff --git a/features/netsocket/emac_stack_mem.h b/features/netsocket/emac_stack_mem.h index d3e0e4dd14f..b0bbd820d04 100644 --- a/features/netsocket/emac_stack_mem.h +++ b/features/netsocket/emac_stack_mem.h @@ -16,10 +16,12 @@ #ifndef MBED_EMAC_STACK_MEM_H #define MBED_EMAC_STACK_MEM_H -#if DEVICE_EMAC - #include +#ifdef __cplusplus +extern "C" { +#endif + /** * Stack memory module * @@ -29,88 +31,81 @@ */ typedef void emac_stack_mem_t; typedef void emac_stack_mem_chain_t; -typedef void emac_stack_t; /** * Allocates stack memory * - * @param stack Emac stack context * @param size Size of memory to allocate * @param align Memory alignment requirements * @return Allocated memory struct, or NULL in case of error */ -emac_stack_mem_t *emac_stack_mem_alloc(emac_stack_t* stack, uint32_t size, uint32_t align); +emac_stack_mem_t *emac_stack_mem_alloc(uint32_t size, uint32_t align); /** * Free memory allocated using @a stack_mem_alloc * - * @param stack Emac stack context * @param mem Memory to be freed */ -void emac_stack_mem_free(emac_stack_t* stack, emac_stack_mem_t *mem); +void emac_stack_mem_free(emac_stack_mem_t *mem); /** * Copy memory * - * @param stack Emac stack context * @param to Memory to copy to * @param from Memory to copy from */ -void emac_stack_mem_copy(emac_stack_t* stack, emac_stack_mem_t *to, emac_stack_mem_t *from); +void emac_stack_mem_copy(emac_stack_mem_t *to, emac_stack_mem_t *from); /** * Return pointer to the payload * - * @param stack Emac stack context * @param mem Memory structure * @return Pointer to the payload */ -void *emac_stack_mem_ptr(emac_stack_t* stack, emac_stack_mem_t *mem); +void *emac_stack_mem_ptr(emac_stack_mem_t *mem); /** * Return actual payload size * - * @param stack Emac stack context * @param mem Memory structure * @return Size in bytes */ -uint32_t emac_stack_mem_len(emac_stack_t* stack, emac_stack_mem_t *mem); +uint32_t emac_stack_mem_len(emac_stack_mem_t *mem); /** * Sets the actual payload size (the allocated payload size will not change) * - * @param stack Emac stack context * @param mem Memory structure * @param len Actual payload size */ -void emac_stack_mem_set_len(emac_stack_t* stack, emac_stack_mem_t *mem, uint32_t len); +void emac_stack_mem_set_len(emac_stack_mem_t *mem, uint32_t len); /** * Returns first memory structure from the list and move the head to point to the next node * - * @param stack Emac stack context * @param chain Pointer to the list * @return First memory structure from the list */ -emac_stack_mem_t *emac_stack_mem_chain_dequeue(emac_stack_t* stack, emac_stack_mem_chain_t **chain); +emac_stack_mem_t *emac_stack_mem_chain_dequeue(emac_stack_mem_chain_t **chain); /** * Return total length of the memory chain * - * @param stack Emac stack context * @param chain Memory chain * @return Chain length */ -uint32_t emac_stack_mem_chain_len(emac_stack_t* stack, emac_stack_mem_chain_t *chain); +uint32_t emac_stack_mem_chain_len(emac_stack_mem_chain_t *chain); /** - * Increases the reference counter for the memory - * - * @param stack Emac stack context - * @param mem Memory structure - */ -void emac_stack_mem_ref(emac_stack_t* stack, emac_stack_mem_t *mem); +* Set total length of the memory chain +* +* @param chain Memory chain +* @param len Total chain length + */ +void emac_stack_mem_set_chain_len(emac_stack_mem_chain_t *chain, uint32_t len); -#endif /* DEVICE_EMAC */ +#ifdef __cplusplus +} +#endif #endif /* EMAC_MBED_STACK_MEM_h */ diff --git a/features/netsocket/mbed_lib.json b/features/netsocket/mbed_lib.json index 35edcf1017f..fb2c50ecae8 100644 --- a/features/netsocket/mbed_lib.json +++ b/features/netsocket/mbed_lib.json @@ -1,6 +1,7 @@ { "name": "nsapi", "config": { - "present": 1 + "present": 1, + "default-stack": "LWIP" } } diff --git a/hal/emac_api.h b/hal/emac_api.h deleted file mode 100644 index e5fbd1a9419..00000000000 --- a/hal/emac_api.h +++ /dev/null @@ -1,160 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2016 ARM Limited - * - * 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. - */ - -#ifndef MBED_EMAC_API_H -#define MBED_EMAC_API_H - -#if DEVICE_EMAC - -#include -#include "emac_stack_mem.h" - -typedef struct emac_interface emac_interface_t; - -/** - * EmacInterface - * - * This interface should be used to abstract low level access to networking hardware - */ - -/** - * Callback to be register with Emac interface and to be called fore received packets - * - * @param data Arbitrary user data (IP stack) - * @param buf Received data - */ -typedef void (*emac_link_input_fn)(void *data, emac_stack_mem_chain_t *buf); - -/** - * Callback to be register with Emac interface and to be called for link status changes - * - * @param data Arbitrary user data (IP stack) - * @param up Link status - */ -typedef void (*emac_link_state_change_fn)(void *data, bool up); - -/** - * Return maximum transmission unit - * - * @param emac Emac interface - * @return MTU in bytes - */ -typedef uint32_t (*emac_get_mtu_size_fn)(emac_interface_t *emac); - -/** - * Return interface name - * - * @param emac Emac interface - * @param name Pointer to where the name should be written - * @param size Maximum number of character to copy - */ -typedef void (*emac_get_ifname_fn)(emac_interface_t *emac, char *name, uint8_t size); - -/** - * Returns size of the underlying interface HW address size - * - * @param emac Emac interface - * @return HW address size in bytes - */ -typedef uint8_t (*emac_get_hwaddr_size_fn)(emac_interface_t *emac); - -/** - * Return interface hw address - * - * Copies HW address to provided memory, @param addr has to be of correct size see @a get_hwaddr_size - * - * @param emac Emac interface - * @param addr HW address for underlying interface - */ -typedef void (*emac_get_hwaddr_fn)(emac_interface_t *emac, uint8_t *addr); - -/** - * Set HW address for interface - * - * Provided address has to be of correct size, see @a get_hwaddr_size - * - * @param emac Emac interface - * @param addr Address to be set - */ -typedef void (*emac_set_hwaddr_fn)(emac_interface_t *emac, uint8_t *addr); - -/** - * Sends the packet over the link - * - * That can not be called from an interrupt context. - * - * @param emac Emac interface - * @param buf Packet to be send - * @return True if the packet was send successfully, False otherwise - */ -typedef bool (*emac_link_out_fn)(emac_interface_t *emac, emac_stack_mem_t *buf); - -/** - * Initializes the HW - * - * @return True on success, False in case of an error. - */ -typedef bool (*emac_power_up_fn)(emac_interface_t *emac); - -/** - * Deinitializes the HW - * - * @param emac Emac interface - */ -typedef void (*emac_power_down_fn)(emac_interface_t *emac); - -/** - * Sets a callback that needs to be called for packets received for that interface - * - * @param emac Emac interface - * @param input_cb Function to be register as a callback - * @param data Arbitrary user data to be passed to the callback - */ -typedef void (*emac_set_link_input_cb_fn)(emac_interface_t *emac, emac_link_input_fn input_cb, void *data); - -/** - * Sets a callback that needs to be called on link status changes for given interface - * - * @param emac Emac interface - * @param state_cb Function to be register as a callback - * @param data Arbitrary user data to be passed to the callback - */ -typedef void (*emac_set_link_state_cb_fn)(emac_interface_t *emac, emac_link_state_change_fn state_cb, void *data); - -typedef struct emac_interface_ops { - emac_get_mtu_size_fn get_mtu_size; - emac_get_ifname_fn get_ifname; - emac_get_hwaddr_size_fn get_hwaddr_size; - emac_get_hwaddr_fn get_hwaddr; - emac_set_hwaddr_fn set_hwaddr; - emac_link_out_fn link_out; - emac_power_up_fn power_up; - emac_power_down_fn power_down; - emac_set_link_input_cb_fn set_link_input_cb; - emac_set_link_state_cb_fn set_link_state_cb; -} emac_interface_ops_t; - -typedef struct emac_interface { - const emac_interface_ops_t ops; - void *hw; -} emac_interface_t; - -#else - -typedef void *emac_interface_t; - -#endif /* DEVICE_EMAC */ -#endif /* MBED_EMAC_API_H */ diff --git a/targets/targets.json b/targets/targets.json index b2ee62f212a..b749ba61375 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -614,7 +614,7 @@ "macros": ["CPU_MK64FN1M0VMD12", "FSL_RTOS_MBED"], "inherits": ["Target"], "detect_code": ["0240"], - "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "STORAGE", "TRNG", "FLASH"], + "device_has": ["ANALOGIN", "ANALOGOUT", "EMAC", "I2C", "I2CSLAVE", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SERIAL_ASYNCH", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "STDIO_MESSAGES", "STORAGE", "TRNG", "FLASH"], "features": ["LWIP", "STORAGE"], "release_versions": ["2", "5"], "device_name": "MK64FN1M0xxx12", @@ -676,7 +676,7 @@ "macros": ["CPU_MK66FN2M0VMD18", "FSL_RTOS_MBED"], "inherits": ["Target"], "detect_code": ["0311"], - "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"], + "device_has": ["ANALOGIN", "ANALOGOUT", "EMAC", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"], "features": ["LWIP"], "release_versions": ["2", "5"], "device_name": "MK66FN2M0xxx18", From 61a424f37a72da2c9f0861bbd8cf4028a7a1b281 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Tue, 5 Dec 2017 12:45:30 +0200 Subject: [PATCH 02/16] Insert EMACInterface class Rather than let "EthernetInterface" be the base EMAC NetworkInterface, insert an "EMACInterface" class. EthernetInterface then derives from EMACInterface and EthInterface. A Wi-Fi driver can derive from EMACInterface and WiFiInterface - this will be more logical than deriving from EthernetInterface and WiFiInterface. This does mean adding a couple of virtual inheritances to avoid duplicate NetworkInterfaces: NetworkInterface / \ virtual / \ virtual / \ EMACInterface WiFiInterface \ / \ / \ / MyCustomWiFiInterface --- features/netsocket/EMAC.h | 2 +- ...thernetInterface.cpp => EMACInterface.cpp} | 22 +-- features/netsocket/EMACInterface.h | 131 ++++++++++++++++++ features/netsocket/EthInterface.h | 2 +- features/netsocket/EthernetInterface.h | 90 +----------- features/netsocket/WiFiInterface.h | 2 +- 6 files changed, 149 insertions(+), 100 deletions(-) rename features/netsocket/{EthernetInterface.cpp => EMACInterface.cpp} (78%) create mode 100644 features/netsocket/EMACInterface.h diff --git a/features/netsocket/EMAC.h b/features/netsocket/EMAC.h index 77d0e967387..c7ff6c0f211 100644 --- a/features/netsocket/EMAC.h +++ b/features/netsocket/EMAC.h @@ -148,7 +148,7 @@ class EMAC { /** These need to be defined by targets wishing to provide an Ethernet driver using EMAC interface. It will - * be used by the EthernetInterface class's default constructor to initialise the networking subsystem. + * be used by the EMACInterface class's default constructor to initialise the networking subsystem. */ //extern const emac_interface_ops_t mbed_emac_eth_ops_default; //extern void *mbed_emac_eth_hw_default; diff --git a/features/netsocket/EthernetInterface.cpp b/features/netsocket/EMACInterface.cpp similarity index 78% rename from features/netsocket/EthernetInterface.cpp rename to features/netsocket/EMACInterface.cpp index 931a76d5cd5..bb32833df31 100644 --- a/features/netsocket/EthernetInterface.cpp +++ b/features/netsocket/EMACInterface.cpp @@ -14,15 +14,15 @@ * limitations under the License. */ -#include "EthernetInterface.h" +#include "EMACInterface.h" /* Interface implementation */ -EthernetInterface::EthernetInterface(EMAC &emac, OnboardNetworkStack &stack) +EMACInterface::EMACInterface(EMAC &emac, OnboardNetworkStack &stack) : _emac(emac), _stack(stack), _interface(NULL), _dhcp(true), _mac_address(), _ip_address(), _netmask(), _gateway() { } -nsapi_error_t EthernetInterface::set_network(const char *ip_address, const char *netmask, const char *gateway) +nsapi_error_t EMACInterface::set_network(const char *ip_address, const char *netmask, const char *gateway) { _dhcp = false; @@ -36,13 +36,13 @@ nsapi_error_t EthernetInterface::set_network(const char *ip_address, const char return NSAPI_ERROR_OK; } -nsapi_error_t EthernetInterface::set_dhcp(bool dhcp) +nsapi_error_t EMACInterface::set_dhcp(bool dhcp) { _dhcp = dhcp; return NSAPI_ERROR_OK; } -nsapi_error_t EthernetInterface::connect() +nsapi_error_t EMACInterface::connect() { if (!_interface) { nsapi_error_t err = _stack.add_ethernet_interface(_emac, true, &_interface); @@ -59,12 +59,12 @@ nsapi_error_t EthernetInterface::connect() DEFAULT_STACK); } -nsapi_error_t EthernetInterface::disconnect() +nsapi_error_t EMACInterface::disconnect() { return _interface->bringdown(); } -const char *EthernetInterface::get_mac_address() +const char *EMACInterface::get_mac_address() { if (_interface->get_mac_address(_mac_address, sizeof(_mac_address))) { return _mac_address; @@ -72,7 +72,7 @@ const char *EthernetInterface::get_mac_address() return NULL; } -const char *EthernetInterface::get_ip_address() +const char *EMACInterface::get_ip_address() { if (_interface->get_ip_address(_ip_address, sizeof(_ip_address))) { return _ip_address; @@ -81,7 +81,7 @@ const char *EthernetInterface::get_ip_address() return NULL; } -const char *EthernetInterface::get_netmask() +const char *EMACInterface::get_netmask() { if (_interface->get_netmask(_netmask, sizeof(_netmask))) { return _netmask; @@ -90,7 +90,7 @@ const char *EthernetInterface::get_netmask() return 0; } -const char *EthernetInterface::get_gateway() +const char *EMACInterface::get_gateway() { if (_interface->get_gateway(_gateway, sizeof(_gateway))) { return _gateway; @@ -99,7 +99,7 @@ const char *EthernetInterface::get_gateway() return 0; } -NetworkStack *EthernetInterface::get_stack() +NetworkStack *EMACInterface::get_stack() { return &_stack; } diff --git a/features/netsocket/EMACInterface.h b/features/netsocket/EMACInterface.h new file mode 100644 index 00000000000..567cd31d263 --- /dev/null +++ b/features/netsocket/EMACInterface.h @@ -0,0 +1,131 @@ +/* LWIP implementation of NetworkInterfaceAPI + * Copyright (c) 2015 ARM Limited + * + * 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. + */ + +#ifndef EMAC_INTERFACE_H +#define EMAC_INTERFACE_H + +#include "nsapi.h" +#include "rtos.h" +#include "EMAC.h" +#include "OnboardNetworkStack.h" + + +/** EMACInterface class + * Implementation of the NetworkInterface for an EMAC-based driver + */ +class EMACInterface : public virtual NetworkInterface +{ +public: + /** Create an EMAC-based network interface. + * + * The default arguments obtain the default EMAC, which will be target- + * dependent (and the target may have some JSON option to choose which + * is the default, if there are multiple). The default stack is configured + * by JSON option nsapi.default-stack. + * + * Due to inability to return errors from the constructor, no real + * work is done until the first call to connect(). + * + * @param emac Reference to EMAC to use + * @param stack Reference to onboard-network stack to use + */ + EMACInterface( + EMAC &emac = EMAC::get_default_instance(), + OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance()); + + /** Set a static IP address + * + * Configures this network interface to use a static IP address. + * Implicitly disables DHCP, which can be enabled in set_dhcp. + * Requires that the network is disconnected. + * + * @param ip_address Null-terminated representation of the local IP address + * @param netmask Null-terminated representation of the local network mask + * @param gateway Null-terminated representation of the local gateway + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_network( + const char *ip_address, const char *netmask, const char *gateway); + + /** Enable or disable DHCP on the network + * + * Requires that the network is disconnected + * + * @param dhcp False to disable dhcp (defaults to enabled) + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_dhcp(bool dhcp); + + /** Start the interface + * @return 0 on success, negative on failure + */ + virtual nsapi_error_t connect(); + + /** Stop the interface + * @return 0 on success, negative on failure + */ + virtual nsapi_error_t disconnect(); + + /** Get the local MAC address + * + * Provided MAC address is intended for info or debug purposes and + * may not be provided if the underlying network interface does not + * provide a MAC address + * + * @return Null-terminated representation of the local MAC address + * or null if no MAC address is available + */ + virtual const char *get_mac_address(); + + /** Get the local IP address + * + * @return Null-terminated representation of the local IP address + * or null if no IP address has been recieved + */ + virtual const char *get_ip_address(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been recieved + */ + virtual const char *get_netmask(); + + /** Get the local gateways + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been recieved + */ + virtual const char *get_gateway(); + +protected: + /** Provide access to the underlying stack + * + * @return The underlying network stack + */ + virtual NetworkStack *get_stack(); + + EMAC &_emac; + OnboardNetworkStack &_stack; + OnboardNetworkStack::Interface *_interface; + bool _dhcp; + char _mac_address[NSAPI_MAC_SIZE]; + char _ip_address[NSAPI_IPv6_SIZE]; + char _netmask[NSAPI_IPv4_SIZE]; + char _gateway[NSAPI_IPv4_SIZE]; +}; + +#endif diff --git a/features/netsocket/EthInterface.h b/features/netsocket/EthInterface.h index 6d4ee9ad24b..b2d50a15394 100644 --- a/features/netsocket/EthInterface.h +++ b/features/netsocket/EthInterface.h @@ -27,7 +27,7 @@ * * Common interface that is shared between ethernet hardware. */ -class EthInterface : public NetworkInterface +class EthInterface : public virtual NetworkInterface { }; diff --git a/features/netsocket/EthernetInterface.h b/features/netsocket/EthernetInterface.h index c11c8d84358..d88377f4ccd 100644 --- a/features/netsocket/EthernetInterface.h +++ b/features/netsocket/EthernetInterface.h @@ -19,14 +19,13 @@ #include "nsapi.h" #include "rtos.h" -#include "EMAC.h" -#include "OnboardNetworkStack.h" +#include "EMACInterface.h" /** EthernetInterface class - * Implementation of the NetworkStack for an EMAC-based driver + * Implementation of the NetworkStack for an EMAC-based Ethernet driver */ -class EthernetInterface : public EthInterface +class EthernetInterface : public EMACInterface, public EthInterface { public: /** Create an EMAC-based ethernet interface. @@ -44,88 +43,7 @@ class EthernetInterface : public EthInterface */ EthernetInterface( EMAC &emac = EMAC::get_default_instance(), - OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance()); - - /** Set a static IP address - * - * Configures this network interface to use a static IP address. - * Implicitly disables DHCP, which can be enabled in set_dhcp. - * Requires that the network is disconnected. - * - * @param ip_address Null-terminated representation of the local IP address - * @param netmask Null-terminated representation of the local network mask - * @param gateway Null-terminated representation of the local gateway - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t set_network( - const char *ip_address, const char *netmask, const char *gateway); - - /** Enable or disable DHCP on the network - * - * Requires that the network is disconnected - * - * @param dhcp False to disable dhcp (defaults to enabled) - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t set_dhcp(bool dhcp); - - /** Start the interface - * @return 0 on success, negative on failure - */ - virtual nsapi_error_t connect(); - - /** Stop the interface - * @return 0 on success, negative on failure - */ - virtual nsapi_error_t disconnect(); - - /** Get the local MAC address - * - * Provided MAC address is intended for info or debug purposes and - * may not be provided if the underlying network interface does not - * provide a MAC address - * - * @return Null-terminated representation of the local MAC address - * or null if no MAC address is available - */ - virtual const char *get_mac_address(); - - /** Get the local IP address - * - * @return Null-terminated representation of the local IP address - * or null if no IP address has been recieved - */ - virtual const char *get_ip_address(); - - /** Get the local network mask - * - * @return Null-terminated representation of the local network mask - * or null if no network mask has been recieved - */ - virtual const char *get_netmask(); - - /** Get the local gateways - * - * @return Null-terminated representation of the local gateway - * or null if no network mask has been recieved - */ - virtual const char *get_gateway(); - -protected: - /** Provide access to the underlying stack - * - * @return The underlying network stack - */ - virtual NetworkStack *get_stack(); - - EMAC &_emac; - OnboardNetworkStack &_stack; - OnboardNetworkStack::Interface *_interface; - bool _dhcp; - char _mac_address[NSAPI_MAC_SIZE]; - char _ip_address[NSAPI_IPv6_SIZE]; - char _netmask[NSAPI_IPv4_SIZE]; - char _gateway[NSAPI_IPv4_SIZE]; + OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance()) : EMACInterface(emac, stack) { } }; #endif diff --git a/features/netsocket/WiFiInterface.h b/features/netsocket/WiFiInterface.h index 9f248495409..e4f6d1f2c66 100644 --- a/features/netsocket/WiFiInterface.h +++ b/features/netsocket/WiFiInterface.h @@ -27,7 +27,7 @@ * Common interface that is shared between WiFi devices * @addtogroup netsocket */ -class WiFiInterface: public NetworkInterface +class WiFiInterface: public virtual NetworkInterface { public: /** WiFiInterface lifetime From 3b987e245675fa76ea936123a9f9fe2ff964e0a5 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Tue, 5 Dec 2017 14:21:47 +0200 Subject: [PATCH 03/16] Remove CellularInterface This has been superceded by CellularBase. Name change occurred late in review of https://github.com/ARMmbed/mbed-os/pull/4119 and original unused CellularInterface was left behind. --- features/netsocket/CellularInterface.h | 71 ------------------- .../PPPCellularInterface.h | 6 +- features/netsocket/nsapi.h | 2 +- 3 files changed, 4 insertions(+), 75 deletions(-) delete mode 100644 features/netsocket/CellularInterface.h diff --git a/features/netsocket/CellularInterface.h b/features/netsocket/CellularInterface.h deleted file mode 100644 index 8851a2ac6c0..00000000000 --- a/features/netsocket/CellularInterface.h +++ /dev/null @@ -1,71 +0,0 @@ -/* CellularInterface - * Copyright (c) 2015 ARM Limited - * - * 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. - */ - -#ifndef CELLULAR_INTERFACE_H -#define CELLULAR_INTERFACE_H - -#include "netsocket/NetworkInterface.h" - - -/** CellularInterface class - * - * Common interface that is shared between ethernet hardware - * @addtogroup netsocket - */ -class CellularInterface : public NetworkInterface -{ -public: - /** CellularInterface lifetime - */ - virtual ~CellularInterface() {}; - - /** Set the cellular network APN and credentials - * - * @param apn Optional name of the network to connect to - * @param username Optional username for the APN - * @param password Optional password fot the APN - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t set_credentials(const char *apn, - const char *username = 0, const char *password = 0) = 0; - - /** Start the interface - * - * @param apn Optional name of the network to connect to - * @param username Optional username for your APN - * @param password Optional password for your APN - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t connect(const char *apn, - const char *username = 0, const char *password = 0) = 0; - - /** Start the interface - * - * Attempts to connect to a cellular network based on supplied credentials - * - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t connect() = 0; - - /** Stop the interface - * - * @return 0 on success, negative error code on failure - */ - virtual nsapi_error_t disconnect() = 0; -}; - - -#endif diff --git a/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.h b/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.h index 8d33ebefe08..073d86c9d9a 100644 --- a/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.h +++ b/features/netsocket/cellular/generic_modem_driver/PPPCellularInterface.h @@ -133,7 +133,7 @@ class PPPCellularInterface : public CellularBase { /** Start the interface * * Attempts to connect to a Cellular network. - * This driver is written mainly for data network connections as CellularInterface + * This driver is written mainly for data network connections as CellularBase * is NetworkInterface. That's why connect() call internally calls nwk_registration() * method with parameter PACKET_SWITCHED network. Circuit switched hook and registration * process is implemented and left in the driver for future extension/subclass support,e.g., @@ -329,8 +329,8 @@ class PPPCellularInterface : public CellularBase { /** Starts network registration process. * * Potential users could be subclasses who are not network interface - * but would like to use CellularInterface infrastructure to register - * with a cellular network, e.g., an SMS extension to CellularInterface. + * but would like to use CellularBase infrastructure to register + * with a cellular network, e.g., an SMS extension to CellularBase. * * @param nwk_type type of network to connect, defaults to packet switched network * diff --git a/features/netsocket/nsapi.h b/features/netsocket/nsapi.h index c9ed8bd6e47..21047dad737 100644 --- a/features/netsocket/nsapi.h +++ b/features/netsocket/nsapi.h @@ -33,7 +33,7 @@ #include "netsocket/NetworkInterface.h" #include "netsocket/EthInterface.h" #include "netsocket/WiFiInterface.h" -#include "netsocket/CellularInterface.h" +#include "netsocket/CellularBase.h" #include "netsocket/MeshInterface.h" #include "netsocket/Socket.h" From 4d5feaa2e16cdbebe74eae737f3642df7d08b549 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Tue, 19 Dec 2017 16:05:35 +0200 Subject: [PATCH 04/16] Add downcast methods to NetworkInterface As we've introduced virtual inheritance to support EMACInterface, we can no longer use C-style casts or static_cast to downcast from NetworkInterface to more specific types. RTTI is disabled in the toolchains, so dynamic_cast is unavailables. Add virtual downcast methods to permit conversions to the 6 derived classes. Probably only needed for EMACInterface, WiFiInterface and EthInterface, but handles the set. --- features/netsocket/CellularBase.h | 1 + features/netsocket/EMACInterface.h | 2 ++ features/netsocket/EthInterface.h | 1 + features/netsocket/MeshInterface.h | 1 + features/netsocket/NetworkInterface.h | 23 +++++++++++++++++++++-- features/netsocket/WiFiInterface.h | 2 ++ 6 files changed, 28 insertions(+), 2 deletions(-) diff --git a/features/netsocket/CellularBase.h b/features/netsocket/CellularBase.h index b1e970c62f3..705be730842 100644 --- a/features/netsocket/CellularBase.h +++ b/features/netsocket/CellularBase.h @@ -101,6 +101,7 @@ class CellularBase: public NetworkInterface { */ virtual const char *get_gateway() = 0; + virtual CellularBase *cellularBase() { return this; } }; #endif //CELLULAR_BASE_H diff --git a/features/netsocket/EMACInterface.h b/features/netsocket/EMACInterface.h index 567cd31d263..a17024363f3 100644 --- a/features/netsocket/EMACInterface.h +++ b/features/netsocket/EMACInterface.h @@ -111,6 +111,8 @@ class EMACInterface : public virtual NetworkInterface */ virtual const char *get_gateway(); + virtual EMACInterface *emacInterface() { return this; } + protected: /** Provide access to the underlying stack * diff --git a/features/netsocket/EthInterface.h b/features/netsocket/EthInterface.h index b2d50a15394..e52b52584b6 100644 --- a/features/netsocket/EthInterface.h +++ b/features/netsocket/EthInterface.h @@ -29,6 +29,7 @@ */ class EthInterface : public virtual NetworkInterface { + virtual EthInterface *ethInterface() { return this; } }; diff --git a/features/netsocket/MeshInterface.h b/features/netsocket/MeshInterface.h index dcbd54a738f..ed836ba8c77 100644 --- a/features/netsocket/MeshInterface.h +++ b/features/netsocket/MeshInterface.h @@ -29,6 +29,7 @@ */ class MeshInterface : public NetworkInterface { + virtual MeshInterface *meshInterface() { return this; } }; diff --git a/features/netsocket/NetworkInterface.h b/features/netsocket/NetworkInterface.h index e7ecb8c0ac3..edba34d8080 100644 --- a/features/netsocket/NetworkInterface.h +++ b/features/netsocket/NetworkInterface.h @@ -20,9 +20,13 @@ #include "netsocket/nsapi_types.h" #include "netsocket/SocketAddress.h" -// Predeclared class +// Predeclared classes class NetworkStack; - +class EthInterface; +class WiFiInterface; +class MeshInterface; +class CellularBase; +class EMACInterface; /** NetworkInterface class * @@ -126,6 +130,21 @@ class NetworkInterface { */ virtual nsapi_error_t add_dns_server(const SocketAddress &address); + /** Dynamic downcast to an EthInterface */ + virtual EthInterface *ethInterface() { return 0; } + + /** Dynamic downcast to a WiFiInterface */ + virtual WiFiInterface *wifiInterface() { return 0; } + + /** Dynamic downcast to a MeshInterface */ + virtual MeshInterface *meshInterface() { return 0; } + + /** Dynamic downcast to a CellularBase */ + virtual CellularBase *cellularBase() { return 0; } + + /** Dynamic downcast to an EMACInterface */ + virtual EMACInterface *emacInterface() { return 0; } + protected: friend class Socket; friend class UDPSocket; diff --git a/features/netsocket/WiFiInterface.h b/features/netsocket/WiFiInterface.h index e4f6d1f2c66..0823ce0dbc9 100644 --- a/features/netsocket/WiFiInterface.h +++ b/features/netsocket/WiFiInterface.h @@ -99,6 +99,8 @@ class WiFiInterface: public virtual NetworkInterface * negative on error see @a nsapi_error */ virtual nsapi_size_or_error_t scan(WiFiAccessPoint *res, nsapi_size_t count) = 0; + + virtual WiFiInterface *wifiInterface() { return this; } }; #endif From 195c5dd41a6871052ba266bb832b7760772f57e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=20Lepp=C3=A4nen?= Date: Mon, 8 Jan 2018 10:04:11 +0200 Subject: [PATCH 05/16] Updated greentea network interface configuration files --- tools/test_configs/EthernetInterface.json | 2 +- tools/test_configs/HeapBlockDeviceAndEthernetInterface.json | 2 +- tools/test_configs/OdinInterface.json | 2 +- tools/test_configs/Odin_EthernetInterface.json | 2 +- tools/test_configs/RealtekInterface.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/test_configs/EthernetInterface.json b/tools/test_configs/EthernetInterface.json index 69bbac0b3a5..517474721a3 100644 --- a/tools/test_configs/EthernetInterface.json +++ b/tools/test_configs/EthernetInterface.json @@ -9,7 +9,7 @@ }, "connect-statement" : { "help" : "Must use 'net' variable name", - "value" : "((EthernetInterface *)net)->connect()" + "value" : "net->connect()" }, "echo-server-addr" : { "help" : "IP address of echo server", diff --git a/tools/test_configs/HeapBlockDeviceAndEthernetInterface.json b/tools/test_configs/HeapBlockDeviceAndEthernetInterface.json index f445e780416..93b1b1ce008 100644 --- a/tools/test_configs/HeapBlockDeviceAndEthernetInterface.json +++ b/tools/test_configs/HeapBlockDeviceAndEthernetInterface.json @@ -9,7 +9,7 @@ }, "connect-statement" : { "help" : "Must use 'net' variable name", - "value" : "((EthernetInterface *)net)->connect()" + "value" : "net->connect()" }, "echo-server-addr" : { "help" : "IP address of echo server", diff --git a/tools/test_configs/OdinInterface.json b/tools/test_configs/OdinInterface.json index 00d24bc0f63..75e7931ccb3 100644 --- a/tools/test_configs/OdinInterface.json +++ b/tools/test_configs/OdinInterface.json @@ -9,7 +9,7 @@ }, "connect-statement" : { "help" : "Must use 'net' variable name", - "value" : "((OdinWiFiInterface *)net)->connect(WIFI_SSID, WIFI_PASSWORD)" + "value" : "net->wifiInterface()->connect(WIFI_SSID, WIFI_PASSWORD)" }, "echo-server-addr" : { "help" : "IP address of echo server", diff --git a/tools/test_configs/Odin_EthernetInterface.json b/tools/test_configs/Odin_EthernetInterface.json index 97f61b680ea..7eec91001db 100644 --- a/tools/test_configs/Odin_EthernetInterface.json +++ b/tools/test_configs/Odin_EthernetInterface.json @@ -9,7 +9,7 @@ }, "connect-statement" : { "help" : "Must use 'net' variable name", - "value" : "((EthernetInterface *)net)->connect()" + "value" : "net->connect()" }, "echo-server-addr" : { "help" : "IP address of echo server", diff --git a/tools/test_configs/RealtekInterface.json b/tools/test_configs/RealtekInterface.json index 2191a4bf10d..063179270ee 100644 --- a/tools/test_configs/RealtekInterface.json +++ b/tools/test_configs/RealtekInterface.json @@ -9,7 +9,7 @@ }, "connect-statement" : { "help" : "Must use 'net' variable name, replace WIFI_SSID, WIFI_PASSWORD, WIFI_SECURITY, WIFI_CHANNEL with your WiFi settings", - "value" : "((RTWInterface *)net)->connect(WIFI_SSID, WIFI_PASSWORD, WIFI_SECURITY, WIFI_CHANNEL)" + "value" : "net->wifiInterface()->connect(WIFI_SSID, WIFI_PASSWORD, WIFI_SECURITY, WIFI_CHANNEL)" }, "echo-server-addr" : { "help" : "IP address of echo server", From 1185d634679030979d7a450fb931413a3c2446c4 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Mon, 15 Jan 2018 15:48:53 +0200 Subject: [PATCH 06/16] Move Freescale EMAC driver out of lwIP --- .../arch/TARGET_Freescale/lwipopts_conf.h | 28 ------------------- .../TARGET_K64F/hardware_init_MK64F12.c | 0 .../TARGET_K66F/hardware_init_MK66F18.c | 0 .../TARGET_Freescale/k64f_emac.cpp | 0 .../TARGET_Freescale/k64f_emac.h | 0 .../TARGET_Freescale/k64f_emac_config.h | 0 6 files changed, 28 deletions(-) delete mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h rename features/{FEATURE_LWIP/lwip-interface/lwip-eth/arch => netsocket/emac-drivers}/TARGET_Freescale/TARGET_K64F/hardware_init_MK64F12.c (100%) rename features/{FEATURE_LWIP/lwip-interface/lwip-eth/arch => netsocket/emac-drivers}/TARGET_Freescale/TARGET_K66F/hardware_init_MK66F18.c (100%) rename features/{FEATURE_LWIP/lwip-interface/lwip-eth/arch => netsocket/emac-drivers}/TARGET_Freescale/k64f_emac.cpp (100%) rename features/{FEATURE_LWIP/lwip-interface/lwip-eth/arch => netsocket/emac-drivers}/TARGET_Freescale/k64f_emac.h (100%) rename features/{FEATURE_LWIP/lwip-interface/lwip-eth/arch => netsocket/emac-drivers}/TARGET_Freescale/k64f_emac_config.h (100%) diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h deleted file mode 100644 index ca0c0f78de6..00000000000 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef LWIPOPTS_CONF_H -#define LWIPOPTS_CONF_H - -#include "k64f_emac_config.h" - -#define LWIP_TRANSPORT_ETHERNET 1 - -#define MEM_SIZE (ENET_RX_RING_LEN * (ENET_ETH_MAX_FLEN + ENET_BUFF_ALIGNMENT) + ENET_TX_RING_LEN * ENET_ETH_MAX_FLEN) - -#endif diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/TARGET_K64F/hardware_init_MK64F12.c b/features/netsocket/emac-drivers/TARGET_Freescale/TARGET_K64F/hardware_init_MK64F12.c similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/TARGET_K64F/hardware_init_MK64F12.c rename to features/netsocket/emac-drivers/TARGET_Freescale/TARGET_K64F/hardware_init_MK64F12.c diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/TARGET_K66F/hardware_init_MK66F18.c b/features/netsocket/emac-drivers/TARGET_Freescale/TARGET_K66F/hardware_init_MK66F18.c similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/TARGET_K66F/hardware_init_MK66F18.c rename to features/netsocket/emac-drivers/TARGET_Freescale/TARGET_K66F/hardware_init_MK66F18.c diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.cpp b/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.cpp similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.cpp rename to features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.cpp diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.h b/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.h similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac.h rename to features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.h diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h b/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac_config.h similarity index 100% rename from features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/k64f_emac_config.h rename to features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac_config.h From ca299d0231a9da5763170670ef7c8a6de0346352 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Mon, 15 Jan 2018 16:05:07 +0200 Subject: [PATCH 07/16] Tell mbed build to ignore old lwIP+EMAC drivers --- features/FEATURE_LWIP/lwip-interface/.mbedignore | 1 + features/FEATURE_LWIP/lwip-interface/lwip-eth/README | 3 +++ features/FEATURE_LWIP/lwip-interface/lwipopts.h | 4 ---- features/FEATURE_LWIP/lwip-interface/mbed_lib.json | 6 ++++++ targets/targets.json | 4 ++-- 5 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 features/FEATURE_LWIP/lwip-interface/lwip-eth/README diff --git a/features/FEATURE_LWIP/lwip-interface/.mbedignore b/features/FEATURE_LWIP/lwip-interface/.mbedignore index e12200526f3..30bc847cb50 100644 --- a/features/FEATURE_LWIP/lwip-interface/.mbedignore +++ b/features/FEATURE_LWIP/lwip-interface/.mbedignore @@ -4,3 +4,4 @@ lwip/src/apps/* lwip/src/netif/lwip_slipif.c lwip/src/include/lwip/apps/* lwip/src/include/posix/* +lwip-eth/* diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-eth/README b/features/FEATURE_LWIP/lwip-interface/lwip-eth/README new file mode 100644 index 00000000000..4f25a4ece0f --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/lwip-eth/README @@ -0,0 +1,3 @@ +This directory contains lwIP drivers that are no longer built. Any drivers +remaining here must be convered to use the EMAC interface, and moved to +features/netsocket/emac-drivers. diff --git a/features/FEATURE_LWIP/lwip-interface/lwipopts.h b/features/FEATURE_LWIP/lwip-interface/lwipopts.h index 608cc994e78..fe8ff61b094 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwipopts.h +++ b/features/FEATURE_LWIP/lwip-interface/lwipopts.h @@ -19,10 +19,6 @@ #ifndef LWIPOPTS_H #define LWIPOPTS_H -#if MBED_CONF_LWIP_ETHERNET_ENABLED -#include "lwipopts_conf.h" -#endif - // Workaround for Linux timeval #if defined (TOOLCHAIN_GCC) #define LWIP_TIMEVAL_PRIVATE 0 diff --git a/features/FEATURE_LWIP/lwip-interface/mbed_lib.json b/features/FEATURE_LWIP/lwip-interface/mbed_lib.json index 6d9def2aa17..741bd05634f 100644 --- a/features/FEATURE_LWIP/lwip-interface/mbed_lib.json +++ b/features/FEATURE_LWIP/lwip-interface/mbed_lib.json @@ -100,6 +100,12 @@ "target_overrides": { "REALTEK_RTL8195AM": { "tcpip-thread-stacksize": 1600 + }, + "STM": { + "mem-size": 25600 + }, + "Freescale": { + "mem-size": 36560 } } } diff --git a/targets/targets.json b/targets/targets.json index b749ba61375..6779b01040e 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1982,7 +1982,7 @@ "core": "Cortex-M4F", "extra_labels_add": ["STM32F4", "STM32F439", "STM32F439ZI","STM32F439xx", "STM32F439xI"], "macros": ["MBEDTLS_CONFIG_HW_SUPPORT", "HSE_VALUE=24000000", "HSE_STARTUP_TIMEOUT=5000", "CB_INTERFACE_SDIO","CB_CHIP_WL18XX","SUPPORT_80211D_ALWAYS","WLAN_ENABLED","MBEDTLS_ARC4_C","MBEDTLS_DES_C","MBEDTLS_MD4_C","MBEDTLS_MD5_C","MBEDTLS_SHA1_C"], - "device_has_add": ["CAN", "EMAC", "TRNG", "FLASH"], + "device_has_add": ["CAN", "TRNG", "FLASH"], "device_has_remove": ["RTC", "SLEEP"], "features": ["LWIP"], "device_name": "STM32F439ZI", @@ -3666,7 +3666,7 @@ "extra_labels": ["Realtek", "AMEBA", "RTL8195A"], "macros": ["__RTL8195A__","CONFIG_PLATFORM_8195A","CONFIG_MBED_ENABLED","PLATFORM_CMSIS_RTOS"], "supported_toolchains": ["GCC_ARM", "ARM", "IAR"], - "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "TRNG", "EMAC", "FLASH"], + "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SPI", "TRNG", "FLASH"], "features": ["LWIP"], "post_binary_hook": { "function": "RTL8195ACode.binary_hook", From 41a9cec5cf4e9ffad40e875e29f3830d2bab92f4 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Tue, 16 Jan 2018 13:05:55 +0200 Subject: [PATCH 08/16] Work around Nuvoton #define EMAC --- features/netsocket/EMAC.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/features/netsocket/EMAC.h b/features/netsocket/EMAC.h index c7ff6c0f211..25f4caf7107 100644 --- a/features/netsocket/EMAC.h +++ b/features/netsocket/EMAC.h @@ -21,6 +21,9 @@ #include "Callback.h" #include "emac_stack_mem.h" +// Nuvoton platform headers define EMAC - avoid the collision +#undef EMAC + /** * This interface should be used to abstract low level access to networking hardware * All operations receive a `void *` hw pointer which an emac device provides when From 9b4c2694fd5ea6f13545ecc83a0bea370c19428b Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Fri, 26 Jan 2018 11:46:23 +0200 Subject: [PATCH 09/16] Add get_emac() to EMACInterface --- features/netsocket/EMACInterface.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/features/netsocket/EMACInterface.h b/features/netsocket/EMACInterface.h index a17024363f3..85e0830f008 100644 --- a/features/netsocket/EMACInterface.h +++ b/features/netsocket/EMACInterface.h @@ -25,6 +25,16 @@ /** EMACInterface class * Implementation of the NetworkInterface for an EMAC-based driver + * + * This class provides the necessary glue logic to create a NetworkInterface + * based on an EMAC and an OnboardNetworkStack. EthernetInterface and + * EMAC-based Wi-Fi drivers derive from it. + * + * Drivers derived from EMACInterface should be constructed so that their + * EMAC is functional without the need to call `connect()`. For example + * a Wi-Fi driver should permit `WiFi::get_emac().power_up()` as soon as + * the credentials have been set. This is necessary to support specialised + * applications such as 6LoWPAN mesh border routers. */ class EMACInterface : public virtual NetworkInterface { @@ -111,6 +121,16 @@ class EMACInterface : public virtual NetworkInterface */ virtual const char *get_gateway(); + /** Provide access to the EMAC + * + * This should be used with care - normally the network stack would + * control the EMAC, so manipulating the EMAC while the stack + * is also using it (ie after connect) will likely cause problems. + * + * @return Reference to the EMAC in use + */ + EMAC &get_emac() const { return _emac; } + virtual EMACInterface *emacInterface() { return this; } protected: From b756576270c2e9e80c6ec65781d9f9e734eb0d35 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Wed, 31 Jan 2018 11:55:43 +0200 Subject: [PATCH 10/16] Adjust test configurations for EMAC Make ETHERNET configuration the default if DEVICE_EMAC is present, instead of if FEATURE_LWIP is present. This limits it to targets which have been ported to the new EMAC API. Add LWIP feature to JSON config, as in principle the targets shouldn't be adding it themselves. Opens scope to having Nanostack-based tests. Disable tests for the Realtek and Wifi drivers that aren't ported yet. --- tools/test_configs/EthernetInterface.json | 6 ++++++ .../HeapBlockDeviceAndEthernetInterface.json | 6 ++++++ tools/test_configs/OdinInterface.json | 10 ++++++++-- tools/test_configs/Odin_EthernetInterface.json | 7 ++++--- tools/test_configs/RealtekInterface.json | 10 ++++++++-- tools/test_configs/__init__.py | 4 ++-- 6 files changed, 34 insertions(+), 9 deletions(-) diff --git a/tools/test_configs/EthernetInterface.json b/tools/test_configs/EthernetInterface.json index 517474721a3..b758c33fb07 100644 --- a/tools/test_configs/EthernetInterface.json +++ b/tools/test_configs/EthernetInterface.json @@ -23,5 +23,11 @@ "help" : "Some servers send a prefix before echoed message", "value" : "\"u-blox AG TCP/UDP test service\\n\"" } + }, + "target_overrides": { + "*": { + "target.features_add": ["LWIP"], + "nsapi.default-stack": "LWIP" + } } } diff --git a/tools/test_configs/HeapBlockDeviceAndEthernetInterface.json b/tools/test_configs/HeapBlockDeviceAndEthernetInterface.json index 93b1b1ce008..feedcae3889 100644 --- a/tools/test_configs/HeapBlockDeviceAndEthernetInterface.json +++ b/tools/test_configs/HeapBlockDeviceAndEthernetInterface.json @@ -28,5 +28,11 @@ "macro_name": "MBED_TEST_SIM_BLOCKDEVICE", "value": "HeapBlockDevice" } + }, + "target_overrides": { + "*": { + "target.features_add": ["LWIP"], + "nsapi.default-stack": "LWIP" + } } } diff --git a/tools/test_configs/OdinInterface.json b/tools/test_configs/OdinInterface.json index 75e7931ccb3..9b2358a5500 100644 --- a/tools/test_configs/OdinInterface.json +++ b/tools/test_configs/OdinInterface.json @@ -8,8 +8,8 @@ "value" : "new OdinWiFiInterface()" }, "connect-statement" : { - "help" : "Must use 'net' variable name", - "value" : "net->wifiInterface()->connect(WIFI_SSID, WIFI_PASSWORD)" + "help" : "Disabled until EMAC updated", + "value" : null }, "echo-server-addr" : { "help" : "IP address of echo server", @@ -28,5 +28,11 @@ "macro_name": "MBED_TEST_SIM_BLOCKDEVICE", "value": "HeapBlockDevice" } + }, + "target_overrides": { + "*": { + "target.features_add": ["LWIP"], + "nsapi.default-stack": "LWIP" + } } } diff --git a/tools/test_configs/Odin_EthernetInterface.json b/tools/test_configs/Odin_EthernetInterface.json index 7eec91001db..feedcae3889 100644 --- a/tools/test_configs/Odin_EthernetInterface.json +++ b/tools/test_configs/Odin_EthernetInterface.json @@ -29,9 +29,10 @@ "value": "HeapBlockDevice" } }, - "target_overrides": { - "UBLOX_EVK_ODIN_W2": { - "target.device_has_remove": ["EMAC"] + "target_overrides": { + "*": { + "target.features_add": ["LWIP"], + "nsapi.default-stack": "LWIP" } } } diff --git a/tools/test_configs/RealtekInterface.json b/tools/test_configs/RealtekInterface.json index 063179270ee..ee016d2e263 100644 --- a/tools/test_configs/RealtekInterface.json +++ b/tools/test_configs/RealtekInterface.json @@ -8,8 +8,8 @@ "value" : "new RTWInterface()" }, "connect-statement" : { - "help" : "Must use 'net' variable name, replace WIFI_SSID, WIFI_PASSWORD, WIFI_SECURITY, WIFI_CHANNEL with your WiFi settings", - "value" : "net->wifiInterface()->connect(WIFI_SSID, WIFI_PASSWORD, WIFI_SECURITY, WIFI_CHANNEL)" + "help" : "Disabled until EMAC updated", + "value" : null }, "echo-server-addr" : { "help" : "IP address of echo server", @@ -28,5 +28,11 @@ "macro_name": "MBED_TEST_SIM_BLOCKDEVICE", "value": "HeapBlockDevice" } + }, + "target_overrides": { + "*": { + "target.features_add": ["LWIP"], + "nsapi.default-stack": "LWIP" + } } } diff --git a/tools/test_configs/__init__.py b/tools/test_configs/__init__.py index 4f884465e76..e3973743390 100644 --- a/tools/test_configs/__init__.py +++ b/tools/test_configs/__init__.py @@ -11,7 +11,7 @@ def get_valid_configs(target_name): if target_name in TARGET_CONFIGS: target_config = TARGET_CONFIGS[target_name] - elif (target_name in TARGET_MAP and 'LWIP' in TARGET_MAP[target_name].features): + elif (target_name in TARGET_MAP and 'EMAC' in TARGET_MAP[target_name].device_has): target_config = { "default_test_configuration": "ETHERNET", "test_configurations": ["ETHERNET"] } else: return {} @@ -37,7 +37,7 @@ def get_default_config(source_dir, target_name): return join(CONFIG_DIR, CONFIG_MAP[config_name]) elif Config.find_app_config(source_dir): return None - elif (target_name in TARGET_MAP and 'LWIP' in TARGET_MAP[target_name].features): + elif (target_name in TARGET_MAP and 'EMAC' in TARGET_MAP[target_name].device_has): return join(CONFIG_DIR, CONFIG_MAP["ETHERNET"]) else: return None From bc0357430b443a569bfd0d24d46721b05d5701cb Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Wed, 31 Jan 2018 14:31:42 +0200 Subject: [PATCH 11/16] Restrict client and socket example tests to K64F+K66F I would like to restrict these to devices with "device_has": "EMAC", but the framework doesn't currently permit that. Revisit as more drivers are EMAC-enabled or if the framework changes. --- tools/test/examples/examples.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/test/examples/examples.json b/tools/test/examples/examples.json index af369e4b5cb..d8bf0cf4a42 100644 --- a/tools/test/examples/examples.json +++ b/tools/test/examples/examples.json @@ -39,7 +39,7 @@ ], "test-repo-source": "mbed", "features" : [], - "targets" : ["K64F", "NUCLEO_F429ZI"], + "targets" : ["K64F"], "toolchains" : ["GCC_ARM", "ARM"], "exporters": [], "compile" : true, @@ -94,7 +94,7 @@ ], "test-repo-source": "github", "features" : ["LWIP"], - "targets" : [], + "targets" : ["K64F", "K66F"], "toolchains" : [], "exporters": [], "compile" : false, @@ -108,7 +108,7 @@ ], "test-repo-source": "github", "features" : ["LWIP"], - "targets" : [], + "targets" : ["K64F", "K66F"], "toolchains" : [], "exporters": [], "compile" : true, From 0782e9f578e5732cca12d876bfd2c61e2417a2bb Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Wed, 31 Jan 2018 15:58:23 +0200 Subject: [PATCH 12/16] Disable Nanostack border router test Pending Nanostack EMAC work, disable the border router. --- tools/test/examples/examples.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/test/examples/examples.json b/tools/test/examples/examples.json index d8bf0cf4a42..b7dee477ec1 100644 --- a/tools/test/examples/examples.json +++ b/tools/test/examples/examples.json @@ -222,8 +222,8 @@ "targets" : ["K64F", "K66F", "NUCLEO_F429ZI"], "toolchains" : [], "exporters": [], - "compile" : true, - "export": true, + "compile" : false, + "export": false, "auto-update" : false }, { From f568ba6e9c21d75ea5ff770be6ef9540dafbe3e4 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Wed, 31 Jan 2018 15:59:19 +0200 Subject: [PATCH 13/16] Ignore old EMAC Wifi drivers Suppress Odin W2 and Realtek Wi-fi drivers using .mbedignore --- targets/TARGET_Realtek/TARGET_AMEBA/.mbedignore | 4 ++++ .../TARGET_MODULE_UBLOX_ODIN_W2/sdk/wifi_emac/.mbedignore | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 targets/TARGET_Realtek/TARGET_AMEBA/.mbedignore create mode 100644 targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F439xI/TARGET_MODULE_UBLOX_ODIN_W2/sdk/wifi_emac/.mbedignore diff --git a/targets/TARGET_Realtek/TARGET_AMEBA/.mbedignore b/targets/TARGET_Realtek/TARGET_AMEBA/.mbedignore new file mode 100644 index 00000000000..ad1d2bea668 --- /dev/null +++ b/targets/TARGET_Realtek/TARGET_AMEBA/.mbedignore @@ -0,0 +1,4 @@ +rtw_emac.cpp +RTWInterface.cpp +sdk/common/drivers/wlan/realtek/src/osdep/lwip_intf.c +sdk/common/api/wifi/* diff --git a/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F439xI/TARGET_MODULE_UBLOX_ODIN_W2/sdk/wifi_emac/.mbedignore b/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F439xI/TARGET_MODULE_UBLOX_ODIN_W2/sdk/wifi_emac/.mbedignore new file mode 100644 index 00000000000..ece49e4227a --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F439xI/TARGET_MODULE_UBLOX_ODIN_W2/sdk/wifi_emac/.mbedignore @@ -0,0 +1,2 @@ +wifi_emac_api.cpp +wifi_emac_api.h From b2d6d97bd9ea365738226c00cdcbeff66b49c22a Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Wed, 31 Jan 2018 17:24:30 +0200 Subject: [PATCH 14/16] Remove Ethernet from NUCLEO_F429ZI test Pending EMAC driver update, these tests won't compile. --- tools/test_configs/target_configs.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/test_configs/target_configs.json b/tools/test_configs/target_configs.json index c25c546faaf..b2c9ff9f0d3 100644 --- a/tools/test_configs/target_configs.json +++ b/tools/test_configs/target_configs.json @@ -12,7 +12,7 @@ "test_configurations": ["HEAPBLOCKDEVICE_AND_ETHERNET", "ESP8266_WIFI", "ETHERNET"] }, "NUCLEO_F429ZI": { - "default_test_configuration": "HEAPBLOCKDEVICE_AND_ETHERNET", - "test_configurations": ["HEAPBLOCKDEVICE_AND_ETHERNET"] + "default_test_configuration": "HEAPBLOCKDEVICE", + "test_configurations": ["HEAPBLOCKDEVICE"] } } From f9fc89626e3b88e084810dd2796fb25b94f3a3e4 Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Thu, 1 Feb 2018 12:59:23 +0200 Subject: [PATCH 15/16] Connectivity test: don't create interface object twice --- TESTS/netsocket/connectivity/main.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/TESTS/netsocket/connectivity/main.cpp b/TESTS/netsocket/connectivity/main.cpp index 3330d2bbc37..3645b6cc116 100644 --- a/TESTS/netsocket/connectivity/main.cpp +++ b/TESTS/netsocket/connectivity/main.cpp @@ -27,10 +27,18 @@ using namespace utest::v1; +// Avoid creating the interface twice +static NetworkInterface *get_interface() +{ + static NetworkInterface *interface = MBED_CONF_APP_OBJECT_CONSTRUCTION; + + return interface; +} + // Bringing the network up and down template void test_bring_up_down() { - NetworkInterface* net = MBED_CONF_APP_OBJECT_CONSTRUCTION; + NetworkInterface* net = get_interface(); for (int i = 0; i < COUNT; i++) { int err = MBED_CONF_APP_CONNECT_STATEMENT; From 12feecb0ff4e768e60f57f5c558e034f39566a4c Mon Sep 17 00:00:00 2001 From: Kevin Bracey Date: Mon, 5 Feb 2018 12:54:15 +0200 Subject: [PATCH 16/16] Correct lwIP connection/dhcp flags Fix "connect twice" GreenTea test --- .../FEATURE_LWIP/lwip-interface/LWIPInterface.cpp | 13 +++++-------- features/FEATURE_LWIP/lwip-interface/LWIPStack.h | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp b/features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp index c6d7d7b7e55..c9f5d973502 100644 --- a/features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp +++ b/features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp @@ -230,7 +230,7 @@ char *LWIP::Interface::get_gateway(char *buf, nsapi_size_t buflen) LWIP::Interface::Interface() : hw(NULL), has_addr_state(0), - connected(false), dhcp(false), ppp(false) + connected(false), dhcp_started(false), ppp(false) { memset(&netif, 0, sizeof netif); @@ -271,7 +271,6 @@ nsapi_error_t LWIP::add_ethernet_interface(EMAC &emac, bool default_if, OnboardN return NSAPI_ERROR_NO_MEMORY; } interface->emac = &emac; - interface->dhcp = true; interface->ppp = false; #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) @@ -328,7 +327,6 @@ nsapi_error_t LWIP::_add_ppp_interface(void *hw, bool default_if, LWIP::Interfac return NSAPI_ERROR_NO_MEMORY; } interface->hw = hw; - interface->dhcp = true; interface->ppp = true; ret = ppp_lwip_if_init(hw, &interface->netif); @@ -427,13 +425,12 @@ nsapi_error_t LWIP::Interface::bringup(bool dhcp, const char *ip, const char *ne #if LWIP_DHCP if (stack != IPV6_STACK) { // Connect to the network - dhcp = dhcp; - if (dhcp) { err_t err = dhcp_start(&netif); if (err) { return NSAPI_ERROR_DHCP_FAILURE; } + dhcp_started = true; } } #endif @@ -446,8 +443,8 @@ nsapi_error_t LWIP::Interface::bringup(bool dhcp, const char *ip, const char *ne } return NSAPI_ERROR_DHCP_FAILURE; } - connected = true; } + connected = true; #if PREF_ADDR_TIMEOUT if (stack != IPV4_STACK && stack != IPV6_STACK) { @@ -482,10 +479,10 @@ nsapi_error_t LWIP::Interface::bringdown() #if LWIP_DHCP // Disconnect from the network - if (dhcp) { + if (dhcp_started) { dhcp_release(&netif); dhcp_stop(&netif); - dhcp = false; + dhcp_started = false; } #endif diff --git a/features/FEATURE_LWIP/lwip-interface/LWIPStack.h b/features/FEATURE_LWIP/lwip-interface/LWIPStack.h index fd2b6f0c038..e746f68a925 100644 --- a/features/FEATURE_LWIP/lwip-interface/LWIPStack.h +++ b/features/FEATURE_LWIP/lwip-interface/LWIPStack.h @@ -139,7 +139,7 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable { #endif char has_addr_state; bool connected; - bool dhcp; + bool dhcp_started; bool ppp; struct netif netif; };