| /* |
| * Copyright (c) 2021 Intel Corporation. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <logging/log.h> |
| LOG_MODULE_DECLARE(net_echo_server_sample, LOG_LEVEL_DBG); |
| |
| #include <zephyr.h> |
| |
| #include <net/ethernet.h> |
| #include <net/virtual_mgmt.h> |
| |
| /* 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)) { |
| 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; |
| |
| 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 (CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR[0] == '\0') { |
| LOG_INF("Tunnel peer address not set."); |
| return 0; |
| } |
| |
| if (!net_ipaddr_parse(CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR, |
| strlen(CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR), |
| &peer)) { |
| LOG_ERR("Tunnel peer address \"%s\" invalid.", |
| CONFIG_NET_SAMPLE_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", |
| CONFIG_NET_SAMPLE_TUNNEL_PEER_ADDR); |
| return -ENETUNREACH; |
| } |
| |
| net_if_foreach(iface_cb, &ud); |
| |
| 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)", |
| CONFIG_NET_SAMPLE_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, |
| CONFIG_NET_SAMPLE_TUNNEL_MY_ADDR); |
| if (ret < 0) { |
| LOG_ERR("Cannot set IP address %s to tunnel interface", |
| CONFIG_NET_SAMPLE_TUNNEL_MY_ADDR); |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |