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 virtual_interface_context *ctx;
49 	struct net_shell_user_data *data = user_data;
50 	const struct shell *sh = data->sh;
51 	int *count = data->user_data;
52 	char name[NET_IFNAMSIZ];
53 
54 	if (!net_eth_is_vlan_interface(iface)) {
55 		return;
56 	}
57 
58 
59 	if (*count == 0) {
60 		PR("    Interface  Name        \tTag\tAttached\n");
61 	}
62 
63 	(void)net_if_get_name(iface, name, sizeof(name));
64 
65 	ctx = net_if_l2_data(iface);
66 	if (ctx->iface != NULL) {
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 	} else {
71 		PR("[%d] %p  %-12s\n", net_if_get_by_iface(iface), iface, name);
72 	}
73 
74 	(*count)++;
75 }
76 #endif /* CONFIG_NET_VLAN */
77 
cmd_net_vlan(const struct shell * sh,size_t argc,char * argv[])78 static int cmd_net_vlan(const struct shell *sh, size_t argc, char *argv[])
79 {
80 #if defined(CONFIG_NET_VLAN)
81 	struct net_shell_user_data user_data;
82 	int count = 0;
83 
84 	user_data.sh = sh;
85 	user_data.user_data = &count;
86 
87 	net_if_foreach(iface_vlan_cb, &user_data);
88 #else
89 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_VLAN", "VLAN");
90 #endif /* CONFIG_NET_VLAN */
91 
92 	return 0;
93 }
94 
cmd_net_vlan_add(const struct shell * sh,size_t argc,char * argv[])95 static int cmd_net_vlan_add(const struct shell *sh, size_t argc, char *argv[])
96 {
97 #if defined(CONFIG_NET_VLAN)
98 	int arg = 0;
99 	int ret;
100 	uint16_t tag;
101 	struct net_if *iface;
102 	char *endptr;
103 	uint32_t iface_idx;
104 
105 	/* vlan add <tag> <interface index> */
106 	if (!argv[++arg]) {
107 		PR_WARNING("VLAN tag missing.\n");
108 		goto usage;
109 	}
110 
111 	tag = strtol(argv[arg], &endptr, 10);
112 	if (*endptr != '\0') {
113 		PR_WARNING("Invalid tag %s\n", argv[arg]);
114 		return -ENOEXEC;
115 	}
116 
117 	if (!argv[++arg]) {
118 		PR_WARNING("Network interface index missing.\n");
119 		goto usage;
120 	}
121 
122 	iface_idx = strtol(argv[arg], &endptr, 10);
123 	if (*endptr != '\0') {
124 		PR_WARNING("Invalid index %s\n", argv[arg]);
125 		goto usage;
126 	}
127 
128 	iface = net_if_get_by_index(iface_idx);
129 	if (!iface) {
130 		PR_WARNING("Network interface index %d is invalid.\n",
131 			   iface_idx);
132 		goto usage;
133 	}
134 
135 	if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
136 		PR_WARNING("Network interface %d (%p) is not ethernet interface\n",
137 			   net_if_get_by_iface(iface), iface);
138 		return -ENOEXEC;
139 	}
140 
141 	ret = net_eth_vlan_enable(iface, tag);
142 	if (ret < 0) {
143 		if (ret == -ENOENT) {
144 			PR_WARNING("No IP address configured.\n");
145 		}
146 
147 		PR_WARNING("Cannot set VLAN tag (%d)\n", ret);
148 
149 		return -ENOEXEC;
150 	}
151 
152 	iface = net_eth_get_vlan_iface(iface, tag);
153 
154 	PR("VLAN tag %d set to interface %d (%p)\n", tag,
155 	   net_if_get_by_iface(iface), iface);
156 
157 	return 0;
158 
159 usage:
160 	PR("Usage:\n");
161 	PR("\tvlan add <tag> <interface index>\n");
162 #else
163 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_VLAN", "VLAN");
164 #endif /* CONFIG_NET_VLAN */
165 
166 	return 0;
167 }
168 
cmd_net_vlan_del(const struct shell * sh,size_t argc,char * argv[])169 static int cmd_net_vlan_del(const struct shell *sh, size_t argc, char *argv[])
170 {
171 #if defined(CONFIG_NET_VLAN)
172 	int arg = 0;
173 	struct net_shell_user_data user_data;
174 	char *endptr;
175 	uint16_t tag;
176 
177 	/* vlan del <tag> */
178 	if (!argv[++arg]) {
179 		PR_WARNING("VLAN tag missing.\n");
180 		goto usage;
181 	}
182 
183 	tag = strtol(argv[arg], &endptr, 10);
184 	if (*endptr != '\0') {
185 		PR_WARNING("Invalid tag %s\n", argv[arg]);
186 		return -ENOEXEC;
187 	}
188 
189 	user_data.sh = sh;
190 	user_data.user_data = UINT_TO_POINTER((uint32_t)tag);
191 
192 	net_if_foreach(iface_vlan_del_cb, &user_data);
193 
194 	return 0;
195 
196 usage:
197 	PR("Usage:\n");
198 	PR("\tvlan del <tag>\n");
199 #else
200 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_VLAN", "VLAN");
201 #endif /* CONFIG_NET_VLAN */
202 
203 	return 0;
204 }
205 
206 SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_vlan,
207 	SHELL_CMD_ARG(add, NULL,
208 		      "'net vlan add <tag> <index>' adds VLAN tag to the "
209 		      "network interface.",
210 		      cmd_net_vlan_add, 3, 0),
211 	SHELL_CMD_ARG(del, NULL,
212 		      "'net vlan del <tag>' deletes VLAN tag from the network "
213 		      "interface.",
214 		      cmd_net_vlan_del, 2, 0),
215 	SHELL_SUBCMD_SET_END
216 );
217 
218 SHELL_SUBCMD_ADD((net), vlan, &net_cmd_vlan,
219 		 "Show VLAN information.",
220 		 cmd_net_vlan, 1, 0);
221