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 void mbed_lwip_netif_status_irq(struct netif *lwip_netif) { static bool any_addr = true; // Indicates that has address if (any_addr == true && mbed_lwip_get_ip_addr(true, lwip_netif)) { sys_sem_signal(&lwip_netif_has_addr); any_addr = false; return; } // Indicates that has preferred address if (mbed_lwip_get_ip_addr(false, lwip_netif)) { sys_sem_signal(&lwip_netif_has_addr); } }
void add_dns_addr(struct netif *lwip_netif) { const ip_addr_t *ip_addr = mbed_lwip_get_ip_addr(true, lwip_netif); if (ip_addr) { if (IP_IS_V6(ip_addr)) { const ip_addr_t *dns_ip_addr; bool dns_addr_exists = false; for (char numdns = 0; numdns < DNS_MAX_SERVERS; numdns++) { dns_ip_addr = dns_getserver(numdns); if (!ip_addr_isany(dns_ip_addr)) { dns_addr_exists = true; break; } } if (!dns_addr_exists) { /* 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(0, &ipv6_dns_addr); } } } }
static void mbed_lwip_netif_status_irq(struct netif *lwip_netif) { if (netif_is_up(lwip_netif)) { bool dns_addr_has_to_be_added = false; if (!(lwip_has_addr_state & HAS_ANY_ADDR) && mbed_lwip_get_ip_addr(true, lwip_netif)) { if (lwip_blocking) { sys_sem_signal(&lwip_netif_has_any_addr); } lwip_has_addr_state |= HAS_ANY_ADDR; dns_addr_has_to_be_added = true; } #if PREF_ADDR_TIMEOUT if (!(lwip_has_addr_state & HAS_PREF_ADDR) && mbed_lwip_get_ip_addr(false, lwip_netif)) { if (lwip_blocking) { sys_sem_signal(&lwip_netif_has_pref_addr); } lwip_has_addr_state |= HAS_PREF_ADDR; dns_addr_has_to_be_added = true; } #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)) { if (lwip_blocking) { sys_sem_signal(&lwip_netif_has_both_addr); } lwip_has_addr_state |= HAS_BOTH_ADDR; dns_addr_has_to_be_added = true; } #endif if (dns_addr_has_to_be_added && !lwip_blocking) { add_dns_addr(lwip_netif); } if (lwip_has_addr_state & HAS_ANY_ADDR) { lwip_connected = NSAPI_STATUS_GLOBAL_UP; } } else { lwip_connected = NSAPI_STATUS_DISCONNECTED; } if (lwip_client_callback) { lwip_client_callback(lwip_status_cb_handle, NSAPI_EVENT_CONNECTION_STATUS_CHANGE, lwip_connected); } }
/* 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 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 } }
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 return NULL; }
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; } u8_t lwip_proto = proto == NSAPI_TCP ? NETCONN_TCP : NETCONN_UDP; #if LWIP_IPV6 && LWIP_IPV4 const ip_addr_t *ip_addr; ip_addr = mbed_lwip_get_ip_addr(true, &lwip_netif); if (IP_IS_V6(ip_addr)) { // Enable IPv6 (or dual-stack). LWIP dual-stack support is // currently incomplete as of 2.0.0rc2 - eg we will only be able // to do a UDP sendto to an address matching the type selected // here. Matching "get_ip_addr" and DNS logic, use v4 if // available. lwip_proto |= NETCONN_TYPE_IPV6; } #elif LWIP_IPV6 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; }
nsapi_error_t mbed_lwip_bringup(bool dhcp, const char *ip, const char *netmask, const char *gw) { // Check if we've already connected if (lwip_connected) { return NSAPI_ERROR_PARAMETER; } if(mbed_lwip_init(NULL) != NSAPI_ERROR_OK) { return NSAPI_ERROR_DEVICE_ERROR; } // Zero out socket set mbed_lwip_arena_init(); #if LWIP_IPV6 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, MLD6_ADD_MAC_FILTER); } #endif /* LWIP_IPV6_MLD */ #if LWIP_IPV6_AUTOCONFIG /* IPv6 address autoconfiguration not enabled by default */ lwip_netif.ip6_autoconfig_enabled = 1; #endif /* LWIP_IPV6_AUTOCONFIG */ #endif u32_t ret; if (!netif_is_link_up(&lwip_netif)) { ret = sys_arch_sem_wait(&lwip_netif_linked, 15000); if (ret == SYS_ARCH_TIMEOUT) { return NSAPI_ERROR_NO_CONNECTION; } } #if LWIP_IPV4 if (!dhcp) { 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 netif_set_up(&lwip_netif); #if LWIP_IPV4 // 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)) { ret = sys_arch_sem_wait(&lwip_netif_has_addr, 15000); if (ret == SYS_ARCH_TIMEOUT) { return NSAPI_ERROR_DHCP_FAILURE; } lwip_connected = true; } #if ADDR_TIMEOUT // 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)) { ret = sys_arch_sem_wait(&lwip_netif_has_addr, ADDR_TIMEOUT * 1000); } #endif #if LWIP_IPV6 add_dns_addr(&lwip_netif); #endif return 0; }
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 == NSAPI_STATUS_GLOBAL_UP) { return NSAPI_ERROR_IS_CONNECTED; } else if (lwip_connected == NSAPI_STATUS_CONNECTING) { return NSAPI_ERROR_ALREADY; } lwip_connected = NSAPI_STATUS_CONNECTING; lwip_ppp = ppp; #if LWIP_DHCP lwip_dhcp_has_to_be_set = true; if (stack != IPV6_STACK) { lwip_dhcp = dhcp; } else { lwip_dhcp = false; } #endif 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) { lwip_connected = NSAPI_STATUS_DISCONNECTED; return ret; } if (lwip_client_callback) { lwip_client_callback(lwip_status_cb_handle, NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_CONNECTING); } 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)) { lwip_connected = NSAPI_STATUS_DISCONNECTED; if (lwip_client_callback) { lwip_client_callback(lwip_status_cb_handle, NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); } 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) { lwip_connected = NSAPI_STATUS_DISCONNECTED; if (lwip_client_callback) { lwip_client_callback(lwip_status_cb_handle, NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); } return mbed_lwip_err_remap(err); } } if (!netif_is_link_up(&lwip_netif)) { if (lwip_blocking) { if (sys_arch_sem_wait(&lwip_netif_linked, 15000) == SYS_ARCH_TIMEOUT) { if (ppp) { ppp_lwip_disconnect(); } return NSAPI_ERROR_NO_CONNECTION; } } } else { ret = mbed_set_dhcp(&lwip_netif); if (ret != NSAPI_ERROR_OK) { return ret; } } if (lwip_blocking) { // 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) { ppp_lwip_disconnect(); } return NSAPI_ERROR_DHCP_FAILURE; } } } else { return NSAPI_ERROR_OK; } #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); return NSAPI_ERROR_OK; }