--- /dev/null
-int main_loop_continue;
-
+
+ #ifdef HAVE_CONFIG_H
+ #include "config.h"
+ #endif
+
+ #include <stdio.h>
+ #include <signal.h>
+ #include <unistd.h>
+ #include <setjmp.h>
+
+ #include <getopt.h>
+ #ifdef HAVE_LIBREADLINE
+ #include <readline/readline.h>
+ #include <readline/history.h>
+ #endif
+
+ #include "common.h"
+ #include "commands.h"
+
+
+ #define MAXCOM 32
+
+
- if (!batch)
+
+ static const struct TreeNode* getSubCom (char **com, int n, int *t)
+ {
+ int i;
+ const struct TreeNode *cur, *next;
+
+
+ cur = &commands;
+ for (i = 0; i < n; i++) {
+ /* we have reached a terminal command, exit */
+ if (cur->sub == NULL)
+ break;
+
+ /* search sub command in sub command array */
+ for (next = cur->sub; next->name != NULL && strcmp(next->name, com[i]) != 0; next++);
+
+ /* sub command not found, exit */
+ if (next->name == NULL)
+ break;
+
+ /* next command is now the current one */
+ cur = next;
+ }
+
+ *t = i;
+
+
+ return cur;
+ }
+
+
+ #ifdef HAVE_LIBREADLINE
+ static const struct TreeNode *compcur;
+
+
+ static char* my_generator (const char* text, int state)
+ {
+ static int len;
+ static const struct TreeNode *tn;
+ const char *name;
+
+
+ if (compcur == NULL) {
+ /* sub command not found */
+ return NULL;
+ } else if (state == 0) {
+ tn = compcur->sub;
+ len = strlen(text);
+ }
+
+ if (tn == NULL) /* terminal command */
+ return NULL;
+
+ while ((name = tn++->name) != NULL) {
+ if (strncmp(name, text, len) == 0)
+ return strdup(name);
+ }
+
+
+ return NULL;
+ }
+
+
+ static char** my_completion (const char *text, int start, int end UNUSED)
+ {
+ char **matches = NULL;
+ char *line, *com[MAXCOM];
+ int i, n;
+
+
+ memset(com, 0, MAXCOM * sizeof(char*));
+ line = strdup(rl_line_buffer);
+ line[start] = '\0';
+ trim(line, start);
+ n = explode(line, com, MAXCOM);
+ free(line);
+
+ compcur = getSubCom(com, n, &i);
+
+ if (i < n)
+ compcur = NULL;
+ matches = rl_completion_matches(text, my_generator);
+
+ for (i = 0; com[i] != NULL; i++)
+ free(com[i]);
+
+
+ return matches;
+ }
+ #endif /* HAVE_LIBREADLINE */
+
+
++int main_loop_continue;
+ static struct ngadmin *nga;
+ static sigjmp_buf jmpbuf;
+ static struct termios orig_term;
+ struct termios current_term;
+ static bool batch;
+
+
+ NORET static void handler (int sig)
+ {
+ switch (sig) {
+
+ case SIGTERM:
+ case SIGINT:
+ printf("interrupt\n");
+
+ current_term.c_lflag |= ECHO;
+ tcsetattr(STDIN_FILENO, TCSANOW, ¤t_term);
+
- continue;
++ if (!batch && main_loop_continue)
+ siglongjmp(jmpbuf, 1);
+
+ default:
+ ngadmin_close(nga);
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
+
+ exit(0);
+ }
+ }
+
+
+ static int pre_login (const struct ether_addr *mac, int retries)
+ {
+ const struct swi_attr *sa;
+ int i, n, err;
+
+
+ for (i = 1; retries <= 0 || i <= retries; i++) {
+ /* scan */
+ printf("scan... ");
+ fflush(stdout);
+ err = ngadmin_scan(nga);
+ if (err < 0) {
+ printErrCode(err);
- {"global-broadcast", no_argument, NULL, 'g'},
++ return err;
+ }
+
+ /* search switch with requested MAC */
+ sa = ngadmin_getSwitchTab(nga, &n);
+ while (--n >= 0) {
+ if (memcmp(mac, &sa[n].mac, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (n < 0) {
+ printf("no switch found\n");
+ } else {
+ printf("done\n");
+ break;
+ }
+ }
+
+ if (n < 0)
+ return 1;
+
+ /* login */
+ printf("login... ");
+ fflush(stdout);
+ err = ngadmin_login(nga, n);
+ if (err < 0)
+ printErrCode(err);
+ else
+ printf("done\n");
+
+ return err;
+ }
+
+
+ int main (int argc, char **argv)
+ {
+ static const struct option opts[] = {
+ {"batch", no_argument, NULL, 'a'},
+ {"keep-broadcasting", no_argument, NULL, 'b'},
+ {"force-interface", no_argument, NULL, 'f'},
- bool kb = false, force = false, global = false;
+ {"help", no_argument, NULL, 'h'},
+ {"interface", required_argument, NULL, 'i'},
++ {"local-broadcast", no_argument, NULL, 'l'},
+ {"mac", required_argument, NULL, 'm'},
+ {"password", required_argument, NULL, 'p'},
+ {"retries", required_argument, NULL, 'r'},
+ {"timeout", required_argument, NULL, 't'},
+ {0, 0, 0, 0}
+ };
+ char *line, *com[MAXCOM];
+ const char *iface = "eth0", *password = NULL;
+ float timeout = 0.f;
- while ((n = getopt_long(argc, argv, "abfghi:m:p:r:t:", opts, NULL)) != -1) {
++ bool kb = false, force = false, global = true;
+ struct timeval tv;
+ const struct TreeNode *cur, *next;
+ struct ether_addr *mac = NULL;
+ int i, n, retries = 3;
+
+
+ tcgetattr(STDIN_FILENO, &orig_term);
+ current_term = orig_term;
+ #ifdef HAVE_LIBREADLINE
+ batch = false;
+ #else
+ batch = true;
+ #endif
+
+ opterr = 0;
+
- case 'g':
- global = true;
- break;
-
++ while ((n = getopt_long(argc, argv, "abfhi:lm:p:r:t:", opts, NULL)) != -1) {
+ switch (n) {
+
+ case 'a':
+ batch = true;
+ break;
+
+ case 'b':
+ kb = true;
+ break;
+
+ case 'f':
+ force = true;
+ break;
+
- if (kb && ngadmin_setKeepBroadcasting(nga, true) != ERR_OK)
+ case 'h':
+ printf("usage: %s [-a] [-b] [-f] [-g] [-i <interface>] [-m <MAC>] [-p <password>]\n", argv[0]);
+ goto end;
+
+ case 'i':
+ iface = optarg;
+ break;
+
++ case 'l':
++ global = false;
++ break;
++
+ case 'm':
+ mac = ether_aton(optarg);
+ if (mac == NULL) {
+ printf("invalid MAC\n");
+ goto end;
+ }
+ break;
+
+ case 'p':
+ password = optarg;
+ break;
+
+ case 'r':
+ retries = strtol(optarg, NULL, 0);
+ break;
+
+ case 't':
+ timeout = strtof(optarg, NULL);
+ break;
+
+ case '?':
+ printf("unknown option: \"%s\"\n", argv[optind - 1]);
+ goto end;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0) {
+ printf("unknown trailing options\n");
+ goto end;
+ }
+
+
+ memset(com, 0, MAXCOM * sizeof(char*));
+
+ nga = ngadmin_init(iface);
+ if (nga == NULL) {
+ fprintf(stderr, "initialization error\n");
+ goto end;
+ }
+
+ /* set timeout */
+ if (timeout > 0.f) {
+ tv.tv_sec = (int)timeout;
+ tv.tv_usec = (int)((timeout - (float)tv.tv_sec) * 1.e6f);
+ ngadmin_setTimeout(nga, &tv);
+ }
+
+
- if (global && ngadmin_useGlobalBroadcast(nga, true) != ERR_OK)
++ if (ngadmin_setKeepBroadcasting(nga, kb) != ERR_OK)
+ goto end;
+
+ if (force && ngadmin_forceInterface(nga) != ERR_OK)
+ goto end;
+
- if (!batch) {
++ if (ngadmin_useGlobalBroadcast(nga, global) != ERR_OK)
+ goto end;
+
+ /* non-TTY inputs are automatically set to batch mode */
+ if (!isatty(STDIN_FILENO))
+ batch = true;
+
+ if (password != NULL)
+ ngadmin_setPassword(nga, password);
+
+ signal(SIGTERM, handler);
+ signal(SIGINT, handler);
+
+ /* automatic scan & login when switch MAC is specified on the command line */
+ if (mac != NULL && pre_login(mac, retries) != 0)
+ goto end;
+
-
++ if (batch) {
++ /* in batch mode, we must be logged to continue */
++ if (ngadmin_getCurrentSwitch(nga) == NULL) {
++ printf("must be logged\n");
++ goto end;
++ }
++ } else {
+ #ifdef HAVE_LIBREADLINE
+ /* initialize readline functions */
+ rl_attempted_completion_function = my_completion;
+ rl_completion_entry_function = my_generator;
+
+ sigsetjmp(jmpbuf, 1);
+ #endif
+ }
+
+ main_loop_continue = 1;
+ while (main_loop_continue) {
+ /* read user input */
+ line = NULL;
+ n = 0;
+ if (batch)
+ n = getline(&line, (size_t*)&i, stdin);
+ #ifdef HAVE_LIBREADLINE
+ else
+ line = readline("> ");
+ #endif
+ if (n < 0 || line == NULL)
+ goto end;
+
+ /* split string into words */
+ trim(line, strlen(line));
+ n = explode(line, com, MAXCOM);
+
+ if (n == 0) {
+ free(line);
+ continue;
+ } else {
+ #ifdef HAVE_LIBREADLINE
+ if (!batch)
+ add_history(line);
+ #endif
+ free(line);
+ }
+
+ cur = getSubCom(com, n, &i);
+
+ if (cur->sub != NULL) {
+ /* not terminal command */
+ if (i == 0) {
+ /* root command */
+ printf("unknown command: %s\n", com[i]);
+ } else if (i < n) {
+ /* intermediate command, remaining string */
+ printf("unknown %s subcommand: %s\n", com[i - 1], com[i]);
+ } else {
+ /* intermediate command, no remaining string */
+ /* print available subcommands */
+ for (next = cur->sub; next->name != NULL; next++)
+ printf("%s ", next->name);
+ putchar('\n');
+ }
+ } else if (cur->comfunc == NULL) {
+ /* erroneous terminal command without function */
+ printf("terminal command without function\n");
+ } else {
+ /* execute terminal command */
+ cur->comfunc(n - i, (const char**)&com[i], nga);
+ }
+
+ for (i = 0; com[i] != NULL; i++) {
+ free(com[i]);
+ com[i] = NULL;
+ }
+ }
+
+ end:
+ handler(0);
+ }
+
+
--- /dev/null
- if (mode < 1 || mode > 4) {
+
+ #include "commands.h"
+
+
+
+ static char vlan_char (int t)
+ {
+ switch (t) {
+
+ case VLAN_TAGGED:
+ return 'T';
+
+ case VLAN_UNTAGGED:
+ return 'U';
+
+ case VLAN_NO:
+ return ' ';
+
+ default:
+ return '?';
+ }
+ }
+
+
+ int do_vlan_8021q_del (int argc, const char **argv, struct ngadmin *nga)
+ {
+ const struct swi_attr *sa;
+ unsigned short vlan;
+ int i;
+
+
+ if (argc != 1) {
+ printf("usage: vlan 8021q del <vlan>\n");
+ return 1;
+ }
+
+ sa = ngadmin_getCurrentSwitch(nga);
+ if (sa == NULL) {
+ printf("must be logged\n");
+ return 1;
+ }
+
+ vlan=strtoul(argv[0], NULL, 0);
+ if (vlan < VLAN_MIN || vlan > VLAN_DOT_MAX) {
+ printf("vlan out of range\n");
+ return 1;
+ }
+
+ i = ngadmin_VLANDestroy(nga, vlan);
+ printErrCode(i);
+
+
+ return 0;
+ }
+
+
+ int do_vlan_port_set (int argc, const char **argv, struct ngadmin *nga)
+ {
+ unsigned char vlan, port, *ports = NULL;
+ const struct swi_attr *sa;
+ int i, k = 0, ret = 0;
+
+
+ if (argc < 2) {
+ printf("usage: vlan port set [all <vlan>] [<port1> <vlan>] [<port2> <vlan>] [...]\n");
+ ret = 1;
+ goto end;
+ }
+
+ sa = ngadmin_getCurrentSwitch(nga);
+ if (sa == NULL) {
+ printf("must be logged\n");
+ ret = 1;
+ goto end;
+ }
+
+ ports = malloc(sa->ports * sizeof(unsigned char));
+
+ /* read defaults */
+ vlan = 0;
+ if (strcmp(argv[k], "all") == 0) {
+ k++;
+ vlan = strtoul(argv[k++], NULL, 0);
+ /* VLAN 0 is allowed and means no change */
+ if (vlan > VLAN_PORT_MAX) {
+ printf("vlan out of range\n");
+ ret = 1;
+ goto end;
+ }
+ }
+
+ /* apply defaults */
+ memset(ports, vlan, sa->ports);
+
+ /* read and apply port specifics */
+ while (k < argc - 1) {
+ /* read port */
+ port = strtoul(argv[k++], NULL, 0);
+ if (port < 1 || port > sa->ports) {
+ printf("port out of range\n");
+ ret = 1;
+ goto end;
+ }
+
+ /* read vlan */
+ vlan = strtoul(argv[k++], NULL, 0);
+ /* VLAN 0 is allowed and means no change */
+ if (vlan > VLAN_PORT_MAX) {
+ printf("vlan out of range\n");
+ ret = 1;
+ goto end;
+ }
+
+ ports[port - 1] = vlan;
+ }
+
+ /* set conf */
+ i = ngadmin_setVLANPortConf(nga, ports);
+ printErrCode(i);
+
+ end:
+ free(ports);
+
+ return ret;
+ }
+
+
+ int do_vlan_port_show (int argc, const char **argv UNUSED, struct ngadmin *nga)
+ {
+ unsigned char *ports = NULL;
+ const struct swi_attr *sa;
+ int i, ret = 0;
+
+
+ if (argc > 0) {
+ printf("this command takes no argument\n");
+ ret = 1;
+ goto end;
+ }
+
+ sa = ngadmin_getCurrentSwitch(nga);
+ if (sa == NULL) {
+ printf("must be logged\n");
+ ret = 1;
+ goto end;
+ }
+
+ ports = malloc(sa->ports * sizeof(unsigned char));
+
+ /* request all VLANs config */
+ i = ngadmin_getVLANPortConf(nga, ports);
+
+ if (i != ERR_OK) {
+ printErrCode(i);
+ ret = 1;
+ goto end;
+ }
+
+ printf("Ports configuration: \n");
+ printf("Port\t");
+ for (i = 1; i <= sa->ports; i++)
+ printf("%i\t", i);
+ putchar('\n');
+
+ /* show all VLANs */
+ printf("VLAN\t");
+ for (i = 0; i < sa->ports; i++)
+ printf("%u\t", ports[i]);
+ putchar('\n');
+
+ end:
+ free(ports);
+
+ return ret;
+ }
+
+
+ int do_vlan_8021q_set (int argc, const char **argv, struct ngadmin *nga)
+ {
+ unsigned char *ports = NULL, p, def = VLAN_UNSPEC;
+ const struct swi_attr *sa;
+ unsigned short vlan;
+ int i, k = 0, ret = 0;
+
+
+ if (argc == 0) {
+ printf("usage: vlan 802.1q set <vlan> [all unspec|no|untagged|tagged] [<port1> unspec|no|untagged|tagged ...]\n");
+ ret = 1;
+ goto end;
+ }
+
+ sa = ngadmin_getCurrentSwitch(nga);
+ if (sa == NULL) {
+ printf("must be logged\n");
+ ret = 1;
+ goto end;
+ }
+
+ /* read vlan */
+ vlan = strtoul(argv[k++], NULL, 0);
+
+ if (vlan < VLAN_MIN || vlan > VLAN_DOT_MAX) {
+ printf("vlan out of range\n");
+ ret = 1;
+ goto end;
+ }
+
+ /* read defaults */
+ if (k < argc - 1 && strcasecmp(argv[k], "all") == 0) {
+ k++;
+ if (strcasecmp(argv[k], "tagged") == 0) {
+ def = VLAN_TAGGED;
+ } else if (strcasecmp(argv[k], "untagged") == 0) {
+ def = VLAN_UNTAGGED;
+ } else if (strcasecmp(argv[k], "no") == 0) {
+ def = VLAN_NO;
+ } else if (strcasecmp(argv[k], "unspec") == 0) {
+ def = VLAN_UNSPEC;
+ } else {
+ printf("incorrect type\n");
+ ret = 1;
+ goto end;
+ }
+ k++;
+ }
+
+ ports = malloc(sa->ports * sizeof(unsigned char));
+
+ /* apply defaults */
+ memset(ports, def, sa->ports);
+
+ /* read and apply port specifics */
+ while (k < argc - 1) {
+ p = strtoul(argv[k++], NULL, 0) - 1;
+ if (p >= sa->ports) {
+ printf("port out of range\n");
+ ret = 1;
+ goto end;
+ }
+ if (strcasecmp(argv[k], "tagged") ==0) {
+ ports[p] = VLAN_TAGGED;
+ } else if (strcasecmp(argv[k], "untagged") == 0) {
+ ports[p] = VLAN_UNTAGGED;
+ } else if (strcasecmp(argv[k], "no") == 0) {
+ ports[p] = VLAN_NO;
+ } else if (strcasecmp(argv[k], "unspec") == 0) {
+ ports[p] = VLAN_UNSPEC;
+ } else {
+ printf("incorrect type\n");
+ ret = 1;
+ goto end;
+ }
+ k++;
+ }
+
+ /* set conf */
+ i = ngadmin_setVLANDotConf(nga, vlan, ports);
+ printErrCode(i);
+
+ end:
+ free(ports);
+
+ return ret;
+ }
+
+
+ int do_vlan_8021q_show (int argc, const char **argv, struct ngadmin *nga)
+ {
+ unsigned short vl = 0, *vlans = NULL;
+ unsigned char *ports = NULL;
+ const struct swi_attr *sa;
+ int i, j, n = 16, ret = 0;
+
+
+ sa = ngadmin_getCurrentSwitch(nga);
+ if (sa == NULL) {
+ printf("must be logged\n");
+ ret = 1;
+ goto end;
+ }
+
+ if (argc > 0)
+ vl = strtoul(argv[0], NULL, 0);
+
+ ports = malloc(sa->ports * n * sizeof(unsigned char));
+
+ if (vl == 0) {
+ /* request all VLANs config */
+ vlans = malloc(n * sizeof(unsigned short));
+ ports = malloc(sa->ports * n * sizeof(unsigned char));
+ i = ngadmin_getVLANDotAllConf(nga, vlans, ports, &n);
+ } else {
+ /* request single VLAN config */
+ ports = malloc(sa->ports * sizeof(unsigned char));
+ i = ngadmin_getVLANDotConf(nga, vl, ports);
+ }
+
+ if (i != ERR_OK) {
+ printErrCode(i);
+ ret = 1;
+ goto end;
+ }
+
+ printf("Ports configuration: \n");
+ printf("VLAN\t");
+ for (i = 1; i <= sa->ports; i++)
+ printf("%i\t", i);
+ putchar('\n');
+
+ if (vl == 0) {
+ /* show all VLANs */
+ for (i = 0; i < n; i++) {
+ printf("%u\t", vlans[i]);
+ for (j = 0; j < sa->ports; j++)
+ printf("%c\t", vlan_char(ports[i * sa->ports + j]));
+ putchar('\n');
+ }
+ } else {
+ /* show single VLAN config */
+ printf("%u\t", vl);
+ for (j = 0; j < sa->ports; j++)
+ printf("%c\t", vlan_char(ports[j]));
+ putchar('\n');
+ }
+
+ end:
+ free(vlans);
+ free(ports);
+
+ return ret;
+ }
+
+
+ int do_vlan_mode_set (int argc, const char **argv, struct ngadmin *nga)
+ {
+ int mode, i;
+
+
+ if (argc == 0) {
+ printf(
+ "usage: vlan mode set <mode>\n"
++ "0 - disabled\n"
+ "1 - basic port based\n"
+ "2 - advanced port based\n"
+ "3 - basic 802.1Q\n"
+ "4 - advanced 802.1Q\n"
+ );
+ return 0;
+ }
+
+ if (ngadmin_getCurrentSwitch(nga) == NULL) {
+ printf("must be logged\n");
+ return 1;
+ }
+
+ mode = strtoul(argv[0], NULL, 0);
++ if (mode < VLAN_DISABLED || mode > VLAN_DOT_ADV) {
+ printf("mode out of range\n");
+ return 1;
+ }
+
+ i = ngadmin_setVLANType(nga, mode);
+ printErrCode(i);
+
+
+ return 0;
+ }
+
+
+ int do_vlan_mode_show (int argc, const char **argv UNUSED, struct ngadmin *nga)
+ {
+ int i, t, ret = 0;
+
+
+ if (argc > 0) {
+ printf("this command takes no argument\n");
+ ret = 1;
+ goto end;
+ }
+
+ if (ngadmin_getCurrentSwitch(nga) == NULL) {
+ printf("must be logged\n");
+ ret = 1;
+ goto end;
+ }
+
+ i = ngadmin_getVLANType(nga, &t);
+ if (i != ERR_OK) {
+ printErrCode(i);
+ ret = 1;
+ goto end;
+ }
+
+ printf("VLAN type: ");
+ switch (t) {
+
+ case VLAN_DISABLED:
+ printf("disabled\n");
+ break;
+
+ case VLAN_PORT_BASIC:
+ printf("port basic\n");
+ break;
+
+ case VLAN_PORT_ADV:
+ printf("port advanced\n");
+ break;
+
+ case VLAN_DOT_BASIC:
+ printf("802.1Q basic\n");
+ break;
+
+ case VLAN_DOT_ADV:
+ printf("802.1Q advanced\n");
+ break;
+
+ default:
+ printf("unknown (%i)\n", t);
+ }
+
+ end:
+
+ return ret;
+ }
+
+
+ int do_vlan_pvid_set (int argc, const char **argv, struct ngadmin *nga)
+ {
+ const struct swi_attr *sa;
+ unsigned char port;
+ unsigned short vlan;
+ int i;
+
+
+ if (argc != 2) {
+ printf("usage: vlan pvid set <port> <vlan>\n");
+ return 1;
+ }
+
+ sa = ngadmin_getCurrentSwitch(nga);
+ if (sa == NULL) {
+ printf("must be logged\n");
+ return 1;
+ }
+
+ port = strtoul(argv[0], NULL, 0);
+ vlan = strtoul(argv[1], NULL, 0);
+
+ if (port < 1 || port > sa->ports) {
+ printf("port out of range\n");
+ return 1;
+ }
+
+ if (vlan < VLAN_MIN || vlan > VLAN_DOT_MAX) {
+ printf("vlan out of range\n");
+ return 1;
+ }
+
+ i = ngadmin_setPVID(nga, port, vlan);
+ printErrCode(i);
+
+
+ return 0;
+ }
+
+
+ int do_vlan_pvid_show (int argc, const char **argv UNUSED, struct ngadmin *nga)
+ {
+ unsigned short *ports = NULL;
+ const struct swi_attr *sa;
+ int i, ret = 0;
+
+
+ if (argc > 0) {
+ printf("this command takes no argument\n");
+ ret = 1;
+ goto end;
+ }
+
+ sa = ngadmin_getCurrentSwitch(nga);
+ if (sa == NULL) {
+ printf("must be logged\n");
+ ret = 1;
+ goto end;
+ }
+
+ ports = malloc(sa->ports * sizeof(unsigned short));
+ i = ngadmin_getAllPVID(nga, ports);
+ if (i != ERR_OK) {
+ printErrCode(i);
+ ret = 1;
+ goto end;
+ }
+
+ printf("Port\t");
+ for (i = 1; i <= sa->ports; i++)
+ printf("%i\t", i);
+ putchar('\n');
+
+ printf("VLAN\t");
+ for (i = 0; i < sa->ports; i++)
+ printf("%u\t", ports[i]);
+ putchar('\n');
+
+ end:
+ free(ports);
+
+ return ret;
+ }
+
+