We need to set a proper IPv4 netmask to each VLAN interface so that IPv4 source address selection will work properly. If we do not do this, then the network interface could be selected incorrectly for the VLAN interfaces which could then mean that the packet might get dropped by the target device. Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
136 lines
2.8 KiB
C
136 lines
2.8 KiB
C
/*
|
|
* Copyright (c) 2018 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>
|
|
|
|
/* User data for the interface callback */
|
|
struct ud {
|
|
struct net_if *first;
|
|
struct net_if *second;
|
|
struct net_if *third;
|
|
};
|
|
|
|
static void iface_cb(struct net_if *iface, void *user_data)
|
|
{
|
|
struct ud *ud = user_data;
|
|
|
|
if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
|
|
return;
|
|
}
|
|
|
|
if (!ud->first) {
|
|
ud->first = iface;
|
|
return;
|
|
}
|
|
|
|
if (!ud->second) {
|
|
ud->second = iface;
|
|
return;
|
|
}
|
|
|
|
if (!ud->third) {
|
|
ud->third = iface;
|
|
return;
|
|
}
|
|
}
|
|
|
|
static int setup_iface(struct net_if *iface, const char *ipv6_addr,
|
|
const char *ipv4_addr, const char *netmask,
|
|
uint16_t vlan_tag)
|
|
{
|
|
struct net_if_addr *ifaddr;
|
|
struct in_addr addr4;
|
|
struct in6_addr addr6;
|
|
int ret;
|
|
|
|
ret = net_eth_vlan_enable(iface, vlan_tag);
|
|
if (ret < 0) {
|
|
LOG_ERR("Cannot enable VLAN for tag %d (%d)", vlan_tag, ret);
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV6)) {
|
|
if (net_addr_pton(AF_INET6, ipv6_addr, &addr6)) {
|
|
LOG_ERR("Invalid address: %s", ipv6_addr);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ifaddr = net_if_ipv6_addr_add(iface, &addr6,
|
|
NET_ADDR_MANUAL, 0);
|
|
if (!ifaddr) {
|
|
LOG_ERR("Cannot add %s to interface %p",
|
|
ipv6_addr, iface);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_NET_IPV4)) {
|
|
if (net_addr_pton(AF_INET, ipv4_addr, &addr4)) {
|
|
LOG_ERR("Invalid address: %s", ipv4_addr);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ifaddr = net_if_ipv4_addr_add(iface, &addr4,
|
|
NET_ADDR_MANUAL, 0);
|
|
if (!ifaddr) {
|
|
LOG_ERR("Cannot add %s to interface %p",
|
|
ipv4_addr, iface);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (netmask && netmask[0]) {
|
|
if (net_addr_pton(AF_INET, netmask, &addr4)) {
|
|
LOG_ERR("Invalid netmask: %s", ipv4_addr);
|
|
return -EINVAL;
|
|
}
|
|
|
|
net_if_ipv4_set_netmask(iface, &addr4);
|
|
}
|
|
}
|
|
|
|
LOG_DBG("Interface %p VLAN tag %d setup done.", iface, vlan_tag);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int init_vlan(void)
|
|
{
|
|
struct ud ud;
|
|
int ret;
|
|
|
|
memset(&ud, 0, sizeof(ud));
|
|
|
|
net_if_foreach(iface_cb, &ud);
|
|
|
|
/* This sample has two VLANs. For the second one we need to manually
|
|
* create IP address for this test. But first the VLAN needs to be
|
|
* added to the interface so that IPv6 DAD can work properly.
|
|
*/
|
|
ret = setup_iface(ud.second,
|
|
CONFIG_NET_SAMPLE_IFACE2_MY_IPV6_ADDR,
|
|
CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_ADDR,
|
|
CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_NETMASK,
|
|
CONFIG_NET_SAMPLE_IFACE2_VLAN_TAG);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = setup_iface(ud.third,
|
|
CONFIG_NET_SAMPLE_IFACE3_MY_IPV6_ADDR,
|
|
CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_ADDR,
|
|
CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_NETMASK,
|
|
CONFIG_NET_SAMPLE_IFACE3_VLAN_TAG);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|