1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright (c) 2025 Nordic Semiconductor
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_samples_common, LOG_LEVEL_DBG);
10
11 #include <stdlib.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/posix/arpa/inet.h>
14 #include <zephyr/net/ethernet.h>
15
16 /* User data for the interface callback */
17 struct ud {
18 struct net_if *first;
19 struct net_if *second;
20 struct net_if *eth;
21 };
22
iface_cb(struct net_if * iface,void * user_data)23 static void iface_cb(struct net_if *iface, void *user_data)
24 {
25 struct ud *ud = user_data;
26
27 if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET) && ud->eth == NULL) {
28 ud->eth = iface;
29 return;
30 }
31
32 if (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
33 return;
34 }
35
36 if (!ud->first) {
37 ud->first = iface;
38 return;
39 }
40
41 if (!ud->second) {
42 ud->second = iface;
43 return;
44 }
45 }
46
setup_iface(struct net_if * eth_iface,struct net_if * vlan_iface,const char * option)47 static int setup_iface(struct net_if *eth_iface,
48 struct net_if *vlan_iface,
49 const char *option)
50 {
51 struct sockaddr_storage addr = { 0 };
52 struct sockaddr *paddr = (struct sockaddr *)&addr;
53 const char *addr_str, *next;
54 struct net_if_addr *ifaddr;
55 uint8_t mask_len = 0;
56 unsigned long value;
57 uint16_t vlan_tag;
58 char *endptr;
59 bool status;
60 int ret;
61
62 if (option[0] == '\0') {
63 return 0;
64 }
65
66 next = strstr(option, ";");
67 if (next == NULL) {
68 LOG_ERR("VLAN tag not found, invalid option \"%s\"", option);
69 return -EINVAL;
70 }
71
72 value = strtoul(option, &endptr, 10);
73 if (*endptr != '\0' && endptr != next) {
74 LOG_ERR("Invalid VLAN tag \"%s\"", option);
75 return -EINVAL;
76 }
77
78 vlan_tag = (uint16_t)value;
79 addr_str = ++next;
80
81 do {
82 char my_addr[INET6_ADDRSTRLEN] = { 'N', 'o', ' ', 'I', 'P', '\0'};
83
84 next = net_ipaddr_parse_mask(addr_str, strlen(addr_str),
85 paddr, &mask_len);
86 if (next == NULL) {
87 LOG_ERR("Cannot parse IP address \"%s\"", addr_str);
88 return -EINVAL;
89 }
90
91 inet_ntop(paddr->sa_family, net_sin(paddr)->sin_addr.s4_addr,
92 my_addr, sizeof(my_addr));
93
94 if (paddr->sa_family == AF_INET) {
95 struct sockaddr_in *addr4 = (struct sockaddr_in *)paddr;
96 struct sockaddr_in mask;
97
98 ifaddr = net_if_ipv4_addr_add(vlan_iface, &addr4->sin_addr,
99 NET_ADDR_MANUAL, 0);
100
101 ret = net_mask_len_to_netmask(AF_INET, mask_len,
102 (struct sockaddr *)&mask);
103 if (ret < 0) {
104 LOG_ERR("Invalid network mask length (%d)", ret);
105 return ret;
106 }
107
108 status = net_if_ipv4_set_netmask_by_addr(vlan_iface,
109 &addr4->sin_addr,
110 &mask.sin_addr);
111
112 } else if (paddr->sa_family == AF_INET6) {
113 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)paddr;
114 struct in6_addr netaddr6;
115
116 ifaddr = net_if_ipv6_addr_add(vlan_iface, &addr6->sin6_addr,
117 NET_ADDR_MANUAL, 0);
118
119 net_ipv6_addr_prefix_mask((uint8_t *)&addr6->sin6_addr,
120 (uint8_t *)&netaddr6,
121 mask_len);
122
123 if (!net_if_ipv6_prefix_add(vlan_iface, &netaddr6, mask_len,
124 (uint32_t)0xffffffff)) {
125 LOG_ERR("Cannot add %s to interface %d", my_addr,
126 net_if_get_by_iface(vlan_iface));
127 return -EINVAL;
128 }
129
130 } else {
131 LOG_ERR("Cannot parse IP address \"%s\"", my_addr);
132 return -EAFNOSUPPORT;
133 }
134
135 if (ifaddr == NULL) {
136 LOG_ERR("Cannot add IP address \"%s\" to interface %d",
137 my_addr, net_if_get_by_iface(vlan_iface));
138 return -ENOENT;
139 }
140
141 addr_str = next;
142 } while (addr_str != NULL && *addr_str != '\0');
143
144 ret = net_eth_vlan_enable(eth_iface, vlan_tag);
145 if (ret < 0) {
146 LOG_ERR("Cannot enable VLAN for tag %d (%d)", vlan_tag, ret);
147 }
148
149 LOG_DBG("Interface %d VLAN tag %d setup done.",
150 net_if_get_by_iface(vlan_iface), vlan_tag);
151
152 /* Take the interface up if the setup was ok */
153 net_if_up(vlan_iface);
154
155 return 0;
156 }
157
init_vlan(void)158 int init_vlan(void)
159 {
160 struct ud user_data;
161 int ret;
162
163 if (CONFIG_NET_VLAN_COUNT == 0) {
164 LOG_DBG("No VLAN interfaces defined.");
165 return 0;
166 }
167
168 memset(&user_data, 0, sizeof(user_data));
169
170 net_if_foreach(iface_cb, &user_data);
171
172 /* This sample has two VLANs. For the second one we need to manually
173 * create IP address for this test. But first the VLAN needs to be
174 * added to the interface so that IPv6 DAD can work properly.
175 */
176 ret = setup_iface(user_data.eth, user_data.first,
177 CONFIG_NET_SAMPLE_COMMON_VLAN_SETUP_1);
178 if (ret < 0) {
179 return ret;
180 }
181
182 ret = setup_iface(user_data.eth, user_data.second,
183 CONFIG_NET_SAMPLE_COMMON_VLAN_SETUP_2);
184 if (ret < 0) {
185 return ret;
186 }
187
188 return 0;
189 }
190