add multicast/broadcast limit support via switch config ioctl
[switch-config/switch-config.git] / switch-config.c
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 #define true 1
17 #define false 0
18 typedef int bool;
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <stddef.h>
26 #include <getopt.h>
27 #include <sys/ioctl.h>
28 #include <net/if.h>
29 #include <linux/sockios.h>
30 #include <linux/ethtool.h>
31 #include <linux/net_switch_config.h>
33 typedef unsigned long long u64;
34 typedef __uint32_t u32;
35 typedef __uint16_t u16;
36 typedef __uint8_t u8;
37 typedef __int32_t s32;
39 enum {
40         EXTENDED_CONFIG_SWITCH_INVALID,
41         EXTENDED_CONFIG_SWITCH_DUMP,
42 };
44 #ifndef DIV_ROUND_UP
45 #define DIV_ROUND_UP(x,y)       (((x) + ((y) - 1)) / (y))
46 #endif
48 #define CPSW_MAJOR_VERSION(reg)         (reg >> 8 & 0x7)
49 #define CPSW_MINOR_VERSION(reg)         (reg & 0xff)
50 #define CPSW_RTL_VERSION(reg)           ((reg >> 11) & 0x1f)
52 #define ADDR_FMT_ARGS(addr)     (addr)[0], (addr)[1], (addr)[2], \
53                                 (addr)[3], (addr)[4], (addr)[5]
55 #define ALE_ENTRY_BITS          68
56 #define ALE_ENTRY_WORDS         DIV_ROUND_UP(ALE_ENTRY_BITS, 32)
58 #define BIT(nr)                 (1 << (nr))
59 #define BITMASK(bits)           (BIT(bits) - 1)
61 #define ALE_TYPE_FREE                   0
62 #define ALE_TYPE_ADDR                   1
63 #define ALE_TYPE_VLAN                   2
64 #define ALE_TYPE_VLAN_ADDR              3
66 static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
67 {
68         int idx;
70         idx    = start / 32;
71         start -= idx * 32;
72         idx    = 2 - idx; /* flip */
73         return (ale_entry[idx] >> start) & BITMASK(bits);
74 }
76 static inline void cpsw_ale_set_field(u32 *ale_entry, u32 start, u32 bits,
77                                       u32 value)
78 {
79         int idx;
81         value &= BITMASK(bits);
82         idx    = start / 32;
83         start -= idx * 32;
84         idx    = 2 - idx; /* flip */
85         ale_entry[idx] &= ~(BITMASK(bits) << start);
86         ale_entry[idx] |=  (value << start);
87 }
89 #define DEFINE_ALE_FIELD(name, start, bits)                             \
90 static inline int cpsw_ale_get_##name(u32 *ale_entry)                   \
91 {                                                                       \
92         return cpsw_ale_get_field(ale_entry, start, bits);              \
93 }                                                                       \
94 static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value)       \
95 {                                                                       \
96         cpsw_ale_set_field(ale_entry, start, bits, value);              \
97 }
99 DEFINE_ALE_FIELD(entry_type,            60,     2)
100 DEFINE_ALE_FIELD(vlan_id,               48,     12)
101 DEFINE_ALE_FIELD(mcast_state,           62,     2)
102 DEFINE_ALE_FIELD(port_mask,             66,     3)
103 DEFINE_ALE_FIELD(super,                 65,     1)
104 DEFINE_ALE_FIELD(ucast_type,            62,     2)
105 DEFINE_ALE_FIELD(port_num,              66,     2)
106 DEFINE_ALE_FIELD(blocked,               65,     1)
107 DEFINE_ALE_FIELD(secure,                64,     1)
108 DEFINE_ALE_FIELD(vlan_untag_force,      24,     3)
109 DEFINE_ALE_FIELD(vlan_reg_mcast,        16,     3)
110 DEFINE_ALE_FIELD(vlan_unreg_mcast,      8,      3)
111 DEFINE_ALE_FIELD(vlan_member_list,      0,      3)
112 DEFINE_ALE_FIELD(mcast,                 40,     1)
114 static inline void cpsw_ale_get_addr(u32 *ale_entry, u8 *addr)
116         int i;
118         for (i = 0; i < 6; i++)
119                 addr[i] = cpsw_ale_get_field(ale_entry, 40 - 8*i, 8);
122 static void cpsw_ale_dump_vlan(int index, u32 *ale_entry)
124         int vlan = cpsw_ale_get_vlan_id(ale_entry);
125         int untag_force = cpsw_ale_get_vlan_untag_force(ale_entry);
126         int reg_mcast   = cpsw_ale_get_vlan_reg_mcast(ale_entry);
127         int unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry);
128         int member_list = cpsw_ale_get_vlan_member_list(ale_entry);
130         fprintf(stdout, "%-4d: type: vlan , vid = %d, untag_force = 0x%x, reg_mcast = 0x%x, unreg_mcast = 0x%x, member_list = 0x%x\n",
131                 index, vlan, untag_force, reg_mcast, unreg_mcast, member_list);
134 static void cpsw_ale_dump_addr(int index, u32 *ale_entry)
136         u8 addr[6];
138         cpsw_ale_get_addr(ale_entry, addr);
139         if (cpsw_ale_get_mcast(ale_entry)) {
140                 static const char *str_mcast_state[] = {"f", "blf", "lf", "f"};
141                 int state     = cpsw_ale_get_mcast_state(ale_entry);
142                 int port_mask = cpsw_ale_get_port_mask(ale_entry);
143                 int super     = cpsw_ale_get_super(ale_entry);
145                 fprintf(stdout, "%-4d: type: mcast, addr = %02x:%02x:%02x:%02x:%02x:%02x, mcast_state = %s, %ssuper, port_mask = 0x%x\n",
146                         index, ADDR_FMT_ARGS(addr), str_mcast_state[state],
147                         super ? "" : "no ", port_mask);
148         } else {
149                 static const char *s_ucast_type[] = {"persistant", "untouched ",
150                                                      "oui       ", "touched   "};
151                 int ucast_type = cpsw_ale_get_ucast_type(ale_entry);
152                 int port_num   = cpsw_ale_get_port_num(ale_entry);
153                 int secure     = cpsw_ale_get_secure(ale_entry);
154                 int blocked    = cpsw_ale_get_blocked(ale_entry);
156                 fprintf(stdout, "%-4d: type: ucast, addr = %02x:%02x:%02x:%02x:%02x:%02x, ucast_type = %s, port_num = 0x%x%s%s\n",
157                         index, ADDR_FMT_ARGS(addr), s_ucast_type[ucast_type],
158                         port_num, secure ? ", Secure" : "",
159                         blocked ? ", Blocked" : "");
160         }
163 static void cpsw_ale_dump_vlan_addr(int index, u32 *ale_entry)
165         u8 addr[6];
166         int vlan = cpsw_ale_get_vlan_id(ale_entry);
168         cpsw_ale_get_addr(ale_entry, addr);
169         if (cpsw_ale_get_mcast(ale_entry)) {
170                 static const char *str_mcast_state[] = {"f", "blf", "lf", "f"};
171                 int state     = cpsw_ale_get_mcast_state(ale_entry);
172                 int port_mask = cpsw_ale_get_port_mask(ale_entry);
173                 int super     = cpsw_ale_get_super(ale_entry);
175                 fprintf(stdout, "%-4d: type: mcast, vid = %d, addr = %02x:%02x:%02x:%02x:%02x:%02x, mcast_state = %s, %ssuper, port_mask = 0x%x\n",
176                         index, vlan, ADDR_FMT_ARGS(addr),
177                         str_mcast_state[state], super ? "" : "no ", port_mask);
178         } else {
179                 static const char *s_ucast_type[] = {"persistant", "untouched ",
180                                                      "oui       ", "touched   "};
181                 int ucast_type = cpsw_ale_get_ucast_type(ale_entry);
182                 int port_num   = cpsw_ale_get_port_num(ale_entry);
183                 int secure     = cpsw_ale_get_secure(ale_entry);
184                 int blocked    = cpsw_ale_get_blocked(ale_entry);
186                 fprintf(stdout, "%-4d: type: ucast, vid = %d, addr = %02x:%02x:%02x:%02x:%02x:%02x, ucast_type = %s, port_num = 0x%x%s%s\n",
187                         index, vlan, ADDR_FMT_ARGS(addr),
188                         s_ucast_type[ucast_type], port_num,
189                         secure ? ", Secure" : "", blocked ? ", Blocked" : "");
190         }
193 int cpsw_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
195         u32 *reg = (u32 *)regs->data;
196         int i;
198         fprintf(stdout, "cpsw hw version %d.%d (%d)\n",
199                 CPSW_MAJOR_VERSION(regs->version),
200                 CPSW_MINOR_VERSION(regs->version),
201                 CPSW_RTL_VERSION(regs->version));
203         for(i = 0; i < 1024; i++, reg += ALE_ENTRY_WORDS) {
204                 int type;
206                 type = cpsw_ale_get_entry_type(reg);
207                 switch (type) {
208                 case ALE_TYPE_FREE:
209                         break;
211                 case ALE_TYPE_ADDR:
212                         cpsw_ale_dump_addr(i, reg);
213                         break;
215                 case ALE_TYPE_VLAN:
216                         cpsw_ale_dump_vlan(i, reg);
217                         break;
219                 case ALE_TYPE_VLAN_ADDR:
220                         cpsw_ale_dump_vlan_addr(i, reg);
221                         break;
223                 default:
224                         fprintf(stdout, "%-4d: Invalid Entry type\n", i);
225                 }
226         }
228         return 0;
231 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
233 #define SWITCH_CONFIG_COMMAND(__var__, __cmd__)                 \
234         if((__var__) == CONFIG_SWITCH_INVALID) {                \
235                 (__var__) = (__cmd__);                          \
236         } else {                                                \
237                 printf("Two or more commands Cannot be "        \
238                         "processed simultaneously\n");          \
239                 return -1;                                      \
240         }
242 static char options[] = "?m:x:i:y:S:GUg:udn:V:sk:K:M:N:D:Y:z:Z:J:vPp:r:ClB:L:t";
244 static struct option long_options[] =
245         {
246                 /* These options set a flag. */
247 {"add-multi",                   required_argument       , 0, 'm'},
248 {"del-multi",                   required_argument       , 0, 'x'},
249 {"add-vlan",                    required_argument       , 0, 'i'},
250 {"del-vlan",                    required_argument       , 0, 'y'},
251 {"add-unknown-vlan-info",       no_argument             , 0, 'U'},
252 {"set-port-config",             required_argument       , 0, 'S'},
253 {"get-port-config",             no_argument             , 0, 'G'},
254 {"set-port-state",              required_argument       , 0, 'g'},
255 {"get-port-state",              no_argument             , 0, 'u'},
256 {"dump",                        optional_argument       , 0, 'd'},
257 {"port",                        required_argument       , 0, 'n'},
258 {"vid",                         required_argument       , 0, 'V'},
259 {"super",                       no_argument             , 0, 's'},
260 {"fwd-state",                   required_argument       , 0, 'k'},
261 {"vid-untag",                   required_argument       , 0, 'K'},
262 {"reg-multi",                   required_argument       , 0, 'M'},
263 {"unreg-multi",                 required_argument       , 0, 'N'},
264 {"vid-untag-port-mask",         required_argument       , 0, 'Y'},
265 {"reg-multi-port-mask",         required_argument       , 0, 'z'},
266 {"unreg-multi-port-mask",       required_argument       , 0, 'Z'},
267 {"unknown-vlan-mem",            required_argument       , 0, 'J'},
268 {"duplex",                      required_argument       , 0, 'D'},
269 {"version",                     no_argument             , 0, 'v'},
270 {"get-port-vlan",               no_argument             , 0, 'P'},
271 {"set-port-vlan",               required_argument       , 0, 'p'},
272 {"priority",                    required_argument       , 0, 'r'},
273 {"cfi",                         no_argument             , 0, 'C'},
274 {"rate-limit",                  no_argument             , 0, 'l'},
275 {"bcast-limit",                 required_argument       , 0, 'B'},
276 {"mcast-limit",                 required_argument       , 0, 'L'},
277 {"direction",                   no_argument             , 0, 't'},
278 {0, 0, 0, 0}
279 };
281 static inline int is_zero_ether_addr(const unsigned char *addr)
283         return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
286 static inline int is_multicast_ether_addr(const unsigned char *addr)
288         return 0x01 & addr[0];
291 static inline int is_valid_ether_addr(const unsigned char *addr)
293         return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
296 /* String to Hex conversion */
297 static unsigned char cpmac_str_to_hexnum(unsigned char c)
299         if(c >= '0' && c <= '9') return c - '0';
300         if(c >= 'a' && c <= 'f') return c - 'a' + 10;
301         if(c >= 'A' && c <= 'F') return c - 'A' + 10;
302         return 0;
305 /* String to ethernet address conversion */
306 static void config_switch_str_to_ethaddr(char *str, unsigned char *addr)
308         int i;
309         unsigned char num;
310         for(i = 0; i < 6; i++) {
311                 if((*str == '.') || (*str == ':')) str++;
312                 num = cpmac_str_to_hexnum(*str++) << 4;
313                 num |= (cpmac_str_to_hexnum(*str++));
314                 addr[i] = num;
315         }
318 static void
319 dump_link_caps(const char *prefix, const char *an_prefix, u32 mask,
320                int link_mode_only)
322         static const struct {
323                 int same_line; /* print on same line as previous */
324                 u32 value;
325                 const char *name;
326         } mode_defs[] = {
327                 { 0, ADVERTISED_10baseT_Half,       "10baseT/Half" },
328                 { 1, ADVERTISED_10baseT_Full,       "10baseT/Full" },
329                 { 0, ADVERTISED_100baseT_Half,      "100baseT/Half" },
330                 { 1, ADVERTISED_100baseT_Full,      "100baseT/Full" },
331                 { 0, ADVERTISED_1000baseT_Half,     "1000baseT/Half" },
332                 { 1, ADVERTISED_1000baseT_Full,     "1000baseT/Full" },
333                 { 0, ADVERTISED_1000baseKX_Full,    "1000baseKX/Full" },
334                 { 0, ADVERTISED_2500baseX_Full,     "2500baseX/Full" },
335                 { 0, ADVERTISED_10000baseT_Full,    "10000baseT/Full" },
336                 { 0, ADVERTISED_10000baseKX4_Full,  "10000baseKX4/Full" },
337                 { 0, ADVERTISED_10000baseKR_Full,   "10000baseKR/Full" },
338                 { 0, ADVERTISED_20000baseMLD2_Full, "20000baseMLD2/Full" },
339                 { 0, ADVERTISED_20000baseKR2_Full,  "20000baseKR2/Full" },
340                 { 0, ADVERTISED_40000baseKR4_Full,  "40000baseKR4/Full" },
341                 { 0, ADVERTISED_40000baseCR4_Full,  "40000baseCR4/Full" },
342                 { 0, ADVERTISED_40000baseSR4_Full,  "40000baseSR4/Full" },
343                 { 0, ADVERTISED_40000baseLR4_Full,  "40000baseLR4/Full" },
344         };
345         int indent;
346         int did1, new_line_pend, i;
348         /* Indent just like the separate functions used to */
349         indent = strlen(prefix) + 14;
350         if (indent < 24)
351                 indent = 24;
353         fprintf(stdout, "       %s link modes:%*s", prefix,
354                 indent - (int)strlen(prefix) - 12, "");
355         did1 = 0;
356         new_line_pend = 0;
357         for (i = 0; i < ARRAY_SIZE(mode_defs); i++) {
358                 if (did1 && !mode_defs[i].same_line)
359                         new_line_pend = 1;
360                 if (mask & mode_defs[i].value) {
361                         if (new_line_pend) {
362                                 fprintf(stdout, "\n");
363                                 fprintf(stdout, "       %*s", indent, "");
364                                 new_line_pend = 0;
365                         }
366                         did1++;
367                         fprintf(stdout, "%s ", mode_defs[i].name);
368                 }
369         }
370         if (did1 == 0)
371                  fprintf(stdout, "Not reported");
372         fprintf(stdout, "\n");
374         if (!link_mode_only) {
375                 fprintf(stdout, "       %s pause frame use: ", prefix);
376                 if (mask & ADVERTISED_Pause) {
377                         fprintf(stdout, "Symmetric");
378                         if (mask & ADVERTISED_Asym_Pause)
379                                 fprintf(stdout, " Receive-only");
380                         fprintf(stdout, "\n");
381                 } else {
382                         if (mask & ADVERTISED_Asym_Pause)
383                                 fprintf(stdout, "Transmit-only\n");
384                         else
385                                 fprintf(stdout, "No\n");
386                 }
388                 fprintf(stdout, "       %s auto-negotiation: ", an_prefix);
389                 if (mask & ADVERTISED_Autoneg)
390                         fprintf(stdout, "Yes\n");
391                 else
392                         fprintf(stdout, "No\n");
393         }
396 static int dump_ecmd(struct ethtool_cmd *ep)
398         u32 speed;
400         dump_link_caps("Advertised", "Advertised", ep->advertising, 0);
401         if (ep->lp_advertising)
402                 dump_link_caps("Link partner advertised",
403                                "Link partner advertised", ep->lp_advertising,
404                                0);
406         fprintf(stdout, "       Speed: ");
407         speed = ethtool_cmd_speed(ep);
408         if (speed == 0 || speed == (u16)(-1) || speed == (u32)(-1))
409                 fprintf(stdout, "Unknown!\n");
410         else
411                 fprintf(stdout, "%uMb/s\n", speed);
413         fprintf(stdout, "       Duplex: ");
414         switch (ep->duplex) {
415         case DUPLEX_HALF:
416                 fprintf(stdout, "Half\n");
417                 break;
418         case DUPLEX_FULL:
419                 fprintf(stdout, "Full\n");
420                 break;
421         default:
422                 fprintf(stdout, "Unknown! (%i)\n", ep->duplex);
423                 break;
424         };
426         fprintf(stdout, "       Port: ");
427         switch (ep->port) {
428         case PORT_TP:
429                 fprintf(stdout, "Twisted Pair\n");
430                 break;
431         case PORT_AUI:
432                 fprintf(stdout, "AUI\n");
433                 break;
434         case PORT_BNC:
435                 fprintf(stdout, "BNC\n");
436                 break;
437         case PORT_MII:
438                 fprintf(stdout, "MII\n");
439                 break;
440         case PORT_FIBRE:
441                 fprintf(stdout, "FIBRE\n");
442                 break;
443         case PORT_DA:
444                 fprintf(stdout, "Direct Attach Copper\n");
445                 break;
446         case PORT_NONE:
447                 fprintf(stdout, "None\n");
448                 break;
449         case PORT_OTHER:
450                 fprintf(stdout, "Other\n");
451                 break;
452         default:
453                 fprintf(stdout, "Unknown! (%i)\n", ep->port);
454                 break;
455         };
457         fprintf(stdout, "       PHYAD: %d\n", ep->phy_address);
458         fprintf(stdout, "       Transceiver: ");
459         switch (ep->transceiver) {
460         case XCVR_INTERNAL:
461                 fprintf(stdout, "internal\n");
462                 break;
463         case XCVR_EXTERNAL:
464                 fprintf(stdout, "external\n");
465                 break;
466         default:
467                 fprintf(stdout, "Unknown!\n");
468                 break;
469         };
471         fprintf(stdout, "       Auto-negotiation: %s\n",
472                 (ep->autoneg == AUTONEG_DISABLE) ?
473                 "off" : "on");
475         if (ep->port == PORT_TP) {
476                 fprintf(stdout, "       MDI-X: ");
477                 if (ep->eth_tp_mdix_ctrl == ETH_TP_MDI) {
478                         fprintf(stdout, "off (forced)\n");
479                 } else if (ep->eth_tp_mdix_ctrl == ETH_TP_MDI_X) {
480                         fprintf(stdout, "on (forced)\n");
481                 } else {
482                         switch (ep->eth_tp_mdix) {
483                         case ETH_TP_MDI:
484                                 fprintf(stdout, "off");
485                                 break;
486                         case ETH_TP_MDI_X:
487                                 fprintf(stdout, "on");
488                                 break;
489                         default:
490                                 fprintf(stdout, "Unknown");
491                                 break;
492                         }
493                         if (ep->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO)
494                                 fprintf(stdout, " (auto)");
495                         fprintf(stdout, "\n");
496                 }
497         }
499         return 0;
502 void print_help(void)
504         printf(
505                 "Switch configuration commands.....\n"
506                 "All input and output values are in Decimal\n"
507                 "switch-config -m,--add-multi <address> -n,--port <Portmask> "
508                         "[-V,--vid <vid>] [-s,--super] "
509                         "[-k,--fwd-state <value 0-3>]\n"
510                 "switch-config -x,--del-multi <address> [-V,--vid <vid>]\n"
511                 "switch-config -i,--add-vlan <vlan id> -n,--port <Portmask> "
512                         "[-K,--vid-untag <Portmask>] "
513                         "[-M,--reg-multi <Portmask>] "
514                         "[-N,--unreg-multi <Portmask>]\n"
515                 "switch-config -y,--del-vlan <vid>\n"
516                 "switch-config -S,--set-port-config <0(auto)/10/100/1000> "
517                         "-n,--port <PortNo> [-D,--duplex <full/half>]\n"
518                 "switch-config -G,--get-port-config -n,--port <PortNo>\n"
519                 "switch-config -U,--add-unknown-vlan-info "
520                         "[-Y,--vid-untag-port-mask <0-7>] [-z,--reg-multi-port-mask <0-7>] "
521                         "[-Z,--unreg-multi-port-mask <0-7>] "
522                         "[-J,--unknown-vlan-mem <0-7>]\n"
523                 "switch-config -g,--get-port-state <disabled/blocked/learn/forward> "
524                         "-n,--port <PortNo>\n"
525                 "switch-config -u,--set-port-state -n,--port <PortNo>\n"
526                 "switch-config -P,--get-port-vlan -n,--port <Port No 0-2>\n"
527                 "switch-config -p,--set-port-vlan <vid> -n,--port <Port No 0-2> "
528                         "[-r,--priority <priority 0-7>] [-C,--cfi]\n"
529                 "switch-config -l,--rate-limit -n,--port <Port No> "
530                         "-B,--bcast-limit <No of Packet 0-255> "
531                         "-L,--limit <No of Packet 0-255> "
532                         "[-t,--direction specify for Tx] ]\n"
533                 "switch-config -d,--dump\n"
534                 "\n"
535                 );
538 int main(int argc, char **argv)
540         int option_index = 0;
541         int c;
542         struct net_switch_config cmd_struct;
543         unsigned int port_num = 0;
544         struct ifreq ifr;
545         int sockfd;  /* socket fd we use to manipulate stuff with */
546         unsigned int speed;
547         unsigned int duplex;
548         unsigned int autoneg;
549         int extended_switch_config;
551         /* get interface name */
552         strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);
553         ifr.ifr_data = (char*)&cmd_struct;
554         /* Create a channel to the NET kernel. */
555         if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
556                 printf("Can't open the socket\n");
557                 return -1;
558         }
559         memset(&cmd_struct, 0, sizeof(struct net_switch_config));
561         /* parse command line arguments */
562         while ((c = getopt_long(argc, argv, options, long_options,
563                         &option_index)) != -1) {
564                 switch (c) {
565                 case '?':
566                         print_help();
567                         return 0;
568                 case 'v':
569                         printf("switch-config version: %s\n", VERSION);
570                         return 0;
572                 case 'm':
573                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
574                                 CONFIG_SWITCH_ADD_MULTICAST);
575                         config_switch_str_to_ethaddr(optarg,
576                                 cmd_struct.addr);
577                 break;
579                 case 'x':
580                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
581                                 CONFIG_SWITCH_DEL_MULTICAST);
582                         config_switch_str_to_ethaddr(optarg,
583                                 cmd_struct.addr);
584                 break;
586                 case 'i':
587                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
588                                 CONFIG_SWITCH_ADD_VLAN);
589                         cmd_struct.vid = atoi(optarg);
590                 break;
592                 case 'y':
593                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
594                                 CONFIG_SWITCH_DEL_VLAN);
595                         cmd_struct.vid = atoi(optarg);
596                 break;
598                 case 'G':
599                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
600                                 CONFIG_SWITCH_GET_PORT_CONFIG);
601                 break;
603                 case 'S':
604                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
605                                 CONFIG_SWITCH_SET_PORT_CONFIG);
606                         speed = atoi(optarg);
607                         if (speed == 0)
608                                 autoneg = AUTONEG_ENABLE;
609                         else
610                                 autoneg = AUTONEG_DISABLE;
611                 break;
613                 case 'U':
614                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
615                                 CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO);
616                         printf("CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO\n");
617                 break;
619                 case 'g':
620                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
621                                 CONFIG_SWITCH_SET_PORT_STATE);
622                         if (!strcmp(optarg, "disabled"))
623                                 cmd_struct.port_state = PORT_STATE_DISABLED;
624                         else if (!strcmp(optarg, "blocked"))
625                                 cmd_struct.port_state = PORT_STATE_BLOCKED;
626                         else if (!strcmp(optarg, "learn"))
627                                 cmd_struct.port_state = PORT_STATE_LEARN;
628                         else if (!strcmp(optarg, "forward"))
629                                 cmd_struct.port_state = PORT_STATE_FORWARD;
630                         else {
631                                 printf("Invalid Port State\n");
632                                 return -1;
633                         }
634                 break;
636                 case 'u':
637                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
638                                 CONFIG_SWITCH_GET_PORT_STATE);
639                 break;
641                 case 'P':
642                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
643                                 CONFIG_SWITCH_GET_PORT_VLAN_CONFIG);
644                 break;
646                 case 'p':
647                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
648                                 CONFIG_SWITCH_SET_PORT_VLAN_CONFIG);
649                         cmd_struct.vid = atoi(optarg);
650                 break;
652                 case 'l':
653                         SWITCH_CONFIG_COMMAND(cmd_struct.cmd,
654                                 CONFIG_SWITCH_RATELIMIT);
655                 break;
657                 /* Extended switch commands */
658                 case 'd':
659                         extended_switch_config = EXTENDED_CONFIG_SWITCH_DUMP;
660                 break;
662 /* Command arguments */
663                 case 'n':
664                         port_num = atoi(optarg);
665                 break;
667                 case 'V':
668                         cmd_struct.vid = atoi(optarg);
669                 break;
671                 case 'k':
672                         cmd_struct.untag_port = atoi(optarg);
673                 break;
675                 case 'K':
676                         cmd_struct.untag_port = atoi(optarg);
677                 break;
679                 case 'M':
680                         cmd_struct.reg_multi = atoi(optarg);
681                 break;
683                 case 'N':
684                         cmd_struct.unreg_multi = atoi(optarg);
685                 break;
687                 case 'D':
688                         if (!strcmp(optarg, "full"))
689                                 duplex = DUPLEX_FULL;
690                         else if (!strcmp(optarg, "half"))
691                                 duplex = DUPLEX_HALF;
692                         else {
693                                 printf("Invalid Options for Duplex\n");
694                                 close(sockfd);
695                                 return -1;
696                         }
697                 break;
699                 case 'Y':
700                         cmd_struct.unknown_vlan_untag = atoi(optarg);
701                 break;
703                 case 'z':
704                         cmd_struct.unknown_vlan_reg_multi = atoi(optarg);
705                 break;
707                 case 'Z':
708                         cmd_struct.unknown_vlan_unreg_multi = atoi(optarg);
709                 break;
711                 case 'J':
712                         cmd_struct.unknown_vlan_member = atoi(optarg);
713                 break;
715                 case 'r':
716                         cmd_struct.prio = atoi(optarg);
717                 break;
719                 case 'C':
720                         cmd_struct.vlan_cfi = true;
721                 break;
723                 case 'B':
724                         cmd_struct.bcast_rate_limit = atoi(optarg);
725                 break;
727                 case 'L':
728                         cmd_struct.mcast_rate_limit = atoi(optarg);
729                 break;
731                 case 't':
732                         cmd_struct.direction = true;
733                 break;
735                 default:
736                         print_help();
737                         return 0;
738                 }
739         }
741         switch (cmd_struct.cmd) {
742                 case CONFIG_SWITCH_INVALID:
743                         if (extended_switch_config != EXTENDED_CONFIG_SWITCH_INVALID)
744                                 goto extended_ioctls;
745                         print_help();
746                         return -1;
747                 break;
749                 case CONFIG_SWITCH_ADD_MULTICAST:
750                         if ((cmd_struct.vid <= 4095) &&
751                                 (port_num > 0) && (port_num <= 7) &&
752                                 is_multicast_ether_addr(cmd_struct.addr)) {
753                                 cmd_struct.port = port_num;
754                                 printf("port number %d\n", cmd_struct.port);
755                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
756                                         printf("Multicast add failed\n");
757                                         close(sockfd);
758                                         return -1;
759                                 } else
760                                         printf("Multicast address added successfully\n");
761                         } else {
762                                 printf("Invalid Arguments\n");
763                                 return -1;
764                         }
765                 break;
767                 case CONFIG_SWITCH_DEL_MULTICAST:
768                         if ((cmd_struct.vid <= 4095) &&
769                                 is_multicast_ether_addr(cmd_struct.addr)) {
770                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
771                                         printf("Multicast Address Not found\n");
772                                         close(sockfd);
773                                         return -1;
774                                 } else
775                                         printf("Multicast Address Deleted successfully\n");
776                         } else {
777                                 printf("Invalid Arguments\n");
778                                 return -1;
779                         }
780                 break;
782                 case CONFIG_SWITCH_ADD_VLAN:
783                         if ((cmd_struct.vid <= 4095) &&
784                                 (port_num > 0) && (port_num <= 7)) {
785                                 cmd_struct.port = port_num;
786                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
787                                         printf("VLAN add failed\n");
788                                         close(sockfd);
789                                         return -1;
790                                 } else
791                                         printf("VLAN added successfully\n");
792                         } else {
793                                 printf("Invalid Arguments\n");
794                                 return -1;
795                         }
796                 break;
798                 case CONFIG_SWITCH_DEL_VLAN:
799                         if ((cmd_struct.vid <= 4095) &&
800                                 (port_num <= 7)) {
801                                 cmd_struct.port = port_num;
802                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
803                                         printf("VLAN Not found\n");
804                                         close(sockfd);
805                                         return -1;
806                                 } else
807                                         printf("VLAN Deleted Successfully\n");
808                         } else {
809                                 printf("Invalid Arguments\n");
810                                 return -1;
811                         }
812                 break;
814                 case CONFIG_SWITCH_SET_PORT_CONFIG:
815                         if ((port_num == 1) || (port_num == 2)) {
816                                 cmd_struct.port = port_num;
817                                 cmd_struct.cmd = CONFIG_SWITCH_GET_PORT_CONFIG;
819                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
820                                         printf("Set Port Config Failed\n");
821                                         close(sockfd);
822                                         return -1;
823                                 } else
824                                         printf("Set Port Config successful\n");
826                                 ethtool_cmd_speed_set(&cmd_struct.ecmd, speed);
827                                 cmd_struct.ecmd.duplex = duplex;
828                                 cmd_struct.ecmd.autoneg = autoneg;
829                                 cmd_struct.cmd = CONFIG_SWITCH_SET_PORT_CONFIG;
831                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
832                                         printf("Set Port Config Failed\n");
833                                         close(sockfd);
834                                         return -1;
835                                 } else
836                                         printf("Set Port Config successful\n");
837                         } else {
838                                 printf("Invalid Arguments\n");
839                                 return -1;
840                         }
841                 break;
843                 case CONFIG_SWITCH_GET_PORT_CONFIG:
844                         if ((port_num == 1) || (port_num == 2)) {
845                                 cmd_struct.port = port_num;
846                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
847                                         printf("Get Port Config Failed\n");
848                                         close(sockfd);
849                                         return -1;
850                                 } else {
851                                         printf("Get Port Config successful\n");
852                                         dump_ecmd(&cmd_struct.ecmd);
853                                 }
854                         } else {
855                                 printf("Invalid Arguments\n");
856                                 return -1;
857                         }
858                 break;
860                 case CONFIG_SWITCH_ADD_UNKNOWN_VLAN_INFO:
861                         if ((cmd_struct.unknown_vlan_member <= 7) &&
862                             (cmd_struct.unknown_vlan_untag <= 7) &&
863                             (cmd_struct.unknown_vlan_unreg_multi <= 7) &&
864                             (cmd_struct.unknown_vlan_reg_multi <= 7)) {
865                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
866                                         printf("Add unknown VLAN Failed\n");
867                                         close(sockfd);
868                                         return -1;
869                                 } else {
870                                         printf("Add unknown VLAN successful\n");
871                                 }
872                         } else {
873                                 printf("Invalid Arguments\n");
874                                 return -1;
875                         }
876                 break;
878                 case CONFIG_SWITCH_SET_PORT_STATE:
879                         if ((port_num == 1) || (port_num == 2)) {
880                                 cmd_struct.port = port_num;
881                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
882                                         printf("Set Port State Failed\n");
883                                         close(sockfd);
884                                         return -1;
885                                 } else
886                                         printf("Set Port State successful\n");
887                         } else {
888                                 printf("Invalid Arguments\n");
889                                 return -1;
890                         }
891                 break;
893                 case CONFIG_SWITCH_GET_PORT_STATE:
894                         if ((port_num == 1) || (port_num == 2)) {
895                                 cmd_struct.port = port_num;
896                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
897                                         printf("Get Port State Failed\n");
898                                         close(sockfd);
899                                         return -1;
900                                 } else
901                                         printf("Get Port State successful\nState is ");
902                                 if (cmd_struct.port_state == PORT_STATE_DISABLED)
903                                         printf("disabled\n");
904                                 else if (cmd_struct.port_state == PORT_STATE_BLOCKED)
905                                         printf("blocked\n");
906                                 else if (cmd_struct.port_state == PORT_STATE_LEARN)
907                                         printf("learn\n");
908                                 else if (cmd_struct.port_state == PORT_STATE_FORWARD)
909                                         printf("forward\n");
910                                 else
911                                         printf("Invalid State\n");
912                         } else {
913                                 printf("Invalid Arguments\n");
914                                 return -1;
915                         }
916                 break;
918                 case CONFIG_SWITCH_GET_PORT_VLAN_CONFIG:
919                         if (port_num <= 2) {
920                                 cmd_struct.port = port_num;
921                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
922                                         printf("Get Port VLAN Failed\n");
923                                         close(sockfd);
924                                         return -1;
925                                 } else {
926                                         printf("Get Port VLAN successful\n");
927                                 }
928                                 printf("Port VLAN id = %d\n", cmd_struct.vid);
929                                 printf("Port VLAN Priority = %d\n", cmd_struct.prio);
930                                 printf("Port VLAN CFI is %sset\n", cmd_struct.vlan_cfi ? "" : "not ");
931                         } else {
932                                 printf("Invalid Arguments\n");
933                                 return -1;
934                         }
935                 break;
937                 case CONFIG_SWITCH_SET_PORT_VLAN_CONFIG:
938                         if ((port_num <= 2) && (cmd_struct.prio <= 7)) {
939                                 cmd_struct.port = port_num;
940                                 if (ioctl(sockfd, SIOCSWITCHCONFIG, &ifr) < 0) {
941                                         printf("Set Port VLAN Failed\n");
942                                         close(sockfd);
943                                         return -1;
944                                 } else {
945                                         printf("Set Port VLAN successful\nState is ");
946                                 }
947                         } else {
948                                 printf("Invalid Arguments\n");
949                                 return -1;
950                         }
951                 break;
952         }
954         close(sockfd);
955         return 0;
957 extended_ioctls:
958         switch (extended_switch_config) {
959                 case EXTENDED_CONFIG_SWITCH_DUMP:
960                 {
961                         struct ethtool_drvinfo drvinfo;
962                         struct ethtool_regs *regs;
964                         drvinfo.cmd = ETHTOOL_GDRVINFO;
965                         ifr.ifr_data = (void *)&drvinfo;
966                         if (ioctl(sockfd, SIOCETHTOOL, &ifr) < 0) {
967                                 perror("Cannot get driver information");
968                                 return -1;
969                         }
971                         regs = calloc(1, sizeof(*regs)+drvinfo.regdump_len);
972                         if (!regs) {
973                                 perror("Cannot allocate memory for register dump");
974                                 return -1;
975                         }
977                         regs->cmd = ETHTOOL_GREGS;
978                         regs->len = drvinfo.regdump_len;
979                         ifr.ifr_data = (void *)regs;
980                         if (ioctl(sockfd, SIOCETHTOOL, &ifr) < 0) {
981                                 perror("Cannot get driver information");
982                                 return -1;
983                         }
984                         cpsw_dump_regs(&drvinfo, regs);
985                 }
986                 break;
988                 case EXTENDED_CONFIG_SWITCH_INVALID:
989                 default:
990                         print_help();
991                         return -1;
992                 break;
993         }
995         close(sockfd);
996         return 0;