1 /*
2 * Copyright (c) 2021 BayLibre SAS
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdlib.h>
8 #include <zephyr/shell/shell.h>
9 #include <zephyr/net/net_if.h>
10 #include <zephyr/net/ethernet.h>
11 #include <zephyr/net/ethernet_bridge.h>
12 #include <zephyr/sys/slist.h>
13
get_idx(const struct shell * sh,char * index_str)14 static int get_idx(const struct shell *sh, char *index_str)
15 {
16 char *endptr;
17 int idx;
18
19 idx = strtol(index_str, &endptr, 10);
20 if (*endptr != '\0') {
21 shell_warn(sh, "Invalid index %s\n", index_str);
22 return -ENOENT;
23 }
24
25 return idx;
26 }
27
cmd_bridge_addif(const struct shell * sh,size_t argc,char * argv[])28 static int cmd_bridge_addif(const struct shell *sh, size_t argc, char *argv[])
29 {
30 int ret = 0, br_idx, if_idx;
31 struct net_if *iface;
32 struct net_if *br;
33
34 br_idx = get_idx(sh, argv[1]);
35 if (br_idx < 0) {
36 return br_idx;
37 }
38
39 br = eth_bridge_get_by_index(br_idx);
40 if (br == NULL) {
41 shell_warn(sh, "Bridge %d not found\n", br_idx);
42 return -ENOENT;
43 }
44
45 for (int i = 2; i < argc; i++) {
46 if_idx = get_idx(sh, argv[i]);
47 if (if_idx < 0) {
48 continue;
49 }
50
51 iface = net_if_get_by_index(if_idx);
52 if (iface == NULL) {
53 shell_warn(sh, "Interface %d not found\n", if_idx);
54 continue;
55 }
56
57 if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
58 shell_warn(sh, "Interface %d is not Ethernet\n", if_idx);
59 continue;
60 }
61
62 if (!(net_eth_get_hw_capabilities(iface) & ETHERNET_PROMISC_MODE)) {
63 shell_warn(sh, "Interface %d cannot do promiscuous mode\n", if_idx);
64 continue;
65 }
66
67 ret = eth_bridge_iface_add(br, iface);
68 if (ret < 0) {
69 shell_error(sh, "error: bridge iface add (%d)\n", ret);
70 }
71 }
72
73 return ret;
74 }
75
cmd_bridge_delif(const struct shell * sh,size_t argc,char * argv[])76 static int cmd_bridge_delif(const struct shell *sh, size_t argc, char *argv[])
77 {
78 int ret = 0, br_idx, if_idx;
79 struct net_if *iface;
80 struct net_if *br;
81
82 br_idx = get_idx(sh, argv[1]);
83 if (br_idx < 0) {
84 return br_idx;
85 }
86
87 br = eth_bridge_get_by_index(br_idx);
88 if (br == NULL) {
89 shell_warn(sh, "Bridge %d not found\n", br_idx);
90 return -ENOENT;
91 }
92
93 for (int i = 2; i < argc; i++) {
94 if_idx = get_idx(sh, argv[i]);
95 if (if_idx < 0) {
96 continue;
97 }
98
99 iface = net_if_get_by_index(if_idx);
100 if (iface == NULL) {
101 shell_warn(sh, "Interface %d not found\n", if_idx);
102 continue;
103 }
104
105 ret = eth_bridge_iface_remove(br, iface);
106 if (ret < 0) {
107 shell_error(sh, "error: bridge iface remove (%d)\n", ret);
108 }
109 }
110
111 return ret;
112 }
113
bridge_show(struct eth_bridge_iface_context * ctx,void * data)114 static void bridge_show(struct eth_bridge_iface_context *ctx, void *data)
115 {
116 int br_idx = eth_bridge_get_index(ctx->iface);
117 const struct shell *sh = data;
118
119 shell_fprintf(sh, SHELL_NORMAL, "%-7d", br_idx);
120
121 if (net_if_is_up(ctx->iface)) {
122 shell_fprintf(sh, SHELL_NORMAL, "%-9s", "up");
123 } else {
124 shell_fprintf(sh, SHELL_NORMAL, "%-9s", "down");
125 }
126
127 if (ctx->is_setup) {
128 shell_fprintf(sh, SHELL_NORMAL, "%-9s", "ok");
129 } else {
130 shell_fprintf(sh, SHELL_NORMAL, "%-9s", "no");
131 }
132
133 k_mutex_lock(&ctx->lock, K_FOREVER);
134
135 ARRAY_FOR_EACH(ctx->eth_iface, i) {
136 int if_idx;
137
138 if (ctx->eth_iface[i] == NULL) {
139 continue;
140 }
141
142 if_idx = net_if_get_by_iface(ctx->eth_iface[i]);
143
144 shell_fprintf(sh, SHELL_NORMAL, "%-2d", if_idx);
145 }
146
147 shell_fprintf(sh, SHELL_NORMAL, "\n");
148
149 k_mutex_unlock(&ctx->lock);
150 }
151
cmd_bridge_show(const struct shell * sh,size_t argc,char * argv[])152 static int cmd_bridge_show(const struct shell *sh, size_t argc, char *argv[])
153 {
154 struct net_if *br = NULL;
155 int br_idx;
156
157 if (argc == 2) {
158 br_idx = get_idx(sh, argv[1]);
159 if (br_idx < 0) {
160 return br_idx;
161 }
162
163 br = eth_bridge_get_by_index(br_idx);
164 if (br == NULL) {
165 shell_warn(sh, "Bridge %d not found\n", br_idx);
166 return -ENOENT;
167 }
168 }
169
170 shell_fprintf(sh, SHELL_NORMAL, "Bridge %-9s%-9sInterfaces\n",
171 "Status", "Config");
172
173 if (br != NULL) {
174 bridge_show(net_if_get_device(br)->data, (void *)sh);
175 } else {
176 net_eth_bridge_foreach(bridge_show, (void *)sh);
177 }
178
179 return 0;
180 }
181
182 SHELL_STATIC_SUBCMD_SET_CREATE(bridge_commands,
183 SHELL_CMD_ARG(addif, NULL,
184 "Add a network interface to a bridge.\n"
185 "'bridge addif <bridge_index> <one or more interface index>'",
186 cmd_bridge_addif, 3, 5),
187 SHELL_CMD_ARG(delif, NULL,
188 "Delete a network interface from a bridge.\n"
189 "'bridge delif <bridge_index> <one or more interface index>'",
190 cmd_bridge_delif, 3, 5),
191 SHELL_CMD_ARG(show, NULL,
192 "Show bridge information.\n"
193 "'bridge show [<bridge_index>]'",
194 cmd_bridge_show, 1, 1),
195 SHELL_SUBCMD_SET_END
196 );
197
198 SHELL_SUBCMD_ADD((net), bridge, &bridge_commands,
199 "Ethernet bridge commands.",
200 cmd_bridge_show, 1, 1);
201