d49cac7b294127a80235d9d0868a444a49b17653
1 /*
2 * Ethernet Switch configuration management
3 *
4 * Copyright (C) 2014 Texas Instruments
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11 * kind, whether express or implied; without even the implied warranty
12 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <stddef.h>
22 #include <getopt.h>
23 #include <sys/ioctl.h>
24 #include <net/if.h>
25 #include <linux/sockios.h>
26 #include <linux/ethtool.h>
27 #include <linux/net_switch_config.h>
29 typedef unsigned long long u64;
30 typedef __uint32_t u32;
31 typedef __uint16_t u16;
32 typedef __uint8_t u8;
33 typedef __int32_t s32;
35 enum {
36 EXTENDED_CONFIG_SWITCH_INVALID,
37 EXTENDED_CONFIG_SWITCH_DUMP,
38 };
40 #ifndef DIV_ROUND_UP
41 #define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y))
42 #endif
44 #define CPSW_MAJOR_VERSION(reg) (reg >> 8 & 0x7)
45 #define CPSW_MINOR_VERSION(reg) (reg & 0xff)
46 #define CPSW_RTL_VERSION(reg) ((reg >> 11) & 0x1f)
48 #define ADDR_FMT_ARGS(addr) (addr)[0], (addr)[1], (addr)[2], \
49 (addr)[3], (addr)[4], (addr)[5]
51 #define ALE_ENTRY_BITS 68
52 #define ALE_ENTRY_WORDS DIV_ROUND_UP(ALE_ENTRY_BITS, 32)
54 #define BIT(nr) (1 << (nr))
55 #define BITMASK(bits) (BIT(bits) - 1)
57 #define ALE_TYPE_FREE 0
58 #define ALE_TYPE_ADDR 1
59 #define ALE_TYPE_VLAN 2
60 #define ALE_TYPE_VLAN_ADDR 3
62 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
63 {
64 int idx;
66 idx = start / 32;
67 start -= idx * 32;
68 idx = 2 - idx; /* flip */
69 return (ale_entry[idx] >> start) & BITMASK(bits);
70 }
72 static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits,
73 u32 value)
74 {
75 int idx;
77 value &= BITMASK(bits);
78 idx = start / 32;
79 start -= idx * 32;
80 idx = 2 - idx; /* flip */
81 ale_entry[idx] &= ~(BITMASK(bits) << start);
82 ale_entry[idx] |= (value << start);
83 }
85 #define DEFINE_ALE_FIELD(name, start, bits) \
86 static inline int cpsw_ale_get_##name(u32 *ale_entry) \
87 { \
88 return cpsw_ale_get_field(ale_entry, start, bits); \
89 } \
90 static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \
91 { \
92 cpsw_ale_set_field(ale_entry, start, bits, value); \
93 }
95 DEFINE_ALE_FIELD(entry_type, 60, 2)
96 DEFINE_ALE_FIELD(vlan_id, 48, 12)
97 DEFINE_ALE_FIELD(mcast_state, 62, 2)
98 DEFINE_ALE_FIELD(port_mask, 66, 3)
99 DEFINE_ALE_FIELD(super, 65, 1)
100 DEFINE_ALE_FIELD(ucast_type, 62, 2)
101 DEFINE_ALE_FIELD(port_num, 66, 2)
102 DEFINE_ALE_FIELD(blocked, 65, 1)
103 DEFINE_ALE_FIELD(secure, 64, 1)
104 DEFINE_ALE_FIELD(vlan_untag_force, 24, 3)
105 DEFINE_ALE_FIELD(vlan_reg_mcast, 16, 3)
106 DEFINE_ALE_FIELD(vlan_unreg_mcast, 8, 3)
107 DEFINE_ALE_FIELD(vlan_member_list, 0, 3)
108 DEFINE_ALE_FIELD(mcast, 40, 1)
110 static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
111 {
112 int i;
114 for (i = 0; i < 6; i++)
115 addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
116 }
118 static void cpsw_ale_dump_vlan(int index, u32 *ale_entry)
119 {
120 int vlan = cpsw_ale_get_vlan_id(ale_entry);
121 int untag_force = cpsw_ale_get_vlan_untag_force(ale_entry);
122 int reg_mcast = cpsw_ale_get_vlan_reg_mcast(ale_entry);
123 int unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry);
124 int member_list = cpsw_ale_get_vlan_member_list(ale_entry);
126 fprintf(stdout, "%-4d: type: vlan , vid = %d, untag_force = 0x%x, reg_mcast = 0x%x, unreg_mcast = 0x%x, member_list = 0x%x\n",
127 index, vlan, untag_force, reg_mcast, unreg_mcast, member_list);
128 }
130 static void cpsw_ale_dump_addr(int index, u32 *ale_entry)
131 {
132 u8 addr[6];
134 cpsw_ale_get_addr(ale_entry, addr);
135 if (cpsw_ale_get_mcast(ale_entry)) {
136 static const char *str_mcast_state[] = {"f", "blf", "lf", "f"};
137 int state = cpsw_ale_get_mcast_state(ale_entry);
138 int port_mask = cpsw_ale_get_port_mask(ale_entry);
139 int super = cpsw_ale_get_super(ale_entry);
141 fprintf(stdout, "%-4d: type: mcast, addr = %02x:%02x:%02x:%02x:%02x:%02x, mcast_state = %s, %ssuper, port_mask = 0x%x\n",
142 index, ADDR_FMT_ARGS(addr), str_mcast_state[state],
143 super ? "" : "no ", port_mask);
144 } else {
145 static const char *s_ucast_type[] = {"persistant", "untouched ",
146 "oui ", "touched "};
147 int ucast_type = cpsw_ale_get_ucast_type(ale_entry);
148 int port_num = cpsw_ale_get_port_num(ale_entry);
149 int secure = cpsw_ale_get_secure(ale_entry);
150 int blocked = cpsw_ale_get_blocked(ale_entry);
152 fprintf(stdout, "%-4d: type: ucast, addr = %02x:%02x:%02x:%02x:%02x:%02x, ucast_type = %s, port_num = 0x%x%s%s\n",
153 index, ADDR_FMT_ARGS(addr), s_ucast_type[ucast_type],
154 port_num, secure ? ", Secure" : "",
155 blocked ? ", Blocked" : "");
156 }
157 }
159 static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry)
160 {
161 u8 addr[6];
162 int vlan = cpsw_ale_get_vlan_id(ale_entry);
164 cpsw_ale_get_addr(ale_entry, addr);
165 if (cpsw_ale_get_mcast(ale_entry)) {
166 static const char *str_mcast_state[] = {"f", "blf", "lf", "f"};
167 int state = cpsw_ale_get_mcast_state(ale_entry);
168 int port_mask = cpsw_ale_get_port_mask(ale_entry);
169 int super = cpsw_ale_get_super(ale_entry);
171 fprintf(stdout, "%-4d: type: mcast, vid = %d, addr = %02x:%02x:%02x:%02x:%02x:%02x, mcast_state = %s, %ssuper, port_mask = 0x%x\n",
172 index, vlan, ADDR_FMT_ARGS(addr),
173 str_mcast_state[state], super ? "" : "no ", port_mask);
174 } else {
175 static const char *s_ucast_type[] = {"persistant", "untouched ",
176 "oui ", "touched "};
177 int ucast_type = cpsw_ale_get_ucast_type(ale_entry);
178 int port_num = cpsw_ale_get_port_num(ale_entry);
179 int secure = cpsw_ale_get_secure(ale_entry);
180 int blocked = cpsw_ale_get_blocked(ale_entry);
182 fprintf(stdout, "%-4d: type: ucast, vid = %d, addr = %02x:%02x:%02x:%02x:%02x:%02x, ucast_type = %s, port_num = 0x%x%s%s\n",
183 index, vlan, ADDR_FMT_ARGS(addr),
184 s_ucast_type[ucast_type], port_num,
185 secure ? ", Secure" : "", blocked ? ", Blocked" : "");
186 }
187 }
189 int cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
190 {
191 u32 *reg = (u32 *)regs->data;
192 int i;
194 fprintf(stdout, "cpsw hw version %d.%d (%d)\n",
195 CPSW_MAJOR_VERSION(regs->version),
196 CPSW_MINOR_VERSION(regs->version),
197 CPSW_RTL_VERSION(regs->version));
199 for(i = 0; i < 1024; i++, reg += ALE_ENTRY_WORDS) {
200 int type;
202 type = cpsw_ale_get_entry_type(reg);
203 switch (type) {
204 case ALE_TYPE_FREE:
205 break;
207 case ALE_TYPE_ADDR:
208 cpsw_ale_dump_addr(i, reg);
209 break;
211 case ALE_TYPE_VLAN:
212 cpsw_ale_dump_vlan(i, reg);
213 break;
215 case ALE_TYPE_VLAN_ADDR:
216 cpsw_ale_dump_vlan_addr(i, reg);
217 break;
219 default:
220 fprintf(stdout, "%-4d: Invalid Entry type\n", i);
221 }
222 }
224 return 0;
225 }
227 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
229 #define SWITCH_CONFIG_COMMAND(__var__, __cmd__) \
230 if((__var__) == CONFIG_SWITCH_INVALID) { \
231 (__var__) = (__cmd__); \
232 } else { \
233 printf("Two or more commands Cannot be " \
234 "processed simultaneously\n"); \
235 return -1; \
236 }
238 static char options[] = "?m:x:i:y:S:GUg:udn:V:sk:K:M:N:D:Y:z:Z:J:v";
240 static struct option long_options[] =
241 {
242 /* These options set a flag. */
243 {"add-multi", required_argument , 0, 'm'},
244 {"del-multi", required_argument , 0, 'x'},
245 {"add-vlan", required_argument , 0, 'i'},
246 {"del-vlan", required_argument , 0, 'y'},
247 {"add-unknown-vlan-info", no_argument , 0, 'U'},
248 {"set-port-config", required_argument , 0, 'S'},
249 {"get-port-config", no_argument , 0, 'G'},
250 {"set-port-state", required_argument , 0, 'g'},
251 {"get-port-state", no_argument , 0, 'u'},
252 {"dump", optional_argument , 0, 'd'},
253 {"port", required_argument , 0, 'n'},
254 {"vid", required_argument , 0, 'V'},
255 {"super", no_argument , 0, 's'},
256 {"fwd-state", required_argument , 0, 'k'},
257 {"vid-untag", required_argument , 0, 'K'},
258 {"reg-multi", required_argument , 0, 'M'},
259 {"unreg-multi", required_argument , 0, 'N'},
260 {"vid-untag-port-mask", required_argument , 0, 'Y'},
261 {"reg-multi-port-mask", required_argument , 0, 'z'},
262 {"unreg-multi-port-mask", required_argument , 0, 'Z'},
263 {"unknown-vlan-mem", required_argument , 0, 'J'},
264 {"duplex", required_argument , 0, 'D'},
265 {"version", no_argument , 0, 'v'},
266 {0, 0, 0, 0}
267 };
269 static inline int is_zero_ether_addr(const unsigned char *addr)
270 {
271 return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
272 }
274 static inline int is_multicast_ether_addr(const unsigned char *addr)
275 {
276 return 0x01 & addr[0];
277 }
279 static inline int is_valid_ether_addr(const unsigned char *addr)
280 {
281 return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
282 }
284 /* String to Hex conversion */
285 static unsigned char cpmac_str_to_hexnum(unsigned char c)
286 {
287 if(c >= '0' && c <= '9') return c - '0';
288 if(c >= 'a' && c <= 'f') return c - 'a' + 10;
289 if(c >= 'A' && c <= 'F') return c - 'A' + 10;
290 return 0;
291 }
293 /* String to ethernet address conversion */
294 static void config_switch_str_to_ethaddr(char *str, unsigned char *addr)
295 {
296 int i;
297 unsigned char num;
298 for(i = 0; i < 6; i++) {
299 if((*str == '.') || (*str == ':')) str++;
300 num = cpmac_str_to_hexnum(*str++) << 4;
301 num |= (cpmac_str_to_hexnum(*str++));
302 addr[i] = num;
303 }
304 }
306 static void
307 dump_link_caps(const char *prefix, const char *an_prefix, u32 mask,
308 int link_mode_only)
309 {
310 static const struct {
311 int same_line; /* print on same line as previous */
312 u32 value;
313 const char *name;
314 } mode_defs[] = {
315 { 0, ADVERTISED_10baseT_Half, "10baseT/Half" },
316 { 1, ADVERTISED_10baseT_Full, "10baseT/Full" },
317 { 0, ADVERTISED_100baseT_Half, "100baseT/Half" },
318 { 1, ADVERTISED_100baseT_Full, "100baseT/Full" },
319 { 0, ADVERTISED_1000baseT_Half, "1000baseT/Half" },
320 { 1, ADVERTISED_1000baseT_Full, "1000baseT/Full" },
321 { 0, ADVERTISED_1000baseKX_Full, "1000baseKX/Full" },
322 { 0, ADVERTISED_2500baseX_Full, "2500baseX/Full" },
323 { 0, ADVERTISED_10000baseT_Full, "10000baseT/Full" },
324 { 0, ADVERTISED_10000baseKX4_Full, "10000baseKX4/Full" },
325 { 0, ADVERTISED_10000baseKR_Full, "10000baseKR/Full" },
326 { 0, ADVERTISED_20000baseMLD2_Full, "20000baseMLD2/Full" },
327 { 0, ADVERTISED_20000baseKR2_Full, "20000baseKR2/Full" },
328 { 0, ADVERTISED_40000baseKR4_Full, "40000baseKR4/Full" },
329 { 0, ADVERTISED_40000baseCR4_Full, "40000baseCR4/Full" },
330 { 0, ADVERTISED_40000baseSR4_Full, "40000baseSR4/Full" },
331 { 0, ADVERTISED_40000baseLR4_Full, "40000baseLR4/Full" },
332 };
333 int indent;
334 int did1, new_line_pend, i;
336 /* Indent just like the separate functions used to */
337 indent = strlen(prefix) + 14;
338 if (indent < 24)
339 indent = 24;
341 fprintf(stdout, " %s link modes:%*s", prefix,
342 indent - (int)strlen(prefix) - 12, "");
343 did1 = 0;
344 new_line_pend = 0;
345 for (i = 0; i < ARRAY_SIZE(mode_defs); i++) {
346 if (did1 && !mode_defs[i].same_line)
347 new_line_pend = 1;
348 if (mask & mode_defs[i].value) {
349 if (new_line_pend) {
350 fprintf(stdout, "\n");
351 fprintf(stdout, " %*s", indent, "");
352 new_line_pend = 0;
353 }
354 did1++;
355 fprintf(stdout, "%s ", mode_defs[i].name);
356 }
357 }
358 if (did1 == 0)
359 fprintf(stdout, "Not reported");
360 fprintf(stdout, "\n");
362 if (!link_mode_only) {
363 fprintf(stdout, " %s pause frame use: ", prefix);
364 if (mask & ADVERTISED_Pause) {
365 fprintf(stdout, "Symmetric");
366 if (mask & ADVERTISED_Asym_Pause)
367 fprintf(stdout, " Receive-only");
368 fprintf(stdout, "\n");
369 } else {
370 if (mask & ADVERTISED_Asym_Pause)
371 fprintf(stdout, "Transmit-only\n");
372 else
373 fprintf(stdout, "No\n");
374 }
376 fprintf(stdout, " %s auto-negotiation: ", an_prefix);
377 if (mask & ADVERTISED_Autoneg)
378 fprintf(stdout, "Yes\n");
379 else
380 fprintf(stdout, "No\n");
381 }
382 }
384 static int dump_ecmd(struct ethtool_cmd *ep)
385 {
386 u32 speed;
388 dump_link_caps("Advertised", "Advertised", ep->advertising, 0);
389 if (ep->lp_advertising)
390 dump_link_caps("Link partner advertised",
391 "Link partner advertised", ep->lp_advertising,
392 0);
394 fprintf(stdout, " Speed: ");
395 speed = ethtool_cmd_speed(ep);
396 if (speed == 0 || speed == (u16)(-1) || speed == (u32)(-1))
397 fprintf(stdout, "Unknown!\n");
398 else
399 fprintf(stdout, "%uMb/s\n", speed);
401 fprintf(stdout, " Duplex: ");
402 switch (ep->duplex) {
403 case DUPLEX_HALF:
404 fprintf(stdout, "Half\n");
405 break;
406 case DUPLEX_FULL:
407 fprintf(stdout, "Full\n");
408 break;
409 default:
410 fprintf(stdout, "Unknown! (%i)\n", ep->duplex);
411 break;
412 };
414 fprintf(stdout, " Port: ");
415 switch (ep->port) {
416 case PORT_TP:
417 fprintf(stdout, "Twisted Pair\n");
418 break;
419 case PORT_AUI:
420 fprintf(stdout, "AUI\n");
421 break;
422 case PORT_BNC:
423 fprintf(stdout, "BNC\n");
424 break;
425 case PORT_MII:
426 fprintf(stdout, "MII\n");
427 break;
428 case PORT_FIBRE:
429 fprintf(stdout, "FIBRE\n");
430 break;
431 case PORT_DA:
432 fprintf(stdout, "Direct Attach Copper\n");
433 break;
434 case PORT_NONE:
435 fprintf(stdout, "None\n");
436 break;
437 case PORT_OTHER:
438 fprintf(stdout, "Other\n");
439 break;
440 default:
441 fprintf(stdout, "Unknown! (%i)\n", ep->port);
442 break;
443 };
445 fprintf(stdout, " PHYAD: %d\n", ep->phy_address);
446 fprintf(stdout, " Transceiver: ");
447 switch (ep->transceiver) {
448 case XCVR_INTERNAL:
449 fprintf(stdout, "internal\n");
450 break;
451 case XCVR_EXTERNAL:
452 fprintf(stdout, "external\n");
453 break;
454 default:
455 fprintf(stdout, "Unknown!\n");
456 break;
457 };
459 fprintf(stdout, " Auto-negotiation: %s\n",
460 (ep->autoneg == AUTONEG_DISABLE) ?
461 "off" : "on");
463 if (ep->port == PORT_TP) {
464 fprintf(stdout, " MDI-X: ");
465 if (ep->eth_tp_mdix_ctrl == ETH_TP_MDI) {
466 fprintf(stdout, "off (forced)\n");
467 } else if (ep->eth_tp_mdix_ctrl == ETH_TP_MDI_X) {
468 fprintf(stdout, "on (forced)\n");
469 } else {
470 switch (ep->eth_tp_mdix) {
471 case ETH_TP_MDI:
472 fprintf(stdout, "off");
473 break;
474 case ETH_TP_MDI_X:
475 fprintf(stdout, "on");
476 break;
477 default:
478 fprintf(stdout, "Unknown");
479 break;
480 }
481 if (ep->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO)
482 fprintf(stdout, " (auto)");
483 fprintf(stdout, "\n");
484 }
485 }
487 return 0;
488 }
490 void print_help(void)
491 {
492 printf(
493 "Switch configuration commands.....\n"
494 "All input and output values are in Decimal\n"
495 "switch-config -m,--add-multi <address> -n,--port <Portmask> "
496 "[-V,--vid <vid>] [-s,--super] "
497 "[-k,--fwd-state <value 0-3>]\n"
498 "switch-config -x,--del-multi <address> [-V,--vid <vid>]\n"
499 "switch-config -i,--add-vlan <vlan id> -n,--port <Portmask> "
500 "[-K,--vid-untag <Portmask>] "
501 "[-M,--reg-multi <Portmask>] "
502 "[-N,--unreg-multi <Portmask>]\n"
503 "switch-config -y,--del-vlan <vid>\n"
504 "switch-config -S,--set-port-config <0(auto)/10/100/1000> "
505 "-n,--port <PortNo> [-D,--duplex <full/half>]\n"
506 "switch-config -G,--get-port-config -n,--port <PortNo>\n"
507 "switch-config -U,--add-unknown-vlan-info "
508 "[-Y,--vid-untag-port-mask <0-7>] [-z,--reg-multi-port-mask <0-7>] "
509 "[-Z,--unreg-multi-port-mask <0-7>] "
510 "[-J,--unknown-vlan-mem <0-7>]\n"
511 "switch-config -g,--get-port-state <disabled/blocked/learn/forward> "
512 "-n,--port <PortNo>\n"
513 "switch-config -u,--set-port-state -n,--port <PortNo>\n"
514 "switch-config -d,--dump\n"
515 "\n"
516 );
517 }
519 int main(int argc, char **argv)
520 {
521 int option_index = 0;
522 int c;
523 struct net_switch_config cmd_struct;
524 unsigned int port_num = 0;
525 struct ifreq ifr;
526 int sockfd; /* socket fd we use to manipulate stuff with */
527 unsigned int speed;
528 unsigned int duplex;
529 unsigned int autoneg;
530 int extended_switch_config;
532 /* get interface name */
533 strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);
534 ifr.ifr_data = (char*)&cmd_struct;
535 /* Create a channel to the NET kernel. */
536 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
537 printf("Can't open the socket\n");
538 return -1;
539 }
540 memset(&cmd_struct, 0, sizeof(struct net_switch_config));
542 /* parse command line arguments */
543 while ((c = getopt_long(argc, argv, options, long_options,
544 &option_index)) != -1) {
545 switch (c) {
546 case '?':
547 print_help();
548 return 0;
549 case 'v':
550 printf("switch-config version: %s\n", VERSION);
551 return 0;
553 case 'm':
554 SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
555 CONFIG_SWITCH_ADD_MULTICAST);
556 config_switch_str_to_ethaddr(optarg,
557 cmd_struct.addr);
558 break;
560 case 'x':
561 SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
562 CONFIG_SWITCH_DEL_MULTICAST);
563 config_switch_str_to_ethaddr(optarg,
564 cmd_struct.addr);
565 break;
567 case 'i':
568 SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
569 CONFIG_SWITCH_ADD_VLAN);
570 cmd_struct.vid = atoi(optarg);
571 break;
573 case 'y':
574 SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
575 CONFIG_SWITCH_DEL_VLAN);
576 cmd_struct.vid = atoi(optarg);
577 break;
579 case 'G':
580 SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
581 CONFIG_SWITCH_GET_PORT_CONFIG);
582 break;
584 case 'S':
585 SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
586 CONFIG_SWITCH_SET_PORT_CONFIG);
587 speed = atoi(optarg);
588 if (speed == 0)
589 autoneg = AUTONEG_ENABLE;
590 else
591 autoneg = AUTONEG_DISABLE;
592 break;
594 case 'U':
595 SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
596 CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO);
597 printf("CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO\n");
598 break;
600 case 'g':
601 SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
602 CONFIG_SWITCH_SET_PORT_STATE);
603 if (!strcmp(optarg, "disabled"))
604 cmd_struct.port_state = PORT_STATE_DISABLED;
605 else if (!strcmp(optarg, "blocked"))
606 cmd_struct.port_state = PORT_STATE_BLOCKED;
607 else if (!strcmp(optarg, "learn"))
608 cmd_struct.port_state = PORT_STATE_LEARN;
609 else if (!strcmp(optarg, "forward"))
610 cmd_struct.port_state = PORT_STATE_FORWARD;
611 else {
612 printf("Invalid Port State\n");
613 return -1;
614 }
615 break;
617 case 'u':
618 SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
619 CONFIG_SWITCH_GET_PORT_STATE);
620 break;
622 /* Extended switch commands */
623 case 'd':
624 extended_switch_config = EXTENDED_CONFIG_SWITCH_DUMP;
625 break;
627 /* Command arguments */
628 case 'n':
629 port_num = atoi(optarg);
630 break;
632 case 'V':
633 cmd_struct.vid = atoi(optarg);
634 break;
636 case 'k':
637 cmd_struct.untag_port = atoi(optarg);
638 break;
640 case 'K':
641 cmd_struct.untag_port = atoi(optarg);
642 break;
644 case 'M':
645 cmd_struct.reg_multi = atoi(optarg);
646 break;
648 case 'N':
649 cmd_struct.unreg_multi = atoi(optarg);
650 break;
652 case 'D':
653 if (!strcmp(optarg, "full"))
654 duplex = DUPLEX_FULL;
655 else if (!strcmp(optarg, "half"))
656 duplex = DUPLEX_HALF;
657 else {
658 printf("Invalid Options for Duplex\n");
659 close(sockfd);
660 return -1;
661 }
662 break;
664 case 'Y':
665 cmd_struct.unknown_vlan_untag = atoi(optarg);
666 break;
668 case 'z':
669 cmd_struct.unknown_vlan_reg_multi = atoi(optarg);
670 break;
672 case 'Z':
673 cmd_struct.unknown_vlan_unreg_multi = atoi(optarg);
674 break;
676 case 'J':
677 cmd_struct.unknown_vlan_member = atoi(optarg);
678 break;
680 default:
681 print_help();
682 return 0;
683 }
684 }
686 switch (cmd_struct.cmd) {
687 case CONFIG_SWITCH_INVALID:
688 if (extended_switch_config != EXTENDED_CONFIG_SWITCH_INVALID)
689 goto extended_ioctls;
690 print_help();
691 return -1;
692 break;
694 case CONFIG_SWITCH_ADD_MULTICAST:
695 if ((cmd_struct.vid <= 4095) &&
696 (port_num > 0) && (port_num <= 7) &&
697 is_multicast_ether_addr(cmd_struct.addr)) {
698 cmd_struct.port = port_num;
699 printf("port number %d\n", cmd_struct.port);
700 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
701 printf("Multicast add failed\n");
702 close(sockfd);
703 return -1;
704 } else
705 printf("Multicast address added successfully\n");
706 } else {
707 printf("Invalid Arguments\n");
708 return -1;
709 }
710 break;
712 case CONFIG_SWITCH_DEL_MULTICAST:
713 if ((cmd_struct.vid <= 4095) &&
714 is_multicast_ether_addr(cmd_struct.addr)) {
715 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
716 printf("Multicast Address Not found\n");
717 close(sockfd);
718 return -1;
719 } else
720 printf("Multicast Address Deleted successfully\n");
721 } else {
722 printf("Invalid Arguments\n");
723 return -1;
724 }
725 break;
727 case CONFIG_SWITCH_ADD_VLAN:
728 if ((cmd_struct.vid <= 4095) &&
729 (port_num > 0) && (port_num <= 7)) {
730 cmd_struct.port = port_num;
731 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
732 printf("VLAN add failed\n");
733 close(sockfd);
734 return -1;
735 } else
736 printf("VLAN added successfully\n");
737 } else {
738 printf("Invalid Arguments\n");
739 return -1;
740 }
741 break;
743 case CONFIG_SWITCH_DEL_VLAN:
744 if ((cmd_struct.vid <= 4095) &&
745 (port_num <= 7)) {
746 cmd_struct.port = port_num;
747 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
748 printf("VLAN Not found\n");
749 close(sockfd);
750 return -1;
751 } else
752 printf("VLAN Deleted Successfully\n");
753 } else {
754 printf("Invalid Arguments\n");
755 return -1;
756 }
757 break;
759 case CONFIG_SWITCH_SET_PORT_CONFIG:
760 if ((port_num == 1) || (port_num == 2)) {
761 cmd_struct.port = port_num;
762 cmd_struct.cmd = CONFIG_SWITCH_GET_PORT_CONFIG;
764 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
765 printf("Set Port Config Failed\n");
766 close(sockfd);
767 return -1;
768 } else
769 printf("Set Port Config successful\n");
771 ethtool_cmd_speed_set(&cmd_struct.ecmd, speed);
772 cmd_struct.ecmd.duplex = duplex;
773 cmd_struct.ecmd.autoneg = autoneg;
774 cmd_struct.cmd = CONFIG_SWITCH_SET_PORT_CONFIG;
776 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
777 printf("Set Port Config Failed\n");
778 close(sockfd);
779 return -1;
780 } else
781 printf("Set Port Config successful\n");
782 } else {
783 printf("Invalid Arguments\n");
784 return -1;
785 }
786 break;
788 case CONFIG_SWITCH_GET_PORT_CONFIG:
789 if ((port_num == 1) || (port_num == 2)) {
790 cmd_struct.port = port_num;
791 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
792 printf("Get Port Config Failed\n");
793 close(sockfd);
794 return -1;
795 } else {
796 printf("Get Port Config successful\n");
797 dump_ecmd(&cmd_struct.ecmd);
798 }
799 } else {
800 printf("Invalid Arguments\n");
801 return -1;
802 }
803 break;
805 case CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO:
806 if ((cmd_struct.unknown_vlan_member <= 7) &&
807 (cmd_struct.unknown_vlan_untag <= 7) &&
808 (cmd_struct.unknown_vlan_unreg_multi <= 7) &&
809 (cmd_struct.unknown_vlan_reg_multi <= 7)) {
810 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
811 printf("Add unknown VLAN Failed\n");
812 close(sockfd);
813 return -1;
814 } else {
815 printf("Add unknown VLAN successful\n");
816 }
817 } else {
818 printf("Invalid Arguments\n");
819 return -1;
820 }
821 break;
823 case CONFIG_SWITCH_SET_PORT_STATE:
824 if ((port_num == 1) || (port_num == 2)) {
825 cmd_struct.port = port_num;
826 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
827 printf("Set Port State Failed\n");
828 close(sockfd);
829 return -1;
830 } else
831 printf("Set Port State successful\n");
832 } else {
833 printf("Invalid Arguments\n");
834 return -1;
835 }
836 break;
838 case CONFIG_SWITCH_GET_PORT_STATE:
839 if ((port_num == 1) || (port_num == 2)) {
840 cmd_struct.port = port_num;
841 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
842 printf("Get Port State Failed\n");
843 close(sockfd);
844 return -1;
845 } else
846 printf("Get Port State successful\nState is ");
847 if (cmd_struct.port_state == PORT_STATE_DISABLED)
848 printf("disabled\n");
849 else if (cmd_struct.port_state == PORT_STATE_BLOCKED)
850 printf("blocked\n");
851 else if (cmd_struct.port_state == PORT_STATE_LEARN)
852 printf("learn\n");
853 else if (cmd_struct.port_state == PORT_STATE_FORWARD)
854 printf("forward\n");
855 else
856 printf("Invalid State\n");
857 } else {
858 printf("Invalid Arguments\n");
859 return -1;
860 }
861 break;
862 }
864 close(sockfd);
865 return 0;
867 extended_ioctls:
868 switch (extended_switch_config) {
869 case EXTENDED_CONFIG_SWITCH_DUMP:
870 {
871 struct ethtool_drvinfo drvinfo;
872 struct ethtool_regs *regs;
874 drvinfo.cmd = ETHTOOL_GDRVINFO;
875 ifr.ifr_data = (void *)&drvinfo;
876 if (ioctl(sockfd, SIOCETHTOOL, &ifr) < 0) {
877 perror("Cannot get driver information");
878 return -1;
879 }
881 regs = calloc(1, sizeof(*regs)+drvinfo.regdump_len);
882 if (!regs) {
883 perror("Cannot allocate memory for register dump");
884 return -1;
885 }
887 regs->cmd = ETHTOOL_GREGS;
888 regs->len = drvinfo.regdump_len;
889 ifr.ifr_data = (void *)regs;
890 if (ioctl(sockfd, SIOCETHTOOL, &ifr) < 0) {
891 perror("Cannot get driver information");
892 return -1;
893 }
894 cpsw_dump_regs(&drvinfo, regs);
895 }
896 break;
898 case EXTENDED_CONFIG_SWITCH_INVALID:
899 default:
900 print_help();
901 return -1;
902 break;
903 }
905 close(sockfd);
906 return 0;
907 }