Merge pull request #9387 from tymoteuszblochmobica/Sockets
Multihoming initial releasepull/9796/head
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "mbed_interface.h"
|
||||
#include "netsocket/nsapi_types.h"
|
||||
#include "cellular_driver_l3ip.h"
|
||||
|
||||
Cellular_driver_L3IP::Cellular_driver_L3IP()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool Cellular_driver_L3IP::link_out(net_stack_mem_buf_t *buf)
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Cellular_driver_L3IP::power_up()
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t Cellular_driver_L3IP::get_mtu_size() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Cellular_driver_L3IP::get_align_preference() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Cellular_driver_L3IP::get_ifname(char *name, uint8_t size) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Cellular_driver_L3IP::set_link_input_cb(l3ip_link_input_cb_t input_cb)
|
||||
{
|
||||
l3ip_link_input_cb = input_cb;
|
||||
}
|
||||
|
||||
void Cellular_driver_L3IP::set_link_state_cb(l3ip_link_state_change_cb_t state_cb)
|
||||
{
|
||||
l3ip_link_state_cb = state_cb;
|
||||
}
|
||||
|
||||
void Cellular_driver_L3IP::add_ipv4_multicast_group(const char *address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Cellular_driver_L3IP::add_ipv6_multicast_group(const char *address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Cellular_driver_L3IP::remove_ipv4_multicast_group(const char *address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Cellular_driver_L3IP::remove_ipv6_multicast_group(const char *address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Cellular_driver_L3IP::set_all_multicast(bool all)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Cellular_driver_L3IP::power_down()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Cellular_driver_L3IP::set_memory_manager(NetStackMemoryManager &mem_mngr)
|
||||
{
|
||||
memory_manager = &mem_mngr;
|
||||
}
|
||||
|
||||
|
||||
Cellular_driver_L3IP &Cellular_driver_L3IP::get_instance()
|
||||
{
|
||||
static Cellular_driver_L3IP l3ip_test_driver;
|
||||
return l3ip_test_driver;
|
||||
}
|
||||
|
||||
// Weak so a module can override
|
||||
MBED_WEAK L3IP &L3IP::get_default_instance()
|
||||
{
|
||||
return Cellular_driver_L3IP::get_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* --------------------------------- End Of File ------------------------------ */
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ARM Limited
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CELLULAR_DRIVER_L3IP_H_
|
||||
#define CELLULAR_DRIVER_L3IP_H_
|
||||
|
||||
#include "L3IP.h"
|
||||
|
||||
|
||||
class Cellular_driver_L3IP : public L3IP {
|
||||
public:
|
||||
Cellular_driver_L3IP();
|
||||
|
||||
static Cellular_driver_L3IP &get_instance();
|
||||
|
||||
/**
|
||||
* Return maximum transmission unit
|
||||
*
|
||||
* @return MTU in bytes
|
||||
*/
|
||||
virtual uint32_t get_mtu_size() const;
|
||||
|
||||
/**
|
||||
* Gets memory buffer alignment preference
|
||||
*
|
||||
* Gets preferred memory buffer alignment of the cellular device.
|
||||
* @return Memory alignment requirement in bytes
|
||||
*/
|
||||
virtual uint32_t get_align_preference() const;
|
||||
|
||||
/**
|
||||
* Return interface name
|
||||
*
|
||||
* @param name Pointer to where the name should be written
|
||||
* @param size Maximum number of characters to copy
|
||||
*/
|
||||
virtual void get_ifname(char *name, uint8_t size) const;
|
||||
|
||||
/**
|
||||
* Sends the packet over the link
|
||||
*
|
||||
* That cannot be called from an interrupt context.
|
||||
*
|
||||
* @param buf Packet to be sent
|
||||
* @return True if the packet was sent, false otherwise
|
||||
*/
|
||||
virtual bool link_out(net_stack_mem_buf_t *buf);
|
||||
|
||||
/**
|
||||
* Initializes the hardware
|
||||
*
|
||||
* @return True on success, False in case of an error.
|
||||
*/
|
||||
virtual bool power_up();
|
||||
|
||||
/**
|
||||
* Deinitializes the hardware
|
||||
*
|
||||
*/
|
||||
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(l3ip_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(l3ip_link_state_change_cb_t state_cb);
|
||||
|
||||
/** Add device to an IP4 multicast group
|
||||
*
|
||||
* @param address an IP4 multicast group address
|
||||
*/
|
||||
virtual void add_ipv4_multicast_group(const char *address);
|
||||
|
||||
/** Add device to an IP6 multicast group
|
||||
*
|
||||
* @param address an IP6 multicast group address
|
||||
*/
|
||||
virtual void add_ipv6_multicast_group(const char *address);
|
||||
|
||||
/** Remove device from an IPV4 multicast group
|
||||
*
|
||||
* @param address An IPV4 multicast group address
|
||||
*/
|
||||
virtual void remove_ipv4_multicast_group(const char *address);
|
||||
|
||||
/** Remove device from an IPV6 multicast group
|
||||
*
|
||||
* @param address An IPV6 multicast group address
|
||||
*/
|
||||
virtual void remove_ipv6_multicast_group(const char *address);
|
||||
|
||||
/** Request reception of all multicast packets
|
||||
*
|
||||
* @param all True to receive all multicasts
|
||||
* False to receive only multicasts addressed to specified groups
|
||||
*/
|
||||
virtual void set_all_multicast(bool all);
|
||||
|
||||
/** Sets memory manager that is used to handle memory buffers
|
||||
*
|
||||
* @param mem_mngr Pointer to memory manager
|
||||
*/
|
||||
virtual void set_memory_manager(NetStackMemoryManager &mem_mngr);
|
||||
|
||||
private:
|
||||
|
||||
l3ip_link_input_cb_t l3ip_link_input_cb; /**< Callback for incoming data */
|
||||
l3ip_link_state_change_cb_t l3ip_link_state_cb; /**< Link state change callback */
|
||||
NetStackMemoryManager *memory_manager; /**< Memory manager */
|
||||
|
||||
};
|
||||
|
||||
#endif /* CELLULAR_DRIVER_L3IP_H_ */
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "mbed.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity/unity.h"
|
||||
#include "utest.h"
|
||||
#include "utest/utest_stack_trace.h"
|
||||
#include "L3IPInterface.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
namespace {
|
||||
NetworkInterface *l3interface;
|
||||
}
|
||||
|
||||
void L3IP_START()
|
||||
{
|
||||
printf("MBED: L3IP_START\n");
|
||||
}
|
||||
|
||||
void L3IP_STOP()
|
||||
{
|
||||
printf("MBED: L3IP_STOP\n");
|
||||
}
|
||||
|
||||
|
||||
static void _ifup()
|
||||
{
|
||||
printf("MBED: ifdown\n");
|
||||
}
|
||||
|
||||
static void _ifdown()
|
||||
{
|
||||
printf("MBED: ifdown\n");
|
||||
}
|
||||
|
||||
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
|
||||
int fetch_stats()
|
||||
{
|
||||
return SocketStats::mbed_stats_socket_get_each(&udp_stats[0], MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Test setup
|
||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
|
||||
{
|
||||
GREENTEA_SETUP(480, "default_auto");
|
||||
_ifup();
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
void greentea_teardown(const size_t passed, const size_t failed, const failure_t failure)
|
||||
{
|
||||
_ifdown();
|
||||
return greentea_test_teardown_handler(passed, failed, failure);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("L3IP_START", L3IP_START),
|
||||
Case("L3IP_STOP", L3IP_STOP),
|
||||
};
|
||||
|
||||
Specification specification(greentea_setup, cases, greentea_teardown, greentea_continue_handlers);
|
||||
|
||||
int main()
|
||||
{
|
||||
return !Harness::run(specification);
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define WIFI 2
|
||||
#if !defined(MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE) || \
|
||||
(MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == WIFI && !defined(MBED_CONF_NSAPI_DEFAULT_WIFI_SSID))
|
||||
#error [NOT_SUPPORTED] No network configuration found for this target.
|
||||
#endif
|
||||
#ifndef MBED_CONF_APP_ECHO_SERVER_ADDR
|
||||
#error [NOT_SUPPORTED] Requires parameters from mbed_app.json
|
||||
#endif
|
||||
|
||||
#include "mbed.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity/unity.h"
|
||||
#include "utest.h"
|
||||
#include "utest/utest_stack_trace.h"
|
||||
#include "multihoming_tests.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
namespace {
|
||||
NetworkInterface *net;
|
||||
}
|
||||
|
||||
char interface_name[MBED_CONF_MULTIHOMING_MAX_INTERFACES_NUM][INTERFACE_NAME_LEN];
|
||||
int interface_num = 0;
|
||||
|
||||
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
|
||||
mbed_stats_socket_t udp_stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
|
||||
#endif
|
||||
|
||||
#if defined(MBED_CONF_APP_WIFI_SECURE_SSID) || defined(MBED_CONF_APP_WIFI_UNSECURE_SSID)
|
||||
#define SSID_MAX_LEN 32
|
||||
#define PWD_MAX_LEN 64
|
||||
|
||||
WiFiInterface *wifi;
|
||||
#endif
|
||||
|
||||
NetworkInterface *get_interface()
|
||||
{
|
||||
return net;
|
||||
}
|
||||
|
||||
static void _ifup()
|
||||
{
|
||||
|
||||
#if DEVICE_EMAC
|
||||
net = EthInterface::get_default_instance();
|
||||
nsapi_error_t err = net->connect();
|
||||
net->get_interface_name(interface_name[0]);
|
||||
interface_num++;
|
||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, err);
|
||||
printf("MBED: IP address is '%s' interface name %s\n", net->get_ip_address(), interface_name[0]);
|
||||
#endif
|
||||
#if defined(MBED_CONF_APP_WIFI_SECURE_SSID) || defined(MBED_CONF_APP_WIFI_UNSECURE_SSID)
|
||||
wifi = WiFiInterface::get_default_instance();
|
||||
|
||||
if (wifi) {
|
||||
#if defined(MBED_CONF_APP_WIFI_SECURE_SSID)
|
||||
char ssid[SSID_MAX_LEN + 1] = MBED_CONF_APP_WIFI_SECURE_SSID;
|
||||
char pwd[PWD_MAX_LEN + 1] = MBED_CONF_APP_WIFI_PASSWORD;
|
||||
nsapi_security_t security = NSAPI_SECURITY_WPA_WPA2;
|
||||
|
||||
#elif defined(MBED_CONF_APP_WIFI_UNSECURE_SSID)
|
||||
char ssid[SSID_MAX_LEN + 1] = MBED_CONF_APP_WIFI_UNSECURE_SSID;
|
||||
char pwd[PWD_MAX_LEN + 1] = NULL;
|
||||
nsapi_security_t security = NSAPI_SECURITY_NONE;
|
||||
#endif
|
||||
|
||||
printf("\nConnecting to %s...\n", ssid);
|
||||
int ret = wifi->connect(ssid, pwd, security);
|
||||
if (ret != 0) {
|
||||
TEST_FAIL_MESSAGE("Wifi connection error!");
|
||||
return;
|
||||
}
|
||||
wifi->get_interface_name(interface_name[1]);
|
||||
interface_num++;
|
||||
printf("MAC: %s\n", wifi->get_mac_address());
|
||||
printf("IP: %s\n", wifi->get_ip_address());
|
||||
printf("Netmask: %s\n", wifi->get_netmask());
|
||||
printf("Gateway: %s\n", wifi->get_gateway());
|
||||
printf("RSSI: %d\n\n", wifi->get_rssi());
|
||||
printf("Wifi interface name: %s\n\n", interface_name[1]);
|
||||
|
||||
} else {
|
||||
TEST_FAIL_MESSAGE("ERROR: No WiFiInterface found!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _ifdown()
|
||||
{
|
||||
interface_num = 0;
|
||||
net->disconnect();
|
||||
#if defined(MBED_CONF_APP_WIFI_SECURE_SSID) || defined(MBED_CONF_APP_WIFI_UNSECURE_SSID)
|
||||
wifi->disconnect();
|
||||
#endif
|
||||
printf("MBED: ifdown\n");
|
||||
}
|
||||
|
||||
void fill_tx_buffer_ascii(char *buff, size_t len)
|
||||
{
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
buff[i] = (rand() % 43) + '0';
|
||||
}
|
||||
}
|
||||
|
||||
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
|
||||
int fetch_stats()
|
||||
{
|
||||
return SocketStats::mbed_stats_socket_get_each(&udp_stats[0], MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Test setup
|
||||
utest::v1::status_t greentea_setup(const size_t number_of_cases)
|
||||
{
|
||||
GREENTEA_SETUP(480, "default_auto");
|
||||
_ifup();
|
||||
return greentea_test_setup_handler(number_of_cases);
|
||||
}
|
||||
|
||||
void greentea_teardown(const size_t passed, const size_t failed, const failure_t failure)
|
||||
{
|
||||
_ifdown();
|
||||
return greentea_test_teardown_handler(passed, failed, failure);
|
||||
}
|
||||
|
||||
Case cases[] = {
|
||||
Case("MULTIHOMING_SYNCHRONOUS_DNS", MULTIHOMING_SYNCHRONOUS_DNS),
|
||||
Case("MULTIHOMING_ASYNCHRONOUS_DNS", MULTIHOMING_ASYNCHRONOUS_DNS),
|
||||
Case("MULTIHOMING_UDPSOCKET_ECHOTEST", MULTIHOMING_UDPSOCKET_ECHOTEST),
|
||||
Case("MULTIHOMING_UDPSOCKET_ECHOTEST_NONBLOCK", MULTIHOMING_UDPSOCKET_ECHOTEST_NONBLOCK),
|
||||
};
|
||||
|
||||
Specification specification(greentea_setup, cases, greentea_teardown, greentea_continue_handlers);
|
||||
|
||||
int main()
|
||||
{
|
||||
return !Harness::run(specification);
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mbed.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity.h"
|
||||
#include "utest.h"
|
||||
#include "multihoming_tests.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
namespace {
|
||||
int result_ok;
|
||||
int result_no_mem;
|
||||
int result_dns_failure;
|
||||
int result_exp_timeout;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Callback used for asynchronous DNS result
|
||||
void hostbyname_cb(void *data, nsapi_error_t result, SocketAddress *address)
|
||||
{
|
||||
dns_application_data *app_data = static_cast<dns_application_data *>(data);
|
||||
app_data->result = result;
|
||||
if (address) {
|
||||
app_data->addr = *address;
|
||||
}
|
||||
app_data->semaphore->release();
|
||||
app_data->value_set = true;
|
||||
}
|
||||
|
||||
void MULTIHOMING_ASYNCHRONOUS_DNS()
|
||||
{
|
||||
rtos::Semaphore semaphore;
|
||||
dns_application_data data;
|
||||
data.semaphore = &semaphore;
|
||||
|
||||
|
||||
|
||||
for (unsigned int i = 0; i < MBED_CONF_APP_DNS_TEST_HOSTS_NUM; i++) {
|
||||
|
||||
for (unsigned int j = 0; j < interface_num; j++) {
|
||||
|
||||
nsapi_error_t err = get_interface()->gethostbyname_async(dns_test_hosts[i],
|
||||
mbed::Callback<void(nsapi_error_t, SocketAddress *)>(hostbyname_cb, (void *) &data), NSAPI_UNSPEC, interface_name[j]);
|
||||
TEST_ASSERT(err >= 0);
|
||||
|
||||
semaphore.wait();
|
||||
|
||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, data.result);
|
||||
printf("DNS: query interface_name %s %d \n", interface_name[j], j);
|
||||
if (data.result == NSAPI_ERROR_OK) {
|
||||
result_ok++;
|
||||
printf("DNS: query OK \"%s\" => \"%s\"\n", dns_test_hosts[i], data.addr.get_ip_address());
|
||||
} else if (data.result == NSAPI_ERROR_DNS_FAILURE) {
|
||||
result_dns_failure++;
|
||||
printf("DNS: query \"%s\" => DNS failure\n", dns_test_hosts[i]);
|
||||
} else if (data.result == NSAPI_ERROR_TIMEOUT) {
|
||||
result_exp_timeout++;
|
||||
printf("DNS: query \"%s\" => timeout\n", dns_test_hosts[i]);
|
||||
} else if (data.result == NSAPI_ERROR_NO_MEMORY) {
|
||||
result_no_mem++;
|
||||
printf("DNS: query \"%s\" => no memory\n", dns_test_hosts[i]);
|
||||
} else {
|
||||
printf("DNS: query \"%s\" => %d, unexpected answer\n", dns_test_hosts[i], data.result);
|
||||
TEST_ASSERT(data.result == NSAPI_ERROR_OK || data.result == NSAPI_ERROR_NO_MEMORY || data.result == NSAPI_ERROR_DNS_FAILURE || data.result == NSAPI_ERROR_TIMEOUT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mbed.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity.h"
|
||||
#include "utest.h"
|
||||
#include "multihoming_tests.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
int result_ok;
|
||||
int result_no_mem;
|
||||
int result_dns_failure;
|
||||
int result_exp_timeout;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MULTIHOMING_SYNCHRONOUS_DNS()
|
||||
{
|
||||
|
||||
result_ok = 0;
|
||||
result_no_mem = 0;
|
||||
result_dns_failure = 0;
|
||||
result_exp_timeout = 0;
|
||||
|
||||
for (unsigned int i = 0; i < MBED_CONF_APP_DNS_TEST_HOSTS_NUM; i++) {
|
||||
SocketAddress address;
|
||||
for (unsigned int j = 0; j < interface_num; j++) {
|
||||
|
||||
nsapi_error_t err = get_interface()->gethostbyname(dns_test_hosts[i], &address, NSAPI_UNSPEC, interface_name[j]);
|
||||
printf("DNS: query interface_name %s %d \n", interface_name[j], j);
|
||||
|
||||
if (err == NSAPI_ERROR_OK) {
|
||||
result_ok++;
|
||||
printf("DNS: query OK \"%s\" => \"%s\"\n", dns_test_hosts[i], address.get_ip_address());
|
||||
} else if (err == NSAPI_ERROR_DNS_FAILURE) {
|
||||
result_dns_failure++;
|
||||
printf("DNS: query \"%s\" => DNS failure\n", dns_test_hosts[i]);
|
||||
} else if (err == NSAPI_ERROR_TIMEOUT) {
|
||||
result_exp_timeout++;
|
||||
printf("DNS: query \"%s\" => timeout\n", dns_test_hosts[i]);
|
||||
} else if (err == NSAPI_ERROR_NO_MEMORY) {
|
||||
result_no_mem++;
|
||||
printf("DNS: query \"%s\" => no memory\n", dns_test_hosts[i]);
|
||||
} else {
|
||||
printf("DNS: query \"%s\" => %d, unexpected answer\n", dns_test_hosts[i], err);
|
||||
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_NO_MEMORY || err == NSAPI_ERROR_DNS_FAILURE || err == NSAPI_ERROR_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef MULTIHOMING_TESTS_H
|
||||
#define MULTIHOMING_TESTS_H
|
||||
|
||||
#define DNS_TEST_HOST_LEN 40
|
||||
#define INTERFACE_NAME_LEN 6
|
||||
|
||||
#ifndef MBED_CONF_MULTIHOMING_MAX_INTERFACES_NUM
|
||||
#define MBED_CONF_MULTIHOMING_MAX_INTERFACES_NUM 3
|
||||
#endif
|
||||
|
||||
#ifndef MBED_CONF_APP_DNS_TEST_HOSTS_NUM
|
||||
#define MBED_CONF_APP_DNS_TEST_HOSTS_NUM 12
|
||||
#endif
|
||||
|
||||
// Hostnames for testing against
|
||||
// Both lists must have A and AAAA records
|
||||
#ifndef MBED_CONF_APP_DNS_TEST_HOSTS
|
||||
#define MBED_CONF_APP_DNS_TEST_HOSTS {"google.com", "youtube.com", "facebook.com", "wikipedia.org", "yahoo.com", "instagram.com", "ipv6ready.org", "wireshark.org", "bbc.co.uk", "cnn.com", "www.flickr.com", "www.mozilla.org"}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
struct dns_application_data {
|
||||
rtos::Semaphore *semaphore;
|
||||
nsapi_error_t result;
|
||||
SocketAddress addr;
|
||||
nsapi_error_t req_result;
|
||||
bool value_set;
|
||||
};
|
||||
|
||||
|
||||
extern char interface_name[MBED_CONF_MULTIHOMING_MAX_INTERFACES_NUM][INTERFACE_NAME_LEN];
|
||||
extern int interface_num;
|
||||
|
||||
const char dns_test_hosts[MBED_CONF_APP_DNS_TEST_HOSTS_NUM][DNS_TEST_HOST_LEN] = MBED_CONF_APP_DNS_TEST_HOSTS;
|
||||
|
||||
|
||||
NetworkInterface *get_interface();
|
||||
void drop_bad_packets(UDPSocket &sock, int orig_timeout);
|
||||
void fill_tx_buffer_ascii(char *buff, size_t len);
|
||||
|
||||
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
|
||||
extern mbed_stats_socket_t udp_stats[MBED_CONF_NSAPI_SOCKET_STATS_MAX_COUNT];
|
||||
int fetch_stats(void);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Test cases
|
||||
*/
|
||||
void MULTIHOMING_SYNCHRONOUS_DNS();
|
||||
void MULTIHOMING_ASYNCHRONOUS_DNS();
|
||||
void MULTIHOMING_UDPSOCKET_ECHOTEST();
|
||||
void MULTIHOMING_UDPSOCKET_ECHOTEST_NONBLOCK();
|
||||
|
||||
#endif //UDP_TESTS_H
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (c) 2019, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "mbed.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity/unity.h"
|
||||
#include "utest.h"
|
||||
#include "multihoming_tests.h"
|
||||
|
||||
using namespace utest::v1;
|
||||
|
||||
namespace {
|
||||
static const int SIGNAL_SIGIO = 0x1;
|
||||
static const int SIGIO_TIMEOUT = 5000; //[ms]
|
||||
static const int WAIT2RECV_TIMEOUT = 1000; //[ms]
|
||||
static const int RETRIES = 2;
|
||||
|
||||
static const double EXPECTED_LOSS_RATIO = 0.0;
|
||||
static const double TOLERATED_LOSS_RATIO = 0.3;
|
||||
|
||||
UDPSocket sock;
|
||||
Semaphore tx_sem(0, 1);
|
||||
|
||||
static const int BUFF_SIZE = 1200;
|
||||
char rx_buffer[BUFF_SIZE] = {0};
|
||||
char tx_buffer[BUFF_SIZE] = {0};
|
||||
|
||||
static const int PKTS = 22;
|
||||
static const int pkt_sizes[PKTS] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, \
|
||||
100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, \
|
||||
1100, 1200
|
||||
};
|
||||
}
|
||||
|
||||
static void _sigio_handler(osThreadId id)
|
||||
{
|
||||
osSignalSet(id, SIGNAL_SIGIO);
|
||||
}
|
||||
|
||||
void MULTIHOMING_UDPSOCKET_ECHOTEST()
|
||||
{
|
||||
SocketAddress udp_addr;
|
||||
get_interface()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
|
||||
udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
|
||||
|
||||
UDPSocket sock;
|
||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(get_interface()));
|
||||
|
||||
for (unsigned int j = 0; j < interface_num; j++) {
|
||||
int recvd;
|
||||
int sent;
|
||||
int s_idx = 0;
|
||||
int packets_sent = 0;
|
||||
int packets_recv = 0;
|
||||
sock.setsockopt(NSAPI_SOCKET, NSAPI_BIND_TO_DEVICE, interface_name[j], INTERFACE_NAME_LEN);
|
||||
for (int pkt_s = pkt_sizes[s_idx]; s_idx < PKTS; pkt_s = ++s_idx) {
|
||||
pkt_s = pkt_sizes[s_idx];
|
||||
fill_tx_buffer_ascii(tx_buffer, BUFF_SIZE);
|
||||
for (int retry_cnt = 0; retry_cnt <= 2; retry_cnt++) {
|
||||
memset(rx_buffer, 0, BUFF_SIZE);
|
||||
sent = sock.sendto(udp_addr, tx_buffer, pkt_s);
|
||||
if (sent > 0) {
|
||||
packets_sent++;
|
||||
}
|
||||
if (sent != pkt_s) {
|
||||
printf("[Round#%02d - Sender] error, returned %d\n", s_idx, sent);
|
||||
continue;
|
||||
}
|
||||
recvd = sock.recvfrom(NULL, rx_buffer, pkt_s);
|
||||
if (recvd == pkt_s) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (memcmp(tx_buffer, rx_buffer, pkt_s) == 0) {
|
||||
packets_recv++;
|
||||
}
|
||||
}
|
||||
// Packet loss up to 30% tolerated
|
||||
if (packets_sent > 0) {
|
||||
double loss_ratio = 1 - ((double)packets_recv / (double)packets_sent);
|
||||
printf("Interface %s, packets sent: %d, packets received %d, loss ratio %.2lf\r\n", interface_name[j], packets_sent, packets_recv, loss_ratio);
|
||||
TEST_ASSERT_DOUBLE_WITHIN(TOLERATED_LOSS_RATIO, EXPECTED_LOSS_RATIO, loss_ratio);
|
||||
}
|
||||
}
|
||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
|
||||
}
|
||||
|
||||
void udpsocket_echotest_nonblock_receiver(void *receive_bytes)
|
||||
{
|
||||
int expt2recv = *(int *)receive_bytes;
|
||||
int recvd;
|
||||
for (int retry_cnt = 0; retry_cnt <= RETRIES; retry_cnt++) {
|
||||
recvd = sock.recvfrom(NULL, rx_buffer, expt2recv);
|
||||
if (recvd == NSAPI_ERROR_WOULD_BLOCK) {
|
||||
wait_ms(WAIT2RECV_TIMEOUT);
|
||||
--retry_cnt;
|
||||
continue;
|
||||
} else if (recvd == expt2recv) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tx_sem.release();
|
||||
}
|
||||
|
||||
void MULTIHOMING_UDPSOCKET_ECHOTEST_NONBLOCK()
|
||||
{
|
||||
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
|
||||
int j = 0;
|
||||
int count = fetch_stats();
|
||||
for (; j < count; j++) {
|
||||
TEST_ASSERT_EQUAL(SOCK_CLOSED, udp_stats[j].state);
|
||||
}
|
||||
#endif
|
||||
|
||||
SocketAddress udp_addr;
|
||||
get_interface()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
|
||||
udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
|
||||
|
||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(get_interface()));
|
||||
sock.set_blocking(false);
|
||||
sock.sigio(callback(_sigio_handler, ThisThread::get_id()));
|
||||
for (unsigned int j = 0; j < interface_num; j++) {
|
||||
int s_idx = 0;
|
||||
int packets_sent = 0;
|
||||
int packets_recv = 0;
|
||||
int sent;
|
||||
Thread *thread;
|
||||
unsigned char *stack_mem = (unsigned char *)malloc(OS_STACK_SIZE);
|
||||
sock.setsockopt(NSAPI_SOCKET, NSAPI_BIND_TO_DEVICE, interface_name[j], INTERFACE_NAME_LEN);
|
||||
TEST_ASSERT_NOT_NULL(stack_mem);
|
||||
|
||||
for (int pkt_s = pkt_sizes[s_idx]; s_idx < PKTS; ++s_idx) {
|
||||
pkt_s = pkt_sizes[s_idx];
|
||||
|
||||
thread = new Thread(osPriorityNormal,
|
||||
OS_STACK_SIZE,
|
||||
stack_mem,
|
||||
"receiver");
|
||||
TEST_ASSERT_EQUAL(osOK, thread->start(callback(udpsocket_echotest_nonblock_receiver, &pkt_s)));
|
||||
|
||||
for (int retry_cnt = 0; retry_cnt <= RETRIES; retry_cnt++) {
|
||||
fill_tx_buffer_ascii(tx_buffer, pkt_s);
|
||||
|
||||
sent = sock.sendto(udp_addr, tx_buffer, pkt_s);
|
||||
if (sent > 0) {
|
||||
packets_sent++;
|
||||
}
|
||||
if (sent == NSAPI_ERROR_WOULD_BLOCK) {
|
||||
if (osSignalWait(SIGNAL_SIGIO, SIGIO_TIMEOUT).status == osEventTimeout) {
|
||||
continue;
|
||||
}
|
||||
--retry_cnt;
|
||||
} else if (sent != pkt_s) {
|
||||
printf("[Round#%02d - Sender] error, returned %d\n", s_idx, sent);
|
||||
continue;
|
||||
}
|
||||
if (tx_sem.wait(WAIT2RECV_TIMEOUT * 2) == 0) { // RX might wait up to WAIT2RECV_TIMEOUT before recvfrom
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
thread->join();
|
||||
delete thread;
|
||||
if (memcmp(tx_buffer, rx_buffer, pkt_s) == 0) {
|
||||
packets_recv++;
|
||||
}
|
||||
}
|
||||
free(stack_mem);
|
||||
|
||||
// Packet loss up to 30% tolerated
|
||||
if (packets_sent > 0) {
|
||||
double loss_ratio = 1 - ((double)packets_recv / (double)packets_sent);
|
||||
printf("Interface %s, Packets sent: %d, packets received %d, loss ratio %.2lf\r\n", interface_name[j], packets_sent, packets_recv, loss_ratio);
|
||||
TEST_ASSERT_DOUBLE_WITHIN(TOLERATED_LOSS_RATIO, EXPECTED_LOSS_RATIO, loss_ratio);
|
||||
|
||||
#if MBED_CONF_NSAPI_SOCKET_STATS_ENABLE
|
||||
count = fetch_stats();
|
||||
for (j = 0; j < count; j++) {
|
||||
if ((NSAPI_UDP == udp_stats[j].proto) && (SOCK_OPEN == udp_stats[j].state)) {
|
||||
TEST_ASSERT(udp_stats[j].sent_bytes != 0);
|
||||
TEST_ASSERT(udp_stats[j].recv_bytes != 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
loss_ratio = 1 - ((double)udp_stats[j].recv_bytes / (double)udp_stats[j].sent_bytes);
|
||||
printf("Bytes sent: %d, bytes received %d, loss ratio %.2lf\r\n", udp_stats[j].sent_bytes, udp_stats[j].recv_bytes, loss_ratio);
|
||||
TEST_ASSERT_DOUBLE_WITHIN(TOLERATED_LOSS_RATIO, EXPECTED_LOSS_RATIO, loss_ratio);
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
|
||||
}
|
|
@ -128,7 +128,7 @@ TEST_F(TestNetworkInterface, gethostbyname_async)
|
|||
TEST_F(TestNetworkInterface, add_dns_server)
|
||||
{
|
||||
SocketAddress a("127.0.0.1", 1024);
|
||||
EXPECT_EQ(iface->add_dns_server(a), NSAPI_ERROR_OK);
|
||||
EXPECT_EQ(iface->add_dns_server(a, ""), NSAPI_ERROR_OK);
|
||||
}
|
||||
|
||||
TEST_F(TestNetworkInterface, get_connection_status)
|
||||
|
|
|
@ -52,12 +52,12 @@ nsapi_error_t NetworkInterface::set_dhcp(bool dhcp)
|
|||
}
|
||||
|
||||
// DNS operations go through the underlying stack by default
|
||||
nsapi_error_t NetworkInterface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
|
||||
nsapi_error_t NetworkInterface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version, const char *interface_name)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address)
|
||||
nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address, const char *interface_name)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ nsapi_error_t NetworkInterface::set_blocking(bool blocking)
|
|||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
nsapi_value_or_error_t NetworkInterface::gethostbyname_async(char const *, mbed::Callback<void (int, SocketAddress *)>, nsapi_version)
|
||||
nsapi_value_or_error_t NetworkInterface::gethostbyname_async(char const *, mbed::Callback<void (int, SocketAddress *)>, nsapi_version, const char *interface_name)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
@ -87,6 +87,15 @@ nsapi_error_t NetworkInterface::gethostbyname_async_cancel(int id)
|
|||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
void NetworkInterface::set_as_default()
|
||||
{
|
||||
}
|
||||
|
||||
char *NetworkInterface::get_interface_name(char *interface_name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NetworkInterface::~NetworkInterface()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -22,17 +22,17 @@
|
|||
#include <new>
|
||||
|
||||
// Default NetworkStack operations
|
||||
nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
|
||||
nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version, const char *interface_name)
|
||||
{
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address)
|
||||
nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address, const char *interface_name)
|
||||
{
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkStack::get_dns_server(int index, SocketAddress *address)
|
||||
nsapi_error_t NetworkStack::get_dns_server(int index, SocketAddress *address, const char *interface_name)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
@ -68,8 +68,8 @@ NetworkStack *nsapi_create_stack(NetworkStack *stack)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *host, hostbyname_cb_t callback,
|
||||
nsapi_version_t version)
|
||||
nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version,
|
||||
const char *interface_name)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
@ -93,3 +93,7 @@ const char *NetworkStack::get_ip_address()
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
const char *NetworkStack::get_ip_address_if(const char *interface_name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -38,12 +38,12 @@ public:
|
|||
return "127.0.0.1";
|
||||
}
|
||||
virtual nsapi_error_t gethostbyname(const char *host,
|
||||
SocketAddress *address, nsapi_version_t version)
|
||||
SocketAddress *address, nsapi_version_t version, const char *interface_name)
|
||||
{
|
||||
return return_value;
|
||||
}
|
||||
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback,
|
||||
nsapi_version_t version)
|
||||
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version,
|
||||
const char *interface_name)
|
||||
{
|
||||
return return_value;
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@ NetworkStack::hostbyname_cb_t query_callback;
|
|||
call_in_callback_cb_t callin_callback;
|
||||
|
||||
nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
|
||||
SocketAddress *addr, nsapi_version_t version)
|
||||
SocketAddress *addr, const char *interface_name, nsapi_version_t version)
|
||||
{
|
||||
return nsapi_stub_return_value;
|
||||
}
|
||||
|
||||
nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
|
||||
NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb,
|
||||
NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb, const char *interface_name,
|
||||
nsapi_version_t version)
|
||||
{
|
||||
query_callback = callback;
|
||||
|
@ -42,7 +42,7 @@ nsapi_error_t nsapi_dns_query_async_cancel(nsapi_error_t id)
|
|||
return nsapi_stub_return_value;
|
||||
}
|
||||
|
||||
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr)
|
||||
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr, const char *interface_name)
|
||||
{
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 9.7 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 20 KiB |
|
@ -0,0 +1,707 @@
|
|||
# Multihoming in MbedOS
|
||||
|
||||
## Table of contents
|
||||
|
||||
1. [Revision history](#revision-history).
|
||||
1. [Introduction](#introduction).
|
||||
1. [Overview and background](#overview-and-background).
|
||||
1. [Requirements and assumptions](#requirements-and-assumptions).
|
||||
1. [System architecture and high-level design](#system-architecture-and-high-level-design).
|
||||
1. [Architecture](#architecture).
|
||||
1. [Component interaction](#component-interaction).
|
||||
1. [Detailed design](#detailed-design).
|
||||
1. [MbedOS networking class diagram extension proposal](#mbedos-networking-class-diagram-extension-proposal).
|
||||
2. [Simplified LWIP and EMAC](#simplified-lwip-and-emac).
|
||||
1. [LWIPInterface changes](#lwipinterface-changes).
|
||||
1. [EMACInterface and EMAC driver](#emacinterface-and-emac-driver).
|
||||
1. [L3IPInterface and L3IP driver](#l3ipinterface-and-l3ip-driver).
|
||||
1. [Memory manager](#memory-manager).
|
||||
1. [Network default interface construction](#network-default-interface-construction).
|
||||
1. [Adding interface](#adding-interface).
|
||||
1. [Removing interface](#removing-interface).
|
||||
1. [Connecting Ethernet or Wifi](#connecting-ethernet-or-Wifi).
|
||||
1. [Disconnecting Ethernet or Wifi](#disconnecting-ethernet-or-Wifi).
|
||||
1. [Connecting Cellular](#connecting-cellular).
|
||||
1. [Disconnecting Cellular](#disconnecting-cellular).
|
||||
1. [Addressing](#addressing).
|
||||
1. [LWIP IP core](#lwip-ip-core).
|
||||
1. [EMAC based outgoing traffic for ethernet and wifi](#emac-based-outgoing-traffic-for-ethernet-and-wifi).
|
||||
1. [PPP based outgoing traffic for cellular](#ppp-based-outgoing-traffic-for-cellular).
|
||||
1. [EMAC based incoming traffic for ethernet and wifi](#emac-based-incoming-traffic-for-ethernet-and-wifi).
|
||||
1. [PPP based incoming traffic for cellular](#ppp-based-incoming-traffic-for-cellular).
|
||||
1. [IP Route changes](#IP-Route-changes).
|
||||
1. [Network stack interface](#network-stack-interface).
|
||||
1. [Sockets changes](#sockets-changes).
|
||||
1. [DNS changes](#dns-changes).
|
||||
1. [Usage scenario](#usage-scenario).
|
||||
|
||||
|
||||
## Revision history
|
||||
|
||||
| Revision | Date | Authors | Mbed OS version | Comments |
|
||||
|
||||
| 1.0 | 25 September 2018 | Tymoteusz Bloch | 5.11 | Initial revision |
|
||||
|
||||
# Introduction
|
||||
|
||||
## Overview and background
|
||||
|
||||
This document refers to mutlihoming for MbedOS ARM CortexM based embedded devices.
|
||||
Multihoming is the way of connecting device to more than one network interface. This can be done in order to increase reliability or performance.
|
||||
|
||||
Under normal operating condition embedded ip stack is connected to only one network driver. In many situations , it can be useful to connect an embedded device to multiple networks, to increase reliability (if a one network link fails, data can still be routed through the remaining networks) and to improve performance (depending on the destination, it is more efficient to route through multiple networks ).
|
||||
|
||||
## Requirements and assumptions
|
||||
To use multihoming embedded device board must be equipped with more than one network interface, driver and physical medium device. It can be a combination of ethernet, wifi, cellular modules as well as the same type multiple devices eg. two ethernet physical devices.
|
||||
|
||||
# System architecture and high-level design
|
||||
|
||||
|
||||
## Architecture
|
||||
|
||||
Mbed OS network functionality is implemented inside **features** module.
|
||||
|
||||
High level view is on picture below
|
||||
|
||||
![high_level_architecture]
|
||||
|
||||
For connectivity MbedOS uses Netsocket module. It contains :
|
||||
|
||||
- sockets
|
||||
- DNS
|
||||
- TCP/UDP
|
||||
- network interfaces
|
||||
- IP stacks
|
||||
- glue logic between IP stacks and network interfaces
|
||||
|
||||
MbedOS support following IP stacks :
|
||||
|
||||
- LWIP
|
||||
- Nanostack
|
||||
|
||||
This design refers to only LWIP multihoming support so Nanostack will be omitted.
|
||||
|
||||
## Component interaction
|
||||
|
||||
|
||||
|
||||
![components]
|
||||
|
||||
|
||||
# Detailed design
|
||||
|
||||
## MbedOS networking class diagram extension proposal
|
||||
![class_diagram]
|
||||
|
||||
## Simplified LWIP and EMAC
|
||||
|
||||
![simply_emac]
|
||||
|
||||
![simply_lwip]
|
||||
|
||||
NetworkInterface *net;
|
||||
net = NetworkInterface::get_default_instance();
|
||||
net->connect();
|
||||
|
||||
**EMACInterface::connect** will call:
|
||||
|
||||
- Stack -> add interface.
|
||||
- Stack::Interface ->bringup.
|
||||
|
||||
## LWIPInterface changes
|
||||
|
||||
LWIP and is a top class responsible for LWIP network stack implementation in Mbed OS.
|
||||
**LWIP/inner Interface** class view is shown below.
|
||||
For better readability view is simplified.
|
||||
|
||||
![lwip_class]
|
||||
|
||||
It's existing **EMAC only** version.
|
||||
|
||||
For clear view all members from **LWIP/inner Interface** are removed except **EMAC** related ones which are important from multi interface point of view.
|
||||
|
||||
![lwip_changes_old]
|
||||
|
||||
Those members are defined in **LWIPInterfaceEMAC.cpp** module.
|
||||
|
||||
To use **non EMAC** drivers for cellular new members must be add. **Lwip/Interface** after extension is shown below.
|
||||
|
||||
|
||||
![lwip_changes_new]
|
||||
|
||||
New **L3IP** related members will be defined in **LWIPInterfaceL3IP.cpp** module.
|
||||
|
||||
## EMACInterface and EMAC driver
|
||||
![EMACInterface]
|
||||
|
||||
**EMAC driver** class 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.
|
||||
|
||||
Existing **EMAC** class pure virtual definitions are shown below and must be overrided by target HW dedicated class driver derived from it.
|
||||
|
||||
![EMAC]
|
||||
|
||||
## L3IPInterface and L3IP driver
|
||||
**L3IPInterface** is new helper class dedicated to cellular connection. It based on existing
|
||||
**EMACInterface** and looks similar to it. However class methods have different implementation eg connect calls **lwip::add\_l3ip\_interface(**) to add the interface instead of **lwip::add\_ethernet\_interface**.
|
||||
Currently the existing interface does not support destruct and remove drivers.
|
||||
So **remove/destruct** functionality is proposed to implement.
|
||||
|
||||
|
||||
![L3IPInterface]
|
||||
|
||||
**L3IP** driver abstract class ia also based on **EMAC** class it also looks similar but is bound to cellular driver.
|
||||
![L3IP]
|
||||
|
||||
## Memory manager
|
||||
Currently there is memory manager dedicated to ethernet.
|
||||
It does not require changes however should be renamed from **EMACMemoryManager** to non confusing generic name like **NetStackMemoryManager**. Also memory buffer **emac\_mem\_buf\_t** should folow this change to just **net\_stack\_mem\_buf\_t**.
|
||||
|
||||
## Network default interface construction
|
||||
|
||||
|
||||
|
||||
Mbed OS support automated factories for default interface.
|
||||
|
||||
It depends on JSON configuration customized for particular target HW.
|
||||
|
||||
To instantiate it **::get\_default\_instance** must be invoked on user desired interface type.
|
||||
|
||||
The top-level NetworkInterface use the following parameter
|
||||
|
||||
|
||||
**MBED\_CONF\_TARGET\_NETWORK\_DEFAULT\_INTERFACE\_TYPE** for creating proper one :
|
||||
|
||||
- (ETHERNET ) EthInterface ::get\_default\_instance()
|
||||
- (CELLULAR ) CellularBase ::get\_default\_instance()
|
||||
- (WIFI ) WiFiInterface::get\_default\_instance()
|
||||
- (MESH ) MeshInterface::get\_default\_instance()
|
||||
|
||||
|
||||
Code for automated construction is in **NetwokInterfaceDefaults.cpp** module.
|
||||
|
||||
|
||||
|
||||
## Adding interface
|
||||
|
||||
Since automated factory suport creation only one **default interface**, others must be constructed and added to LWIP manually.
|
||||
|
||||
For **ethernet/wifi** first new interface, **EMACInterface** helper and **EMAC** driver must be instantiated. For this connection types constructors are already implemented
|
||||
|
||||
EthernetInterface(EMAC &emac = EMAC::get_default_instance(),
|
||||
OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance()) : EMACInterface(emac, stack) { }
|
||||
|
||||
or
|
||||
|
||||
OdinWiFiInterface(OdinWiFiEMAC &emac = OdinWiFiEMAC::get_instance(), OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance());
|
||||
|
||||
|
||||
For cellular the situation is a little bit different due no support any ethernet like interfaces (ethernet,wlan).
|
||||
In this case constructor looks like below and is not yet implemented. This is new code proposal for new clases L3IPInterface and L3IP.
|
||||
|
||||
|
||||
L3IPInterface(L3IP &l3ip = L3IP::get_default_instance(),OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance());
|
||||
|
||||
|
||||
Regardless of interface type LWIP must be informed about new low level interface.
|
||||
This can be done by calling **connect()** method on proper helper class( **EMACInterface** or **L3IPInterface**). Connect adds new network interface and then sets up a connection on LWIP stack with **bringup()** method.
|
||||
|
||||
First it registers a network interface with the IP stack. Connects **EMAC/L3IP** layer with the IP stack and initializes all the required infrastructure. This function should be called only once for each available interface.
|
||||
|
||||
For **ethernet/wifi** its already implemented as:
|
||||
|
||||
LWIP::add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out)
|
||||
|
||||
Cellular connection doesn't support it yet. This is new feature. Proposal is shown below
|
||||
|
||||
LWIP::add_l3ip_interface(L3IP &l3ip, bool default_if, OnboardNetworkStack::Interface **interface_out)
|
||||
|
||||
|
||||
Both methods have the same purpose but must differ in implementation due to cellular handles layer 2 differently and doesn't support any ethernet like interfaces (ethernet,wlan) and ARP.
|
||||
|
||||
|
||||
Important part of addition new network interface is configuring LWIP struct called **netif**.
|
||||
This is the core part of LWIP.
|
||||
Simplifed more readable form (removed comments and preprocesors directives) is shown below.
|
||||
|
||||
**netif** is a generic data structure used for all lwIP network interfaces.
|
||||
|
||||
struct netif {
|
||||
struct netif *next;
|
||||
ip_addr_t ip_addr;
|
||||
ip_addr_t netmask;
|
||||
ip_addr_t gw;
|
||||
ip_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];
|
||||
u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
|
||||
u32_t ip6_addr_valid_life[LWIP_IPV6_NUM_ADDRESSES];
|
||||
u32_t ip6_addr_pref_life[LWIP_IPV6_NUM_ADDRESSES];
|
||||
netif_input_fn input;
|
||||
netif_output_fn output;
|
||||
netif_linkoutput_fn linkoutput;
|
||||
netif_output_ip6_fn output_ip6;
|
||||
netif_status_callback_fn status_callback;
|
||||
netif_status_callback_fn link_callback;
|
||||
netif_status_callback_fn remove_callback;
|
||||
void *state;
|
||||
u8_t ip6_autoconfig_enabled;
|
||||
|
||||
const char* hostname;
|
||||
u16_t chksum_flags;
|
||||
u16_t mtu;
|
||||
u8_t hwaddr_len;
|
||||
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
|
||||
u8_t flags;
|
||||
char name[2];
|
||||
u8_t num;
|
||||
netif_igmp_mac_filter_fn igmp_mac_filter;
|
||||
netif_mld_mac_filter_fn mld_mac_filter;
|
||||
u8_t *addr_hint;
|
||||
u16_t loop_cnt_current;
|
||||
};
|
||||
|
||||
|
||||
Existing member **name[2]** can be used to bind **netif** to socket.
|
||||
It is get with **EMAC** class member **get_ifname** from hw driver and have unique 2 char in length name.
|
||||
|
||||
Currently following names exists:
|
||||
|
||||
"en" ethernet
|
||||
"wl" wifi
|
||||
"l6" mesh
|
||||
"lo" loopback
|
||||
"pp" ppp
|
||||
etc.
|
||||
For cellular it can be "cl"
|
||||
|
||||
Two character name string is concatenated with 8 bit value containing index which is incremented on each netif addition eg **"wl0"**.
|
||||
If no multiple interfaces of one type **"en0", "en1","en2"** ... exists, **name[2]** member is sufficient to distinguish between different interface types like** wifi, ethernet** and **cellular**.
|
||||
|
||||
This **netif** struct uses handlers passed by
|
||||
|
||||
- (emac/l3ip)_low_level_output
|
||||
- (emac/l3ip)_input
|
||||
- (emac/l3ip)_state_change
|
||||
- (emac/l3ip)_igmp_mac_filter
|
||||
- (emac/l3ip)_mld_mac_filter
|
||||
- (emac/l3ip)_if_init
|
||||
|
||||
for bounding
|
||||
|
||||
-received data from driver to LWIP input handler
|
||||
-LWIP outgoing data to driver for tramsmiting
|
||||
-status callback from device driver
|
||||
-filters settings
|
||||
|
||||
|
||||
From our point of view important function pointers are:
|
||||
|
||||
-netif_output_fn output
|
||||
-netif_linkoutput_fn linkoutput
|
||||
|
||||
From LWIP documentation we can read.
|
||||
|
||||
**"output"** is called by the IP module when it wants to send a packet on the interface. It firts resolves the hardware address, then sends the packet. For ethernet physical layer, this is usually **etharp_output()**.
|
||||
|
||||
|
||||
**"linkoutput"** is called by **ethernet_output()** when it wants to send a packet on the interface. This function outputs the pbuf as-is on the link medium.
|
||||
|
||||
|
||||
ARP in used in ethernet and wifi but for Cellular modem **output** must be bound to low level write handler. In case of cellular this is done by PPP over serial module (**PPPOS**) and currently is bound to **pppos\_netif\_output** with proper IP4/IP6 flag. This writes data to cellular modem UART based file handler. Due to different implementation of **PPPOS** **"linkoutput"** is not used for cellular.
|
||||
|
||||
To add all params to **new netif** following function must be called. This is the part of LWIP stack.
|
||||
|
||||
|
||||
struct netif * netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
|
||||
|
||||
|
||||
|
||||
## Removing interface
|
||||
|
||||
To remove interface proper method must be called
|
||||
|
||||
|
||||
LWIP::remove_L3IP_interface(OnboardNetworkStack::Interface *interface)
|
||||
|
||||
Currently the **EMACInterface** does not support remove and **EMAC** drivers do not support destruct however implementation of remove/destruct functionality is considered for EMAC interface/drivers.
|
||||
|
||||
|
||||
## Connecting Ethernet or Wifi
|
||||
|
||||
|
||||
**EMACInterface** is constructed with **EMAC** driver and (default) onboard network stack.
|
||||
|
||||
|
||||
|
||||
When **EMACInterface::connect()** is called it calls the LWIP::**add\_ethernet\_interface()** from lwip and after that lwip **bringup()** which activates the interface on lwip.
|
||||
|
||||
## Disconnecting Ethernet or Wifi
|
||||
|
||||
EMACInterface::**disconnect()** will bring the interface down.
|
||||
|
||||
## Connecting Cellular
|
||||
|
||||
|
||||
**L3IPInterface** is constructed with **L3IP** driver and (default) onboard network stack.
|
||||
|
||||
|
||||
|
||||
When **L3IPInterface::connect()** is called it will call the LWIP::**add\_l3ip\_interface()** from lwip and after that lwip **bringup()** which activates the interface on lwip as in EMACInterface.
|
||||
|
||||
## Disconnecting Cellular
|
||||
|
||||
**L3IPInterface::disconnect()** will bring the interface down.
|
||||
|
||||
Its destructor will call the LWIP::**L3IP\_remove\_interface()** and remove itself from lwip/lwip **netif*.
|
||||
|
||||
## Addressing
|
||||
|
||||
IP address can provided as **LWIP::Interface::bringup()** parameter as a static IP or DHCP. If DHCP flag is true than address is set ansynchronously as negotiation finish. Currently static address change after **LWIP::Interface::bringup()** is not used but there is proper setting member implemented for DHCP so it can be used for static IP change. This is open issue.
|
||||
|
||||
For **L3IPInterface** IPv6 unique identifier for construction link local address can be used similarly as in PPP. Both SLAAC and DHCP can be used. This is also open issue.
|
||||
|
||||
|
||||
## LWIP IP core
|
||||
|
||||
All outgoing packets regardles of TCP,UDP or RAW are procesed by
|
||||
**ip(4\6)\_output\_if\_opt\_src** in LWIP IP module.
|
||||
|
||||
|
||||
### EMAC based outgoing traffic for ethernet and wifi
|
||||
For this interface **\ip_output\_if\_opt\_src** calls **netif->output** bound for low level ARP (ethernet) and proceed **netif->linkoutput** bound for ethernet output driver function.
|
||||
|
||||
![outgoing_eth]
|
||||
|
||||
### PPP based outgoing traffic for cellular
|
||||
For cellular **\ip_output\_if\_opt\_src** calls **netif->output** bound for low level ARP (ethernet) or PPP (cellular).
|
||||
![outgoing_ppp]
|
||||
|
||||
### EMAC based incoming traffic for ethernet and wifi
|
||||
![incoming_emac]
|
||||
|
||||
### PPP based incoming traffic for cellular
|
||||
![incoming_ppp]
|
||||
|
||||
|
||||
### IP Route changes
|
||||
This LWIP IP netif selection must be extended for routing to a specific **netif** instead **default one**.
|
||||
|
||||
|
||||
Original **ip4\_route** finds the appropriate network interface for a given IP address.
|
||||
It searches the list of network interfaces linearly. A match is found
|
||||
if the masked IP address of the network interface equals the masked
|
||||
IP address given to the function.
|
||||
|
||||
Passed param dest is the destination IP address for which to find the route
|
||||
New paremeter **interface\_name** will be add to origin **ip4\_route** for improved selection of desired **netif**.
|
||||
|
||||
Function returns the proper **netif** responsible for sending data to reach dest
|
||||
|
||||
struct netif * ip4_route(const ip4_addr_t *dest)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
#if LWIP_MULTICAST_TX_OPTIONS
|
||||
/* Use administratively selected interface for multicast by default */
|
||||
if (ip4_addr_ismulticast(dest) && ip4_default_multicast_netif) {
|
||||
return ip4_default_multicast_netif;
|
||||
}
|
||||
#endif /* LWIP_MULTICAST_TX_OPTIONS */
|
||||
|
||||
/* iterate through netifs */
|
||||
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
/* is the netif up, does it have a link and a valid address? */
|
||||
if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) {
|
||||
/* network mask matches? */
|
||||
if (ip4_addr_netcmp(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) {
|
||||
/* return netif on which to forward IP packet */
|
||||
return netif;
|
||||
}
|
||||
/* gateway matches on a non broadcast interface? (i.e. peer in a point to point interface) */
|
||||
if (((netif->flags & NETIF_FLAG_BROADCAST) == 0) && ip4_addr_cmp(dest, netif_ip4_gw(netif))) {
|
||||
/* return netif on which to forward IP packet */
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF
|
||||
/* loopif is disabled, looopback traffic is passed through any netif */
|
||||
if (ip4_addr_isloopback(dest)) {
|
||||
/* don't check for link on loopback traffic */
|
||||
if (netif_default != NULL && netif_is_up(netif_default)) {
|
||||
return netif_default;
|
||||
}
|
||||
/* default netif is not up, just use any netif for loopback traffic */
|
||||
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (netif_is_up(netif)) {
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */
|
||||
|
||||
#ifdef LWIP_HOOK_IP4_ROUTE_SRC
|
||||
netif = LWIP_HOOK_IP4_ROUTE_SRC(dest, NULL);
|
||||
if (netif != NULL) {
|
||||
return netif;
|
||||
}
|
||||
#elif defined(LWIP_HOOK_IP4_ROUTE)
|
||||
netif = LWIP_HOOK_IP4_ROUTE(dest);
|
||||
if (netif != NULL) {
|
||||
return netif;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) ||
|
||||
ip4_addr_isany_val(*netif_ip4_addr(netif_default))) {
|
||||
/* No matching netif found and default netif is not usable.
|
||||
If this is not good enough for you, use LWIP_HOOK_IP4_ROUTE() */
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
|
||||
IP_STATS_INC(ip.rterr);
|
||||
MIB2_STATS_INC(mib2.ipoutnoroutes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return netif_default;
|
||||
}
|
||||
|
||||
|
||||
## Network stack interface
|
||||
|
||||
For multiple **netif's** there is need to get DNS and IP addresses for an **interface\_name**
|
||||
|
||||
Currently LWIP class members has no such parameter
|
||||
|
||||
get_ip_address()
|
||||
get_dns_server(int index, SocketAddress *address)
|
||||
|
||||
Also there is only pointer to one **netif**.
|
||||
|
||||
const struct netif *netif
|
||||
|
||||
So single netif should be replaced with array of netif pointers and members above must support to get IP and DNS from proper netif instance.
|
||||
Therefore new parameter "interface_name" should be added to **get\_dns\_server** and new member **get\_ip\_address\_if** must be implemented to the **NetworkInterface** class.
|
||||
|
||||
|
||||
get_ip_address_if(const char *interface_name)
|
||||
get_dns_server(int index, SocketAddress *address, const char *interface_name)
|
||||
|
||||
From multihoming point of view it is desirable to get interface name and select any interface to default one at runtime. Therefore following new members need to be implemented
|
||||
|
||||
get_interface_name(char *interface_name)
|
||||
set_as_default()
|
||||
|
||||
Netif **interface\_name** should be added also to
|
||||
|
||||
dns_setserver(u8_t numdns, const ip_addr_t *dnsserver,const char *interface_name);
|
||||
|
||||
|
||||
|
||||
# Sockets changes
|
||||
|
||||
For multihoming its needed to bind socket to desired network interface. To perform this new socket option must be add for socket class.
|
||||
|
||||
Member for LWIP stack specific socket option settings already exist in LWIP class.
|
||||
New option for socket binding to netif must be implemented inside:
|
||||
|
||||
|
||||
nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, const void *optval, unsigned optlen)
|
||||
|
||||
|
||||
New socket option enum **NSAPI\_BIND\_NETIF** must be added.
|
||||
|
||||
Socket options after changes.
|
||||
|
||||
typedef enum nsapi_socket_option {
|
||||
NSAPI_REUSEADDR, /*!< Allow bind to reuse local addresses */
|
||||
NSAPI_KEEPALIVE, /*!< Enables sending of keepalive messages */
|
||||
NSAPI_KEEPIDLE, /*!< Sets timeout value to initiate keepalive */
|
||||
NSAPI_KEEPINTVL, /*!< Sets timeout value for keepalive */
|
||||
NSAPI_LINGER, /*!< Keeps close from returning until queues empty */
|
||||
NSAPI_SNDBUF, /*!< Sets send buffer size */
|
||||
NSAPI_RCVBUF, /*!< Sets recv buffer size */
|
||||
NSAPI_ADD_MEMBERSHIP, /*!< Add membership to multicast address */
|
||||
NSAPI_DROP_MEMBERSHIP, /*!< Drop membership to multicast address */
|
||||
NSAPI_BIND_NETIF, /*!< Biid nefit to socket */
|
||||
} nsapi_socket_option_t;
|
||||
|
||||
LWIP specific socket is shown below
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
New binding option should be placed into **netconn** struct.
|
||||
Descriptor for **netconn** is shown below.
|
||||
|
||||
|
||||
struct netconn {
|
||||
enum netconn_type type;
|
||||
enum netconn_state state;
|
||||
union {
|
||||
struct ip_pcb *ip;
|
||||
struct tcp_pcb *tcp;
|
||||
struct udp_pcb *udp;
|
||||
struct raw_pcb *raw;
|
||||
} pcb;
|
||||
err_t last_err;
|
||||
sys_sem_t op_completed;
|
||||
sys_mbox_t recvmbox;
|
||||
sys_mbox_t acceptmbox;
|
||||
int socket;
|
||||
s32_t send_timeout;
|
||||
int recv_timeout;
|
||||
int recv_bufsize;
|
||||
int recv_avail;
|
||||
s16_t linger;
|
||||
u8_t flags;
|
||||
size_t write_offset;
|
||||
struct api_msg *current_msg;
|
||||
netconn_callback callback;
|
||||
};
|
||||
|
||||
|
||||
|
||||
LWIP selects the proper netif on IP layer using **ip\_route**.
|
||||
|
||||
Currently it uses only ip adress as input parameter so choice is based on ip adress only. To extend choice ctiteria also to interface index **ip\_route** must be modified and must take desired **interface\_name** as second argument.
|
||||
Therefore new member with information about **netif interface\_name** bound to current socket should be placed in the common part of all PCB types.
|
||||
|
||||
|
||||
|
||||
#define IP_PCB \
|
||||
ip_addr_t local_ip; \
|
||||
ip_addr_t remote_ip; \
|
||||
u8_t so_options; \
|
||||
u8_t tos; \
|
||||
u8_t ttl \
|
||||
IP_PCB_ADDRHINT \
|
||||
const char* interface_name -new member
|
||||
|
||||
New member **char* interface\_name** should be add for binding socket to netif.
|
||||
|
||||
|
||||
## DNS changes
|
||||
|
||||
Currently in Nsapi_dns module there is only one array for 5 DNS server adresses.
|
||||
|
||||
static nsapi_addr_t dns_servers[DNS_SERVERS_SIZE] = {
|
||||
{NSAPI_IPv4, {8, 8, 8, 8}}, // Google
|
||||
{NSAPI_IPv4, {209, 244, 0, 3}}, // Level 3
|
||||
{NSAPI_IPv4, {84, 200, 69, 80}}, // DNS.WATCH
|
||||
{NSAPI_IPv6, {0x20,0x01, 0x48,0x60, 0x48,0x60, 0,0, // Google
|
||||
0,0, 0,0, 0,0, 0x88,0x88}},
|
||||
{NSAPI_IPv6, {0x20,0x01, 0x16,0x08, 0,0x10, 0,0x25, // DNS.WATCH
|
||||
0,0, 0,0, 0x1c,0x04, 0xb1,0x2f}},
|
||||
};
|
||||
It would be desirable to add storage for interface specific DNS server addresses.
|
||||
|
||||
It can be done as below.
|
||||
|
||||
static nsapi_addr_t dns_servers[NETIF_INDEX][DNS_SERVERS_SIZE]
|
||||
|
||||
Add interface name as option to DNS query
|
||||
|
||||
To resolve IP adress Netsocket module uses following functions
|
||||
|
||||
gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
|
||||
nsapi_dns_query(NetworkStack *stack, const char *host, SocketAddress *address, nsapi_version_t version)
|
||||
|
||||
Query above uses only single dns_servers array described before. So it is also desired to add interface_name.
|
||||
|
||||
gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
|
||||
nsapi_dns_query(NetworkStack *stack, const char *host, SocketAddress *address, nsapi_version_t version)
|
||||
|
||||
|
||||
Second one **nsapi\_dns\_query** finally calls **get\_dns\_server** descirbed before. It has new parameter **interface\_name** for proper **netif** selecting. So it would be logical to add also **interface\_name** also to:
|
||||
|
||||
|
||||
DNS::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version,const char* interface_name)
|
||||
nsapi_dns_query(NetworkStack *stack, const char *host, SocketAddress *address, nsapi_version_t version, const char* interface_name)
|
||||
|
||||
|
||||
|
||||
If async DNS query is used therefore UDP socket created for this purpose must be assigned for proper interface.
|
||||
|
||||
To perform this following UDPSocket base class member
|
||||
|
||||
InternetSocket::setsockopt(int level, int optname, const void *optval, unsigned optlen)
|
||||
|
||||
is used with parameters:
|
||||
|
||||
- optname NSAPI_BIND_NETIF
|
||||
- optval netif name
|
||||
|
||||
It finally calls stack specific implementation for socket option setting.
|
||||
|
||||
|
||||
# Usage scenario
|
||||
|
||||
|
||||
Currently Mbed OS can construct only one **default** interface.
|
||||
|
||||
Its type depends on configuration file and **MBED\_CONF\_TARGET_NETWORK\_DEFAULT\_INTERFACE\_TYPE** value.
|
||||
|
||||
Example of default network init code is shown below
|
||||
|
||||
NetworkInterface *net;
|
||||
net = NetworkInterface::get_default_instance();
|
||||
net->connect();
|
||||
|
||||
If it's set to ETHERNET following code constructs **EthInterface** for ethernet EMAC.
|
||||
|
||||
If is set to WIFI **WiFiInterface** instance is constructed.
|
||||
|
||||
Similarly if type is CELLULAR **EasyCellularConnection** instance is created.
|
||||
|
||||
Second or third interface can be added manually
|
||||
|
||||
NetworkInterface *wifi_net;
|
||||
wifi_net = WiFiInterface::get_target_default_instance();
|
||||
wifi_net->connect();
|
||||
|
||||
or
|
||||
|
||||
NetworkInterface *cellular_net;
|
||||
cellular_net = EasyCellularConnection::get_target_default_instance();
|
||||
cellular_net->connect();
|
||||
|
||||
To construct network instance both Ethernet and WiFi uses EMAC and EMACInterface internally.
|
||||
|
||||
IP layer 3 interface can be created following way:
|
||||
|
||||
NetworkInterface *l3interface;
|
||||
l3interface =new L3IPInterface(L3IP::get_default_instance(), OnboardNetworkStack::get_default_instance());
|
||||
l3interface->connect();
|
||||
|
||||
[high_level_architecture]: hi_level.png
|
||||
[components]: components.png
|
||||
[class_diagram]:class_diagram.png
|
||||
[lwip_class]: lwip_class.png
|
||||
[lwip_changes_old]:lwip_changes_old.png
|
||||
[lwip_changes_new]:lwip_changes_new.png
|
||||
[EMACInterface]:EMACInterface.png
|
||||
[EMAC]:EMAC.png
|
||||
[L3IPInterface]:L3IPInterface.png
|
||||
[L3IP]:L3IP.png
|
||||
[outgoing_eth]:outgoing_eth.png
|
||||
[outgoing_ppp]:outgoing_ppp.png
|
||||
[incoming_emac]:incoming_emac.png
|
||||
[incoming_ppp]:incoming_ppp.png
|
||||
[simply_emac]:EmacInterface_simple.png
|
||||
[simply_lwip]:lwip_simply.png
|
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 26 KiB |
|
@ -468,7 +468,7 @@ const char *UBLOX_AT_CellularStack::get_ip_address()
|
|||
return _ip;
|
||||
}
|
||||
|
||||
nsapi_error_t UBLOX_AT_CellularStack::gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version)
|
||||
nsapi_error_t UBLOX_AT_CellularStack::gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version, const char *interface_name)
|
||||
{
|
||||
char ipAddress[NSAPI_IP_SIZE];
|
||||
nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION;
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
virtual const char *get_ip_address();
|
||||
|
||||
virtual nsapi_error_t gethostbyname(const char *host,
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC);
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC, const char *interface_name = NULL);
|
||||
|
||||
protected:
|
||||
virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog);
|
||||
|
|
|
@ -53,7 +53,7 @@ LWIP::Interface *LWIP::Interface::our_if_from_netif(struct netif *netif)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void add_dns_addr_to_dns_list_index(const u8_t addr_type, const u8_t index)
|
||||
static void add_dns_addr_to_dns_list_index(const u8_t addr_type, const u8_t index, struct netif *netif)
|
||||
{
|
||||
#if LWIP_IPV6
|
||||
if (addr_type == IPADDR_TYPE_V6) {
|
||||
|
@ -63,14 +63,14 @@ static void add_dns_addr_to_dns_list_index(const u8_t addr_type, const u8_t inde
|
|||
PP_HTONL(0x48600000UL),
|
||||
PP_HTONL(0x00000000UL),
|
||||
PP_HTONL(0x00008888UL));
|
||||
dns_setserver(index, &ipv6_dns_addr);
|
||||
dns_setserver(index, &ipv6_dns_addr, netif);
|
||||
}
|
||||
#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);
|
||||
dns_setserver(index, &ipv4_dns_addr, netif);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -92,11 +92,16 @@ static int get_ip_addr_type(const ip_addr_t *ip_addr)
|
|||
#endif
|
||||
}
|
||||
|
||||
void LWIP::add_dns_addr(struct netif *lwip_netif)
|
||||
void LWIP::add_dns_addr(struct netif *lwip_netif, const char *interface_name)
|
||||
{
|
||||
|
||||
if (!netif_check_default(lwip_netif)) {
|
||||
interface_name = NULL;
|
||||
}
|
||||
|
||||
// Check for existing dns address
|
||||
for (char numdns = 0; numdns < DNS_MAX_SERVERS; numdns++) {
|
||||
const ip_addr_t *dns_ip_addr = dns_getserver(numdns);
|
||||
const ip_addr_t *dns_ip_addr = dns_getserver(numdns, interface_name);
|
||||
if (!ip_addr_isany(dns_ip_addr)) {
|
||||
return;
|
||||
}
|
||||
|
@ -109,7 +114,7 @@ void LWIP::add_dns_addr(struct netif *lwip_netif)
|
|||
// 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);
|
||||
add_dns_addr_to_dns_list_index(addr_type, 0, lwip_netif);
|
||||
}
|
||||
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
|
@ -121,7 +126,7 @@ void LWIP::add_dns_addr(struct netif *lwip_netif)
|
|||
}
|
||||
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);
|
||||
add_dns_addr_to_dns_list_index(addr_type, 0, lwip_netif);
|
||||
}
|
||||
|
||||
if (addr_type == IPADDR_TYPE_V4) {
|
||||
|
@ -136,7 +141,7 @@ void LWIP::add_dns_addr(struct netif *lwip_netif)
|
|||
|
||||
if (ip_addr) {
|
||||
addr_type = get_ip_addr_type(ip_addr);
|
||||
add_dns_addr_to_dns_list_index(addr_type, 1);
|
||||
add_dns_addr_to_dns_list_index(addr_type, 1, lwip_netif);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -224,7 +229,7 @@ void LWIP::Interface::netif_status_irq(struct netif *netif)
|
|||
}
|
||||
#endif
|
||||
if (dns_addr_has_to_be_added && !interface->blocking) {
|
||||
add_dns_addr(&interface->netif);
|
||||
add_dns_addr(&interface->netif, interface->get_interface_name(interface->_interface_name));
|
||||
}
|
||||
|
||||
if (interface->has_addr_state & HAS_ANY_ADDR) {
|
||||
|
@ -267,6 +272,12 @@ char *LWIP::Interface::get_mac_address(char *buf, nsapi_size_t buflen)
|
|||
return buf;
|
||||
}
|
||||
|
||||
char *LWIP::Interface::get_interface_name(char *buf)
|
||||
{
|
||||
sprintf(buf, "%c%c%d", netif.name[0], netif.name[1], netif.num);
|
||||
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);
|
||||
|
@ -288,6 +299,33 @@ char *LWIP::Interface::get_ip_address(char *buf, nsapi_size_t buflen)
|
|||
#endif
|
||||
}
|
||||
|
||||
char *LWIP::Interface::get_ip_address_if(char *buf, nsapi_size_t buflen, const char *interface_name)
|
||||
{
|
||||
const ip_addr_t *addr;
|
||||
|
||||
if (interface_name == NULL) {
|
||||
addr = LWIP::get_ip_addr(true, &netif);
|
||||
} else {
|
||||
addr = LWIP::get_ip_addr(true, netif_find(interface_name));
|
||||
}
|
||||
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
|
||||
|
@ -429,7 +467,7 @@ nsapi_error_t LWIP::add_l3ip_interface(L3IP &l3ip, bool default_if, OnboardNetwo
|
|||
#if LWIP_IPV4
|
||||
0, 0, 0,
|
||||
#endif
|
||||
interface, &LWIP::Interface::emac_if_init, ip_input)) {
|
||||
interface, &LWIP::Interface::l3ip_if_init, ip_input)) {
|
||||
return NSAPI_ERROR_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -457,6 +495,31 @@ nsapi_error_t LWIP::add_l3ip_interface(L3IP &l3ip, bool default_if, OnboardNetwo
|
|||
nsapi_error_t LWIP::remove_l3ip_interface(OnboardNetworkStack::Interface **interface_out)
|
||||
{
|
||||
#if LWIP_L3IP
|
||||
if ((interface_out != NULL) && (*interface_out != NULL)) {
|
||||
|
||||
Interface *lwip = static_cast<Interface *>(*interface_out);
|
||||
Interface *node = lwip->list;
|
||||
|
||||
if (lwip->list != NULL) {
|
||||
if (lwip->list == lwip) {
|
||||
lwip->list = lwip->list->next;
|
||||
netif_remove(&node->netif);
|
||||
delete node;
|
||||
} else {
|
||||
while (node->next != NULL && node->next != lwip) {
|
||||
node = node->next;
|
||||
}
|
||||
if (node->next != NULL && node->next == lwip) {
|
||||
Interface *remove = node->next;
|
||||
node->next = node->next->next;
|
||||
remove->l3ip->power_down();
|
||||
netif_remove(&remove->netif);
|
||||
delete remove;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
#else
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
|
@ -495,7 +558,13 @@ nsapi_error_t LWIP::_add_ppp_interface(void *hw, bool default_if, nsapi_ip_stack
|
|||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
#endif //LWIP_PPP_API
|
||||
}
|
||||
|
||||
void LWIP::set_default_interface(OnboardNetworkStack::Interface *interface)
|
||||
{
|
||||
if (interface) {
|
||||
default_interface = static_cast<LWIP::Interface *>(interface);
|
||||
netif_set_default(&default_interface->netif);
|
||||
}
|
||||
}
|
||||
|
||||
nsapi_error_t LWIP::Interface::bringup(bool dhcp, const char *ip, const char *netmask, const char *gw, const nsapi_ip_stack_t stack, bool block)
|
||||
{
|
||||
|
@ -627,7 +696,7 @@ nsapi_error_t LWIP::Interface::bringup(bool dhcp, const char *ip, const char *ne
|
|||
}
|
||||
#endif
|
||||
|
||||
add_dns_addr(&netif);
|
||||
add_dns_addr(&netif, get_interface_name(_interface_name));
|
||||
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ err_t LWIP::Interface::emac_if_init(struct netif *netif)
|
|||
/* Then we write back either what they gave us, or our default */
|
||||
mbed_if->emac->set_hwaddr(netif->hwaddr);
|
||||
|
||||
mbed_if->emac->get_ifname(netif->name, 2);
|
||||
mbed_if->emac->get_ifname(netif->name, NSAPI_INTERFACE_PREFIX_SIZE);
|
||||
|
||||
#if LWIP_IPV4
|
||||
netif->output = etharp_output;
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
#include "LWIPStack.h"
|
||||
|
||||
#if LWIP_L3IP
|
||||
|
||||
err_t LWIP::Interface::l3ip_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
|
||||
#if LWIP_IPV4
|
||||
err_t LWIP::Interface::l3ip4_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
|
||||
{
|
||||
/* Increase reference counter since lwip stores handle to pbuf and frees
|
||||
it after output */
|
||||
|
@ -37,7 +37,19 @@ err_t LWIP::Interface::l3ip_output(struct netif *netif, struct pbuf *p, const ip
|
|||
bool ret = mbed_if->l3ip->link_out(p);
|
||||
return ret ? ERR_OK : ERR_IF;
|
||||
}
|
||||
#endif
|
||||
#if LWIP_IPV6
|
||||
err_t LWIP::Interface::l3ip6_output(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr)
|
||||
{
|
||||
/* Increase reference counter since lwip stores handle to pbuf and frees
|
||||
it after output */
|
||||
pbuf_ref(p);
|
||||
|
||||
LWIP::Interface *mbed_if = static_cast<LWIP::Interface *>(netif->state);
|
||||
bool ret = mbed_if->l3ip->link_out(p);
|
||||
return ret ? ERR_OK : ERR_IF;
|
||||
}
|
||||
#endif
|
||||
void LWIP::Interface::l3ip_input(net_stack_mem_buf_t *buf)
|
||||
{
|
||||
struct pbuf *p = static_cast<struct pbuf *>(buf);
|
||||
|
@ -130,24 +142,24 @@ err_t LWIP::Interface::l3ip_if_init(struct netif *netif)
|
|||
mbed_if->l3ip->set_link_state_cb(mbed::callback(mbed_if, &LWIP::Interface::l3ip_state_change));
|
||||
|
||||
/* Interface capabilities */
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
|
||||
netif->flags = NETIF_FLAG_BROADCAST;
|
||||
|
||||
if (!mbed_if->l3ip->power_up()) {
|
||||
err = ERR_IF;
|
||||
}
|
||||
|
||||
netif->mtu = mbed_if->l3ip->get_mtu_size();
|
||||
mbed_if->l3ip->get_ifname(netif->name, NSAPI_INTERFACE_NAME_SIZE);
|
||||
mbed_if->l3ip->get_ifname(netif->name, NSAPI_INTERFACE_PREFIX_SIZE);
|
||||
|
||||
#if LWIP_IPV4
|
||||
netif->output = &LWIP::Interface::l3ip_output;
|
||||
netif->output = &LWIP::Interface::l3ip4_output;
|
||||
#if LWIP_IGMP
|
||||
netif->igmp_mac_filter = &LWIP::Interface::l3ip_multicast_ipv4_filter;
|
||||
netif->flags |= NETIF_FLAG_IGMP;
|
||||
#endif /* LWIP_IGMP */
|
||||
#endif /* LWIP_IPV4 */
|
||||
#if LWIP_IPV6
|
||||
//netif->output_ip6 = ethip6_output;//to be done
|
||||
netif->output_ip6 = &LWIP::Interface::l3ip6_output;
|
||||
#if LWIP_IPV6_MLD
|
||||
netif->mld_mac_filter = &LWIP::Interface::l3ip_multicast_ipv6_filter;
|
||||
netif->flags |= NETIF_FLAG_MLD6;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "lwip/igmp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/lwip_errno.h"
|
||||
#include "lwip-sys/arch/sys_arch.h"
|
||||
|
||||
|
@ -175,12 +176,12 @@ LWIP::LWIP()
|
|||
arena_init();
|
||||
}
|
||||
|
||||
nsapi_error_t LWIP::get_dns_server(int index, SocketAddress *address)
|
||||
nsapi_error_t LWIP::get_dns_server(int index, SocketAddress *address, const char *interface_name)
|
||||
{
|
||||
int dns_entries = 0;
|
||||
|
||||
for (int i = 0; i < DNS_MAX_SERVERS; i++) {
|
||||
const ip_addr_t *ip_addr = dns_getserver(i);
|
||||
const ip_addr_t *ip_addr = dns_getserver(i, interface_name);
|
||||
if (!ip_addr_isany(ip_addr)) {
|
||||
if (index == dns_entries) {
|
||||
nsapi_addr_t addr;
|
||||
|
@ -509,6 +510,24 @@ nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, co
|
|||
struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
|
||||
|
||||
switch (optname) {
|
||||
case NSAPI_BIND_TO_DEVICE:
|
||||
if (optlen > NSAPI_INTERFACE_NAME_MAX_SIZE) {
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (NETCONNTYPE_GROUP(s->conn->type) == NETCONN_TCP) {
|
||||
s->conn->pcb.tcp->interface_name = (const char *)optval;
|
||||
}
|
||||
|
||||
if (NETCONNTYPE_GROUP(s->conn->type) == NETCONN_UDP) {
|
||||
s->conn->pcb.udp->interface_name = (const char *)optval;
|
||||
}
|
||||
#if LWIP_RAW
|
||||
if (NETCONNTYPE_GROUP(s->conn->type) == NETCONN_RAW) {
|
||||
s->conn->pcb.raw->interface_name = (const char *)optval;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
#if LWIP_TCP
|
||||
case NSAPI_KEEPALIVE:
|
||||
if (optlen != sizeof(int) || NETCONNTYPE_GROUP(s->conn->type) != NETCONN_TCP) {
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
|
||||
public:
|
||||
|
||||
using NetworkStack::get_ip_address;
|
||||
static LWIP &get_instance();
|
||||
|
||||
class Interface : public OnboardNetworkStack::Interface {
|
||||
|
@ -80,6 +80,12 @@ public:
|
|||
*/
|
||||
virtual nsapi_connection_status_t get_connection_status() const;
|
||||
|
||||
/** Return netif interface name
|
||||
*
|
||||
* @return netif name eg "en0"
|
||||
*/
|
||||
virtual char *get_interface_name(char *buf);
|
||||
|
||||
/** Return MAC address of the network interface
|
||||
*
|
||||
* @return MAC address as "V:W:X:Y:Z"
|
||||
|
@ -88,13 +94,21 @@ public:
|
|||
|
||||
/** 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 IP address of the name based 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
|
||||
* @param interface_name naame of the interface
|
||||
* @return Pointer to a buffer, or NULL if the buffer is too small
|
||||
*/
|
||||
virtual char *get_ip_address_if(char *buf, nsapi_size_t buflen, const char *interface_name);
|
||||
|
||||
/** Copies netmask of the network interface to user supplied buffer
|
||||
*
|
||||
* @param buf buffer to which netmask will be copied as "W:X:Y:Z"
|
||||
|
@ -136,7 +150,12 @@ public:
|
|||
#endif
|
||||
|
||||
#if LWIP_L3IP
|
||||
static err_t l3ip_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr);
|
||||
#if LWIP_IPV4
|
||||
static err_t l3ip4_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr);
|
||||
#endif
|
||||
#if LWIP_IPV6
|
||||
static err_t l3ip6_output(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr);
|
||||
#endif
|
||||
void l3ip_input(net_stack_mem_buf_t *buf);
|
||||
void l3ip_state_change(bool up);
|
||||
#if LWIP_IGMP
|
||||
|
@ -177,6 +196,7 @@ public:
|
|||
osSemaphoreId_t has_both_addr;
|
||||
#define HAS_BOTH_ADDR 4
|
||||
#endif
|
||||
char _interface_name[NSAPI_INTERFACE_NAME_MAX_SIZE];
|
||||
char has_addr_state;
|
||||
nsapi_connection_status_t connected;
|
||||
bool dhcp_started;
|
||||
|
@ -235,10 +255,7 @@ public:
|
|||
|
||||
/** Remove a network interface from IP stack
|
||||
*
|
||||
* Connects L3IP layer with the IP stack and initializes all the required infrastructure.
|
||||
* This function should be called only once for each available interface.
|
||||
|
||||
|
||||
* Removes layer 3 IP objects,network interface from stack list, and shutdown device driver .
|
||||
* @param[out] interface_out pointer to stack interface object controlling the L3IP
|
||||
* @return NSAPI_ERROR_OK on success, or error code
|
||||
*/
|
||||
|
@ -253,7 +270,7 @@ public:
|
|||
* @param address Destination for the host address
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t get_dns_server(int index, SocketAddress *address);
|
||||
virtual nsapi_error_t get_dns_server(int index, SocketAddress *address, const char *interface_name);
|
||||
|
||||
/** Get the local IP address
|
||||
*
|
||||
|
@ -261,6 +278,9 @@ public:
|
|||
* or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address();
|
||||
/** Set the network interface as default one
|
||||
*/
|
||||
virtual void set_default_interface(OnboardNetworkStack::Interface *interface);
|
||||
|
||||
protected:
|
||||
LWIP();
|
||||
|
@ -521,7 +541,7 @@ private:
|
|||
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 void add_dns_addr(struct netif *lwip_netif, const char *interface_name);
|
||||
|
||||
/* Static arena of sockets */
|
||||
struct mbed_lwip_socket arena[MEMP_NUM_NETCONN];
|
||||
|
|
|
@ -187,6 +187,7 @@ tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
|
|||
|
||||
msg->type = TCPIP_MSG_INPKT;
|
||||
msg->msg.inp.p = p;
|
||||
msg->msg.inp.p->netif = inp;
|
||||
msg->msg.inp.netif = inp;
|
||||
msg->msg.inp.input_fn = input_fn;
|
||||
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
|
||||
|
|
|
@ -659,7 +659,7 @@ dhcp_handle_ack(struct netif *netif)
|
|||
for (n = 0; (n < LWIP_DHCP_PROVIDE_DNS_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) {
|
||||
ip_addr_t dns_addr;
|
||||
ip_addr_set_ip4_u32(&dns_addr, lwip_htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
|
||||
dns_setserver(n, &dns_addr);
|
||||
dns_setserver(n, &dns_addr, netif);
|
||||
}
|
||||
#endif /* LWIP_DHCP_PROVIDE_DNS_SERVERS */
|
||||
}
|
||||
|
|
|
@ -371,14 +371,15 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
|
|||
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
|
||||
|
||||
ip4_addr_copy(iphdr_src, iphdr->src);
|
||||
|
||||
#ifdef LWIP_HOOK_IP4_ROUTE_SRC
|
||||
{
|
||||
ip4_addr_t iphdr_dst;
|
||||
ip4_addr_copy(iphdr_dst, iphdr->dest);
|
||||
netif = ip4_route_src(&iphdr_src, &iphdr_dst);
|
||||
netif = ip4_route_src(&iphdr_src, &iphdr_dst, netif_get_name(p->netif));
|
||||
}
|
||||
#else
|
||||
netif = ip4_route(&iphdr_src);
|
||||
netif = ip4_route(&iphdr_src, netif_get_name(p->netif));
|
||||
#endif
|
||||
if (netif != NULL) {
|
||||
/* calculate checksum */
|
||||
|
|
|
@ -126,7 +126,7 @@ ip4_set_default_multicast_netif(struct netif* default_multicast_netif)
|
|||
* LWIP_HOOK_IP4_ROUTE_SRC(). This function only provides he parameters.
|
||||
*/
|
||||
struct netif *
|
||||
ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src)
|
||||
ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src, const char *interface_name)
|
||||
{
|
||||
if (src != NULL) {
|
||||
/* when src==NULL, the hook is called from ip4_route(dest) */
|
||||
|
@ -135,7 +135,7 @@ ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src)
|
|||
return netif;
|
||||
}
|
||||
}
|
||||
return ip4_route(dest);
|
||||
return ip4_route(dest, interface_name);
|
||||
}
|
||||
#endif /* LWIP_HOOK_IP4_ROUTE_SRC */
|
||||
|
||||
|
@ -149,7 +149,7 @@ ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src)
|
|||
* @return the netif on which to send to reach dest
|
||||
*/
|
||||
struct netif *
|
||||
ip4_route(const ip4_addr_t *dest)
|
||||
ip4_route(const ip4_addr_t *dest, const char *interface_name)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
|
@ -160,6 +160,20 @@ ip4_route(const ip4_addr_t *dest)
|
|||
}
|
||||
#endif /* LWIP_MULTICAST_TX_OPTIONS */
|
||||
|
||||
if(interface_name !=NULL) {
|
||||
/* iterate through netifs */
|
||||
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
/* is the netif up, does it have a link and a valid address? */
|
||||
if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) {
|
||||
/* interface name matches? */
|
||||
if (!strcmp(netif_get_name(netif), interface_name)) {
|
||||
/* return netif with matched name */
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* iterate through netifs */
|
||||
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
/* is the netif up, does it have a link and a valid address? */
|
||||
|
@ -980,13 +994,13 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
|
|||
*/
|
||||
err_t
|
||||
ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto)
|
||||
u8_t ttl, u8_t tos, u8_t proto, const char *interface_name)
|
||||
{
|
||||
struct netif *netif;
|
||||
|
||||
LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
|
||||
|
||||
if ((netif = ip4_route_src(dest, src)) == NULL) {
|
||||
if ((netif = ip4_route_src(dest, src, interface_name)) == NULL) {
|
||||
LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
|
||||
IP_STATS_INC(ip.rterr);
|
||||
|
|
|
@ -311,7 +311,8 @@ icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
|
|||
ip6_addr_copy(reply_src_local, ip6hdr->dest);
|
||||
reply_dest = &reply_dest_local;
|
||||
reply_src = &reply_src_local;
|
||||
netif = ip6_route(reply_src, reply_dest);
|
||||
|
||||
netif = ip6_route(reply_src, reply_dest, netif_get_name(p->netif));
|
||||
if (netif == NULL) {
|
||||
/* drop */
|
||||
pbuf_free(q);
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "lwip/mld6.h"
|
||||
#include "lwip/debug.h"
|
||||
#include "lwip/stats.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef LWIP_HOOK_FILENAME
|
||||
#include LWIP_HOOK_FILENAME
|
||||
|
@ -81,11 +82,24 @@
|
|||
* @return the netif on which to send to reach dest
|
||||
*/
|
||||
struct netif *
|
||||
ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
|
||||
ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest, const char *interface_name)
|
||||
{
|
||||
struct netif *netif;
|
||||
s8_t i;
|
||||
|
||||
if(interface_name != NULL) {
|
||||
/* iterate through netifs */
|
||||
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (!netif_is_up(netif) || !netif_is_link_up(netif)) {
|
||||
continue;
|
||||
}
|
||||
/* interface name matches? */
|
||||
if (!strcmp(netif_get_name(netif), interface_name)) {
|
||||
/* return netif with matched name */
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If single netif configuration, fast return. */
|
||||
if ((netif_list != NULL) && (netif_list->next == NULL)) {
|
||||
if (!netif_is_up(netif_list) || !netif_is_link_up(netif_list)) {
|
||||
|
@ -955,7 +969,7 @@ ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
|
|||
*/
|
||||
err_t
|
||||
ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
|
||||
u8_t hl, u8_t tc, u8_t nexth)
|
||||
u8_t hl, u8_t tc, u8_t nexth, const char *interface_name)
|
||||
{
|
||||
struct netif *netif;
|
||||
struct ip6_hdr *ip6hdr;
|
||||
|
@ -964,13 +978,13 @@ ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
|
|||
LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
|
||||
|
||||
if (dest != LWIP_IP_HDRINCL) {
|
||||
netif = ip6_route(src, dest);
|
||||
netif = ip6_route(src, dest, interface_name);
|
||||
} else {
|
||||
/* IP header included in p, read addresses. */
|
||||
ip6hdr = (struct ip6_hdr *)p->payload;
|
||||
ip6_addr_copy(src_addr, ip6hdr->src);
|
||||
ip6_addr_copy(dest_addr, ip6hdr->dest);
|
||||
netif = ip6_route(&src_addr, &dest_addr);
|
||||
netif = ip6_route(&src_addr, &dest_addr, interface_name);
|
||||
}
|
||||
|
||||
if (netif == NULL) {
|
||||
|
|
|
@ -719,14 +719,14 @@ nd6_input(struct pbuf *p, struct netif *inp)
|
|||
|
||||
if (htonl(rdnss_opt->lifetime) > 0) {
|
||||
/* TODO implement Lifetime > 0 */
|
||||
dns_setserver(rdnss_server_idx++, &rdnss_address);
|
||||
dns_setserver(rdnss_server_idx++, &rdnss_address, inp);
|
||||
} else {
|
||||
/* TODO implement DNS removal in dns.c */
|
||||
u8_t s;
|
||||
for (s = 0; s < DNS_MAX_SERVERS; s++) {
|
||||
const ip_addr_t *addr = dns_getserver(s);
|
||||
if(ip_addr_cmp(addr, &rdnss_address)) {
|
||||
dns_setserver(s, NULL);
|
||||
dns_setserver(s, NULL, inp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -305,6 +305,7 @@ static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
|
|||
static struct dns_req_entry dns_requests[DNS_MAX_REQUESTS];
|
||||
#endif
|
||||
static ip_addr_t dns_servers[DNS_MAX_SERVERS];
|
||||
struct dns_server_interface *multihoming_dns_servers;
|
||||
|
||||
#if LWIP_IPV4
|
||||
const ip_addr_t dns_mquery_v4group = DNS_MQUERY_IPV4_GROUP_INIT;
|
||||
|
@ -324,7 +325,7 @@ dns_init(void)
|
|||
/* initialize default DNS server address */
|
||||
ip_addr_t dnsserver;
|
||||
DNS_SERVER_ADDRESS(&dnsserver);
|
||||
dns_setserver(0, &dnsserver);
|
||||
dns_setserver(0, &dnsserver, NULL);
|
||||
#endif /* DNS_SERVER_ADDRESS */
|
||||
|
||||
#if LWIP_FULL_DNS
|
||||
|
@ -366,14 +367,21 @@ dns_init(void)
|
|||
* @param dnsserver IP address of the DNS server to set
|
||||
*/
|
||||
void
|
||||
dns_setserver(u8_t numdns, const ip_addr_t *dnsserver)
|
||||
dns_setserver(u8_t numdns, const ip_addr_t *dnsserver, struct netif *netif)
|
||||
{
|
||||
if (numdns < DNS_MAX_SERVERS) {
|
||||
if (dnsserver != NULL) {
|
||||
dns_servers[numdns] = (*dnsserver);
|
||||
} else {
|
||||
dns_servers[numdns] = *IP_ADDR_ANY;
|
||||
|
||||
if (netif == NULL || netif_check_default(netif)) {
|
||||
if (numdns < DNS_MAX_SERVERS) {
|
||||
if (dnsserver != NULL) {
|
||||
dns_servers[numdns] = (*dnsserver);
|
||||
} else {
|
||||
dns_servers[numdns] = *IP_ADDR_ANY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char name[INTERFACE_NAME_MAX_SIZE];
|
||||
sprintf(name, "%c%c%d", netif->name[0], netif->name[1], netif->num);
|
||||
dns_add_interface_server(numdns, name, dnsserver);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,13 +394,112 @@ dns_setserver(u8_t numdns, const ip_addr_t *dnsserver)
|
|||
* server has not been configured.
|
||||
*/
|
||||
const ip_addr_t*
|
||||
dns_getserver(u8_t numdns)
|
||||
dns_getserver(u8_t numdns, const char *interface_name)
|
||||
{
|
||||
if (numdns < DNS_MAX_SERVERS) {
|
||||
return &dns_servers[numdns];
|
||||
if (interface_name == NULL) {
|
||||
if (numdns < DNS_MAX_SERVERS) {
|
||||
return &dns_servers[numdns];
|
||||
} else {
|
||||
return IP_ADDR_ANY;
|
||||
}
|
||||
} else {
|
||||
return dns_get_interface_server(numdns, interface_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup dns
|
||||
* Initialize one of the DNS servers.
|
||||
*
|
||||
* @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
|
||||
* @param dnsserver IP address of the DNS server to set
|
||||
*/
|
||||
void
|
||||
dns_add_interface_server(u8_t numdns, const char *interface_name, const ip_addr_t *dnsserver)
|
||||
{
|
||||
struct dns_server_interface *new_interface_server;
|
||||
|
||||
if (numdns >= DNS_MAX_SERVERS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (multihoming_dns_servers != NULL) {
|
||||
// if interface server already exists on the list just update it
|
||||
for (new_interface_server = multihoming_dns_servers; new_interface_server != NULL; new_interface_server = new_interface_server->next) {
|
||||
if (!strcmp(interface_name, new_interface_server->interface_name)) {
|
||||
new_interface_server->dns_servers[numdns] = (*dnsserver);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// add new dns server to the list tail
|
||||
new_interface_server = mem_malloc(sizeof(struct dns_server_interface));
|
||||
strncpy(new_interface_server->interface_name, interface_name, INTERFACE_NAME_MAX_SIZE);
|
||||
new_interface_server->dns_servers[numdns] = (*dnsserver);
|
||||
new_interface_server->next = NULL;
|
||||
|
||||
if (multihoming_dns_servers == NULL) {
|
||||
multihoming_dns_servers = new_interface_server;
|
||||
} else {
|
||||
struct dns_server_interface *tail;
|
||||
tail = multihoming_dns_servers;
|
||||
|
||||
while (tail->next != NULL) {
|
||||
tail = tail->next;
|
||||
}
|
||||
tail->next = new_interface_server;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dns_remove_interface_servers(const char *interface_name)
|
||||
{
|
||||
struct dns_server_interface *temp = multihoming_dns_servers;
|
||||
struct dns_server_interface *prev = NULL;
|
||||
|
||||
if (temp != NULL && !strcmp(interface_name, temp->interface_name)) {
|
||||
multihoming_dns_servers = temp->next;
|
||||
mem_free(temp);
|
||||
return;
|
||||
}
|
||||
|
||||
while (temp != NULL && strcmp(interface_name, temp->interface_name)) {
|
||||
prev = temp;
|
||||
temp = temp->next;
|
||||
}
|
||||
|
||||
if (temp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
prev->next = temp->next;
|
||||
mem_free(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup dns
|
||||
* Obtain one of the currently configured DNS server.
|
||||
*
|
||||
* @param numdns the index of the DNS server
|
||||
* @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
|
||||
* server has not been configured.
|
||||
*/
|
||||
const ip_addr_t *
|
||||
dns_get_interface_server(u8_t numdns, const char *interface_name)
|
||||
{
|
||||
struct dns_server_interface *interface_server;
|
||||
|
||||
if (numdns < DNS_MAX_SERVERS) {
|
||||
return IP_ADDR_ANY;
|
||||
}
|
||||
|
||||
for (interface_server = multihoming_dns_servers; interface_server != NULL; interface_server = interface_server->next) {
|
||||
if (!strcmp(interface_name, interface_server->interface_name)) {
|
||||
return &interface_server->dns_servers[numdns];
|
||||
}
|
||||
}
|
||||
return IP_ADDR_ANY;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -105,6 +105,7 @@ struct netif *netif_list;
|
|||
struct netif *netif_default;
|
||||
|
||||
static u8_t netif_num;
|
||||
static char netif_name [INTERFACE_NAME_MAX_SIZE];
|
||||
|
||||
#if LWIP_NUM_NETIF_CLIENT_DATA > 0
|
||||
static u8_t netif_client_id;
|
||||
|
@ -465,6 +466,20 @@ netif_remove(struct netif *netif)
|
|||
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netif
|
||||
* Get a network interface name
|
||||
*
|
||||
* @param netif
|
||||
* @return name the name of the netif (like netif->name) plus concatenated number
|
||||
* in ascii representation (e.g. 'en0')
|
||||
*/
|
||||
const char *
|
||||
netif_get_name(struct netif *netif)
|
||||
{
|
||||
sprintf(netif_name, "%c%c%d", netif->name[0], netif->name[1], netif->num);
|
||||
return netif_name;
|
||||
}
|
||||
/**
|
||||
* @ingroup netif
|
||||
* Find a network interface by searching for its name
|
||||
|
@ -619,6 +634,26 @@ netif_set_default(struct netif *netif)
|
|||
netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netif
|
||||
* Checks if network interface is the default network interface
|
||||
* @param netif the default network interface
|
||||
* @return true if netif is set to default one
|
||||
* otherwise return false
|
||||
*/
|
||||
bool
|
||||
netif_check_default(struct netif *netif)
|
||||
{
|
||||
if (netif == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (netif_default == netif) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup netif
|
||||
* Bring an interface up, available for processing
|
||||
|
|
|
@ -322,9 +322,9 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
|
|||
|
||||
if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
|
||||
/* Don't call ip_route() with IP_ANY_TYPE */
|
||||
netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr);
|
||||
netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr, pcb->interface_name);
|
||||
} else {
|
||||
netif = ip_route(&pcb->local_ip, ipaddr);
|
||||
netif = ip_route(&pcb->local_ip, ipaddr, pcb->interface_name);
|
||||
}
|
||||
|
||||
if (netif == NULL) {
|
||||
|
|
|
@ -273,7 +273,7 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
|
|||
/* don't call tcp_abort here: we must not deallocate the pcb since
|
||||
that might not be expected when calling tcp_close */
|
||||
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
|
||||
pcb->local_port, pcb->remote_port);
|
||||
pcb->local_port, pcb->remote_port, pcb->interface_name);
|
||||
|
||||
tcp_pcb_purge(pcb);
|
||||
TCP_RMV_ACTIVE(pcb);
|
||||
|
@ -512,7 +512,7 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
|
|||
tcp_backlog_accepted(pcb);
|
||||
if (send_rst) {
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
|
||||
tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port);
|
||||
tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, local_port, pcb->remote_port, pcb->interface_name);
|
||||
}
|
||||
last_state = pcb->state;
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
|
@ -890,7 +890,7 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port,
|
|||
/* no local IP address set, yet. */
|
||||
struct netif *netif;
|
||||
const ip_addr_t *local_ip;
|
||||
ip_route_get_local_ip(&pcb->local_ip, &pcb->remote_ip, netif, local_ip);
|
||||
ip_route_get_local_ip(&pcb->local_ip, &pcb->remote_ip, netif, local_ip, pcb->interface_name);
|
||||
if ((netif == NULL) || (local_ip == NULL)) {
|
||||
/* Don't even try to send a SYN packet if we have no route
|
||||
since that will fail. */
|
||||
|
@ -944,7 +944,7 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port,
|
|||
The send MSS is updated when an MSS option is received. */
|
||||
pcb->mss = INITIAL_MSS;
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip);
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, pcb->interface_name);
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
pcb->cwnd = 1;
|
||||
#if LWIP_CALLBACK_API
|
||||
|
@ -1162,7 +1162,7 @@ tcp_slowtmr_start:
|
|||
|
||||
if (pcb_reset) {
|
||||
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
|
||||
pcb->local_port, pcb->remote_port);
|
||||
pcb->local_port, pcb->remote_port, pcb->interface_name);
|
||||
}
|
||||
|
||||
err_arg = pcb->callback_arg;
|
||||
|
@ -1911,13 +1911,14 @@ tcp_eff_send_mss_impl(u16_t sendmss, const ip_addr_t *dest
|
|||
#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING
|
||||
, const ip_addr_t *src
|
||||
#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */
|
||||
, const char *interface_name
|
||||
)
|
||||
{
|
||||
u16_t mss_s;
|
||||
struct netif *outif;
|
||||
s16_t mtu;
|
||||
|
||||
outif = ip_route(src, dest);
|
||||
outif = ip_route(src, dest, interface_name);
|
||||
#if LWIP_IPV6
|
||||
#if LWIP_IPV4
|
||||
if (IP_IS_V6(dest))
|
||||
|
|
|
@ -517,8 +517,9 @@ aborted:
|
|||
if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
|
||||
TCP_STATS_INC(tcp.proterr);
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(),
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src);
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src, netif_get_name(inp));
|
||||
}
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
@ -560,7 +561,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
|||
RST. */
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(),
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src);
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src, pcb->interface_name);
|
||||
} else if (flags & TCP_SYN) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
|
@ -615,7 +616,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
|||
npcb->snd_wnd_max = npcb->snd_wnd;
|
||||
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip);
|
||||
npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip, npcb->interface_name);
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
||||
MIB2_STATS_INC(mib2.tcppassiveopens);
|
||||
|
@ -658,7 +659,7 @@ tcp_timewait_input(struct tcp_pcb *pcb)
|
|||
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd)) {
|
||||
/* If the SYN is in the window it is an error, send a reset */
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(),
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src);
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src, pcb->interface_name);
|
||||
return;
|
||||
}
|
||||
} else if (flags & TCP_FIN) {
|
||||
|
@ -765,7 +766,7 @@ tcp_process(struct tcp_pcb *pcb)
|
|||
pcb->state = ESTABLISHED;
|
||||
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip);
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, pcb->interface_name);
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
||||
pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss);
|
||||
|
@ -808,7 +809,7 @@ tcp_process(struct tcp_pcb *pcb)
|
|||
else if (flags & TCP_ACK) {
|
||||
/* send a RST to bring the other side in a non-synchronized state. */
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(),
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src);
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src, pcb->interface_name);
|
||||
/* Resend SYN immediately (don't wait for rto timeout) to establish
|
||||
connection faster, but do not send more SYNs than we otherwise would
|
||||
have, or we might get caught in a loop on loopback interfaces. */
|
||||
|
@ -869,7 +870,7 @@ tcp_process(struct tcp_pcb *pcb)
|
|||
} else {
|
||||
/* incorrect ACK number, send RST */
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(),
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src);
|
||||
ip_current_src_addr(), tcphdr->dest, tcphdr->src, pcb->interface_name);
|
||||
}
|
||||
} else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
|
||||
/* Looks like another copy of the SYN - retransmit our SYN-ACK */
|
||||
|
|
|
@ -953,7 +953,7 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
|
|||
}
|
||||
#endif
|
||||
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip);
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip, pcb->interface_name);
|
||||
if (netif == NULL) {
|
||||
err = ERR_RTE;
|
||||
} else {
|
||||
|
@ -1034,7 +1034,7 @@ tcp_output(struct tcp_pcb *pcb)
|
|||
for (; useg->next != NULL; useg = useg->next);
|
||||
}
|
||||
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip);
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip, pcb->interface_name);
|
||||
if (netif == NULL) {
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
@ -1224,7 +1224,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif
|
|||
if (seg->flags & TF_SEG_OPTS_MSS) {
|
||||
u16_t mss;
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
mss = tcp_eff_send_mss(TCP_MSS, &pcb->local_ip, &pcb->remote_ip);
|
||||
mss = tcp_eff_send_mss(TCP_MSS, &pcb->local_ip, &pcb->remote_ip, pcb->interface_name);
|
||||
#else /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
mss = TCP_MSS;
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
@ -1343,7 +1343,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb, struct netif *netif
|
|||
void
|
||||
tcp_rst(u32_t seqno, u32_t ackno,
|
||||
const ip_addr_t *local_ip, const ip_addr_t *remote_ip,
|
||||
u16_t local_port, u16_t remote_port)
|
||||
u16_t local_port, u16_t remote_port, const char *interface_name)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
|
@ -1373,7 +1373,7 @@ tcp_rst(u32_t seqno, u32_t ackno,
|
|||
TCP_STATS_INC(tcp.xmit);
|
||||
MIB2_STATS_INC(mib2.tcpoutrsts);
|
||||
|
||||
netif = ip_route(local_ip, remote_ip);
|
||||
netif = ip_route(local_ip, remote_ip, interface_name);
|
||||
if (netif != NULL) {
|
||||
#if CHECKSUM_GEN_TCP
|
||||
IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_TCP) {
|
||||
|
@ -1548,7 +1548,7 @@ tcp_keepalive(struct tcp_pcb *pcb)
|
|||
("tcp_keepalive: could not allocate memory for pbuf\n"));
|
||||
return ERR_MEM;
|
||||
}
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip);
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip, pcb->interface_name);
|
||||
if (netif == NULL) {
|
||||
err = ERR_RTE;
|
||||
} else {
|
||||
|
@ -1642,7 +1642,7 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
|||
pcb->snd_nxt = snd_nxt;
|
||||
}
|
||||
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip);
|
||||
netif = ip_route(&pcb->local_ip, &pcb->remote_ip, pcb->interface_name);
|
||||
if (netif == NULL) {
|
||||
err = ERR_RTE;
|
||||
} else {
|
||||
|
|
|
@ -548,9 +548,9 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip,
|
|||
/* find the outgoing network interface for this packet */
|
||||
if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
|
||||
/* Don't call ip_route() with IP_ANY_TYPE */
|
||||
netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(dst_ip_route)), dst_ip_route);
|
||||
netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(dst_ip_route)), dst_ip_route, pcb->interface_name);
|
||||
} else {
|
||||
netif = ip_route(&pcb->local_ip, dst_ip_route);
|
||||
netif = ip_route(&pcb->local_ip, dst_ip_route, pcb->interface_name);
|
||||
}
|
||||
|
||||
/* no outgoing network interface could be found? */
|
||||
|
|
|
@ -49,6 +49,12 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct dns_server_interface {
|
||||
char interface_name [INTERFACE_NAME_MAX_SIZE];
|
||||
ip_addr_t dns_servers[DNS_MAX_SERVERS];
|
||||
struct dns_server_interface *next;
|
||||
};
|
||||
|
||||
/** DNS timer period */
|
||||
#define DNS_TMR_INTERVAL 1000
|
||||
|
||||
|
@ -103,8 +109,11 @@ typedef void (*dns_found_callback)(const char *name, const ip_addr_t *ipaddr, vo
|
|||
|
||||
void dns_init(void);
|
||||
void dns_tmr(void);
|
||||
void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver);
|
||||
const ip_addr_t* dns_getserver(u8_t numdns);
|
||||
void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver, struct netif *netif);
|
||||
const ip_addr_t* dns_getserver(u8_t numdns, const char *interface_name);
|
||||
void dns_add_interface_server(u8_t numdns, const char *interface_name, const ip_addr_t *dnsserver);
|
||||
void dns_remove_interface_servers(const char *interface_name);
|
||||
const ip_addr_t* dns_get_interface_server(u8_t numdns, const char *interface_name);
|
||||
err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
|
||||
dns_found_callback found, void *callback_arg);
|
||||
err_t dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr,
|
||||
|
|
|
@ -74,16 +74,18 @@ extern "C" {
|
|||
changes to this common part are made in one location instead of
|
||||
having to change all PCB structs. */
|
||||
#define IP_PCB \
|
||||
/* ip addresses in network byte order */ \
|
||||
/* ip addresses in network byte order */ \
|
||||
ip_addr_t local_ip; \
|
||||
ip_addr_t remote_ip; \
|
||||
/* Socket options */ \
|
||||
u8_t so_options; \
|
||||
/* Type Of Service */ \
|
||||
u8_t tos; \
|
||||
/* Time To Live */ \
|
||||
u8_t ttl \
|
||||
/* link layer address resolution hint */ \
|
||||
/* Time To Live */ \
|
||||
u8_t ttl; \
|
||||
/* interface_name */ \
|
||||
const char* interface_name \
|
||||
/* link layer address resolution hint */ \
|
||||
IP_PCB_ADDRHINT
|
||||
|
||||
struct ip_pcb {
|
||||
|
@ -252,10 +254,10 @@ extern struct ip_globals ip_data;
|
|||
* @ingroup ip
|
||||
* Get netif for address combination. See \ref ip6_route and \ref ip4_route
|
||||
*/
|
||||
#define ip_route(src, dest) \
|
||||
#define ip_route(src, dest, interface_name) \
|
||||
(IP_IS_V6(dest) ? \
|
||||
ip6_route(ip_2_ip6(src), ip_2_ip6(dest)) : \
|
||||
ip4_route_src(ip_2_ip4(dest), ip_2_ip4(src)))
|
||||
ip6_route(ip_2_ip6(src), ip_2_ip6(dest), interface_name) : \
|
||||
ip4_route_src(ip_2_ip4(dest), ip_2_ip4(src), interface_name))
|
||||
/**
|
||||
* @ingroup ip
|
||||
* Get netif for IP.
|
||||
|
@ -277,8 +279,8 @@ err_t ip_input(struct pbuf *p, struct netif *inp);
|
|||
ip4_output_if_src(p, src, dest, ttl, tos, proto, netif)
|
||||
#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \
|
||||
ip4_output_hinted(p, src, dest, ttl, tos, proto, addr_hint)
|
||||
#define ip_route(src, dest) \
|
||||
ip4_route_src(dest, src)
|
||||
#define ip_route(src, dest, interface_name) \
|
||||
ip4_route_src(dest, src, interface_name)
|
||||
#define ip_netif_get_local_ip(netif, dest) \
|
||||
ip4_netif_get_local_ip(netif)
|
||||
#define ip_debug_print(is_ipv6, p) ip4_debug_print(p)
|
||||
|
@ -295,8 +297,8 @@ err_t ip_input(struct pbuf *p, struct netif *inp);
|
|||
ip6_output_if_src(p, src, dest, ttl, tos, proto, netif)
|
||||
#define ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) \
|
||||
ip6_output_hinted(p, src, dest, ttl, tos, proto, addr_hint)
|
||||
#define ip_route(src, dest) \
|
||||
ip6_route(src, dest)
|
||||
#define ip_route(src, dest, interface_name) \
|
||||
ip6_route(src, dest, interface_name)
|
||||
#define ip_netif_get_local_ip(netif, dest) \
|
||||
ip6_netif_get_local_ip(netif, dest)
|
||||
#define ip_debug_print(is_ipv6, p) ip6_debug_print(p)
|
||||
|
@ -305,8 +307,8 @@ err_t ip_input(struct pbuf *p, struct netif *inp);
|
|||
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#define ip_route_get_local_ip(src, dest, netif, ipaddr) do { \
|
||||
(netif) = ip_route(src, dest); \
|
||||
#define ip_route_get_local_ip(src, dest, netif, ipaddr, interface_name) do { \
|
||||
(netif) = ip_route(src, dest, interface_name); \
|
||||
(ipaddr) = ip_netif_get_local_ip(netif, dest); \
|
||||
}while(0)
|
||||
|
||||
|
|
|
@ -62,15 +62,15 @@ extern "C" {
|
|||
#define IP_OPTIONS_SEND (LWIP_IPV4 && LWIP_IGMP)
|
||||
|
||||
#define ip_init() /* Compatibility define, no init needed. */
|
||||
struct netif *ip4_route(const ip4_addr_t *dest);
|
||||
struct netif *ip4_route(const ip4_addr_t *dest, const char *interface_name);
|
||||
#if LWIP_IPV4_SRC_ROUTING
|
||||
struct netif *ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src);
|
||||
struct netif *ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src, const char *interface_name);
|
||||
#else /* LWIP_IPV4_SRC_ROUTING */
|
||||
#define ip4_route_src(dest, src) ip4_route(dest)
|
||||
#define ip4_route_src(dest, src, interface_name) ip4_route(dest, interface_name)
|
||||
#endif /* LWIP_IPV4_SRC_ROUTING */
|
||||
err_t ip4_input(struct pbuf *p, struct netif *inp);
|
||||
err_t ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto);
|
||||
u8_t ttl, u8_t tos, u8_t proto, const char *interface_name);
|
||||
err_t ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
|
||||
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif);
|
||||
err_t ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
|
||||
|
|
|
@ -57,11 +57,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest);
|
||||
struct netif *ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest, const char *interface_name);
|
||||
const ip_addr_t *ip6_select_source_address(struct netif *netif, const ip6_addr_t * dest);
|
||||
err_t ip6_input(struct pbuf *p, struct netif *inp);
|
||||
err_t ip6_output(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
|
||||
u8_t hl, u8_t tc, u8_t nexth);
|
||||
u8_t hl, u8_t tc, u8_t nexth, const char *interface_name);
|
||||
err_t ip6_output_if(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
|
||||
u8_t hl, u8_t tc, u8_t nexth, struct netif *netif);
|
||||
err_t ip6_output_if_src(struct pbuf *p, const ip6_addr_t *src, const ip6_addr_t *dest,
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#ifndef LWIP_HDR_NETIF_H
|
||||
#define LWIP_HDR_NETIF_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
|
||||
|
@ -380,7 +381,15 @@ void netif_remove(struct netif * netif);
|
|||
structure. */
|
||||
struct netif *netif_find(const char *name);
|
||||
|
||||
/* Returns a network interface name in the form
|
||||
"et0", where the first two letters are the "name" field in the
|
||||
netif structure, and the digit is in the num field in the same
|
||||
structure. */
|
||||
const char *netif_get_name(struct netif *netif);
|
||||
|
||||
void netif_set_default(struct netif *netif);
|
||||
bool netif_check_default(struct netif *netif);
|
||||
|
||||
|
||||
#if LWIP_IPV4
|
||||
void netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr);
|
||||
|
|
|
@ -170,6 +170,7 @@ struct pbuf {
|
|||
* the stack itself, or pbuf->next pointers from a chain.
|
||||
*/
|
||||
u16_t ref;
|
||||
struct netif *netif;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -453,7 +453,7 @@ void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);
|
|||
|
||||
void tcp_rst(u32_t seqno, u32_t ackno,
|
||||
const ip_addr_t *local_ip, const ip_addr_t *remote_ip,
|
||||
u16_t local_port, u16_t remote_port);
|
||||
u16_t local_port, u16_t remote_port, const char *interface_name);
|
||||
|
||||
u32_t tcp_next_iss(struct tcp_pcb *pcb);
|
||||
|
||||
|
@ -466,11 +466,12 @@ u16_t tcp_eff_send_mss_impl(u16_t sendmss, const ip_addr_t *dest
|
|||
#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING
|
||||
, const ip_addr_t *src
|
||||
#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */
|
||||
, const char *interface_name
|
||||
);
|
||||
#if LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING
|
||||
#define tcp_eff_send_mss(sendmss, src, dest) tcp_eff_send_mss_impl(sendmss, dest, src)
|
||||
#define tcp_eff_send_mss(sendmss, src, dest, interface_name) tcp_eff_send_mss_impl(sendmss, dest, src, interface_name)
|
||||
#else /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */
|
||||
#define tcp_eff_send_mss(sendmss, src, dest) tcp_eff_send_mss_impl(sendmss, dest)
|
||||
#define tcp_eff_send_mss(sendmss, src, dest, interface_name) tcp_eff_send_mss_impl(sendmss, dest, interface_name)
|
||||
#endif /* LWIP_IPV6 || LWIP_IPV4_SRC_ROUTING */
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
||||
|
|
|
@ -1128,9 +1128,9 @@ int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) {
|
|||
LWIP_UNUSED_ARG(pcb);
|
||||
|
||||
ip_addr_set_ip4_u32(&ns, ns1);
|
||||
dns_setserver(0, &ns);
|
||||
dns_setserver(0, &ns, NULL);
|
||||
ip_addr_set_ip4_u32(&ns, ns2);
|
||||
dns_setserver(1, &ns);
|
||||
dns_setserver(1, &ns, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1143,15 +1143,15 @@ int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) {
|
|||
ip_addr_t nsb;
|
||||
LWIP_UNUSED_ARG(pcb);
|
||||
|
||||
nsa = dns_getserver(0);
|
||||
nsa = dns_getserver(0, NULL);
|
||||
ip_addr_set_ip4_u32(&nsb, ns1);
|
||||
if (ip_addr_cmp(nsa, &nsb)) {
|
||||
dns_setserver(0, IP_ADDR_ANY);
|
||||
dns_setserver(0, IP_ADDR_ANY, NULL);
|
||||
}
|
||||
nsa = dns_getserver(1);
|
||||
nsa = dns_getserver(1, NULL);
|
||||
ip_addr_set_ip4_u32(&nsb, ns2);
|
||||
if (ip_addr_cmp(nsa, &nsb)) {
|
||||
dns_setserver(1, IP_ADDR_ANY);
|
||||
dns_setserver(1, IP_ADDR_ANY, NULL);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define LWIP_TIMEVAL_PRIVATE 0
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "nsapi_types.h"
|
||||
// Operating System
|
||||
#define NO_SYS 0
|
||||
|
||||
|
@ -339,7 +339,14 @@
|
|||
#define LWIP_ETHERNET 0
|
||||
#endif // MBED_CONF_LWIP_ETHERNET_ENABLED
|
||||
|
||||
#define LWIP_L3IP 0
|
||||
#if MBED_CONF_LWIP_L3IP_ENABLED
|
||||
#define LWIP_L3IP 1
|
||||
#else
|
||||
#define LWIP_L3IP 0
|
||||
#endif
|
||||
|
||||
//Maximum size of network interface name
|
||||
#define INTERFACE_NAME_MAX_SIZE NSAPI_INTERFACE_NAME_MAX_SIZE
|
||||
// Note generic macro name used rather than MBED_CONF_LWIP_PPP_ENABLED
|
||||
// to allow users like PPPCellularInterface to detect that nsapi_ppp.h is available.
|
||||
#if NSAPI_PPP_AVAILABLE
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
"help": "Enable support for Ethernet interfaces",
|
||||
"value": true
|
||||
},
|
||||
"l3ip-enabled": {
|
||||
"help": "Enable support for L3IP interfaces",
|
||||
"value": false
|
||||
},
|
||||
"debug-enabled": {
|
||||
"help": "Enable debug trace support",
|
||||
"value": false
|
||||
|
|
|
@ -130,11 +130,11 @@ static void ppp_link_status(ppp_pcb *pcb, int err_code, void *ctx)
|
|||
tr_debug(" netmask = %s", ipaddr_ntoa(&ppp_netif(pcb)->netmask));
|
||||
#if LWIP_DNS
|
||||
const ip_addr_t *ns;
|
||||
ns = dns_getserver(0);
|
||||
ns = dns_getserver(0, NULL);
|
||||
if (ns) {
|
||||
tr_debug(" dns1 = %s", ipaddr_ntoa(ns));
|
||||
}
|
||||
ns = dns_getserver(1);
|
||||
ns = dns_getserver(1, NULL);
|
||||
if (ns) {
|
||||
tr_debug(" dns2 = %s", ipaddr_ntoa(ns));
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
class DNS {
|
||||
public:
|
||||
|
||||
/** Translate a hostname to an IP address with specific version.
|
||||
/** Translate a hostname to an IP address with specific version using network interface name.
|
||||
*
|
||||
* 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.
|
||||
|
@ -37,11 +37,11 @@ public:
|
|||
* @param address Pointer to a SocketAddress to store the result.
|
||||
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC).
|
||||
* @param interface_name Network interface name
|
||||
* @return NSAPI_ERROR_OK on success, negative error code on failure.
|
||||
*/
|
||||
virtual nsapi_error_t gethostbyname(const char *host,
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC) = 0;
|
||||
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC, const char *interface_name = NULL) = 0;
|
||||
/** Hostname translation callback for gethostbyname_async.
|
||||
*
|
||||
* The callback is called after DNS resolution completes, or a failure occurs.
|
||||
|
@ -57,7 +57,7 @@ public:
|
|||
*/
|
||||
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address)> hostbyname_cb_t;
|
||||
|
||||
/** Translate a hostname to an IP address (asynchronous).
|
||||
/** Translate a hostname to an IP address (asynchronous)
|
||||
*
|
||||
* 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.
|
||||
|
@ -74,13 +74,14 @@ public:
|
|||
* @param callback Callback that is called to return the result.
|
||||
* @param version IP version of address to resolve. NSAPI_UNSPEC indicates that the
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC).
|
||||
* @param interface_name Network interface name
|
||||
* @return NSAPI_ERROR_OK on immediate success,
|
||||
* negative error code on immediate failure or
|
||||
* a positive unique ID that represents the hostname translation operation
|
||||
* and can be passed to cancel.
|
||||
*/
|
||||
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback,
|
||||
nsapi_version_t version = NSAPI_UNSPEC) = 0;
|
||||
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version = NSAPI_UNSPEC,
|
||||
const char *interface_name = NULL) = 0;
|
||||
|
||||
/** Cancel asynchronous hostname translation.
|
||||
*
|
||||
|
@ -94,9 +95,10 @@ public:
|
|||
/** Add a domain name server to list of servers to query.
|
||||
*
|
||||
* @param address DNS server host address.
|
||||
* @param interface_name Network interface name
|
||||
* @return NSAPI_ERROR_OK on success, negative error code on failure.
|
||||
*/
|
||||
virtual nsapi_error_t add_dns_server(const SocketAddress &address) = 0;
|
||||
virtual nsapi_error_t add_dns_server(const SocketAddress &address, const char *interface_name = NULL) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
#include "EMACInterface.h"
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
/* Interface implementation */
|
||||
|
@ -112,6 +113,22 @@ const char *EMACInterface::get_gateway()
|
|||
return 0;
|
||||
}
|
||||
|
||||
char *EMACInterface::get_interface_name(char *interface_name)
|
||||
{
|
||||
if (_interface) {
|
||||
return _interface->get_interface_name(interface_name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EMACInterface::set_as_default()
|
||||
{
|
||||
if (_interface) {
|
||||
_stack.set_default_interface(_interface);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkStack *EMACInterface::get_stack()
|
||||
{
|
||||
return &_stack;
|
||||
|
|
|
@ -117,6 +117,17 @@ public:
|
|||
*/
|
||||
virtual const char *get_gateway();
|
||||
|
||||
/** Get the network interface name
|
||||
*
|
||||
* @return Null-terminated representation of the network interface name
|
||||
* or null if interface not exists
|
||||
*/
|
||||
virtual char *get_interface_name(char *interface_name);
|
||||
|
||||
/** Set the network interface as default one
|
||||
*/
|
||||
virtual void set_as_default();
|
||||
|
||||
/** Register callback for status reporting
|
||||
*
|
||||
* @param status_cb The callback for status changes
|
||||
|
|
|
@ -55,7 +55,7 @@ nsapi_error_t InternetSocket::open(NetworkStack *stack)
|
|||
_socket = socket;
|
||||
_event = callback(this, &InternetSocket::event);
|
||||
_stack->socket_attach(_socket, Callback<void()>::thunk, &_event);
|
||||
|
||||
_interface_name[0] = '\0';
|
||||
_lock.unlock();
|
||||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ nsapi_error_t InternetSocket::close()
|
|||
_event_flag.wait_any(FINISHED_FLAG, osWaitForever);
|
||||
_lock.lock();
|
||||
}
|
||||
|
||||
_interface_name[0] = '\0';
|
||||
_lock.unlock();
|
||||
|
||||
// When allocated by accept() call, will destroy itself on close();
|
||||
|
@ -176,6 +176,9 @@ nsapi_error_t InternetSocket::setsockopt(int level, int optname, const void *opt
|
|||
ret = NSAPI_ERROR_NO_SOCKET;
|
||||
} else {
|
||||
ret = _stack->setsockopt(_socket, level, optname, optval, optlen);
|
||||
if (optname == NSAPI_BIND_TO_DEVICE && level == NSAPI_SOCKET) {
|
||||
strncpy(_interface_name, static_cast<const char *>(optval), optlen);
|
||||
}
|
||||
}
|
||||
|
||||
_lock.unlock();
|
||||
|
|
|
@ -158,7 +158,7 @@ protected:
|
|||
virtual nsapi_protocol_t get_proto() = 0;
|
||||
virtual void event();
|
||||
int modify_multicast_group(const SocketAddress &address, nsapi_socket_option_t socketopt);
|
||||
|
||||
char _interface_name[NSAPI_INTERFACE_NAME_MAX_SIZE];
|
||||
NetworkStack *_stack;
|
||||
nsapi_socket_t _socket;
|
||||
uint32_t _timeout;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "L3IPInterface.h"
|
||||
#include "LWIPStack.h"
|
||||
using namespace mbed;
|
||||
|
||||
/* Interface implementation */
|
||||
|
@ -56,10 +57,12 @@ nsapi_error_t L3IPInterface::set_dhcp(bool dhcp)
|
|||
return NSAPI_ERROR_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
nsapi_error_t L3IPInterface::connect()
|
||||
{
|
||||
if (!_interface) {
|
||||
nsapi_error_t err = _stack.add_l3ip_interface(_l3ip, true, &_interface);
|
||||
nsapi_error_t err = _stack.add_l3ip_interface(_l3ip, false, &_interface);
|
||||
if (err != NSAPI_ERROR_OK) {
|
||||
_interface = NULL;
|
||||
return err;
|
||||
|
@ -110,6 +113,22 @@ const char *L3IPInterface::get_gateway()
|
|||
return 0;
|
||||
}
|
||||
|
||||
char *L3IPInterface::get_interface_name(char *interface_name)
|
||||
{
|
||||
if (_interface) {
|
||||
return _interface->get_interface_name(interface_name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void L3IPInterface::set_as_default()
|
||||
{
|
||||
if (_interface) {
|
||||
static_cast<LWIP *>(&_stack)->set_default_interface(_interface);
|
||||
}
|
||||
}
|
||||
|
||||
NetworkStack *L3IPInterface::get_stack()
|
||||
{
|
||||
return &_stack;
|
||||
|
|
|
@ -103,6 +103,17 @@ public:
|
|||
*/
|
||||
virtual const char *get_gateway();
|
||||
|
||||
/** Get the network interface name
|
||||
*
|
||||
* @return Null-terminated representation of the network interface name
|
||||
* or null if interface not exists
|
||||
*/
|
||||
virtual char *get_interface_name(char *interface_name);
|
||||
|
||||
/** Set the network interface as default one
|
||||
*/
|
||||
virtual void set_as_default();
|
||||
|
||||
/** Register callback for status reporting
|
||||
*
|
||||
* @param status_cb The callback for status changes
|
||||
|
|
|
@ -21,8 +21,12 @@
|
|||
#include <string.h>
|
||||
#include "ns_list.h"
|
||||
|
||||
|
||||
// Default network-interface state
|
||||
void NetworkInterface::set_as_default()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const char *NetworkInterface::get_mac_address()
|
||||
{
|
||||
return 0;
|
||||
|
@ -43,6 +47,11 @@ const char *NetworkInterface::get_gateway()
|
|||
return 0;
|
||||
}
|
||||
|
||||
char *NetworkInterface::get_interface_name(char *interface_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkInterface::set_network(const char *ip_address, const char *netmask, const char *gateway)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
|
@ -57,15 +66,14 @@ nsapi_error_t NetworkInterface::set_dhcp(bool dhcp)
|
|||
}
|
||||
}
|
||||
|
||||
// DNS operations go through the underlying stack by default
|
||||
nsapi_error_t NetworkInterface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
|
||||
nsapi_error_t NetworkInterface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version, const char *interface_name)
|
||||
{
|
||||
return get_stack()->gethostbyname(name, address, version);
|
||||
return get_stack()->gethostbyname(name, address, version, interface_name);
|
||||
}
|
||||
|
||||
nsapi_value_or_error_t NetworkInterface::gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version)
|
||||
nsapi_value_or_error_t NetworkInterface::gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version, const char *interface_name)
|
||||
{
|
||||
return get_stack()->gethostbyname_async(host, callback, version);
|
||||
return get_stack()->gethostbyname_async(host, callback, version, interface_name);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkInterface::gethostbyname_async_cancel(int id)
|
||||
|
@ -73,9 +81,9 @@ nsapi_error_t NetworkInterface::gethostbyname_async_cancel(int id)
|
|||
return get_stack()->gethostbyname_async_cancel(id);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address)
|
||||
nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address, const char *interface_name)
|
||||
{
|
||||
return get_stack()->add_dns_server(address);
|
||||
return get_stack()->add_dns_server(address, interface_name);
|
||||
}
|
||||
|
||||
void NetworkInterface::attach(mbed::Callback<void(nsapi_event_t, intptr_t)> status_cb)
|
||||
|
|
|
@ -84,6 +84,10 @@ public:
|
|||
*/
|
||||
static NetworkInterface *get_default_instance();
|
||||
|
||||
/** Set network interface as default one.
|
||||
*/
|
||||
virtual void set_as_default();
|
||||
|
||||
/** Get the local MAC address.
|
||||
*
|
||||
* Provided MAC address is intended for info or debug purposes and
|
||||
|
@ -95,10 +99,10 @@ public:
|
|||
*/
|
||||
virtual const char *get_mac_address();
|
||||
|
||||
/** Get the local IP address.
|
||||
/** Get the local IP address
|
||||
*
|
||||
* @return Null-terminated representation of the local IP address
|
||||
* or null if no IP address has been received.
|
||||
* or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address();
|
||||
|
||||
|
@ -116,6 +120,13 @@ public:
|
|||
*/
|
||||
virtual const char *get_gateway();
|
||||
|
||||
/** Get the network interface name
|
||||
*
|
||||
* @return Null-terminated representation of the network interface name
|
||||
* or null if interface not exists
|
||||
*/
|
||||
virtual char *get_interface_name(char *interface_name);
|
||||
|
||||
/** Configure this network interface to use a static IP address.
|
||||
* Implicitly disables DHCP, which can be enabled in set_dhcp.
|
||||
* Requires that the network is disconnected.
|
||||
|
@ -173,7 +184,7 @@ public:
|
|||
*/
|
||||
virtual nsapi_error_t disconnect() = 0;
|
||||
|
||||
/** Translate a hostname to an IP address with specific version.
|
||||
/** Translate a hostname to an IP address with specific version using network interface name.
|
||||
*
|
||||
* 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.
|
||||
|
@ -185,10 +196,11 @@ public:
|
|||
* @param address Pointer to a SocketAddress to store the result.
|
||||
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC).
|
||||
* @param interface_name Network interface name
|
||||
* @return NSAPI_ERROR_OK on success, negative error code on failure.
|
||||
*/
|
||||
virtual nsapi_error_t gethostbyname(const char *host,
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC);
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC, const char *interface_name = NULL);
|
||||
|
||||
/** Hostname translation callback (for use with gethostbyname_async()).
|
||||
*
|
||||
|
@ -205,7 +217,7 @@ public:
|
|||
*/
|
||||
typedef mbed::Callback<void (nsapi_error_t result, SocketAddress *address)> hostbyname_cb_t;
|
||||
|
||||
/** Translate a hostname to an IP address (asynchronous).
|
||||
/** Translate a hostname to an IP address (asynchronous) using network interface name.
|
||||
*
|
||||
* The hostname may be either a domain name or a dotted IP address. If the
|
||||
* hostname is an IP address, no network transactions will be performed.
|
||||
|
@ -222,13 +234,14 @@ public:
|
|||
* @param callback Callback that is called for result.
|
||||
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC).
|
||||
* @param interface_name Network interface name
|
||||
* @return 0 on immediate success,
|
||||
* negative error code on immediate failure or
|
||||
* a positive unique id that represents the hostname translation operation
|
||||
* and can be passed to cancel.
|
||||
*/
|
||||
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback,
|
||||
nsapi_version_t version = NSAPI_UNSPEC);
|
||||
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version = NSAPI_UNSPEC,
|
||||
const char *interface_name = NULL);
|
||||
|
||||
/** Cancel asynchronous hostname translation.
|
||||
*
|
||||
|
@ -245,7 +258,7 @@ public:
|
|||
* @param address Address for the dns host.
|
||||
* @return NSAPI_ERROR_OK on success, negative error code on failure.
|
||||
*/
|
||||
virtual nsapi_error_t add_dns_server(const SocketAddress &address);
|
||||
virtual nsapi_error_t add_dns_server(const SocketAddress &address, const char *interface_name);
|
||||
|
||||
/** Register callback for status reporting.
|
||||
*
|
||||
|
|
|
@ -22,12 +22,19 @@
|
|||
#include "mbed_shared_queues.h"
|
||||
|
||||
// Default NetworkStack operations
|
||||
|
||||
const char *NetworkStack::get_ip_address()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *NetworkStack::get_ip_address_if(const char *interface_name)
|
||||
{
|
||||
return 0;
|
||||
|
||||
}
|
||||
nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
|
||||
|
||||
nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version, const char *interface_name)
|
||||
{
|
||||
if (name[0] == '\0') {
|
||||
return NSAPI_ERROR_PARAMETER;
|
||||
|
@ -51,10 +58,10 @@ nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *addre
|
|||
}
|
||||
}
|
||||
|
||||
return nsapi_dns_query(this, name, address, version);
|
||||
return nsapi_dns_query(this, name, address, interface_name, version);
|
||||
}
|
||||
|
||||
nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *name, hostbyname_cb_t callback, nsapi_version_t version)
|
||||
nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *name, hostbyname_cb_t callback, nsapi_version_t version, const char *interface_name)
|
||||
{
|
||||
SocketAddress address;
|
||||
|
||||
|
@ -83,7 +90,7 @@ nsapi_value_or_error_t NetworkStack::gethostbyname_async(const char *name, hostb
|
|||
|
||||
call_in_callback_cb_t call_in_cb = get_call_in_callback();
|
||||
|
||||
return nsapi_dns_query_async(this, name, callback, call_in_cb, version);
|
||||
return nsapi_dns_query_async(this, name, callback, call_in_cb, interface_name, version);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkStack::gethostbyname_async_cancel(int id)
|
||||
|
@ -91,12 +98,12 @@ nsapi_error_t NetworkStack::gethostbyname_async_cancel(int id)
|
|||
return nsapi_dns_query_async_cancel(id);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address)
|
||||
nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address, const char *interface_name)
|
||||
{
|
||||
return nsapi_dns_add_server(address);
|
||||
return nsapi_dns_add_server(address, interface_name);
|
||||
}
|
||||
|
||||
nsapi_error_t NetworkStack::get_dns_server(int index, SocketAddress *address)
|
||||
nsapi_error_t NetworkStack::get_dns_server(int index, SocketAddress *address, const char *interface_name)
|
||||
{
|
||||
return NSAPI_ERROR_UNSUPPORTED;
|
||||
}
|
||||
|
@ -164,6 +171,8 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
using NetworkStack::get_ip_address;
|
||||
using NetworkStack::gethostbyname;
|
||||
virtual const char *get_ip_address()
|
||||
{
|
||||
if (!_stack_api()->get_ip_address) {
|
||||
|
@ -175,10 +184,10 @@ public:
|
|||
return address->get_ip_address();
|
||||
}
|
||||
|
||||
virtual nsapi_error_t gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version)
|
||||
virtual nsapi_error_t gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version, const char *interface_name)
|
||||
{
|
||||
if (!_stack_api()->gethostbyname) {
|
||||
return NetworkStack::gethostbyname(name, address, version);
|
||||
return NetworkStack::gethostbyname(name, address, version, interface_name);
|
||||
}
|
||||
|
||||
nsapi_addr_t addr = {NSAPI_UNSPEC, 0};
|
||||
|
@ -187,10 +196,10 @@ public:
|
|||
return err;
|
||||
}
|
||||
|
||||
virtual nsapi_error_t add_dns_server(const SocketAddress &address)
|
||||
virtual nsapi_error_t add_dns_server(const SocketAddress &address, const char *interface_name)
|
||||
{
|
||||
if (!_stack_api()->add_dns_server) {
|
||||
return NetworkStack::add_dns_server(address);
|
||||
return NetworkStack::add_dns_server(address, interface_name);
|
||||
}
|
||||
|
||||
return _stack_api()->add_dns_server(_stack(), address.get_addr());
|
||||
|
|
|
@ -48,6 +48,14 @@ public:
|
|||
*/
|
||||
virtual const char *get_ip_address();
|
||||
|
||||
/** Get the local IP address on interface name
|
||||
*
|
||||
* @param interface_name Network interface_name
|
||||
* @return Null-terminated representation of the local IP address
|
||||
* or null if not yet connected
|
||||
*/
|
||||
virtual const char *get_ip_address_if(const char *interface_name);
|
||||
|
||||
/** Translates a hostname to an IP address with specific version
|
||||
*
|
||||
* The hostname may be either a domain name or an IP address. If the
|
||||
|
@ -60,10 +68,11 @@ public:
|
|||
* @param address Pointer to a SocketAddress to store the result.
|
||||
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC)
|
||||
* @param interface_name Network interface_name
|
||||
* @return NSAPI_ERROR_OK on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t gethostbyname(const char *host,
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC);
|
||||
SocketAddress *address, nsapi_version_t version = NSAPI_UNSPEC, const char *interface_name = NULL);
|
||||
|
||||
/** Hostname translation callback (asynchronous)
|
||||
*
|
||||
|
@ -97,13 +106,14 @@ public:
|
|||
* @param callback Callback that is called for result
|
||||
* @param version IP version of address to resolve, NSAPI_UNSPEC indicates
|
||||
* version is chosen by the stack (defaults to NSAPI_UNSPEC)
|
||||
* @param interface_name Network interface_name
|
||||
* @return 0 on immediate success,
|
||||
* negative error code on immediate failure or
|
||||
* a positive unique id that represents the hostname translation operation
|
||||
* and can be passed to cancel
|
||||
*/
|
||||
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback,
|
||||
nsapi_version_t version = NSAPI_UNSPEC);
|
||||
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version = NSAPI_UNSPEC,
|
||||
const char *interface_name = NULL);
|
||||
|
||||
/** Cancels asynchronous hostname translation
|
||||
*
|
||||
|
@ -117,9 +127,10 @@ public:
|
|||
/** Add a domain name server to list of servers to query
|
||||
*
|
||||
* @param address Destination for the host address
|
||||
* @param interface_name Network interface name
|
||||
* @return NSAPI_ERROR_OK on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t add_dns_server(const SocketAddress &address);
|
||||
virtual nsapi_error_t add_dns_server(const SocketAddress &address, const char *interface_name = NULL);
|
||||
|
||||
/** Get a domain name server from a list of servers to query
|
||||
*
|
||||
|
@ -128,9 +139,10 @@ public:
|
|||
*
|
||||
* @param index Index of the DNS server, starts from zero
|
||||
* @param address Destination for the host address
|
||||
* @param interface_name Network interface name
|
||||
* @return NSAPI_ERROR_OK on success, negative error code on failure
|
||||
*/
|
||||
virtual nsapi_error_t get_dns_server(int index, SocketAddress *address);
|
||||
virtual nsapi_error_t get_dns_server(int index, SocketAddress *address, const char *interface_name = NULL);
|
||||
|
||||
/* Set stack options
|
||||
*
|
||||
|
|
|
@ -89,22 +89,47 @@ public:
|
|||
*
|
||||
* @return The connection status according to ConnectionStatusType
|
||||
*/
|
||||
|
||||
virtual nsapi_connection_status_t get_connection_status() const = 0;
|
||||
|
||||
/** Returns interface name
|
||||
*
|
||||
* @return string containing name of network interface for example "en0"
|
||||
*/
|
||||
|
||||
virtual char *get_interface_name(char *buf)
|
||||
{
|
||||
return NULL;
|
||||
};
|
||||
/** 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
|
||||
* @param interface_name Network interface name
|
||||
* @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 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
|
||||
* @param interface_name Network interface name
|
||||
* @return Pointer to a buffer, or NULL if the buffer is too small
|
||||
*/
|
||||
virtual char *get_ip_address_if(char *buf, nsapi_size_t buflen, const char *interface_name)
|
||||
{
|
||||
return NULL;
|
||||
};
|
||||
|
||||
/** Copies netmask of the network interface to user supplied buffer
|
||||
*
|
||||
* @param buf buffer to which netmask will be copied as "W:X:Y:Z"
|
||||
|
@ -144,6 +169,11 @@ public:
|
|||
{
|
||||
return NSAPI_ERROR_OK;
|
||||
};
|
||||
|
||||
virtual void set_default_interface(OnboardNetworkStack::Interface *interface)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif /* MBED_IPSTACK_H */
|
||||
|
|
|
@ -110,7 +110,12 @@ nsapi_error_t TCPSocket::connect(const char *host, uint16_t port)
|
|||
if (!_socket) {
|
||||
return NSAPI_ERROR_NO_SOCKET;
|
||||
}
|
||||
nsapi_error_t err = _stack->gethostbyname(host, &address);
|
||||
nsapi_error_t err;
|
||||
if (!strcmp(_interface_name, "")) {
|
||||
err = _stack->gethostbyname(host, &address);
|
||||
} else {
|
||||
err = _stack->gethostbyname(host, &address, NSAPI_UNSPEC, _interface_name);
|
||||
}
|
||||
if (err) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,14 @@ nsapi_error_t UDPSocket::connect(const SocketAddress &address)
|
|||
nsapi_size_or_error_t UDPSocket::sendto(const char *host, uint16_t port, const void *data, nsapi_size_t size)
|
||||
{
|
||||
SocketAddress address;
|
||||
nsapi_size_or_error_t err = _stack->gethostbyname(host, &address);
|
||||
nsapi_size_or_error_t err;
|
||||
|
||||
if (!strcmp(_interface_name, "")) {
|
||||
err = _stack->gethostbyname(host, &address);
|
||||
} else {
|
||||
err = _stack->gethostbyname(host, &address, NSAPI_UNSPEC, _interface_name);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return NSAPI_ERROR_DNS_FAILURE;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ struct DNS_QUERY {
|
|||
nsapi_error_t status;
|
||||
NetworkStack *stack;
|
||||
char *host;
|
||||
const char *interface_name;
|
||||
NetworkStack::hostbyname_cb_t callback;
|
||||
call_in_callback_cb_t call_in_cb;
|
||||
nsapi_size_t addr_count;
|
||||
|
@ -89,7 +90,7 @@ struct DNS_QUERY {
|
|||
static void nsapi_dns_cache_add(const char *host, nsapi_addr_t *address, uint32_t ttl);
|
||||
static nsapi_size_or_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t version, nsapi_addr_t *address);
|
||||
|
||||
static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, uint8_t *send_success, SocketAddress *dns_addr);
|
||||
static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, uint8_t *send_success, SocketAddress *dns_addr, const char *interface_name);
|
||||
|
||||
static void nsapi_dns_query_async_create(void *ptr);
|
||||
static nsapi_error_t nsapi_dns_query_async_delete(int unique_id);
|
||||
|
@ -128,7 +129,7 @@ static SingletonPtr<call_in_callback_cb_t> dns_call_in;
|
|||
static bool dns_timer_running = false;
|
||||
|
||||
// DNS server configuration
|
||||
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr)
|
||||
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr, const char *interface_name)
|
||||
{
|
||||
memmove(&dns_servers[1], &dns_servers[0],
|
||||
(DNS_SERVERS_SIZE - 1)*sizeof(nsapi_addr_t));
|
||||
|
@ -395,7 +396,7 @@ static nsapi_error_t nsapi_dns_cache_find(const char *host, nsapi_version_t vers
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, uint8_t *send_success, SocketAddress *dns_addr)
|
||||
static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *index, uint8_t *total_attempts, uint8_t *send_success, SocketAddress *dns_addr, const char *interface_name)
|
||||
{
|
||||
bool dns_addr_set = false;
|
||||
|
||||
|
@ -414,7 +415,7 @@ static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *ind
|
|||
}
|
||||
|
||||
if (*index < DNS_STACK_SERVERS_NUM) {
|
||||
nsapi_error_t ret = stack->get_dns_server(*index, dns_addr);
|
||||
nsapi_error_t ret = stack->get_dns_server(*index, dns_addr, interface_name);
|
||||
if (ret < 0) {
|
||||
*index = DNS_STACK_SERVERS_NUM;
|
||||
} else {
|
||||
|
@ -433,7 +434,7 @@ static nsapi_error_t nsapi_dns_get_server_addr(NetworkStack *stack, uint8_t *ind
|
|||
|
||||
// core query function
|
||||
static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host,
|
||||
nsapi_addr_t *addr, unsigned addr_count, nsapi_version_t version)
|
||||
nsapi_addr_t *addr, unsigned addr_count, const char *interface_name, nsapi_version_t version)
|
||||
{
|
||||
// check for valid host name
|
||||
int host_len = host ? strlen(host) : 0;
|
||||
|
@ -455,6 +456,9 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
|
|||
|
||||
socket.set_timeout(MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME);
|
||||
|
||||
if (interface_name != NULL) {
|
||||
socket.setsockopt(NSAPI_SOCKET, NSAPI_BIND_TO_DEVICE, interface_name, NSAPI_INTERFACE_NAME_MAX_SIZE);
|
||||
}
|
||||
// create network packet
|
||||
uint8_t *const packet = (uint8_t *)malloc(DNS_BUFFER_SIZE);
|
||||
if (!packet) {
|
||||
|
@ -471,7 +475,7 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
|
|||
// check against each dns server
|
||||
while (true) {
|
||||
SocketAddress dns_addr;
|
||||
err = nsapi_dns_get_server_addr(stack, &index, &total_attempts, &send_success, &dns_addr);
|
||||
err = nsapi_dns_get_server_addr(stack, &index, &total_attempts, &send_success, &dns_addr, interface_name);
|
||||
if (err != NSAPI_ERROR_OK) {
|
||||
break;
|
||||
}
|
||||
|
@ -540,17 +544,17 @@ static nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const
|
|||
|
||||
// convenience functions for other forms of queries
|
||||
extern "C" nsapi_size_or_error_t nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host,
|
||||
nsapi_addr_t *addr, nsapi_size_t addr_count, nsapi_version_t version)
|
||||
nsapi_addr_t *addr, nsapi_size_t addr_count, const char *interface_name, nsapi_version_t version)
|
||||
{
|
||||
NetworkStack *nstack = nsapi_create_stack(stack);
|
||||
return nsapi_dns_query_multiple(nstack, host, addr, addr_count, version);
|
||||
return nsapi_dns_query_multiple(nstack, host, addr, addr_count, interface_name, version);
|
||||
}
|
||||
|
||||
nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host,
|
||||
SocketAddress *addresses, nsapi_size_t addr_count, nsapi_version_t version)
|
||||
SocketAddress *addresses, nsapi_size_t addr_count, const char *interface_name, nsapi_version_t version)
|
||||
{
|
||||
nsapi_addr_t *addrs = new (std::nothrow) nsapi_addr_t[addr_count];
|
||||
nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, addrs, addr_count, version);
|
||||
nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, addrs, addr_count, interface_name, version);
|
||||
|
||||
if (result > 0) {
|
||||
for (int i = 0; i < result; i++) {
|
||||
|
@ -566,7 +570,7 @@ extern "C" nsapi_error_t nsapi_dns_query(nsapi_stack_t *stack, const char *host,
|
|||
nsapi_addr_t *addr, nsapi_version_t version)
|
||||
{
|
||||
NetworkStack *nstack = nsapi_create_stack(stack);
|
||||
nsapi_size_or_error_t result = nsapi_dns_query_multiple(nstack, host, addr, 1, version);
|
||||
nsapi_size_or_error_t result = nsapi_dns_query_multiple(nstack, host, addr, 1, NULL, version);
|
||||
return (nsapi_error_t)((result > 0) ? 0 : result);
|
||||
}
|
||||
|
||||
|
@ -574,7 +578,16 @@ nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
|
|||
SocketAddress *address, nsapi_version_t version)
|
||||
{
|
||||
nsapi_addr_t addr;
|
||||
nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, &addr, 1, version);
|
||||
nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, &addr, 1, NULL, version);
|
||||
address->set_addr(addr);
|
||||
return (nsapi_error_t)((result > 0) ? 0 : result);
|
||||
}
|
||||
|
||||
nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
|
||||
SocketAddress *address, const char *interface_name, nsapi_version_t version)
|
||||
{
|
||||
nsapi_addr_t addr;
|
||||
nsapi_size_or_error_t result = nsapi_dns_query_multiple(stack, host, &addr, 1, interface_name, version);
|
||||
address->set_addr(addr);
|
||||
return (nsapi_error_t)((result > 0) ? 0 : result);
|
||||
}
|
||||
|
@ -583,7 +596,14 @@ nsapi_value_or_error_t nsapi_dns_query_async(NetworkStack *stack, const char *ho
|
|||
NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb,
|
||||
nsapi_version_t version)
|
||||
{
|
||||
return nsapi_dns_query_multiple_async(stack, host, callback, 0, call_in_cb, version);
|
||||
return nsapi_dns_query_multiple_async(stack, host, callback, 0, call_in_cb, NULL, version);
|
||||
}
|
||||
|
||||
nsapi_value_or_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
|
||||
NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb,
|
||||
const char *interface_name, nsapi_version_t version)
|
||||
{
|
||||
return nsapi_dns_query_multiple_async(stack, host, callback, 0, call_in_cb, interface_name, version);
|
||||
}
|
||||
|
||||
void nsapi_dns_call_in_set(call_in_callback_cb_t callback)
|
||||
|
@ -603,7 +623,7 @@ nsapi_error_t nsapi_dns_call_in(call_in_callback_cb_t cb, int delay, mbed::Callb
|
|||
|
||||
nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *host,
|
||||
NetworkStack::hostbyname_cb_t callback, nsapi_size_t addr_count,
|
||||
call_in_callback_cb_t call_in_cb, nsapi_version_t version)
|
||||
call_in_callback_cb_t call_in_cb, const char *interface_name, nsapi_version_t version)
|
||||
{
|
||||
dns_mutex->lock();
|
||||
|
||||
|
@ -672,7 +692,7 @@ nsapi_value_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const
|
|||
query->total_timeout = MBED_CONF_NSAPI_DNS_TOTAL_ATTEMPTS * MBED_CONF_NSAPI_DNS_RESPONSE_WAIT_TIME + 500;
|
||||
query->count = 0;
|
||||
query->state = DNS_CREATED;
|
||||
|
||||
query->interface_name = interface_name;
|
||||
query->unique_id = dns_unique_id++;
|
||||
if (query->unique_id > 0x7FFF) {
|
||||
query->unique_id = 1;
|
||||
|
@ -870,6 +890,9 @@ static void nsapi_dns_query_async_create(void *ptr)
|
|||
}
|
||||
|
||||
socket->set_timeout(0);
|
||||
if (query->interface_name != NULL) {
|
||||
socket->setsockopt(NSAPI_SOCKET, NSAPI_BIND_TO_DEVICE, query->interface_name, NSAPI_INTERFACE_NAME_MAX_SIZE);
|
||||
}
|
||||
|
||||
if (!query->socket_cb_data) {
|
||||
query->socket_cb_data = new SOCKET_CB_DATA;
|
||||
|
@ -988,7 +1011,7 @@ static void nsapi_dns_query_async_send(void *ptr)
|
|||
|
||||
while (true) {
|
||||
SocketAddress dns_addr;
|
||||
nsapi_size_or_error_t err = nsapi_dns_get_server_addr(query->stack, &(query->dns_server), &(query->total_attempts), &(query->send_success), &dns_addr);
|
||||
nsapi_size_or_error_t err = nsapi_dns_get_server_addr(query->stack, &(query->dns_server), &(query->total_attempts), &(query->send_success), &dns_addr, query->interface_name);
|
||||
if (err != NSAPI_ERROR_OK) {
|
||||
nsapi_dns_query_async_resp(query, NSAPI_ERROR_TIMEOUT, NULL);
|
||||
free(packet);
|
||||
|
|
|
@ -59,7 +59,7 @@ nsapi_size_or_error_t nsapi_dns_query_multiple(nsapi_stack_t *stack, const char
|
|||
* @param addr Destination for the host address
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr);
|
||||
nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr, const char *interface_name);
|
||||
|
||||
|
||||
#else
|
||||
|
@ -78,6 +78,20 @@ typedef mbed::Callback<nsapi_error_t (int delay_ms, mbed::Callback<void()> user_
|
|||
nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
|
||||
SocketAddress *addr, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
/** Query a domain name server for an IP address of a given hostname using Network interface name
|
||||
*
|
||||
* @param stack Network stack as target for DNS query
|
||||
* @param host Hostname to resolve
|
||||
* @param addr Destination for the host address
|
||||
* @param interface_name Network interface name
|
||||
* @param version IP version to resolve (defaults to NSAPI_IPv4)
|
||||
* @return 0 on success, negative error code on failure
|
||||
* NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
|
||||
*/
|
||||
nsapi_error_t nsapi_dns_query(NetworkStack *stack, const char *host,
|
||||
SocketAddress *addr, const char *interface_name, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
|
||||
/** Query a domain name server for an IP address of a given hostname
|
||||
*
|
||||
* @param stack Network stack as target for DNS query
|
||||
|
@ -92,6 +106,21 @@ nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
|
|||
NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb,
|
||||
nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
/** Query a domain name server for an IP address of a given hostname using Network interface name
|
||||
*
|
||||
* @param stack Network stack as target for DNS query
|
||||
* @param host Hostname to resolve
|
||||
* @param callback Callback that is called for result
|
||||
* @param interface_name Network interface name
|
||||
* @param version IP version to resolve (defaults to NSAPI_IPv4)
|
||||
* @return 0 on success, negative error code on failure or an unique id that
|
||||
* represents the hostname translation operation and can be passed to
|
||||
* cancel, NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
|
||||
*/
|
||||
nsapi_error_t nsapi_dns_query_async(NetworkStack *stack, const char *host,
|
||||
NetworkStack::hostbyname_cb_t callback, call_in_callback_cb_t call_in_cb,
|
||||
const char *interface_name, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
/** Query a domain name server for an IP address of a given hostname (asynchronous)
|
||||
*
|
||||
* @param stack Network stack as target for DNS query
|
||||
|
@ -131,7 +160,7 @@ nsapi_error_t nsapi_dns_query(S *stack, const char *host,
|
|||
* NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
|
||||
*/
|
||||
nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *host,
|
||||
SocketAddress *addr, nsapi_size_t addr_count, nsapi_version_t version = NSAPI_IPv4);
|
||||
SocketAddress *addr, nsapi_size_t addr_count, const char *interface_name, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
/** Query a domain name server for an IP address of a given hostname (asynchronous)
|
||||
*
|
||||
|
@ -146,7 +175,7 @@ nsapi_size_or_error_t nsapi_dns_query_multiple(NetworkStack *stack, const char *
|
|||
*/
|
||||
nsapi_size_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const char *host,
|
||||
NetworkStack::hostbyname_cb_t callback, nsapi_size_t addr_count,
|
||||
call_in_callback_cb_t call_in_cb, nsapi_version_t version = NSAPI_IPv4);
|
||||
call_in_callback_cb_t call_in_cb, const char *interface_name, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
/** Query a domain name server for multiple IP address of a given hostname
|
||||
*
|
||||
|
@ -159,7 +188,7 @@ nsapi_size_or_error_t nsapi_dns_query_multiple_async(NetworkStack *stack, const
|
|||
* NSAPI_ERROR_DNS_FAILURE indicates the host could not be found
|
||||
*/
|
||||
extern "C" nsapi_size_or_error_t nsapi_dns_query_multiple(nsapi_stack_t *stack, const char *host,
|
||||
nsapi_addr_t *addr, nsapi_size_t addr_count, nsapi_version_t version = NSAPI_IPv4);
|
||||
nsapi_addr_t *addr, nsapi_size_t addr_count, const char *interface_name, nsapi_version_t version = NSAPI_IPv4);
|
||||
|
||||
|
||||
/** Query a domain name server for multiple IP address of a given hostname
|
||||
|
@ -204,16 +233,16 @@ void nsapi_dns_call_in_set(call_in_callback_cb_t callback);
|
|||
* @param addr Destination for the host address
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr);
|
||||
extern "C" nsapi_error_t nsapi_dns_add_server(nsapi_addr_t addr, const char *interface_name);
|
||||
|
||||
/** Add a domain name server to list of servers to query
|
||||
*
|
||||
* @param addr Destination for the host address
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
static inline nsapi_error_t nsapi_dns_add_server(const SocketAddress &address)
|
||||
static inline nsapi_error_t nsapi_dns_add_server(const SocketAddress &address, const char *interface_name)
|
||||
{
|
||||
return nsapi_dns_add_server(address.get_addr());
|
||||
return nsapi_dns_add_server(address.get_addr(), interface_name);
|
||||
}
|
||||
|
||||
/** Add a domain name server to list of servers to query
|
||||
|
@ -221,9 +250,9 @@ static inline nsapi_error_t nsapi_dns_add_server(const SocketAddress &address)
|
|||
* @param addr Destination for the host address
|
||||
* @return 0 on success, negative error code on failure
|
||||
*/
|
||||
static inline nsapi_error_t nsapi_dns_add_server(const char *address)
|
||||
static inline nsapi_error_t nsapi_dns_add_server(const char *address, const char *interface_name)
|
||||
{
|
||||
return nsapi_dns_add_server(SocketAddress(address));
|
||||
return nsapi_dns_add_server(SocketAddress(address), interface_name);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -128,9 +128,13 @@ typedef enum nsapi_security {
|
|||
NSAPI_SECURITY_UNKNOWN = 0xFF, /*!< unknown/unsupported security in scan results */
|
||||
} nsapi_security_t;
|
||||
|
||||
/** Size of 2 char network interface name from driver
|
||||
*/
|
||||
#define NSAPI_INTERFACE_PREFIX_SIZE 2
|
||||
|
||||
/** Maximum size of network interface name
|
||||
*/
|
||||
#define NSAPI_INTERFACE_NAME_SIZE 2
|
||||
#define NSAPI_INTERFACE_NAME_MAX_SIZE 6
|
||||
|
||||
/** Maximum size of IP address representation
|
||||
*/
|
||||
|
@ -259,6 +263,7 @@ typedef enum nsapi_socket_option {
|
|||
NSAPI_RCVBUF, /*!< Sets recv buffer size */
|
||||
NSAPI_ADD_MEMBERSHIP, /*!< Add membership to multicast address */
|
||||
NSAPI_DROP_MEMBERSHIP, /*!< Drop membership to multicast address */
|
||||
NSAPI_BIND_TO_DEVICE, /*!< Bind socket network interface name*/
|
||||
} nsapi_socket_option_t;
|
||||
|
||||
/** Supported IP protocol versions of IP stack
|
||||
|
|