1 /*
2  * Copyright (c) 2016 Intel Corporation
3  * Copyright (c) 2023 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(net_shell);
10 
11 #if defined(CONFIG_NET_L2_VIRTUAL)
12 #include <zephyr/net/virtual.h>
13 #endif
14 #include <zephyr/net/ethernet.h>
15 
16 #include <zephyr/net/socket.h>
17 #include <stdlib.h>
18 
19 #include "net_shell_private.h"
20 
21 #if defined(CONFIG_NET_VLAN)
iface_vlan_del_cb(struct net_if * iface,void * user_data)22 static void iface_vlan_del_cb(struct net_if *iface, void *user_data)
23 {
24 	struct net_shell_user_data *data = user_data;
25 	const struct shell *sh = data->sh;
26 	uint16_t vlan_tag = POINTER_TO_UINT(data->user_data);
27 	int ret;
28 
29 	ret = net_eth_vlan_disable(iface, vlan_tag);
30 	if (ret < 0) {
31 		if (ret != -ESRCH) {
32 			PR_WARNING("Cannot delete VLAN tag %d from "
33 				   "interface %d (%p)\n",
34 				   vlan_tag,
35 				   net_if_get_by_iface(iface),
36 				   iface);
37 		}
38 
39 		return;
40 	}
41 
42 	PR("VLAN tag %d removed from interface %d (%p)\n", vlan_tag,
43 	   net_if_get_by_iface(iface), iface);
44 }
45 
iface_vlan_cb(struct net_if * iface,void * user_data)46 static void iface_vlan_cb(struct net_if *iface, void *user_data)
47 {
48 	struct net_shell_user_data *data = user_data;
49 	const struct shell *sh = data->sh;
50 	int *count = data->user_data;
51 	char name[IFNAMSIZ];
52 
53 	if (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
54 		return;
55 	}
56 
57 	if (!(net_virtual_get_iface_capabilities(iface) & VIRTUAL_INTERFACE_VLAN)) {
58 		return;
59 	}
60 
61 	if (*count == 0) {
62 		PR("    Interface  Name        \tTag\tAttached\n");
63 	}
64 
65 	(void)net_if_get_name(iface, name, sizeof(name));
66 
67 	PR("[%d] %p  %-12s\t%d\t%d\n", net_if_get_by_iface(iface), iface,
68 	   name, net_eth_get_vlan_tag(iface),
69 	   net_if_get_by_iface(net_eth_get_vlan_main(iface)));
70 
71 	(*count)++;
72 }
73 #endif /* CONFIG_NET_VLAN */
74 
cmd_net_vlan(const struct shell * sh,size_t argc,char * argv[])75 static int cmd_net_vlan(const struct shell *sh, size_t argc, char *argv[])
76 {
77 #if defined(CONFIG_NET_VLAN)
78 	struct net_shell_user_data user_data;
79 	int count = 0;
80 
81 	user_data.sh = sh;
82 	user_data.user_data = &count;
83 
84 	net_if_foreach(iface_vlan_cb, &user_data);
85 #else
86 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_VLAN", "VLAN");
87 #endif /* CONFIG_NET_VLAN */
88 
89 	return 0;
90 }
91 
cmd_net_vlan_add(const struct shell * sh,size_t argc,char * argv[])92 static int cmd_net_vlan_add(const struct shell *sh, size_t argc, char *argv[])
93 {
94 #if defined(CONFIG_NET_VLAN)
95 	int arg = 0;
96 	int ret;
97 	uint16_t tag;
98 	struct net_if *iface;
99 	char *endptr;
100 	uint32_t iface_idx;
101 
102 	/* vlan add <tag> <interface index> */
103 	if (!argv[++arg]) {
104 		PR_WARNING("VLAN tag missing.\n");
105 		goto usage;
106 	}
107 
108 	tag = strtol(argv[arg], &endptr, 10);
109 	if (*endptr != '\0') {
110 		PR_WARNING("Invalid tag %s\n", argv[arg]);
111 		return -ENOEXEC;
112 	}
113 
114 	if (!argv[++arg]) {
115 		PR_WARNING("Network interface index missing.\n");
116 		goto usage;
117 	}
118 
119 	iface_idx = strtol(argv[arg], &endptr, 10);
120 	if (*endptr != '\0') {
121 		PR_WARNING("Invalid index %s\n", argv[arg]);
122 		goto usage;
123 	}
124 
125 	iface = net_if_get_by_index(iface_idx);
126 	if (!iface) {
127 		PR_WARNING("Network interface index %d is invalid.\n",
128 			   iface_idx);
129 		goto usage;
130 	}
131 
132 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
133 		PR_WARNING("Network interface %d (%p) is not ethernet interface\n",
134 			   net_if_get_by_iface(iface), iface);
135 		return -ENOEXEC;
136 	}
137 
138 	ret = net_eth_vlan_enable(iface, tag);
139 	if (ret < 0) {
140 		if (ret == -ENOENT) {
141 			PR_WARNING("No IP address configured.\n");
142 		}
143 
144 		PR_WARNING("Cannot set VLAN tag (%d)\n", ret);
145 
146 		return -ENOEXEC;
147 	}
148 
149 	iface = net_eth_get_vlan_iface(iface, tag);
150 
151 	PR("VLAN tag %d set to interface %d (%p)\n", tag,
152 	   net_if_get_by_iface(iface), iface);
153 
154 	return 0;
155 
156 usage:
157 	PR("Usage:\n");
158 	PR("\tvlan add <tag> <interface index>\n");
159 #else
160 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_VLAN", "VLAN");
161 #endif /* CONFIG_NET_VLAN */
162 
163 	return 0;
164 }
165 
cmd_net_vlan_del(const struct shell * sh,size_t argc,char * argv[])166 static int cmd_net_vlan_del(const struct shell *sh, size_t argc, char *argv[])
167 {
168 #if defined(CONFIG_NET_VLAN)
169 	int arg = 0;
170 	struct net_shell_user_data user_data;
171 	char *endptr;
172 	uint16_t tag;
173 
174 	/* vlan del <tag> */
175 	if (!argv[++arg]) {
176 		PR_WARNING("VLAN tag missing.\n");
177 		goto usage;
178 	}
179 
180 	tag = strtol(argv[arg], &endptr, 10);
181 	if (*endptr != '\0') {
182 		PR_WARNING("Invalid tag %s\n", argv[arg]);
183 		return -ENOEXEC;
184 	}
185 
186 	user_data.sh = sh;
187 	user_data.user_data = UINT_TO_POINTER((uint32_t)tag);
188 
189 	net_if_foreach(iface_vlan_del_cb, &user_data);
190 
191 	return 0;
192 
193 usage:
194 	PR("Usage:\n");
195 	PR("\tvlan del <tag>\n");
196 #else
197 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_VLAN", "VLAN");
198 #endif /* CONFIG_NET_VLAN */
199 
200 	return 0;
201 }
202 
203 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_vlan,
204 	SHELL_CMD_ARG(add, NULL,
205 		      "'net vlan add <tag> <index>' adds VLAN tag to the "
206 		      "network interface.",
207 		      cmd_net_vlan_add, 3, 0),
208 	SHELL_CMD_ARG(del, NULL,
209 		      "'net vlan del <tag>' deletes VLAN tag from the network "
210 		      "interface.",
211 		      cmd_net_vlan_del, 2, 0),
212 	SHELL_SUBCMD_SET_END
213 );
214 
215 SHELL_SUBCMD_ADD((net), vlan, &net_cmd_vlan,
216 		 "Show VLAN information.",
217 		 cmd_net_vlan, 1, 0);
218