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 #include <stdlib.h>
12 
13 #if defined(CONFIG_NET_L2_VIRTUAL)
14 #include <zephyr/net/virtual.h>
15 #endif
16 
17 #include "net_shell_private.h"
18 
19 #if defined(CONFIG_NET_L2_VIRTUAL)
virtual_iface_cb(struct net_if * iface,void * user_data)20 static void virtual_iface_cb(struct net_if *iface, void *user_data)
21 {
22 	struct net_shell_user_data *data = user_data;
23 	const struct shell *sh = data->sh;
24 	int *count = data->user_data;
25 	char *name, buf[CONFIG_NET_L2_VIRTUAL_MAX_NAME_LEN];
26 	struct net_if *orig_iface;
27 
28 	if (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
29 		return;
30 	}
31 
32 	if (*count == 0) {
33 		PR("Interface  Attached-To  Description\n");
34 		(*count)++;
35 	}
36 
37 	orig_iface = net_virtual_get_iface(iface);
38 
39 	name = net_virtual_get_name(iface, buf, sizeof(buf));
40 
41 	PR("%d          %c            %s\n",
42 	   net_if_get_by_iface(iface),
43 	   orig_iface ? net_if_get_by_iface(orig_iface) + '0' : '-',
44 	   name);
45 
46 	(*count)++;
47 }
48 
attached_iface_cb(struct net_if * iface,void * user_data)49 static void attached_iface_cb(struct net_if *iface, void *user_data)
50 {
51 	struct net_shell_user_data *data = user_data;
52 	const struct shell *sh = data->sh;
53 	int *count = data->user_data;
54 	char buf[CONFIG_NET_L2_VIRTUAL_MAX_NAME_LEN];
55 	const char *name;
56 	struct virtual_interface_context *ctx, *tmp;
57 
58 	if (sys_slist_is_empty(&iface->config.virtual_interfaces)) {
59 		return;
60 	}
61 
62 	if (*count == 0) {
63 		PR("Interface  Below-of  Description\n");
64 		(*count)++;
65 	}
66 
67 	PR("%d          ", net_if_get_by_iface(iface));
68 
69 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&iface->config.virtual_interfaces,
70 					  ctx, tmp, node) {
71 		if (ctx->virtual_iface == iface) {
72 			continue;
73 		}
74 
75 		PR("%d ", net_if_get_by_iface(ctx->virtual_iface));
76 	}
77 
78 	name = net_virtual_get_name(iface, buf, sizeof(buf));
79 	if (name == NULL) {
80 		name = iface2str(iface, NULL);
81 	}
82 
83 	PR("        %s\n", name);
84 
85 	(*count)++;
86 }
87 #endif /* CONFIG_NET_L2_VIRTUAL */
88 
cmd_virtual_show(const struct shell * sh,size_t argc,char * argv[])89 static int cmd_virtual_show(const struct shell *sh, size_t argc, char *argv[])
90 {
91 	ARG_UNUSED(argc);
92 	ARG_UNUSED(argv);
93 
94 #if defined(CONFIG_NET_L2_VIRTUAL)
95 	struct net_shell_user_data user_data;
96 	int count = 0;
97 
98 	user_data.sh = sh;
99 	user_data.user_data = &count;
100 
101 	net_if_foreach(virtual_iface_cb, &user_data);
102 
103 	if (count == 0) {
104 		PR("No virtual interfaces found.");
105 	}
106 
107 	count = 0;
108 	PR("\n");
109 
110 	net_if_foreach(attached_iface_cb, &user_data);
111 #else
112 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_L2_VIRTUAL",
113 		"virtual network interface");
114 #endif
115 	return 0;
116 }
117 
cmd_virtual_attach(const struct shell * sh,size_t argc,char * argv[])118 static int cmd_virtual_attach(const struct shell *sh, size_t argc, char *argv[])
119 {
120 #if defined(CONFIG_NET_L2_VIRTUAL)
121 	struct net_if *virtual_iface, *lower_iface;
122 	int ret;
123 
124 	virtual_iface = net_if_get_by_index(atoi(argv[1]));
125 	if (virtual_iface == NULL) {
126 		PR("No %s interface %s found.\n", "virtual", argv[1]);
127 		return -ENOENT;
128 	}
129 
130 	lower_iface = net_if_get_by_index(atoi(argv[2]));
131 	if (lower_iface == NULL) {
132 		PR("No %s interface %s found.\n", "such", argv[2]);
133 		return -ENOENT;
134 	}
135 
136 	ret = net_virtual_interface_attach(virtual_iface, lower_iface);
137 	if (ret < 0) {
138 		PR("Cannot attach interface %s to %s (%d)\n", argv[1], argv[2], ret);
139 		return -ENOENT;
140 	}
141 #else
142 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_L2_VIRTUAL",
143 		"virtual network interface");
144 #endif
145 	return 0;
146 }
147 
cmd_virtual_detach(const struct shell * sh,size_t argc,char * argv[])148 static int cmd_virtual_detach(const struct shell *sh, size_t argc, char *argv[])
149 {
150 #if defined(CONFIG_NET_L2_VIRTUAL)
151 	struct net_if *virtual_iface;
152 	int ret;
153 
154 	virtual_iface = net_if_get_by_index(atoi(argv[1]));
155 	if (virtual_iface == NULL) {
156 		PR("No %s interface %s found.\n", "virtual", argv[1]);
157 		return -ENOENT;
158 	}
159 
160 	ret = net_virtual_interface_attach(virtual_iface, NULL);
161 	if (ret < 0) {
162 		PR("Cannot detach interface %s (%d)\n", argv[1], ret);
163 		return -ENOENT;
164 	}
165 #else
166 	PR_INFO("Set %s to enable %s support.\n", "CONFIG_NET_L2_VIRTUAL",
167 		"virtual network interface");
168 #endif
169 	return 0;
170 }
171 
172 SHELL_STATIC_SUBCMD_SET_CREATE(virtual_commands,
173 	SHELL_CMD_ARG(attach, NULL,
174 		  "Attach a network interface to another interface.\n"
175 		  "'virtual attach <upper virtual iface index> <lower iface index>'",
176 		  cmd_virtual_attach, 3, 0),
177 	SHELL_CMD_ARG(detach, NULL,
178 		  "Detach a network interface from another interface.\n"
179 		  "'virtual detach <upper virtual iface index>'",
180 		  cmd_virtual_detach, 2, 0),
181 	SHELL_CMD_ARG(show, NULL,
182 		  "Show virtual interface information.\n"
183 		  "'virtual show'",
184 		  cmd_virtual_show, 1, 1),
185 	SHELL_SUBCMD_SET_END
186 );
187 
188 SHELL_SUBCMD_ADD((net), virtual, &virtual_commands,
189 		 "Show/manipulate virtual network interfaces.",
190 		 cmd_virtual_show, 1, 1);
191