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