Make sure that we have always a default value for tunnel peer and local addresses. Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
185 lines
4.4 KiB
C
185 lines
4.4 KiB
C
/*
|
|
* Copyright (c) 2021 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_DECLARE(net_samples_common, LOG_LEVEL_DBG);
|
|
|
|
#include <zephyr/kernel.h>
|
|
|
|
#include <zephyr/net/ethernet.h>
|
|
#include <zephyr/net/virtual_mgmt.h>
|
|
#include <zephyr/net/conn_mgr_monitor.h>
|
|
|
|
#if defined(CONFIG_NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR)
|
|
#define NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR CONFIG_NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR
|
|
#else
|
|
#define NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR ""
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_SAMPLE_COMMON_TUNNEL_MY_ADDR)
|
|
#define NET_SAMPLE_COMMON_TUNNEL_MY_ADDR CONFIG_NET_SAMPLE_COMMON_TUNNEL_MY_ADDR
|
|
#else
|
|
#define NET_SAMPLE_COMMON_TUNNEL_MY_ADDR ""
|
|
#endif
|
|
|
|
/* User data for the interface callback */
|
|
struct ud {
|
|
struct net_if *tunnel;
|
|
struct net_if *peer;
|
|
};
|
|
|
|
bool is_tunnel(struct net_if *iface)
|
|
{
|
|
if (net_if_l2(iface) == &NET_L2_GET_NAME(VIRTUAL) &&
|
|
strncmp(net_if_get_device(iface)->name, "IP_TUNNEL0",
|
|
strlen(net_if_get_device(iface)->name)) == 0) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void iface_cb(struct net_if *iface, void *user_data)
|
|
{
|
|
struct ud *ud = user_data;
|
|
|
|
if (!ud->tunnel && is_tunnel(iface)) {
|
|
ud->tunnel = iface;
|
|
return;
|
|
}
|
|
}
|
|
|
|
static int setup_iface(struct net_if *iface, const char *ipaddr)
|
|
{
|
|
struct net_if_addr *ifaddr;
|
|
struct sockaddr addr;
|
|
|
|
/* Before setting up tunnel, make sure it will be ignored by conn_mgr */
|
|
conn_mgr_ignore_iface(iface);
|
|
|
|
if (!net_ipaddr_parse(ipaddr, strlen(ipaddr), &addr)) {
|
|
LOG_ERR("Tunnel peer address \"%s\" invalid.", ipaddr);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) && addr.sa_family == AF_INET6) {
|
|
ifaddr = net_if_ipv6_addr_add(iface,
|
|
&net_sin6(&addr)->sin6_addr,
|
|
NET_ADDR_MANUAL, 0);
|
|
if (!ifaddr) {
|
|
LOG_ERR("Cannot add %s to interface %d",
|
|
ipaddr, net_if_get_by_iface(iface));
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV4) && addr.sa_family == AF_INET) {
|
|
ifaddr = net_if_ipv4_addr_add(iface,
|
|
&net_sin(&addr)->sin_addr,
|
|
NET_ADDR_MANUAL, 0);
|
|
if (!ifaddr) {
|
|
LOG_ERR("Cannot add %s to interface %d",
|
|
ipaddr, net_if_get_by_iface(iface));
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int init_tunnel(void)
|
|
{
|
|
struct virtual_interface_req_params params = { 0 };
|
|
struct sockaddr peer = { 0 };
|
|
struct ud ud;
|
|
int ret;
|
|
int mtu;
|
|
|
|
memset(&ud, 0, sizeof(ud));
|
|
|
|
if (NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR[0] == '\0') {
|
|
LOG_INF("Tunnel peer address not set.");
|
|
return 0;
|
|
}
|
|
|
|
if (!net_ipaddr_parse(NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR,
|
|
strlen(NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR),
|
|
&peer)) {
|
|
LOG_ERR("Tunnel peer address \"%s\" invalid.",
|
|
NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6) && peer.sa_family == AF_INET6) {
|
|
struct net_if *iface;
|
|
|
|
iface = net_if_ipv6_select_src_iface(
|
|
&net_sin6(&peer)->sin6_addr);
|
|
ud.peer = iface;
|
|
params.family = AF_INET6;
|
|
net_ipaddr_copy(¶ms.peer6addr,
|
|
&net_sin6(&peer)->sin6_addr);
|
|
mtu = NET_ETH_MTU - sizeof(struct net_ipv6_hdr);
|
|
|
|
} else if (IS_ENABLED(CONFIG_NET_IPV4) && peer.sa_family == AF_INET) {
|
|
struct net_if *iface;
|
|
|
|
iface = net_if_ipv4_select_src_iface(
|
|
&net_sin(&peer)->sin_addr);
|
|
ud.peer = iface;
|
|
params.family = AF_INET;
|
|
net_ipaddr_copy(¶ms.peer4addr,
|
|
&net_sin(&peer)->sin_addr);
|
|
mtu = NET_ETH_MTU - sizeof(struct net_ipv4_hdr);
|
|
|
|
} else {
|
|
LOG_ERR("Invalid address family %d", peer.sa_family);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (ud.peer == NULL) {
|
|
LOG_ERR("Peer address %s unreachable",
|
|
NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR);
|
|
return -ENETUNREACH;
|
|
}
|
|
|
|
net_if_foreach(iface_cb, &ud);
|
|
|
|
if (ud.tunnel == NULL) {
|
|
LOG_ERR("Tunnel interface not found.");
|
|
return -ENOENT;
|
|
}
|
|
|
|
ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_PEER_ADDRESS,
|
|
ud.tunnel, ¶ms, sizeof(params));
|
|
if (ret < 0 && ret != -ENOTSUP) {
|
|
LOG_ERR("Cannot set peer address %s to "
|
|
"interface %d (%d)",
|
|
NET_SAMPLE_COMMON_TUNNEL_PEER_ADDR,
|
|
net_if_get_by_iface(ud.tunnel),
|
|
ret);
|
|
}
|
|
|
|
params.mtu = mtu;
|
|
|
|
ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_MTU,
|
|
ud.tunnel, ¶ms, sizeof(params));
|
|
if (ret < 0 && ret != -ENOTSUP) {
|
|
LOG_ERR("Cannot set interface %d MTU to %d (%d)",
|
|
net_if_get_by_iface(ud.tunnel), params.mtu, ret);
|
|
}
|
|
|
|
ret = setup_iface(ud.tunnel,
|
|
NET_SAMPLE_COMMON_TUNNEL_MY_ADDR);
|
|
if (ret < 0) {
|
|
LOG_ERR("Cannot set IP address %s to tunnel interface",
|
|
NET_SAMPLE_COMMON_TUNNEL_MY_ADDR);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|