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; 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/.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/LWIPInterface.cpp b/features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp new file mode 100644 index 00000000000..c9f5d973502 --- /dev/null +++ b/features/FEATURE_LWIP/lwip-interface/LWIPInterface.cpp @@ -0,0 +1,532 @@ +/* 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_started(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->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->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 + if (dhcp) { + err_t err = dhcp_start(&netif); + if (err) { + return NSAPI_ERROR_DHCP_FAILURE; + } + dhcp_started = true; + } + } +#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_started) { + dhcp_release(&netif); + dhcp_stop(&netif); + dhcp_started = 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..e746f68a925 --- /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_started; + 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/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/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/lwipopts_conf.h b/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h deleted file mode 100644 index 20d961abe5a..00000000000 --- a/features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_Freescale/lwipopts_conf.h +++ /dev/null @@ -1,29 +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 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) - -#endif 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/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/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/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/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/EMAC.h b/features/netsocket/EMAC.h new file mode 100644 index 00000000000..25f4caf7107 --- /dev/null +++ b/features/netsocket/EMAC.h @@ -0,0 +1,159 @@ +/* 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" + +// 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 + * 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 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; + +#endif /* EMAC_H */ diff --git a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp b/features/netsocket/EMACInterface.cpp similarity index 52% rename from features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp rename to features/netsocket/EMACInterface.cpp index 7c69b48a4c6..bb32833df31 100644 --- a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.cpp +++ b/features/netsocket/EMACInterface.cpp @@ -14,17 +14,15 @@ * limitations under the License. */ -#include "EthernetInterface.h" -#include "lwip_stack.h" - +#include "EMACInterface.h" /* Interface implementation */ -EthernetInterface::EthernetInterface() - : _dhcp(true), _ip_address(), _netmask(), _gateway() +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; @@ -38,59 +36,70 @@ 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() { - 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, DEFAULT_STACK); } -nsapi_error_t EthernetInterface::disconnect() +nsapi_error_t EMACInterface::disconnect() { - return mbed_lwip_bringdown_2(false); + return _interface->bringdown(); } -const char *EthernetInterface::get_mac_address() +const char *EMACInterface::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() +const char *EMACInterface::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; } return NULL; } -const char *EthernetInterface::get_netmask() +const char *EMACInterface::get_netmask() { - if (mbed_lwip_get_netmask(_netmask, sizeof _netmask)) { + if (_interface->get_netmask(_netmask, sizeof(_netmask))) { return _netmask; } return 0; } -const char *EthernetInterface::get_gateway() +const char *EMACInterface::get_gateway() { - if (mbed_lwip_get_gateway(_gateway, sizeof _gateway)) { + if (_interface->get_gateway(_gateway, sizeof(_gateway))) { return _gateway; } return 0; } -NetworkStack *EthernetInterface::get_stack() +NetworkStack *EMACInterface::get_stack() { - return nsapi_create_stack(&lwip_stack); + return &_stack; } diff --git a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.h b/features/netsocket/EMACInterface.h similarity index 55% rename from features/FEATURE_LWIP/lwip-interface/EthernetInterface.h rename to features/netsocket/EMACInterface.h index f92f70e4ebf..85e0830f008 100644 --- a/features/FEATURE_LWIP/lwip-interface/EthernetInterface.h +++ b/features/netsocket/EMACInterface.h @@ -14,26 +14,47 @@ * limitations under the License. */ -#ifndef ETHERNET_INTERFACE_H -#define ETHERNET_INTERFACE_H +#ifndef EMAC_INTERFACE_H +#define EMAC_INTERFACE_H #include "nsapi.h" #include "rtos.h" -#include "lwip/netif.h" +#include "EMAC.h" +#include "OnboardNetworkStack.h" -// Forward declaration -class NetworkStack; - -/** EthernetInterface class - * Implementation of the NetworkStack for LWIP +/** 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 EthernetInterface : public EthInterface +class EMACInterface : public virtual NetworkInterface { public: - /** EthernetInterface lifetime + /** 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 */ - EthernetInterface(); + EMACInterface( + EMAC &emac = EMAC::get_default_instance(), + OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance()); /** Set a static IP address * @@ -41,10 +62,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); @@ -100,6 +121,18 @@ class EthernetInterface : public EthInterface */ 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: /** Provide access to the underlying stack * @@ -107,11 +140,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/EthInterface.h b/features/netsocket/EthInterface.h index 6d4ee9ad24b..e52b52584b6 100644 --- a/features/netsocket/EthInterface.h +++ b/features/netsocket/EthInterface.h @@ -27,8 +27,9 @@ * * Common interface that is shared between ethernet hardware. */ -class EthInterface : public NetworkInterface +class EthInterface : public virtual NetworkInterface { + virtual EthInterface *ethInterface() { return this; } }; diff --git a/features/netsocket/EthernetInterface.h b/features/netsocket/EthernetInterface.h new file mode 100644 index 00000000000..d88377f4ccd --- /dev/null +++ b/features/netsocket/EthernetInterface.h @@ -0,0 +1,49 @@ +/* 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 ETHERNET_INTERFACE_H +#define ETHERNET_INTERFACE_H + +#include "nsapi.h" +#include "rtos.h" +#include "EMACInterface.h" + + +/** EthernetInterface class + * Implementation of the NetworkStack for an EMAC-based Ethernet driver + */ +class EthernetInterface : public EMACInterface, public EthInterface +{ +public: + /** 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( + EMAC &emac = EMAC::get_default_instance(), + OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance()) : EMACInterface(emac, stack) { } +}; + +#endif 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/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/WiFiInterface.h b/features/netsocket/WiFiInterface.h index 9f248495409..0823ce0dbc9 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 @@ -99,6 +99,8 @@ class WiFiInterface: public 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 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/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/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.cpp b/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.cpp new file mode 100644 index 00000000000..0fddbd3283c --- /dev/null +++ b/features/netsocket/emac-drivers/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/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.h b/features/netsocket/emac-drivers/TARGET_Freescale/k64f_emac.h new file mode 100644 index 00000000000..67ed406759f --- /dev/null +++ b/features/netsocket/emac-drivers/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/netsocket/emac-drivers/TARGET_Freescale/k64f_emac_config.h similarity index 91% 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 index 8ec5f2ddaf3..99a4f0981de 100644 --- 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 @@ -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/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/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" 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/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 diff --git a/targets/targets.json b/targets/targets.json index b2ee62f212a..6779b01040e 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", @@ -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", diff --git a/tools/test/examples/examples.json b/tools/test/examples/examples.json index af369e4b5cb..b7dee477ec1 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, @@ -222,8 +222,8 @@ "targets" : ["K64F", "K66F", "NUCLEO_F429ZI"], "toolchains" : [], "exporters": [], - "compile" : true, - "export": true, + "compile" : false, + "export": false, "auto-update" : false }, { diff --git a/tools/test_configs/EthernetInterface.json b/tools/test_configs/EthernetInterface.json index 69bbac0b3a5..b758c33fb07 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", @@ -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 f445e780416..feedcae3889 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", @@ -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 00d24bc0f63..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" : "((OdinWiFiInterface *)net)->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 97f61b680ea..feedcae3889 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", @@ -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 2191a4bf10d..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" : "((RTWInterface *)net)->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 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"] } }