]> git.ipfire.org Git - people/ms/rstp.git/blob - ctl_main.c
rstpctl: Add dump funtionality.
[people/ms/rstp.git] / ctl_main.c
1 /*
2 Command parsing taken from brctl utility.
3 Display code from stp_cli.c in rstplib.
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/errno.h>
10 #include <getopt.h>
11
12 #include <net/if.h>
13
14 /* For scanning through sysfs directories */
15 #include <dirent.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
19 #include <limits.h>
20
21 #include "ctl_socket_client.h"
22 #include "ctl_functions.h"
23
24 int get_index_die(const char *ifname, const char *doc, int die)
25 {
26 int r = if_nametoindex(ifname);
27 if (r == 0) {
28 fprintf(stderr,
29 "Can't find index for %s %s. Not a valid interface.\n",
30 doc, ifname);
31 if (die)
32 exit(1);
33 return -1;
34 }
35 return r;
36 }
37
38 int get_index(const char *ifname, const char *doc)
39 {
40 return get_index_die(ifname, doc, 1);
41 }
42
43 #define BR_ID_FMT "%02x%02x.%02x%02x%02x%02x%02x%02x"
44 #define BR_ID_ARGS(x) x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]
45
46 #define BOOL_STR(x) ((x) ? "yes" : "no")
47
48 static int do_showbridge(const char *br_name)
49 {
50 STP_BridgeStatus s;
51
52 int br_index = get_index_die(br_name, "bridge", 0);
53 if (br_index < 0)
54 return -1;
55
56 int r = CTL_get_bridge_status(br_index, &s);
57 if (r) {
58 return -1;
59 }
60 printf("%s\n", br_name);
61 printf(" enabled\t\t%4s\n", BOOL_STR(s.enabled));
62 printf(" bridge id\t\t" BR_ID_FMT "\n", BR_ID_ARGS(s.bridge_id));
63 printf(" designated root\t" BR_ID_FMT "\n",
64 BR_ID_ARGS(s.designated_root));
65 //printf(" designated bridge\t\t", BR_ID_FMT "\n",
66 // BR_ID_ARGS(s.designated_bridge));
67 printf(" root port\t\t%4u", s.root_port);
68 printf("\t\t\tpath cost\t\t%4u\n", s.root_path_cost);
69 printf(" max age\t\t%4u", s.max_age);
70 printf("\t\t\tbridge max age\t\t%4u\n", s.bridge_max_age);
71 printf(" hello time\t\t%4u", s.hello_time);
72 printf("\t\t\tbridge hello time\t%4u\n", s.bridge_hello_time);
73 printf(" forward delay\t\t%4u", s.forward_delay);
74 printf("\t\t\tbridge forward delay\t%4u\n", s.bridge_forward_delay);
75 printf(" tx hold count\t\t%4u\n", s.tx_hold_count);
76 printf(" protocol version\t%4u\n", s.protocol_version);
77 printf(" time since topology change\t%4u\n",
78 s.time_since_topology_change);
79 printf(" toplogy change count\t\t%4u\n", s.topology_change_count);
80 printf(" topology change\t\t%4s\n", BOOL_STR(s.topology_change));
81
82 return 0;
83 }
84
85 #define SYSFS_PATH_MAX 256
86 #define SYSFS_CLASS_NET "/sys/class/net"
87
88 static int isbridge(const struct dirent *entry)
89 {
90 char path[SYSFS_PATH_MAX];
91 struct stat st;
92
93 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "/%s/bridge",
94 entry->d_name);
95 return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
96 }
97
98 static int cmd_showbridge(int argc, char *const *argv)
99 {
100 int i, count = 0;
101 int r = 0;
102 struct dirent **namelist;
103
104 if (argc > 1) {
105 count = argc - 1;
106 } else {
107 count =
108 scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
109 if (count < 0) {
110 fprintf(stderr, "Error getting list of all bridges\n");
111 return -1;
112 }
113 }
114
115 for (i = 0; i < count; i++) {
116 const char *name;
117 if (argc > 1)
118 name = argv[i + 1];
119 else
120 name = namelist[i]->d_name;
121
122 int err = do_showbridge(name);
123 if (err)
124 r = err;
125 }
126
127 if (argc <= 1) {
128 for (i = 0; i < count; i++)
129 free(namelist[i]);
130 free(namelist);
131 }
132
133 return r;
134 }
135
136
137 #define STATE_STR(_state) \
138 ({ \
139 int _s = _state; \
140 char *_str = "unknown"; \
141 switch (_s) \
142 { \
143 case STP_PORT_STATE_DISCARDING: _str = "discarding"; break; \
144 case STP_PORT_STATE_LEARNING: _str = "learning"; break; \
145 case STP_PORT_STATE_FORWARDING: _str = "forwarding"; break; \
146 } \
147 _str; \
148 })
149
150 #define SHORT_STATE_STR(_state) \
151 ({ \
152 int _s = _state; \
153 char *_str = "unkn"; \
154 switch (_s) \
155 { \
156 case STP_PORT_STATE_DISCARDING: _str = "disc"; break; \
157 case STP_PORT_STATE_LEARNING: _str = "lear"; break; \
158 case STP_PORT_STATE_FORWARDING: _str = "forw"; break; \
159 } \
160 _str; \
161 })
162
163 #define ADMIN_P2P_STR(_state) \
164 ({ \
165 int _s = _state; \
166 char *_str = "unkn"; \
167 switch (_s) \
168 { \
169 case STP_ADMIN_P2P_FORCE_FALSE: _str = "no"; break; \
170 case STP_ADMIN_P2P_FORCE_TRUE: _str = "yes"; break; \
171 case STP_ADMIN_P2P_AUTO: _str = "auto"; break; \
172 } \
173 _str; \
174 })
175
176
177 int detail = 0;
178
179 static int do_showport(int br_index, const char *port_name)
180 {
181 STP_PortStatus s;
182 int r = 0;
183 int port_index = get_index_die(port_name, "port", 0);
184 if (port_index < 0)
185 return -1;
186
187 r = CTL_get_port_status(br_index, port_index, &s);
188 if (r) {
189 fprintf(stderr, "Failed to get port state for port %d\n",
190 port_index);
191 return -1;
192 }
193
194 if (detail) {
195 printf("%s (%u)\n", port_name, (s.id & 0xfff));
196 printf(" enabled\t\t%4s\n", BOOL_STR(s.enabled));
197 printf(" port id\t\t%04x\t\t\tstate\t\t%15s\n",
198 s.id, STATE_STR(s.state));
199 printf(" path cost\t%12d\t\t\tadmin path cost\t%12d\n",
200 s.path_cost, s.admin_path_cost);
201 printf(" designated root\t" BR_ID_FMT,
202 BR_ID_ARGS(s.designated_root));
203 printf("\tdesignated cost\t%12u\n", s.designated_cost);
204 printf(" designated bridge\t" BR_ID_FMT,
205 BR_ID_ARGS(s.designated_bridge));
206 printf("\tdesignated port\t\t%04x\n", s.designated_port);
207 printf(" admin edge port\t%4s", BOOL_STR(s.admin_edge_port));
208 printf("\t\t\tauto edge port\t\t%4s\n",
209 BOOL_STR(s.auto_edge_port));
210 printf(" oper edge port\t\t%4s", BOOL_STR(s.oper_edge_port));
211 printf("\t\t\ttoplogy change ack\t%4s\n", BOOL_STR(s.tc_ack));
212 printf(" point to point\t\t%4s", BOOL_STR(s.oper_p2p));
213 printf("\t\t\tadmin point to point\t%4s\n",
214 ADMIN_P2P_STR(s.admin_p2p));
215 } else {
216 printf("%c%c %4s %04x %4s " BR_ID_FMT " " BR_ID_FMT " %04x\n",
217 (s.oper_p2p) ? ' ' : '*',
218 (s.oper_edge_port) ? 'E' : ' ',
219 port_name,
220 s.id,
221 s.enabled?SHORT_STATE_STR(s.state):"down",
222 BR_ID_ARGS(s.designated_root),
223 BR_ID_ARGS(s.designated_bridge),
224 s.designated_port);
225 }
226 return 0;
227 }
228
229 static int not_dot_dotdot(const struct dirent *entry)
230 {
231 const char *n = entry->d_name;
232
233 return !(n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)));
234 }
235
236 static int cmd_showport(int argc, char *const *argv)
237 {
238 int r = 0;
239
240 int br_index = get_index(argv[1], "bridge");
241
242 int i, count = 0;
243 struct dirent **namelist;
244
245 if (argc > 2) {
246 count = argc - 2;
247 } else {
248 char buf[SYSFS_PATH_MAX];
249 snprintf(buf, sizeof(buf), SYSFS_CLASS_NET "/%s/brif", argv[1]);
250 count = scandir(buf, &namelist, not_dot_dotdot, alphasort);
251 if (count < 0) {
252 fprintf(stderr,
253 "Error getting list of all ports of bridge %s\n",
254 argv[1]);
255 return -1;
256 }
257 }
258
259 for (i = 0; i < count; i++) {
260 const char *name;
261 if (argc > 2)
262 name = argv[i + 2];
263 else
264 name = namelist[i]->d_name;
265
266 int err = do_showport(br_index, name);
267 if (err)
268 r = err;
269 }
270
271 if (argc <= 2) {
272 for (i = 0; i < count; i++)
273 free(namelist[i]);
274 free(namelist);
275 }
276
277 return r;
278 }
279
280 static int cmd_showportdetail(int argc, char *const *argv)
281 {
282 detail = 1;
283 return cmd_showport(argc, argv);
284 }
285
286 unsigned int getuint(const char *s)
287 {
288 char *end;
289 long l;
290 l = strtoul(s, &end, 0);
291 if (*s == 0 || *end != 0 || l > INT_MAX) {
292 fprintf(stderr, "Invalid unsigned int arg %s\n", s);
293 exit(1);
294 }
295 return l;
296 }
297
298 int getenum(const char *s, const char *opt[])
299 {
300 int i;
301 for (i = 0; opt[i] != NULL; i++)
302 if (strcmp(s, opt[i]) == 0)
303 return i;
304
305 fprintf(stderr, "Invalid argument %s: expecting one of ", s);
306 for (i = 0; opt[i] != NULL; i++)
307 fprintf(stderr, "%s%s", opt[i], (opt[i + 1] ? ", " : "\n"));
308
309 exit(1);
310 }
311
312 int getyesno(const char *s, const char *yes, const char *no)
313 {
314 /* Reverse yes and no so error message looks more normal */
315 const char *opt[] = { yes, no, NULL };
316 return 1 - getenum(s, opt);
317 }
318
319 #define set_bridge_cfg(field, value) \
320 ({ \
321 STP_BridgeConfig c; \
322 memset(&c, 0, sizeof(c)); \
323 c.field = value; \
324 c.set_ ## field = 1; \
325 int r = CTL_set_bridge_config(br_index, &c); \
326 if (r) \
327 printf("Couldn't change bridge " #field "\n"); \
328 r; \
329 })
330
331 #define set_port_cfg(field, value) \
332 ({ \
333 STP_PortConfig c; \
334 memset(&c, 0, sizeof(c)); \
335 c.field = value; \
336 c.set_ ## field = 1; \
337 int r = CTL_set_port_config(br_index, port_index, &c); \
338 if (r) \
339 printf("Couldn't change port " #field "\n"); \
340 r; \
341 })
342
343
344
345 static int cmd_setbridgeprio(int argc, char *const *argv)
346 {
347
348 int br_index = get_index(argv[1], "bridge");
349 return set_bridge_cfg(bridge_priority, getuint(argv[2]));
350 }
351
352 static int cmd_setbridgemaxage(int argc, char *const *argv)
353 {
354
355 int br_index = get_index(argv[1], "bridge");
356 return set_bridge_cfg(bridge_max_age, getuint(argv[2]));
357 }
358
359 static int cmd_setbridgehello(int argc, char *const *argv)
360 {
361
362 int br_index = get_index(argv[1], "bridge");
363 return set_bridge_cfg(bridge_hello_time, getuint(argv[2]));
364 }
365
366 static int cmd_setbridgefdelay(int argc, char *const *argv)
367 {
368
369 int br_index = get_index(argv[1], "bridge");
370 return set_bridge_cfg(bridge_forward_delay, getuint(argv[2]));
371 }
372
373 static int cmd_setbridgeforcevers(int argc, char *const *argv)
374 {
375
376 int br_index = get_index(argv[1], "bridge");
377 return set_bridge_cfg(bridge_protocol_version,
378 2 * getyesno(argv[2], "normal", "slow"));
379 }
380
381 static int cmd_setbridgetxholdcount(int argc, char *const *argv)
382 {
383
384 int br_index = get_index(argv[1], "bridge");
385 return set_bridge_cfg(bridge_tx_hold_count, getuint(argv[2]));
386 }
387
388
389 static int cmd_setportprio(int argc, char *const *argv)
390 {
391
392 int br_index = get_index(argv[1], "bridge");
393 int port_index = get_index(argv[2], "port");
394 return set_port_cfg(port_priority, getuint(argv[3]));
395 }
396
397 static int cmd_setportpathcost(int argc, char *const *argv)
398 {
399
400 int br_index = get_index(argv[1], "bridge");
401 int port_index = get_index(argv[2], "port");
402 return set_port_cfg(port_pathcost, getuint(argv[3]));
403 }
404
405 static int cmd_setportadminedge(int argc, char *const *argv)
406 {
407
408 int br_index = get_index(argv[1], "bridge");
409 int port_index = get_index(argv[2], "port");
410 return set_port_cfg(port_admin_edge, getyesno(argv[3], "yes", "no"));
411 }
412
413 static int cmd_setportautoedge(int argc, char *const *argv)
414 {
415
416 int br_index = get_index(argv[1], "bridge");
417 int port_index = get_index(argv[2], "port");
418 return set_port_cfg(port_auto_edge, getyesno(argv[3], "yes", "no"));
419 }
420
421 static int cmd_setportp2p(int argc, char *const *argv)
422 {
423
424 int br_index = get_index(argv[1], "bridge");
425 int port_index = get_index(argv[2], "port");
426 const char *opts[] = { "no", "yes", "auto", NULL };
427 int vals[] = { STP_ADMIN_P2P_FORCE_FALSE, STP_ADMIN_P2P_FORCE_TRUE,
428 STP_ADMIN_P2P_AUTO };
429
430 return set_port_cfg(port_admin_p2p, vals[getenum(argv[3], opts)]);
431 }
432
433 static int cmd_portmcheck(int argc, char *const *argv)
434 {
435
436 int br_index = get_index(argv[1], "bridge");
437 int port_index = get_index(argv[2], "port");
438 return CTL_port_mcheck(br_index, port_index);
439 }
440
441 static int cmd_debuglevel(int argc, char *const *argv)
442 {
443 return CTL_set_debug_level(getuint(argv[1]));
444 }
445
446 #define DUMP_FMT(br_name, key) "%-8s %-26s ", br_name, key
447
448 static int do_dumpbridge(const char *br_name) {
449 STP_BridgeStatus s;
450
451 int br_index = get_index_die(br_name, "bridge", 0);
452 if (br_index < 0)
453 return -1;
454
455 int r = CTL_get_bridge_status(br_index, &s);
456 if (r)
457 return -1;
458
459 /* bridge forward delay */
460 printf(DUMP_FMT(br_name, "bridge_forward_delay"));
461 printf("%u\n", s.bridge_forward_delay);
462
463 /* bridge hello time */
464 printf(DUMP_FMT(br_name, "bridge_hello_time"));
465 printf("%u\n", s.bridge_hello_time);
466
467 /* bridge max age */
468 printf(DUMP_FMT(br_name, "bridge_max_age"));
469 printf("%u\n", s.bridge_max_age);
470
471 /* designated root */
472 printf(DUMP_FMT(br_name, "designated_root"));
473 printf(BR_ID_FMT "\n", BR_ID_ARGS(s.designated_root));
474
475 /* enabled */
476 printf(DUMP_FMT(br_name, "enabled"));
477 printf("%s\n", BOOL_STR(s.enabled));
478
479 /* forward delay */
480 printf(DUMP_FMT(br_name, "forward_delay"));
481 printf("%u\n", s.forward_delay);
482
483 /* hello time */
484 printf(DUMP_FMT(br_name, "hello_time"));
485 printf("%u\n", s.hello_time);
486
487 /* id */
488 printf(DUMP_FMT(br_name, "id"));
489 printf(BR_ID_FMT "\n", BR_ID_ARGS(s.bridge_id));
490
491 /* max age */
492 printf(DUMP_FMT(br_name, "max_age"));
493 printf("%u\n", s.max_age);
494
495 /* root path cost */
496 printf(DUMP_FMT(br_name, "root_path_cost"));
497 printf("%u\n", s.root_path_cost);
498
499 /* root port */
500 printf(DUMP_FMT(br_name, "root_port"));
501 printf("%u\n", s.root_port);
502
503 /* time since topology change */
504 printf(DUMP_FMT(br_name, "time_since_topology_change"));
505 printf("%u\n", s.time_since_topology_change);
506
507 /* topology change */
508 printf(DUMP_FMT(br_name, "topology_change"));
509 printf("%u\n", s.topology_change);
510
511 /* topology change count */
512 printf(DUMP_FMT(br_name, "topology_change_count"));
513 printf("%u\n", s.topology_change_count);
514
515 /* tx hold count */
516 printf(DUMP_FMT(br_name, "tx_hold_count"));
517 printf("%u\n", s.tx_hold_count);
518
519 return 0;
520 }
521
522 static int do_dumpbridgeport(int br_index, const char *pt_name) {
523 STP_PortStatus p;
524 int r = 0;
525 int port_index = get_index_die(pt_name, "port", 0);
526 if (port_index < 0)
527 return -1;
528
529 r = CTL_get_port_status(br_index, port_index, &p);
530 if (r) {
531 fprintf(stderr, "Failed to get port state for port %d\n", port_index);
532 return -1;
533 }
534
535 /* admin edge port */
536 printf(DUMP_FMT(pt_name, "admin_edge_port"));
537 printf("%s\n", BOOL_STR(p.admin_edge_port));
538
539 /* admin point to point */
540 printf(DUMP_FMT(pt_name, "admin_point_to_point"));
541 printf("%s\n", BOOL_STR(p.admin_p2p));
542
543 /* auto edge port */
544 printf(DUMP_FMT(pt_name, "auto_edge_port"));
545 printf("%s\n", BOOL_STR(p.auto_edge_port));
546
547 /* path cost */
548 printf(DUMP_FMT(pt_name, "admin_path_cost"));
549 printf("%d\n", p.admin_path_cost);
550
551 /* designated bridge */
552 printf(DUMP_FMT(pt_name, "designated_bridge"));
553 printf(BR_ID_FMT "\n", BR_ID_ARGS(p.designated_bridge));
554
555 /* designated cost */
556 printf(DUMP_FMT(pt_name, "designated_cost"));
557 printf("%d\n", p.designated_cost);
558
559 /* designated port */
560 printf(DUMP_FMT(pt_name, "designated_port"));
561 printf("%0x\n", p.designated_port);
562
563 /* designated root */
564 printf(DUMP_FMT(pt_name, "designated_root"));
565 printf(BR_ID_FMT "\n", BR_ID_ARGS(p.designated_root));
566
567 /* enabled */
568 printf(DUMP_FMT(pt_name, "enabled"));
569 printf("%s\n", BOOL_STR(p.enabled));
570
571 /* id */
572 printf(DUMP_FMT(pt_name, "id"));
573 printf("%u\n", p.id & 0xfff);
574
575 /* oper edge port */
576 printf(DUMP_FMT(pt_name, "oper_edge_port"));
577 printf("%s\n", BOOL_STR(p.oper_edge_port));
578
579 /* path cost */
580 printf(DUMP_FMT(pt_name, "path_cost"));
581 printf("%d\n", p.path_cost);
582
583 /* point to point */
584 printf(DUMP_FMT(pt_name, "point_to_point"));
585 printf("%s\n", BOOL_STR(p.oper_p2p));
586
587 /* state */
588 printf(DUMP_FMT(pt_name, "state"));
589 printf(STATE_STR(p.state));
590 printf("\n");
591
592 /* topology change ack */
593 printf(DUMP_FMT(pt_name, "topology_change_ack"));
594 printf("%s\n", BOOL_STR(p.tc_ack));
595
596 return 0;
597 }
598
599 static int cmd_dumpbridge(int argc, char *const *argv)
600 {
601 int i, count = 0;
602 int r = 0;
603 struct dirent **namelist;
604
605 if (argc > 1) {
606 count = argc - 1;
607 } else {
608 count =
609 scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
610 if (count < 0) {
611 fprintf(stderr, "Error getting list of all bridges\n");
612 return -1;
613 }
614 }
615
616 for (i = 0; i < count; i++) {
617 const char *name;
618 if (argc > 1)
619 name = argv[i + 1];
620 else
621 name = namelist[i]->d_name;
622
623 int err = do_dumpbridge(name);
624 if (err)
625 r = err;
626 }
627
628 if (argc <= 1) {
629 for (i = 0; i < count; i++)
630 free(namelist[i]);
631 free(namelist);
632 }
633
634 return r;
635 }
636
637 static int cmd_dumpbridgeports(int argc, char *const *argv)
638 {
639 int r = 0;
640
641 int br_index = get_index(argv[1], "bridge");
642
643 int i, count = 0;
644 struct dirent **namelist;
645
646 if (argc > 2) {
647 count = argc - 2;
648 } else {
649 char buf[SYSFS_PATH_MAX];
650 snprintf(buf, sizeof(buf), SYSFS_CLASS_NET "/%s/brif", argv[1]);
651 count = scandir(buf, &namelist, not_dot_dotdot, alphasort);
652 if (count < 0) {
653 fprintf(stderr,
654 "Error getting list of all ports of bridge %s\n",
655 argv[1]);
656 return -1;
657 }
658 }
659
660 for (i = 0; i < count; i++) {
661 const char *name;
662 name = namelist[i]->d_name;
663
664 int err = do_dumpbridgeport(br_index, name);
665 if (err)
666 r = err;
667 }
668
669 for (i = 0; i < count; i++)
670 free(namelist[i]);
671 free(namelist);
672
673 return r;
674 }
675
676 struct command {
677 int nargs;
678 int optargs;
679 const char *name;
680 int (*func) (int argc, char *const *argv);
681 const char *help;
682 };
683
684 static const struct command commands[] = {
685 {0, 32, "showbridge", cmd_showbridge,
686 "[<bridge> ... ]\t\tshow bridge state"},
687 {1, 32, "showport", cmd_showport,
688 "<bridge> [<port> ... ]\tshow port state"},
689 {1, 32, "showportdetail", cmd_showportdetail,
690 "<bridge> [<port> ... ]\tshow port state (detail)"},
691 {2, 0, "setbridgeprio", cmd_setbridgeprio,
692 "<bridge> <priority>\tset bridge priority (0-61440)"},
693 {2, 0, "sethello", cmd_setbridgehello,
694 "<bridge> <hellotime>\tset bridge hello time (1-10)"},
695 {2, 0, "setmaxage", cmd_setbridgemaxage,
696 "<bridge> <maxage>\tset bridge max age (6-40)"},
697 {2, 0, "setfdelay", cmd_setbridgefdelay,
698 "<bridge> <fwd_delay>\tset bridge forward delay (4-30)"},
699 {2, 0, "setforcevers", cmd_setbridgeforcevers,
700 "<bridge> {normal|slow}\tnormal RSTP or force to STP"},
701 {2, 0, "settxholdcount", cmd_setbridgetxholdcount,
702 "<bridge> <tx_hold_count>\tset bridge transmit hold count (1-10)"},
703 {3, 0, "setportprio", cmd_setportprio,
704 "<bridge> <port> <priority>\tset port priority (0-240)"},
705 {3, 0, "setportpathcost", cmd_setportpathcost,
706 "<bridge> <port> <cost>\tset port path cost"},
707 {3, 0, "setportadminedge", cmd_setportadminedge,
708 "<bridge> <port> {yes|no}\tconfigure if it is an admin edge port"},
709 {3, 0, "setportautoedge", cmd_setportautoedge,
710 "<bridge> <port> {yes|no}\tconfigure if it is an auto edge port"},
711 {3, 0, "setportp2p", cmd_setportp2p,
712 "<bridge> <port> {yes|no|auto}\tset whether p2p connection"},
713 {2, 0, "portmcheck", cmd_portmcheck,
714 "<bridge> <port>\ttry to get back from STP to RSTP mode"},
715 {1, 0, "debuglevel", cmd_debuglevel, "<level>\t\tLevel of verbosity"},
716 {0, 32, "dumpbridge", cmd_dumpbridge,
717 "Dump all information about a bridge in machine parseable format"},
718 {1, 0, "dumpports", cmd_dumpbridgeports,
719 "Dump all port information in machine parseable format"},
720 };
721
722 const struct command *command_lookup(const char *cmd)
723 {
724 int i;
725
726 for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
727 if (!strcmp(cmd, commands[i].name))
728 return &commands[i];
729 }
730
731 return NULL;
732 }
733
734 void command_helpall(void)
735 {
736 int i;
737
738 for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
739 printf("\t%-10s\t%s\n", commands[i].name, commands[i].help);
740 }
741 }
742
743 static void help()
744 {
745 printf("Usage: rstpctl [commands]\n");
746 printf("commands:\n");
747 command_helpall();
748 }
749
750 #define PACKAGE_VERSION2(v, b) "rstp, " #v "-" #b
751 #define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
752
753 int main(int argc, char *const *argv)
754 {
755 const struct command *cmd;
756 int f;
757 static const struct option options[] = {
758 {.name = "help",.val = 'h'},
759 {.name = "version",.val = 'V'},
760 {0}
761 };
762
763 while ((f = getopt_long(argc, argv, "Vh", options, NULL)) != EOF)
764 switch (f) {
765 case 'h':
766 help();
767 return 0;
768 case 'V':
769 printf("%s\n", PACKAGE_VERSION(VERSION, BUILD));
770 return 0;
771 default:
772 fprintf(stderr, "Unknown option '%c'\n", f);
773 goto help;
774 }
775
776 if (argc == optind)
777 goto help;
778
779 if (ctl_client_init()) {
780 fprintf(stderr, "can't setup control connection\n");
781 return 1;
782 }
783
784 argc -= optind;
785 argv += optind;
786 if ((cmd = command_lookup(argv[0])) == NULL) {
787 fprintf(stderr, "never heard of command [%s]\n", argv[0]);
788 goto help;
789 }
790
791 if (argc < cmd->nargs + 1 || argc > cmd->nargs + cmd->optargs + 1) {
792 printf("Incorrect number of arguments for command\n");
793 printf("Usage: rstpctl %s %s\n", cmd->name, cmd->help);
794 return 1;
795 }
796
797 return cmd->func(argc, argv);
798
799 help:
800 help();
801 return 1;
802 }