]> git.ipfire.org Git - people/ms/rstp.git/blame - ctl_main.c
update ignore file
[people/ms/rstp.git] / ctl_main.c
CommitLineData
ad02a0eb
SH
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
20#include "ctl_socket_client.h"
21#include "ctl_functions.h"
22
23#ifndef False
24# define False 0
25# define True 1
26#endif
27
28#define STP_IN_get_error_explanation CTL_error_explanation
29
30static void
31print_bridge_id (UID_BRIDGE_ID_T *bridge_id, unsigned char cr)
32{
33 printf("%04lX-%02x%02x%02x%02x%02x%02x",
34 (unsigned long) bridge_id->prio,
35 (unsigned char) bridge_id->addr[0],
36 (unsigned char) bridge_id->addr[1],
37 (unsigned char) bridge_id->addr[2],
38 (unsigned char) bridge_id->addr[3],
39 (unsigned char) bridge_id->addr[4],
40 (unsigned char) bridge_id->addr[5]);
41 if (cr)
42 printf("\n");
43}
44
45static char *
46stp_state2str (RSTP_PORT_STATE stp_port_state, int detail)
47{
48 if (detail) {
49 switch (stp_port_state) {
50 case UID_PORT_DISABLED: return "Disabled";
51 case UID_PORT_DISCARDING: return "Discarding";
52 case UID_PORT_LEARNING: return "Learning";
53 case UID_PORT_FORWARDING: return "Forwarding";
54 case UID_PORT_NON_STP: return "NoStp";
55 default: return "Unknown";
56 }
57 }
58
59 switch (stp_port_state) {
60 case UID_PORT_DISABLED: return "Dis";
61 case UID_PORT_DISCARDING: return "Blk";
62 case UID_PORT_LEARNING: return "Lrn";
63 case UID_PORT_FORWARDING: return "Fwd";
64 case UID_PORT_NON_STP: return "Non";
65 default: return "Unk";
66 }
67}
68
69static void CLI_out_port_id (int port, unsigned char cr)
70{
71 static char ifname[IFNAMSIZ];
72 if (if_indextoname(port, ifname))
73 printf("%s", ifname);
74 else
75 printf ("Ifindex %02d", port);
76 if (cr)
77 printf("\n");
78}
79
80int get_index_die(const char *ifname, const char *doc, int die)
81{
82 int r = if_nametoindex(ifname);
83 if (r == 0) {
84 fprintf(stderr, "Can't find index for %s %s. Not a valid interface.\n",
85 doc, ifname);
86 if (die)
87 exit(1);
88 return -1;
89 }
90 return r;
91}
92
93int get_index(const char *ifname, const char *doc)
94{
95 return get_index_die(ifname, doc, 1);
96}
97
98static int cmd_rstp(int argc, char *const* argv)
99{
100 int stp, r;
101 int br_index = get_index(argv[1], "bridge");
102
103 if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes")
104 || !strcmp(argv[2], "1"))
105 stp = 1;
106 else if (!strcmp(argv[2], "off") || !strcmp(argv[2], "no")
107 || !strcmp(argv[2], "0"))
108 stp = 0;
109 else {
110 fprintf(stderr, "expect on/off for argument\n");
111 return 1;
112 }
113 r = CTL_enable_bridge_rstp(br_index, stp);
114 if (r) {
115 fprintf(stderr, "Failed to enable/disable RSTP: %s\n",
116 CTL_error_explanation(r));
117 return -1;
118 }
119 return 0;
120}
121
122static int do_showbridge(const char *br_name)
123{
124 UID_STP_STATE_T uid_state;
125 UID_STP_CFG_T uid_cfg;
126
127 int br_index = get_index_die(br_name, "bridge", 0);
128 if (br_index < 0)
129 return -1;
130
131 int r = CTL_get_bridge_state(br_index, &uid_cfg, &uid_state);
132 if (r) {
133 fprintf(stderr, "Failed to get bridge state: %s\n",
134 CTL_error_explanation(r));
135 return -1;
136 }
137
138#if 0
139 printf("Interface: %-7s (tag:%d) State: ",
140 uid_state.vlan_name, (int) uid_state.vlan_id);
141#else
142 printf("Bridge: %-7s State:",
143 uid_state.vlan_name);
144#endif
145 switch (uid_state.stp_enabled) {
146 case STP_ENABLED: printf("enabled\n"); break;
147 case STP_DISABLED: printf("disabled\n");break;
148 default: printf("unknown\n"); return 0;
149 }
150
151 printf("BridgeId: "); print_bridge_id (&uid_state.bridge_id, 0);
152 printf(" Bridge Proirity: %lu (0x%lX)\n",
153 (unsigned long) uid_state.bridge_id.prio, (unsigned long) uid_state.bridge_id.prio);
154 if (uid_cfg.force_version < 2)
155 printf("Force Version: stp\n");
156
157 printf("Designated Root: "); print_bridge_id (&uid_state.designated_root, 1);
158 if (uid_state.root_port) {
159 printf("Root Port: %04lx", (unsigned long) uid_state.root_port);
160 // CLI_out_port_id (uid_state.root_port & 0xfff, False);
161 // printf("not implemented"); // XXX
162 printf(", Root Cost: %-lu\n", (unsigned long) uid_state.root_path_cost);
163 } else {
164 printf("Root Port: none\n");
165 }
166
167 if (uid_state.Topo_Change)
168 printf ("Topology Change Count: %lu\n", uid_state.Topo_Change_Count);
169 else
170 printf ("Time Since Topology Change: %lu\n", uid_state.timeSince_Topo_Change);
171
172 printf ("Max Age: %2d Bridge Max Age: %-2d\n",
173 (int) uid_state.max_age, (int) uid_cfg.max_age);
174 printf ("Hello Time: %2d Bridge Hello Time: %-2d\n",
175 (int) uid_state.hello_time, (int) uid_cfg.hello_time);
176 printf ("Forward Delay: %2d Bridge Forward Delay: %-2d\n",
177 (int) uid_state.forward_delay, (int) uid_cfg.forward_delay);
178 printf ("Hold Time: %2d\n", (int) uid_cfg.hold_time);
179
180 return 0;
181}
182
183#define SYSFS_PATH_MAX 256
184#define SYSFS_CLASS_NET "/sys/class/net"
185
186static int isbridge(const struct dirent *entry)
187{
188 char path[SYSFS_PATH_MAX];
189 struct stat st;
190
191 snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "/%s/bridge",
192 entry->d_name);
193 return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
194}
195
196static int cmd_showbridge(int argc, char *const* argv)
197{
198 int i, count = 0;
199 int r = 0;
200 struct dirent **namelist;
201
202 if (argc > 1) {
203 count = argc - 1;
204 }
205 else {
206 count = scandir(SYSFS_CLASS_NET, &namelist, isbridge, alphasort);
207 if (count < 0) {
208 fprintf(stderr, "Error getting list of all bridges\n");
209 return -1;
210 }
211 }
212
213 for (i = 0; i < count; i++) {
214 const char *name;
215 if (argc > 1)
216 name = argv[i+1];
217 else
218 name = namelist[i]->d_name;
219
220 int err = do_showbridge(name);
221 if (err)
222 r = err;
223 }
224
225 if (argc <= 1) {
226 for (i = 0; i < count; i++)
227 free(namelist[i]);
228 free(namelist);
229 }
230
231 return r;
232}
233
234int detail = 0;
235
236static int do_showport(int br_index, const char *port_name,
237 UID_STP_STATE_T *uid_state)
238{
239 UID_STP_PORT_STATE_T uid_port;
240 UID_STP_PORT_CFG_T uid_cfg;
241 int r = 0;
242 int port_index = get_index_die(port_name, "port", 0);
243 if (port_index < 0)
244 return -1;
245
246 memset (&uid_cfg, 0, sizeof (UID_STP_PORT_CFG_T));
247 r = CTL_get_port_state(br_index, port_index, &uid_cfg, &uid_port);
248 if (r) {
249 fprintf(stderr, "Failed to get port state for port %d: %s\n",
250 port_index, CTL_error_explanation(r));
251 return -1;
252 }
253
254 if (detail) {
255 printf("Stp Port "); CLI_out_port_id (port_index, False);
256#if 0
257 printf(": PortId: %04lx in vlan '%s' with tag %d:\n",
258 (unsigned long) uid_port.port_id, uid_state->vlan_name, (int) uid_state->vlan_id);
259#else
260 printf(": PortId: %04lx in Bridge '%s':\n",
261 (unsigned long) uid_port.port_id, uid_state->vlan_name);
262#endif
263 printf ("Priority: %-d\n", (int) (uid_port.port_id >> 8));
264 printf ("State: %-16s", stp_state2str (uid_port.state, 1));
265 printf (" Uptime: %-9lu\n", uid_port.uptime);
266 printf ("PortPathCost: admin: ");
267 if (ADMIN_PORT_PATH_COST_AUTO == uid_cfg.admin_port_path_cost)
268 printf ("%-9s", "Auto");
269 else
270 printf ("%-9lu", uid_cfg.admin_port_path_cost);
271 printf (" oper: %-9lu\n", uid_port.oper_port_path_cost);
272
273 printf ("Point2Point: admin: ");
274 switch (uid_cfg.admin_point2point) {
275 case P2P_FORCE_TRUE:
276 printf ("%-9s", "ForceYes");
277 break;
278 case P2P_FORCE_FALSE:
279 printf ("%-9s", "ForceNo");
280 break;
281 case P2P_AUTO:
282 printf ("%-9s", "Auto");
283 break;
284 }
285 printf (" oper: %-9s\n", uid_port.oper_point2point ? "Yes" : "No");
286 printf ("Edge: admin: %-9s oper: %-9s\n",
287 uid_cfg.admin_edge ? "Y" : "N",
288 uid_port.oper_edge ? "Y" : "N");
289 printf ("Partner: oper: %-9s\n",
290 uid_port.oper_stp_neigb ? "Slow" : "Rapid");
291
292 if (' ' != uid_port.role) {
293 if ('-' != uid_port.role) {
294 printf("PathCost: %-lu\n", (unsigned long) (uid_port.path_cost));
295 printf("Designated Root: "); print_bridge_id (&uid_port.designated_root, 1);
296 printf("Designated Cost: %-ld\n", (unsigned long) uid_port.designated_cost);
297 printf("Designated Bridge: "); print_bridge_id (&uid_port.designated_bridge, 1);
298 printf("Designated Port: %-4lx\n\r", (unsigned long) uid_port.designated_port);
299 }
300 printf("Role: ");
301 switch (uid_port.role) {
302 case 'A': printf("Alternate\n"); break;
303 case 'B': printf("Backup\n"); break;
304 case 'R': printf("Root\n"); break;
305 case 'D': printf("Designated\n"); break;
306 case '-': printf("NonStp\n"); break;
307 default: printf("Unknown(%c)\n", uid_port.role); break;
308 }
309
310 if ('R' == uid_port.role || 'D' == uid_port.role) {
311 /* printf("Tc: %c ", uid_port.tc ? 'Y' : 'n'); */
312 printf("TcAck: %c ",
313 uid_port.top_change_ack ? 'Y' : 'N');
314 printf("TcWhile: %3d\n", (int) uid_port.tcWhile);
315 }
316 }
317
318 if (UID_PORT_DISABLED == uid_port.state || '-' == uid_port.role) {
319#if 0
320 printf("helloWhen: %3d ", (int) uid_port.helloWhen);
321 printf("lnkWhile: %3d\n", (int) uid_port.lnkWhile);
322 printf("fdWhile: %3d\n", (int) uid_port.fdWhile);
323#endif
324 } else if ('-' != uid_port.role) {
325 printf("fdWhile: %3d ", (int) uid_port.fdWhile);
326 printf("rcvdInfoWhile: %3d\n", (int) uid_port.rcvdInfoWhile);
327 printf("rbWhile: %3d ", (int) uid_port.rbWhile);
328 printf("rrWhile: %3d\n", (int) uid_port.rrWhile);
329#if 0
330 printf("mdelayWhile: %3d ", (int) uid_port.mdelayWhile);
331 printf("lnkWhile: %3d\n", (int) uid_port.lnkWhile);
332 printf("helloWhen: %3d ", (int) uid_port.helloWhen);
333 printf("txCount: %3d\n", (int) uid_port.txCount);
334#endif
335 }
336
337 printf("RSTP BPDU rx: %lu\n", (unsigned long) uid_port.rx_rstp_bpdu_cnt);
338 printf("CONFIG BPDU rx: %lu\n", (unsigned long) uid_port.rx_cfg_bpdu_cnt);
339 printf("TCN BPDU rx: %lu\n", (unsigned long) uid_port.rx_tcn_bpdu_cnt);
340 } else {
341 printf("%c%c%c ",
342 (uid_port.oper_point2point) ? ' ' : '*',
343 (uid_port.oper_edge) ? 'E' : ' ',
344 (uid_port.oper_stp_neigb) ? 's' : ' ');
345 CLI_out_port_id (port_index, False);
346 printf(" %04lx %3s ", (unsigned long) uid_port.port_id,
347 stp_state2str (uid_port.state, 0));
348 printf (" ");
349 print_bridge_id (&uid_port.designated_root, 0);
350 printf(" ");
351 print_bridge_id (&uid_port.designated_bridge, 0);
352 printf(" %4lx %c", (unsigned long) uid_port.designated_port, uid_port.role);
353 printf ("\n");
354 }
355 return 0;
356}
357
358static int not_dot_dotdot(const struct dirent *entry)
359{
1b21e109
SH
360 const char *n = entry->d_name;
361
362 return !(n[0] == '.' && (n[1] == 0 || (n[1] == '.' && n[2] == 0)));
ad02a0eb
SH
363}
364
365static int cmd_showport(int argc, char *const* argv)
366{
367 UID_STP_STATE_T uid_state;
368 UID_STP_CFG_T uid_br_cfg;
369 int r = 0;
370
371 int br_index = get_index(argv[1], "bridge");
372
373 r = CTL_get_bridge_state(br_index, &uid_br_cfg, &uid_state);
374 if (r) {
375 fprintf(stderr, "Failed to get bridge state: %s\n",
376 CTL_error_explanation(r));
377 return -1;
378 }
379
380 int i, count = 0;
381 struct dirent **namelist;
382
383 if (argc > 2) {
384 count = argc - 2;
385 }
386 else {
387 char buf[SYSFS_PATH_MAX];
388 snprintf(buf, sizeof(buf), SYSFS_CLASS_NET "/%s/brif", argv[1]);
389 count = scandir(buf, &namelist, not_dot_dotdot, alphasort);
390 if (count < 0) {
391 fprintf(stderr, "Error getting list of all ports of bridge %s\n",
392 argv[1]);
393 return -1;
394 }
395 }
396
397 for (i = 0; i < count; i++) {
398 const char *name;
399 if (argc > 2)
400 name = argv[i+2];
401 else
402 name = namelist[i]->d_name;
403
404 int err = do_showport(br_index, name, &uid_state);
405 if (err)
406 r = err;
407 }
408
409 if (argc <= 2) {
410 for (i = 0; i < count; i++)
411 free(namelist[i]);
412 free(namelist);
413 }
414
415 return r;
416}
417
418static int cmd_showportdetail(int argc, char *const* argv)
419{
420 detail = 1;
421 return cmd_showport(argc, argv);
422}
423
424unsigned int getuint(const char *s)
425{
426 char *end;
427 long l;
428 l = strtoul(s, &end, 0);
429 if (*s == 0 || *end != 0 || l > INT_MAX) {
430 fprintf(stderr, "Invalid unsigned int arg %s\n", s);
431 exit(1);
432 }
433 return l;
434}
435
436int getenum(const char *s, const char *opt[])
437{
438 int i;
439 for (i = 0; opt[i] != NULL; i++)
440 if (strcmp(s, opt[i]) == 0)
441 return i;
442
443 fprintf(stderr, "Invalid argument %s: expecting one of ", s);
444 for (i = 0; opt[i] != NULL; i++)
445 fprintf(stderr, "%s%s", opt[i], (opt[i+1]?", ":"\n"));
446
447 exit(1);
448}
449
450int getyesno(const char *s, const char *yes, const char *no)
451{
452 /* Reverse yes and no so error message looks more normal */
453 const char *opt[] = { yes, no, NULL };
454 return 1 - getenum(s, opt);
455}
456
457static int set_bridge_cfg_value (int br_index, unsigned long value,
458 unsigned long val_mask)
459{
460 UID_STP_CFG_T uid_cfg;
461 char* val_name;
462 int rc;
463
464 uid_cfg.field_mask = val_mask;
465 switch (val_mask) {
466 case BR_CFG_STATE:
467 uid_cfg.stp_enabled = value;
468 val_name = "state";
469 break;
470 case BR_CFG_PRIO:
471 uid_cfg.bridge_priority = value;
472 val_name = "priority";
473 break;
474 case BR_CFG_AGE:
475 uid_cfg.max_age = value;
476 val_name = "max_age";
477 break;
478 case BR_CFG_HELLO:
479 uid_cfg.hello_time = value;
480 val_name = "hello_time";
481 break;
482 case BR_CFG_DELAY:
483 uid_cfg.forward_delay = value;
484 val_name = "forward_delay";
485 break;
486 case BR_CFG_FORCE_VER:
487 uid_cfg.force_version = value;
488 val_name = "force_version";
489 break;
490 case BR_CFG_AGE_MODE:
491 case BR_CFG_AGE_TIME:
492 default: printf ("Invalid value mask 0X%lx\n", val_mask); return -1;
493 break;
494 }
495
496 rc = CTL_set_bridge_config(br_index, &uid_cfg);
497
498 if (0 != rc) {
499 printf ("Can't change rstp bridge %s:%s\n", val_name, STP_IN_get_error_explanation (rc));
500 return -1;
501 }
502 return 0;
503}
504
505static int cmd_setbridgestate(int argc, char *const* argv)
506{
507
508 int br_index = get_index(argv[1], "bridge");
509 return set_bridge_cfg_value(br_index,
510 getyesno(argv[2], "on", "off"),
511 BR_CFG_STATE);
512}
513
514static int cmd_setbridgeprio(int argc, char *const* argv)
515{
516
517 int br_index = get_index(argv[1], "bridge");
518 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_PRIO);
519}
520
521static int cmd_setbridgemaxage(int argc, char *const* argv)
522{
523
524 int br_index = get_index(argv[1], "bridge");
525 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_AGE);
526}
527
528static int cmd_setbridgehello(int argc, char *const* argv)
529{
530
531 int br_index = get_index(argv[1], "bridge");
532 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_HELLO);
533}
534
535static int cmd_setbridgefdelay(int argc, char *const* argv)
536{
537
538 int br_index = get_index(argv[1], "bridge");
539 return set_bridge_cfg_value(br_index, getuint(argv[2]), BR_CFG_DELAY);
540}
541
542static int cmd_setbridgeforcevers(int argc, char *const* argv)
543{
544
545 int br_index = get_index(argv[1], "bridge");
546 return set_bridge_cfg_value(br_index,
547 2 * getyesno(argv[2], "normal", "slow"),
548 BR_CFG_FORCE_VER);
549}
550
551
552static int
553set_port_cfg_value (int br_index, int port_index,
554 unsigned long value,
555 unsigned long val_mask)
556{
557 UID_STP_PORT_CFG_T uid_cfg;
558 int rc;
559 char *val_name;
560
561 BitmapClear(&uid_cfg.port_bmp);
562 uid_cfg.field_mask = val_mask;
563 switch (val_mask) {
564 case PT_CFG_MCHECK:
565 val_name = "mcheck";
566 break;
567 case PT_CFG_COST:
568 uid_cfg.admin_port_path_cost = value;
569 val_name = "path cost";
570 break;
571 case PT_CFG_PRIO:
572 uid_cfg.port_priority = value;
573 val_name = "priority";
574 break;
575 case PT_CFG_P2P:
576 uid_cfg.admin_point2point = (ADMIN_P2P_T) value;
577 val_name = "p2p flag";
578 break;
579 case PT_CFG_EDGE:
580 uid_cfg.admin_edge = value;
581 val_name = "adminEdge";
582 break;
583 case PT_CFG_NON_STP:
584 uid_cfg.admin_non_stp = value;
585 val_name = "adminNonStp";
586 break;
587#ifdef STP_DBG
588 case PT_CFG_DBG_SKIP_TX:
589 uid_cfg.skip_tx = value;
590 val_name = "skip tx";
591 break;
592 case PT_CFG_DBG_SKIP_RX:
593 uid_cfg.skip_rx = value;
594 val_name = "skip rx";
595 break;
596#endif
597 case PT_CFG_STATE:
598 default:
599 printf ("Invalid value mask 0X%lx\n", val_mask);
600 return -1;
601 }
602
603 rc = CTL_set_port_config(br_index, port_index, &uid_cfg);
604
605 if (0 != rc) {
606 printf ("can't change rstp port[s] %s: %s\n",
607 val_name, STP_IN_get_error_explanation (rc));
608 return -1;
609 }
610 return 0;
611}
612
613static int cmd_setportprio(int argc, char *const* argv)
614{
615
616 int br_index = get_index(argv[1], "bridge");
617 int port_index = get_index(argv[2], "port");
618 return set_port_cfg_value(br_index, port_index,
619 getuint(argv[3]), PT_CFG_PRIO);
620}
621
622static int cmd_setportpathcost(int argc, char *const* argv)
623{
624
625 int br_index = get_index(argv[1], "bridge");
626 int port_index = get_index(argv[2], "port");
627 return set_port_cfg_value(br_index, port_index,
628 getuint(argv[3]), PT_CFG_COST);
629}
630
631static int cmd_setportedge(int argc, char *const* argv)
632{
633
634 int br_index = get_index(argv[1], "bridge");
635 int port_index = get_index(argv[2], "port");
636 return set_port_cfg_value(br_index, port_index,
637 getyesno(argv[3], "yes", "no"), PT_CFG_EDGE);
638}
639
640static int cmd_setportnonstp(int argc, char *const* argv)
641{
642
643 int br_index = get_index(argv[1], "bridge");
644 int port_index = get_index(argv[2], "port");
645 return set_port_cfg_value(br_index, port_index,
646 getyesno(argv[3], "yes", "no"), PT_CFG_NON_STP);
647}
648
649static int cmd_setportp2p(int argc, char *const* argv)
650{
651
652 int br_index = get_index(argv[1], "bridge");
653 int port_index = get_index(argv[2], "port");
654 const char *opts[] = {"yes", "no", "auto", NULL };
655 int vals[] = { P2P_FORCE_TRUE, P2P_FORCE_FALSE, P2P_AUTO };
656
657 return set_port_cfg_value(br_index, port_index,
658 vals[getenum(argv[3], opts)], PT_CFG_P2P);
659}
660
661static int cmd_portmcheck(int argc, char *const* argv)
662{
663
664 int br_index = get_index(argv[1], "bridge");
665 int port_index = get_index(argv[2], "port");
666 return set_port_cfg_value(br_index, port_index, 0, PT_CFG_MCHECK);
667}
668
669static int cmd_debuglevel(int argc, char *const* argv)
670{
671 return CTL_set_debug_level(getuint(argv[1]));
672}
673
674struct command
675{
676 int nargs;
677 int optargs;
678 const char *name;
679 int (*func)(int argc, char *const* argv);
680 const char *help;
681};
682
683static const struct command commands[] = {
684 { 0, 32, "showbridge", cmd_showbridge, "[<bridge> ... ]\t\tshow bridge state" },
685 { 1, 32, "showport", cmd_showport, "<bridge> [<port> ... ]\tshow port state" },
686 { 1, 32, "showportdetail", cmd_showportdetail, "<bridge> [<port> ... ]\tshow port state (detail)" },
687 { 2, 0, "rstp", cmd_rstp, "<bridge> {on|off}\tenable/disable rstpd control" },
688 { 2, 0, "setbridgestate", cmd_setbridgestate, "<bridge> {on|off}\tstart/stop rstp (when enabled)" },
689 { 2, 0, "setbridgeprio", cmd_setbridgeprio, "<bridge> <priority>\tset bridge priority (0-61440)" },
690 { 2, 0, "sethello", cmd_setbridgehello, "<bridge> <hellotime>\tset bridge hello time (1-10)" },
691 { 2, 0, "setmaxage", cmd_setbridgemaxage, "<bridge> <maxage>\tset bridge max age (6-40)" },
692 { 2, 0, "setfdelay", cmd_setbridgefdelay, "<bridge> <fwd_delay>\tset bridge forward delay (4-30)" },
693 { 2, 0, "setforcevers", cmd_setbridgeforcevers, "<bridge> {normal|slow}\tnormal RSTP or force to STP" },
694 { 3, 0, "setportprio", cmd_setportprio, "<bridge> <port> <priority>\tset port priority (0-240)" },
695 { 3, 0, "setportpathcost", cmd_setportpathcost, "<bridge> <port> <cost>\tset port path cost" },
696 { 3, 0, "setportedge", cmd_setportedge, "<bridge> <port> {yes|no}\tconfigure if it is an edge port" },
697 { 3, 0, "setportnonstp", cmd_setportnonstp, "<bridge> <port> {yes|no}\tdisable STP for the port" },
698 { 3, 0, "setportp2p", cmd_setportp2p, "<bridge> <port> {yes|no|auto}\tset whether p2p connection" },
699 { 2, 0, "portmcheck", cmd_portmcheck, "<bridge> <port>\ttry to get back from STP to RSTP mode" },
700 { 1, 0, "debuglevel", cmd_debuglevel, "<level>\t\tLevel of verbosity" },
701};
702
703const struct command *command_lookup(const char *cmd)
704{
705 int i;
706
707 for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
708 if (!strcmp(cmd, commands[i].name))
709 return &commands[i];
710 }
711
712 return NULL;
713}
714
715void command_helpall(void)
716{
717 int i;
718
719 for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
720 printf("\t%-10s\t%s\n", commands[i].name, commands[i].help);
721 }
722}
723
724static void help()
725{
726 printf("Usage: rstpctl [commands]\n");
727 printf("commands:\n");
728 command_helpall();
729}
730
731#define PACKAGE_VERSION2(v, b) "rstp, " #v "-" #b
732#define PACKAGE_VERSION(v, b) PACKAGE_VERSION2(v, b)
733
734int main(int argc, char *const* argv)
735{
736 const struct command *cmd;
737 int f;
738 static const struct option options[] = {
739 { .name = "help", .val = 'h' },
740 { .name = "version", .val = 'V' },
741 { 0 }
742 };
743
744 while ((f = getopt_long(argc, argv, "Vh", options, NULL)) != EOF)
745 switch(f) {
746 case 'h':
747 help();
748 return 0;
749 case 'V':
750 printf("%s\n", PACKAGE_VERSION(VERSION, BUILD));
751 return 0;
752 default:
753 fprintf(stderr, "Unknown option '%c'\n", f);
754 goto help;
755 }
756
757 if (argc == optind)
758 goto help;
759
760 if (ctl_client_init()) {
761 fprintf(stderr, "can't setup control connection\n");
762 return 1;
763 }
764
765 argc -= optind;
766 argv += optind;
767 if ((cmd = command_lookup(argv[0])) == NULL) {
768 fprintf(stderr, "never heard of command [%s]\n", argv[0]);
769 goto help;
770 }
771
772 if (argc < cmd->nargs + 1 || argc > cmd->nargs + cmd->optargs + 1) {
773 printf("Incorrect number of arguments for command\n");
774 printf("Usage: rstpctl %s %s\n", cmd->name, cmd->help);
775 return 1;
776 }
777
778 return cmd->func(argc, argv);
779
780help:
781 help();
782 return 1;
783}