Separated low level protocol handling in a library and CLI.
Removed switch emulator.
CLI: command input using libreadline.
+++ /dev/null
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <termios.h>
-
-
-
-#include "protocol.h"
-#include "command.h"
-#include "controller.h"
-
-
-
-#define MAXCOM 8
-#define MAXSW 16
-
-
-/*
-getVlanStatus ()
-setVlanMode (char mode)
-
-makeCableTest (int n, const unsigned char* ports)
-
-char speedIndex (const char* txt);
-getBitrateStatus ()
-setBiratePorts (int n, const unsigned char* ports, char index)
-
-getBroadfiltStatus ()
-disableBroadfilt ()
-setBroadfiltPorts (int n, cons unsigned char* ports, char index)
-*/
-
-
-/*
-sendPacket ()
-receivePacket()
-*/
-
-
-
-void printErrCode (int err) {
-
-
- switch ( err ) {
- case ERR_OK: /*printf("ok\n");*/ break;
- case ERR_NOTLOG: printf("not switch selected\n"); break;
- case ERR_BADPASS: printf("wrong password\n"); break;
- default: printf("unknown status code (%i)\n", err);
- }
-
-
-}
-
-
-void displaySwitchList (const List *l) {
-
- ListNode *ln;
- struct swi_attr *sa;
- int i=0;
-
-
-
- if ( l->count==0 ) {
- printf("no switch found\n");
- return;
- }
-
-
- printf("Num\tMac\t\t\tProduct\t\tName\t\t\tIP/mask\n");
-
- for (ln=l->first; ln!=NULL; ln=ln->next) {
- sa=ln->data;
- printf("%i\t%s\t%s\t\t%s\t%s/", i, ether_ntoa(&sa->mac), sa->product, sa->name, inet_ntoa(sa->nc.ip));
- printf("%s\n", inet_ntoa(sa->nc.netmask));
- i++;
- }
-
- printf("\nfound %i switch(es)\n", l->count);
-
-
-}
-
-
-
-
-int main (int argc, char **argv) {
-
- char buffer[512], *com[MAXCOM], cont=1;
- int n, i;
- //struct termios tr;
- const List *swi;
-
-
-
- if ( argc<2 ) {
- printf("Usage: %s <interface>\n", argv[0]);
- return 1;
- }
-
-
- memset(com, 0, sizeof(com));
-
- if ( startNetwork(argv[1])<0 ) {
- printf("networking error\n");
- goto end;
- }
-
- startController();
- swi=getSwitchList();
-
-
- //printf("client: ip %s, mac %s\n", inet_ntoa(local.sin_addr), ether_ntoa(&localmac));
-
- while ( cont ) {
-
- printf("> ");
- fflush(stdout);
-
- if ( fgets(buffer, sizeof(buffer), stdin)==NULL ) {
- if ( !feof(stdin) ) {
- perror("fgets");
- }
- goto end;
- }
-
- trim(buffer, strlen(buffer));
- n=explode(buffer, com, MAXCOM);
-
- /*
- } else if ( strcmp(com[0], "password")==0 ) {
- // password: specify password to use to login
-
- printf("enter password: ");
- fflush(stdout);
-
- tcgetattr(STDIN_FILENO, &tr);
- tr.c_lflag &= ~ECHO ;
- tcsetattr(STDIN_FILENO, TCSANOW, &tr);
-
- if ( fgets(password, sizeof(password), stdin)==NULL ) {
- perror("fgets");
- }
-
- tr.c_lflag |= ECHO ;
- tcsetattr(STDIN_FILENO, TCSANOW, &tr);
-
- putchar('\n');
-
- trim(password, strlen(password));
-
-
- } else if ( strcmp(com[0], "ports")==0 ) {
- // ports: show ports status
-
- if ( current==NULL ) {
- printf("no switch selected for configuration\n");
- goto nxt;
- }
-
- initNgPacket(&np);
- initNgHeader(np.nh, CODE_READ_REQ, &localmac, ¤t->mac, ++seq);
-
- addPacketEmptyAttr(&np, ATTR_PORT_STATUS);
- addPacketEmptyAttr(&np, ATTR_END);
-
- len=getPacketTotalSize(&np);
- remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
- remote.sin_port=htons(SWITCH_PORT);
- if ( sendto(sock, buffer, len, 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in))<0 ) {
- perror("sendto");
- goto nxt;
- }
-
- while ( (len=recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&remote, &slen))>=0 && !validateNgHeader(np.nh, &localmac, ¤t->mac, seq) );
-
- if ( len<0 ) {
- printf("time out\n");
- goto nxt;
- }
-
- initNgPacket(&np);
- l=extractPacketAttributes(&np);
-
- for (ln=l->first; ln!=NULL; ln=ln->next) {
- at=ln->data;
- char *p=at->data;
- if ( at->attr==ATTR_PORT_STATUS ) {
- printf("port %i: ", p[0]);
- switch ( p[1] ) {
- case 0: printf("down"); break;
- case SPEED_10: printf("up, 10M"); break;
- case SPEED_100: printf("up, 100M"); break;
- case SPEED_1000: printf("up, 1000M"); break;
- default: printf("unknown (%i)", p[2]);
- }
- putchar('\n');
- }
- }
-
- destroyList(l, (void(*)(void*))freeAttr);
-
- } else if ( strcmp(com[0], "mirror")==0 ) {
- //
-
- if ( current==NULL ) {
- printf("no switch selected for configuration\n");
- goto nxt;
- }
-
- if ( n==1 ) {
-
- initNgPacket(&np);
- initNgHeader(np.nh, CODE_READ_REQ, &localmac, ¤t->mac, ++seq);
-
- addPacketEmptyAttr(&np, ATTR_MIRROR);
- addPacketEmptyAttr(&np, ATTR_END);
-
- len=getPacketTotalSize(&np);
- remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
- remote.sin_port=htons(SWITCH_PORT);
- if ( sendto(sock, buffer, len, 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in))<0 ) {
- perror("sendto");
- goto nxt;
- }
-
-
- while ( (len=recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&remote, &slen))>=0 && !validateNgHeader(np.nh, &localmac, ¤t->mac, seq) );
-
- if ( len<0 ) {
- printf("time out\n");
- goto nxt;
- }
-
- initNgPacket(&np);
- l=extractPacketAttributes(&np);
-
- for (ln=l->first; ln!=NULL; ln=ln->next) {
- at=ln->data;
- char *p=at->data;
- if ( at->attr==ATTR_MIRROR ) {
- if ( p[0]==0 ) {
- printf("mirorring disabled\n");
- } else {
- printf("ports ");
- // FIXME
- printf("redirected to port %i\n", p[0]);
- }
- }
- }
-
- destroyList(l, (void(*)(void*))freeAttr);
-
-
- } else {
-
- initNgPacket(&np);
-
- strcpy(np.ah->data, password);
- addPacketAttr(&np, ATTR_PASSWORD, strlen(password), NULL);
-
- if ( strcmp(com[1], "disable")==0 ) {
-
- }
-
- addPacketEmptyAttr(&np, ATTR_END);
-
- initNgHeader(np.nh, CODE_WRITE_REQ, &localmac, ¤t->mac, ++seq);
-
- len=getPacketTotalSize(&np);
- remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
- remote.sin_port=htons(SWITCH_PORT);
- if ( sendto(sock, buffer, len, 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in))<0 ) {
- perror("sendto");
- goto nxt;
- }
-
-
- }
-
-
- } else if ( strcmp(com[0], "clear")==0 ) {
- //
-
- printf("\e[H\e[J");
-
- } else {
- // unknown command
-
- printf("unknown command\n");
-
- }
- */
-
-
- if ( n==0 ) {
- // nothing: do nothing
-
- } else if ( strcmp(com[0], "quit")==0 ) {
- // quit: exits
-
- cont=0;
-
- } else if ( strcmp(com[0], "scan")==0 ) {
- // scan: scan for switches
-
- if ( (i=discoverSwitches())<0 ) {
- printErrCode(i);
- goto nxt;
- }
-
- displaySwitchList(swi);
-
- } else if ( strcmp(com[0], "list")==0 ) {
- // list: display last detected switches
-
- displaySwitchList(swi);
-
- } else if ( strcmp(com[0], "login")==0 ) {
- // login: selects a switch from the list
-
- printErrCode(i=login(strtol(com[1], NULL, 0)));
-
- } else if ( strcmp(com[0], "ports")==0 ) {
- //
-
- if ( n==1 ) {
-
- printf("ports\n");
- printf("\tstate\n");
- printf("\tstats\n");
- printf("\t\tshow\n");
- printf("\t\treset\n");
-
- } else if ( strcmp(com[1], "state")==0 ) {
-
- unsigned char ports[16];
- if ( (i=getPortsStatus(ports, 16))<0 ) {
- printErrCode(i);
- goto nxt;
- }
-
- for (i=0; i<8; i++) { // FIXME
- printf("port %i: ", i+1);
- switch ( ports[i] ) {
- case 0: printf("down"); break;
- case SPEED_10: printf("up, 10M"); break;
- case SPEED_100: printf("up, 100M"); break;
- case SPEED_1000: printf("up, 1000M"); break;
- default: printf("unknown (%i)", ports[i]);
- }
- putchar('\n');
- }
-
- }
-
- } else if ( strcmp(com[0], "password")==0 ) {
- //
-
- if ( n==1 ) {
- printf("usage: password set|change\n");
- } else if ( strcmp(com[1], "set")==0 ) {
- printf("password set\n");
- } else if ( strcmp(com[1], "change")==0 ) {
- printf("password change\n");
- } else {
- printf("unknown password subcommand\n");
- }
-
- } else if ( strcmp(com[0], "timeout")==0 ) {
- //
-
-
-
- } else {
- // unknown command
-
- printf("unknown command\n");
-
- }
-
-
- nxt:
- for (i=0; i<MAXCOM; i++) {
- if ( com[i]!=NULL ) {
- free(com[i]);
- com[i]=NULL;
- }
- }
-
- }
-
-
- end:
- stopController();
- stopNetwork();
-
-
-
- return 0;
-
-}
-
--- /dev/null
+
+CC=gcc
+CFLAGS=-I../lib -W -Wall -Wextra -Os -fomit-frame-pointer
+LDFLAGS=-L../lib -lngadmin -lreadline -s
+EXEC=admin
+
+SRC=$(wildcard *.c)
+OBJ=$(SRC:.c=.o)
+
+
+
+$(EXEC): $(OBJ)
+ $(CC) $^ -o $@ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) -c $^ -o $@ $(CFLAGS)
+
+
+clean:
+ @rm -f *.o
+
+mrproper: clean
+ @rm -f $(EXEC)
+
+
+
--- /dev/null
+
+#include <stdio.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "command.h"
+#include "common.h"
+
+
+
+
+#define MAXCOM 8
+
+
+
+
+
+int cont=1;
+
+
+static const struct TreeNode rootNode={.sub={
+ &com_quit,
+ &com_login,
+ &com_scan,
+ &com_ports,
+ &com_password,
+ &com_list,
+ &com_firmware,
+ &com_name,
+ NULL
+}};
+
+
+
+void printErrCode (int err) {
+
+
+ switch ( err ) {
+ case ERR_OK: /*printf("ok\n");*/ break;
+ case ERR_NET: printf("network error\n"); break;
+ case ERR_NOTLOG: printf("no switch selected\n"); break;
+ case ERR_BADPASS: printf("wrong password\n"); break;
+ case ERR_BADID: printf("bad switch id\n"); break;
+ case ERR_INVARG: printf("invalid argument\n"); break;
+ case ERR_TIMEOUT: printf("timeout\n"); break;
+ default: printf("unknown status code (%i)\n", err);
+ }
+
+
+}
+
+
+
+void displaySwitchTab (const struct swi_attr *sa, int nb) {
+
+ int i=0;
+
+
+ if ( nb==0 ) {
+ printf("no switch found\n");
+ return;
+ }
+
+
+ printf("Num\tMac\t\t\tProduct\t\tName\t\t\tIP/mask\t\t\t\tDHCP\tPorts\tFirmware\n");
+
+ for (i=0; i<nb; ++i) {
+ printf("%i\t%s\t%s\t\t%s\t%s/", i, ether_ntoa(&sa[i].mac), sa[i].product, sa[i].name, inet_ntoa(sa[i].nc.ip));
+ printf("%s\t%s\t%i\t%s\n", inet_ntoa(sa[i].nc.netmask), ( sa[i].nc.dhcp ? "Yes" : "No" ), sa[i].ports, sa[i].firmware);
+ }
+
+ printf("\nfound %i switch(es)\n", nb);
+
+
+}
+
+
+
+
+int main (int argc, char **argv) {
+
+ char *line, *com[MAXCOM];
+ struct ngadmin *nga=NULL;
+ struct timeval tv;
+ const struct TreeNode *cur, *next, **tab;
+ int i, n;
+
+
+
+ if ( argc<2 ) {
+ printf("Usage: %s <interface>\n", argv[0]);
+ return 1;
+ }
+
+ memset(com, 0, MAXCOM*sizeof(char*));
+
+ if ( (nga=ngadmin_init(argv[1]))==NULL ) {
+ fprintf(stderr, "Initialization error\n");
+ goto end;
+ }
+
+ // set timeout
+ tv.tv_sec=3;
+ tv.tv_usec=0;
+ ngadmin_setTimeout(nga, &tv);
+
+
+ rl_bind_key('\t', rl_abort); // disable auto completion
+
+
+ while ( cont ) {
+
+ if ( (line=readline("> "))==NULL ) goto end;
+ trim(line, strlen(line));
+ if ( *line!=0 ) add_history(line);
+ n=explode(line, com, MAXCOM);
+ free(line);
+
+
+ i=0;
+ for (next=&rootNode; i<n; ++i) {
+ cur=next;
+ for (tab=cur->sub; (next=*tab)!=NULL && strcmp(next->name, com[i])!=0; ++tab);
+ if ( next==NULL ) break;
+ }
+
+
+ if ( i<n ) { // commands left uncompared
+
+ if ( cur->hasArgs ) { // left "commands" are in fact parameters
+ cur->comfunc(cur, n-i, (const char**)&com[i], nga);
+ } else {
+ if ( i==0 ) {
+ printf("unknown command\n");
+ } else {
+ printf("unknown %s subcommand\n", com[i-1]);
+ }
+ }
+
+ } else {
+
+ cur=next;
+ if ( cur->comfunc==NULL ) {
+ // print available subcommands
+ for (tab=cur->sub; (next=*tab)!=NULL; ++tab) {
+ printf("%s ", next->name);
+ }
+ printf("\n");
+
+ } else { // terminal command
+
+ cur->comfunc(cur, 0, NULL, nga);
+
+ }
+ }
+
+ /*
+ if ( n==0 ) {
+ // nothing: do nothing
+
+ } else if ( strcmp(com[0], "timeout")==0 ) {
+ //
+
+ }
+ */
+
+ for (i=0; i<MAXCOM; i++) {
+ if ( com[i]!=NULL ) {
+ free(com[i]);
+ com[i]=NULL;
+ }
+ }
+
+ }
+
+
+ end:
+ ngadmin_close(nga);
+
+
+ return 0;
+
+}
+
+
--- /dev/null
+
+#include "common.h"
+
+
+
+
+static bool do_firmware_show (const struct TreeNode *tn UNUSED, int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+
+ const struct swi_attr *sa;
+ bool ret=true;
+
+
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+ printf("must be logged\n");
+ ret=false;
+ goto end;
+ }
+
+ puts(sa->firmware);
+
+
+ end:
+
+ return ret;
+
+}
+
+
+
+static bool do_firmware_upgrade (const struct TreeNode *tn UNUSED, int nb, const char **com UNUSED, struct ngadmin *nga) {
+
+ const struct swi_attr *sa;
+ bool ret=true;
+
+
+ if ( nb!=1 ) {
+ printf("Usage: firmware upgrade <file>\n");
+ ret=false;
+ }
+
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+ printf("must be logged\n");
+ ret=false;
+ goto end;
+ }
+
+ printf("not implemented yet\n");
+
+
+ end:
+
+ return ret;
+
+}
+
+
+
+static const struct TreeNode com_firmware_show=COM("show", do_firmware_show, false, NULL);
+static const struct TreeNode com_firmware_upgrade=COM("upgrade", do_firmware_upgrade, true, NULL);
+
+const struct TreeNode com_firmware=COM("firmware", NULL, false, &com_firmware_show, &com_firmware_upgrade, NULL);
+
+
+
--- /dev/null
+
+#include "common.h"
+
+
+
+
+static bool do_list (const struct TreeNode *tn UNUSED, int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+
+ int n;
+ const struct swi_attr *sa;
+
+
+ sa=ngadmin_getSwitchTab(nga, &n);
+ displaySwitchTab(sa, n);
+
+
+ return true;
+
+}
+
+
+
+const struct TreeNode com_list=COM("list", do_list, false, NULL);
+
+
+
--- /dev/null
+
+#include "common.h"
+
+
+
+
+static bool do_login (const struct TreeNode *tn UNUSED, int nb, const char **com, struct ngadmin *nga) {
+
+ int i;
+
+
+ if ( nb!=1 ) {
+ printf("Usage: login <num>\n");
+ return false;
+ }
+
+
+ i=strtol(com[0], NULL, 0);
+ i=ngadmin_login(nga, i);
+ printErrCode(i);
+
+
+ return true;
+
+}
+
+
+
+const struct TreeNode com_login=COM("login", do_login, true, NULL);
+
+
+
--- /dev/null
+
+#include "common.h"
+
+
+
+
+static bool do_name_show (const struct TreeNode *tn UNUSED, int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+
+ const struct swi_attr *sa;
+
+
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+ printf("must be logged\n");
+ return false;
+ }
+
+ puts(sa->name);
+
+
+ return true;
+
+}
+
+
+
+static bool do_name_set (const struct TreeNode *tn UNUSED, int nb, const char **com, struct ngadmin *nga) {
+
+ int i;
+ const struct swi_attr *sa;
+
+
+ if ( nb!=1 ) {
+ printf("Usage: name set <value>\n");
+ return false;
+ }
+
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+ printf("must be logged\n");
+ return false;
+ }
+
+ i=ngadmin_setName(nga, com[0]);
+ printErrCode(i);
+
+
+ return true;
+
+}
+
+
+
+static bool do_name_clear (const struct TreeNode *tn UNUSED, int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+
+ int i;
+ const struct swi_attr *sa;
+
+
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+ printf("must be logged\n");
+ return false;
+ }
+
+ i=ngadmin_setName(nga, NULL);
+ printErrCode(i);
+
+
+ return true;
+
+}
+
+
+
+static struct TreeNode com_name_show=COM("show", do_name_show, false, NULL);
+static struct TreeNode com_name_set=COM("set", do_name_set, true, NULL);
+static struct TreeNode com_name_clear=COM("clear", do_name_clear, false, NULL);
+
+const struct TreeNode com_name=COM("name", NULL, false, &com_name_show, &com_name_set, &com_name_clear, NULL);
+
+
+
--- /dev/null
+
+#include "common.h"
+
+
+
+
+static bool do_password_change (const struct TreeNode *tn UNUSED, int nb, const char **com, struct ngadmin *nga) {
+
+ int i;
+ const struct swi_attr *sa;
+
+
+ if ( nb!=1 ) {
+ printf("Usage: password set <value>\n");
+ return false;
+ }
+
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+ printf("must be logged\n");
+ return false;
+ }
+
+ i=ngadmin_changePassword(nga, com[0]);
+ printErrCode(i);
+
+
+ return true;
+
+}
+
+
+
+static bool do_password_set (const struct TreeNode *tn UNUSED, int nb, const char **com, struct ngadmin *nga) {
+
+ int i;
+
+
+ if ( nb!=1 ) {
+ printf("Usage: password set <value>\n");
+ return false;
+ }
+
+ i=ngadmin_setPassword(nga, com[0]);
+ printErrCode(i);
+
+
+ return true;
+
+}
+
+
+
+
+static const struct TreeNode com_password_change=COM("change", do_password_change, true, NULL);
+static const struct TreeNode com_password_set=COM("set", do_password_set, true, NULL);
+
+const struct TreeNode com_password=COM("password", NULL, false, &com_password_change, &com_password_set, NULL);
+
+
+
--- /dev/null
+
+#include "common.h"
+
+
+
+
+static bool do_ports_state (const struct TreeNode *tn UNUSED, int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+
+ int i;
+ const struct swi_attr *sa;
+ unsigned char *ports=NULL;
+ bool ret=true;
+
+
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+ printf("must be logged\n");
+ ret=false;
+ goto end;
+ }
+
+
+ ports=malloc(sa->ports*sizeof(unsigned char));
+ if ( (i=ngadmin_getPortsStatus(nga, ports))<0 ) {
+ printErrCode(i);
+ ret=false;
+ goto end;
+ }
+
+ for (i=0; i<sa->ports; i++) {
+ printf("port %i: ", i+1);
+ switch ( ports[i] ) {
+ case 0: printf("down"); break;
+ case SPEED_10: printf("up, 10M"); break;
+ case SPEED_100: printf("up, 100M"); break;
+ case SPEED_1000: printf("up, 1000M"); break;
+ default: printf("unknown (%i)", ports[i]);
+ }
+ putchar('\n');
+ }
+
+ end:
+ free(ports);
+
+
+ return ret;
+
+}
+
+
+
+static bool do_ports_stats_show (const struct TreeNode *tn UNUSED, int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+
+ int i;
+ const struct swi_attr *sa;
+ bool ret=true;
+ struct port_stats *ps=NULL;
+
+
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+ printf("must be logged\n");
+ ret=false;
+ goto end;
+ }
+
+ ps=calloc(sa->ports, sizeof(struct port_stats));
+ if ( (i=ngadmin_getPortsStatistics(nga, ps))<0 ) {
+ printErrCode(i);
+ ret=false;
+ goto end;
+ }
+
+ printf("Port\tReceived\tSent\t\tCRC errors\n");
+ for (i=0; i<sa->ports; ++i) {
+ printf("%i\t%8llu\t%8llu\t%8llu\n", i+1, ps[i].recv, ps[i].sent, ps[i].crc);
+ }
+
+ end:
+ free(ps);
+
+
+ return ret;
+
+}
+
+
+
+static bool do_ports_stats_reset (const struct TreeNode *tn UNUSED, int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+
+ int i;
+
+
+ if ( ngadmin_getCurrentSwitch(nga)==NULL ) {
+ printf("must be logged\n");
+ return false;
+ }
+
+ i=ngadmin_resetPortsStatistics(nga);
+ printErrCode(i);
+
+
+ return true;
+
+}
+
+
+
+static const struct TreeNode com_ports_state=COM("state", do_ports_state, false, NULL);
+
+static const struct TreeNode com_ports_stats_show=COM("show", do_ports_stats_show, false, NULL);
+static const struct TreeNode com_ports_stats_reset=COM("reset", do_ports_stats_reset, false, NULL);
+static const struct TreeNode com_ports_stats=COM("stats", NULL, false, &com_ports_stats_reset, &com_ports_stats_show, NULL);
+
+const struct TreeNode com_ports=COM("ports", NULL, false, &com_ports_state, &com_ports_stats, NULL);
+
+
+
--- /dev/null
+
+#include "common.h"
+
+
+
+
+static bool do_quit (const struct TreeNode *tn UNUSED, int nb UNUSED, const char **com UNUSED, struct ngadmin *nga UNUSED) {
+
+ cont=0;
+
+ return true;
+
+}
+
+
+
+const struct TreeNode com_quit=COM("quit", do_quit, false, NULL);
+
+
+
--- /dev/null
+
+#include "common.h"
+
+
+
+
+static bool do_scan (const struct TreeNode *tn UNUSED, int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+
+ int i;
+ const struct swi_attr *sa;
+
+
+ if ( (i=ngadmin_scan(nga))<0 ) {
+ printErrCode(i);
+ return false;
+ }
+
+ sa=ngadmin_getSwitchTab(nga, &nb);
+ displaySwitchTab(sa, nb);
+
+
+ return true;
+
+}
+
+
+
+const struct TreeNode com_scan=COM("scan", do_scan, false, NULL);
+
+
+
--- /dev/null
+
+#include "command.h"
+
+
+
+
+// ----------------------------
+int trim (char *txt, int start) {
+
+ char *p, c;
+
+
+ if ( txt==NULL ) {
+ return 0;
+ }
+
+ //for (p=txt; *p!=0; p++);
+ p=txt+start;
+ for (p--; p>=txt && ( (c=*p)==' ' || c=='\n' ); *p--=0);
+
+
+ return p-txt+1;
+
+}
+
+
+
+// --------------------------------------------------------
+int explode (const char *commande, char** tab, int maximum) {
+
+ const char *start, *end;
+ char c;
+ int n=0, len;
+
+
+ for (end=commande; ; n++) {
+
+ for (start=end; (c=*start)==' ' && c!=0; start++);
+ for (end=start; ( (c=*end)!=' ' || n>=maximum-1 ) && c!=0; end++);
+
+ if ( (len=end-start)==0 ) {
+ break;
+ }
+
+ tab[n]=malloc(sizeof(char)*(len+1));
+ memcpy(tab[n], start, len);
+ tab[n][len]=0;
+
+ }
+
+
+ return n;
+
+}
+
+
--- /dev/null
+
+#ifndef DEF_COMMAND
+#define DEF_COMMAND
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+
+//
+int trim (char *txt, int start);
+
+//
+int explode (const char *commande, char** tab, int maximum);
+
+
+
+#endif
+
--- /dev/null
+
+#ifndef DEF_COMMON
+#define DEF_COMMON
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <ngadmin.h>
+
+
+#define UNUSED __attribute__((unused))
+#define COM(nam, func, args, ...) {.name=nam, .comfunc=func, .hasArgs=args, .sub={__VA_ARGS__}}
+
+
+
+struct TreeNode {
+ const char *name;
+ bool (* const comfunc)(const struct TreeNode*, int, const char**, struct ngadmin*);
+ bool hasArgs;
+ const struct TreeNode *sub[];
+};
+
+
+
+extern int cont;
+
+
+
+extern const struct TreeNode com_quit;
+extern const struct TreeNode com_login;
+extern const struct TreeNode com_scan;
+extern const struct TreeNode com_ports;
+extern const struct TreeNode com_password;
+extern const struct TreeNode com_list;
+extern const struct TreeNode com_list;
+extern const struct TreeNode com_firmware;
+extern const struct TreeNode com_name;
+
+
+
+void displaySwitchTab (const struct swi_attr *sa, int nb);
+void printErrCode (int err);
+
+
+
+#endif
+
+++ /dev/null
-
-#include "command.h"
-
-
-
-
-// ----------------------------
-int trim (char *txt, int start) {
-
- char *p, c;
-
-
- if ( txt==NULL ) {
- return 0;
- }
-
- //for (p=txt; *p!=0; p++);
- p=txt+start;
- for (p--; p>=txt && ( (c=*p)==' ' || c=='\n' ); *p--=0);
-
-
- return p-txt+1;
-
-}
-
-
-
-// --------------------------------------------------------
-int explode (const char *commande, char** tab, int maximum) {
-
- const char *start, *end;
- char c;
- int n=0, len;
-
-
- for (end=commande; ; n++) {
-
- for (start=end; (c=*start)==' ' && c!=0; start++);
- for (end=start; ( (c=*end)!=' ' || n>=maximum-1 ) && c!=0; end++);
-
- if ( (len=end-start)==0 ) {
- break;
- }
-
- tab[n]=malloc(sizeof(char)*(len+1));
- memcpy(tab[n], start, len);
- tab[n][len]=0;
-
- }
-
-
- return n;
-
-}
-
-
+++ /dev/null
-
-#ifndef DEF_COMMAND
-#define DEF_COMMAND
-
-
-#include <stdlib.h>
-#include <string.h>
-
-
-
-//
-int trim (char *txt, int start);
-
-//
-int explode (const char *commande, char** tab, int maximum);
-
-
-
-#endif
-
+++ /dev/null
-
-scan
-
-login 5
-
-password set
-password change
-
-timeout show
-timeout set 10
-
-restart
-
-defaults
-
-firmware show
-firmware update new_firmware.bin
-
-mirror show
-mirror disable
-mirror set 1 4 6 3 2 to 8
-
-ports state
-ports stats show
-ports stats reset
-
-vlan show
-vlan disable
-vlan set mode port|dot basic|adv
-
-cabletest 1 5 8 7
-
-qos show
-qos set mode dot|port
-qos set 5 high|mid|norm|low
-
-bitrate show
-bitrate set 4 in nl|512K|1M|2M|4M|8M|16M|32M|64M|128M|256M|512M out nl|512K|1M|2M|4M|8M|16M|32M|64M|128M|256M|512M
-
-broadfilt show
-broadfilt disable
-broadfilt set 8 nl|512K|1M|2M|4M|8M|16M|32M|64M|128M|256M|512M
-
-ip show
-ip set dhcp enable|disable
-ip set ip 192.168.0.1 mask 255.255.255.0|24 gw 192.168.0.254
-
-name show
-name set bordel_de_merde
-
-quit
-
+++ /dev/null
-
-#include "controller.h"
-
-
-
-
-static char password[128];
-static List *swiList=NULL;
-static struct swi_attr *current=NULL;
-static unsigned int seq=0;
-
-
-
-
-// =============================================================================
-
-
-// ------------------------
-void startController (void) {
-
- password[0]=0;
- swiList=createEmptyList();
-
-}
-
-
-// -----------------------
-void stopController (void) {
-
- destroyList(swiList, free);
- current=NULL;
-
-}
-
-
-
-// =============================================================================
-
-
-static void getSwitchAttributes (struct swi_attr *sa, const List *l) {
-
- const ListNode *ln;
- const struct attr *at;
- int len;
-
-
- memset(sa, 0, sizeof(struct swi_attr));
- sa->ports=0;
-
-
- for (ln=l->first; ln!=NULL; ln=ln->next) {
- at=ln->data;
-
- switch ( at->attr ) {
-
- case ATTR_PRODUCT:
- len=min(at->size, PRODUCT_SIZE);
- memcpy(sa->product, at->data, len);
- trim(sa->product, len);
- break;
-
- case ATTR_NAME:
- len=min(at->size, NAME_SIZE);
- memcpy(sa->name, at->data, len);
- trim(sa->name, len);
- break;
-
- case ATTR_MAC:
- memcpy(&sa->mac, at->data, ETH_ALEN);
- break;
-
- case ATTR_IP:
- sa->nc.ip=*(struct in_addr*)at->data;
- break;
-
- case ATTR_NETMASK:
- sa->nc.netmask=*(struct in_addr*)at->data;
- break;
-
- case ATTR_GATEWAY:
- sa->nc.gw=*(struct in_addr*)at->data;
- break;
-
- case ATTR_END:
- return;
-
- }
-
- }
-
-
-}
-
-
-
-// ------------------------
-int discoverSwitches (void) {
-
- int i;
- List *attr;
- struct swi_attr *sa;
-
-
- clearList(swiList, free);
- current=NULL;
-
- attr=createEmptyList();
-
- i=0;
- do {
- pushBackList(attr, newEmptyAttr(helloRequest[i]));
- } while ( helloRequest[i++]!=ATTR_END );
-
- i=sendNgPacket(CODE_READ_REQ, NULL, ++seq, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 ) {
- return ERR_NET;
- }
-
-
- while ( (attr=recvNgPacket (CODE_READ_REP, NULL, seq))!=NULL ) {
- sa=malloc(sizeof(struct swi_attr));
- getSwitchAttributes(sa, attr);
- pushBackList(swiList, sa);
- }
-
- destroyList(attr, (void(*)(void*))freeAttr);
-
-
- return ERR_OK;
-
-}
-
-
-// -----------------------------
-const List* getSwitchList (void) {
- return swiList;
-}
-
-
-// ------------------------------------
-const struct swi_attr* getCurrentSwitch (void) {
- return current;
-}
-
-
-// --------------
-int login (int i) {
-
- List *attr;
- ListNode *ln;
-
-
- if ( i<0 || i>(int)swiList->count ) {
- return ERR_BADID;
- }
-
-
- for (ln=swiList->first; i-->0; ln=ln->next);
- current=ln->data;
-
-
- //attr=createEmptyList();
-
-
-
- return ERR_OK;
-
-}
-
-
-//int logout (void);
-
-
-// --------------------------------
-void setPassword (const char *pass) {
-
- strncpy(password, pass, sizeof(password));
-
-}
-
-
-//int changePassword (const char *pass);
-
-
-
-// =============================================================================
-
-
-//int getPortsNumber (void);
-
-// ------------------------------------------------
-int getPortsStatus (unsigned char *ports, int size) {
-
- List *attr;
- ListNode *ln;
- struct attr *at;
- char *p;
- int i;
-
-
- if ( ports==NULL || size<=0 ) {
- return ERR_INVARG;
- } else if ( current==NULL ) {
- return ERR_NOTLOG;
- }
-
-
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
- pushBackList(attr, newEmptyAttr(ATTR_END));
-
-
- i=sendNgPacket(CODE_READ_REQ, NULL, ++seq, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 ) {
- return ERR_NET;
- }
-
- if ( (attr=recvNgPacket (CODE_READ_REP, NULL, seq))==NULL ) {
- return ERR_TIMEOUT;
- }
-
- for (ln=attr->first; ln!=NULL; ln=ln->next) {
- at=ln->data;
- p=at->data;
- if ( at->attr==ATTR_PORT_STATUS && p[0]-1<size ) {
- i=p[0]-1;
- ports[i]=p[1];
- }
- }
-
- destroyList(attr, (void(*)(void*))freeAttr);
-
-
- return ERR_OK;
-
-}
-
-
-//int getPortsStatistics (unsigned long long stats[][6], int size);
-
-//int resetPortsStatistics (void);
-
-
-
+++ /dev/null
-
-#ifndef DEF_CONTROLLER
-#define DEF_CONTROLLER
-
-
-#include <stdbool.h>
-#include <arpa/inet.h>
-#include <netinet/ether.h>
-
-#include "list.h"
-#include "protocol.h"
-#include "network.h"
-
-
-
-#define ERR_OK 0
-#define ERR_NET -1
-#define ERR_NOTLOG -2
-#define ERR_BADPASS -3
-#define ERR_BADID -4
-#define ERR_INVARG -5
-#define ERR_TIMEOUT -6
-
-#define PRODUCT_SIZE 64
-#define NAME_SIZE 64
-#define FIRMWARE_SIZE 64
-
-
-
-struct net_conf {
- struct in_addr ip, netmask, gw;
- bool dhcp;
-};
-
-
-struct swi_attr {
- char product[PRODUCT_SIZE];
- char name[NAME_SIZE];
- char firmware[FIRMWARE_SIZE];
- unsigned char ports;
- struct ether_addr mac;
- struct net_conf nc;
-};
-
-
-
-
-
-void startController (void);
-
-void stopController (void);
-
-
-
-int discoverSwitches (void);
-
-const List* getSwitchList (void);
-
-const struct swi_attr* getCurrentSwitch (void);
-
-int login (int i);
-
-int logout (void);
-
-
-
-void setPassword (const char *pass);
-
-int changePassword (const char *pass);
-
-
-
-int getFirmwareVersion (char *buf, int size);
-
-int getMirrorPorts (unsigned char *ports, int size);
-
-int setMirrorPorts (const unsigned char *ports, int size);
-
-
-
-int getPortsNumber (void);
-
-int getPortsStatus (unsigned char *ports, int size);
-
-int getPortsStatistics (unsigned long long stats[][6], int size);
-
-int resetPortsStatistics (void);
-
-
-
-int getQosStatus (void);
-
-int setQosMode (char mode);
-
-int setQosPorts (const unsigned char* ports, int size, char level);
-
-
-
-int getNetConf (struct net_conf *nc);
-
-int setNetConf (const struct net_conf *nc);
-
-
-
-int getName (char *name, int size);
-
-int setName (const char *name);
-
-
-
-#endif
-
+++ /dev/null
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <signal.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netinet/ether.h>
-#include <sys/ioctl.h>
-
-#include "protocol.h"
-
-
-
-
-int sock;
-
-
-
-__attribute__((noreturn)) void handler (int sig) {
-
-
- if ( sig==SIGINT ) {
- printf("\033[1G");
- }
-
-
- close(sock);
-
-
- exit(0);
-
-}
-
-
-
-int main (int argc, char **argv) {
-
- char buffer[1024];
- socklen_t slen=sizeof(struct sockaddr_in);
- struct sockaddr_in local, client;
- struct ether_addr localmac;
- struct in_addr localip;
- struct ifreq ifr;
- int len, i;
- unsigned char ports=8;
- struct ng_packet np;
- struct attr *at;
- List *l;
- ListNode *ln;
-
-
-
- if ( argc<2 ) {
- printf("Usage: %s <interface>\n", argv[0]);
- return 1;
- }
-
- memset(&local, 0, sizeof(struct sockaddr_in));
- local.sin_family=AF_INET;
- client=local;
- local.sin_addr.s_addr=htonl(INADDR_ANY);
- local.sin_port=htons(SWITCH_PORT);
-
- memset(&ifr, 0, sizeof(struct ifreq));
- strncpy(ifr.ifr_name, argv[1], IFNAMSIZ-1);
-
- np.buffer=buffer;
- np.maxlen=sizeof(buffer);
-
- if ( (sock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))<0 ) {
- perror("socket");
- } else if ( bind(sock, (struct sockaddr*)&local, sizeof(struct sockaddr_in))<0 ) {
- perror("bind");
- }
-
- i=1;
- if ( setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i))<0 ) {
- perror("setsockopt(SO_BROADCAST)");
- }
-
- /*
- i=0;
- if ( setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &i, sizeof(i)) ) {
- perror("setsockopt(IP_MULTICAST_LOOP)");
- }
- */
-
-
- if ( ioctl(sock, SIOCGIFHWADDR, &ifr)<0 ) {
- perror("ioctl(SIOCGIFHWADDR)");
- }
- memcpy(&localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
-
- if ( ioctl(sock, SIOCGIFADDR, &ifr)<0 ) {
- perror("ioctl(SIOCGIFADDR)");
- }
- localip=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
-
-
- printf("server: ip %s, mac %s\n", inet_ntoa(localip), ether_ntoa(&localmac));
-
- signal(SIGINT, handler);
- signal(SIGTERM, handler);
-
-
- while ( 1 ) {
-
- if ( (len=recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&client, &slen))<0 ) {
- perror("recvfrom");
- break;
- }
-
- if ( len<(int)sizeof(struct ng_header) || ( memcmp(&np.nh->switch_mac, &nullMac, 6)!=0 && memcmp(&np.nh->switch_mac, &localmac, 6)!=0 ) ) {
- continue;
- }
-
- printf("received %d bytes from %s: \n", len, inet_ntoa(client.sin_addr));
-
- printf("code: %i\n", np.nh->code);
- printf("client mac: %s\n", ether_ntoa((struct ether_addr*)np.nh->client_mac));
- printf("seq num: %d\n", ntohl(np.nh->seqnum));
- printf("\n");
-
- memcpy(np.nh->switch_mac, &localmac, ETH_ALEN);
-
- initNgPacket(&np);
- l=extractPacketAttributes(&np);
-
- initNgPacket(&np);
-
-
- switch ( np.nh->code ) {
-
- case CODE_READ_REQ:
-
- for (ln=l->first; ln!=NULL; ln=ln->next) {
- at=ln->data;
-
- switch ( at->attr ) {
-
- case ATTR_PRODUCT:
- strcpy(np.ah->data, "NgEmu");
- addPacketAttr(&np, ATTR_PRODUCT, strlen(np.ah->data), NULL);
- break;
-
- case ATTR_UNK2:
- addPacketShortAttr(&np, ATTR_UNK2, 0);
- break;
-
- case ATTR_NAME:
- strcpy(np.ah->data, "netgear switch emulator");
- addPacketAttr(&np, ATTR_NAME, strlen(np.ah->data), NULL);
- break;
-
- case ATTR_MAC:
- memcpy(np.ah->data, &localmac, ETH_ALEN);
- addPacketAttr(&np, ATTR_MAC, ETH_ALEN, NULL);
- break;
-
- case ATTR_UNK5:
- memset(np.ah->data, 0, 64);
- addPacketAttr(&np, ATTR_UNK5, 64, NULL);
- break;
-
- case ATTR_IP:
- *(struct in_addr*)np.ah->data=localip;
- addPacketAttr(&np, ATTR_IP, 4, NULL);
- break;
-
- case ATTR_NETMASK:
- *(in_addr_t*)np.ah->data=inet_addr("255.255.255.0");
- addPacketAttr(&np, ATTR_NETMASK, 4, NULL);
- break;
-
- case ATTR_GATEWAY:
- *(in_addr_t*)np.ah->data=inet_addr("192.168.0.16");
- addPacketAttr(&np, ATTR_GATEWAY, 4, NULL);
- break;
-
- case ATTR_DHCP:
- addPacketShortAttr(&np, ATTR_DHCP, 1);
- break;
-
- case ATTR_UNK12:
- addPacketByteAttr(&np, ATTR_UNK12, 1);
- break;
-
- case ATTR_FIRM_VER:
- strcpy(np.ah->data, "NgAdmin 0.0.1");
- addPacketAttr(&np, ATTR_FIRM_VER, strlen(np.ah->data), NULL);
- break;
-
- case ATTR_UNK15:
- addPacketByteAttr(&np, ATTR_UNK15, 1);
- break;
-
- case ATTR_PORTS_NUMBER:
- addPacketByteAttr(&np, ATTR_PORTS_NUMBER, ports);
- break;
-
- case ATTR_PORT_STATUS:
- for (i=1; i<=ports; i++) {
- np.ah->data[0]=i;
- switch ( i&3 ) {
- case 0: np.ah->data[2]=0; np.ah->data[1]=0; break;
- case 1: np.ah->data[2]=1; np.ah->data[1]=SPEED_10; break;
- case 2: np.ah->data[2]=1; np.ah->data[1]=SPEED_100; break;
- case 3: np.ah->data[2]=1; np.ah->data[1]=SPEED_1000;
- }
- addPacketAttr(&np, ATTR_PORT_STATUS, 3, NULL);
- }
- break;
-
- case ATTR_QOS_TYPE:
- addPacketByteAttr(&np, ATTR_QOS_TYPE, QOS_PORT);
- break;
-
- case ATTR_QOS_CONFIG:
- for (i=1; i<=(int)ports; i++) {
- np.ah->data[0]=i;
- np.ah->data[1]=(i&3)+1;
- addPacketAttr(&np, ATTR_QOS_CONFIG, 2, NULL);
- }
- break;
-
- case 0x5400:
- addPacketByteAttr(&np, 0x5400, 0);
- break;
-
- /*
- case 0x1000: // System -> Monitoring -> Port Statistics
- len=1+3*8;
- for (i=1; i<=(int)ports; i++) {
- memset(np.ah->data, 0, len);
- addPacketAttr(&np, 0x1000, len, NULL);
- }
- break;
- */
-
- case ATTR_MIRROR:
- np.ah->data[0]=ports;
- np.ah->data[1]=0;
- len=(ports>>3)+((ports&7)!=0);
- *(unsigned int*)&np.ah->data[2]=0;
- for (i=0; i<ports-1; i+=2) {
- np.ah->data[2+(i>>3)] |= 1<<(7-(i&7)) ;
- }
- addPacketAttr(&np, ATTR_MIRROR, 2+len, NULL);
- break;
-
- case ATTR_VLAN_TYPE:
- addPacketByteAttr(&np, ATTR_VLAN_TYPE, VLAN_DOT_ADV);
- break;
-
- /*
- case 0x7400:
- break
- */
-
- default:
- addPacketEmptyAttr(&np, at->attr);
-
- }
-
- }
-
- np.nh->code=CODE_READ_REP;
- len=getPacketTotalSize(&np);
-
- break;
-
- case CODE_WRITE_REQ:
- np.nh->code=CODE_WRITE_REP;
- break;
-
- default:
- printf("unkown code\n");
-
- }
-
-
- destroyList(l, (void(*)(void*))freeAttr);
-
- client.sin_addr.s_addr=htonl(INADDR_BROADCAST);
- client.sin_port=htons(CLIENT_PORT);
- if ( sendto(sock, buffer, len, 0, (struct sockaddr*)&client, sizeof(struct sockaddr))<0 ) {
- perror("sendto");
- }
-
-
- }
-
- handler(0);
-
-}
-
--- /dev/null
+
+#ifndef DEF_NGADMIN
+#define DEF_NGADMIN
+
+
+#include <stdbool.h>
+#include <arpa/inet.h>
+#include <netinet/ether.h>
+
+
+#ifdef BUILD_LIB
+#define EXPORT __attribute__((visibility("default")))
+#else
+#define EXPORT
+#endif
+
+
+#define ERR_OK 0 // no error
+#define ERR_NET -1 // network
+#define ERR_NOTLOG -2 // not logged on a switch
+#define ERR_BADPASS -3 // bad password
+#define ERR_BADID -4 // bad switch id
+#define ERR_INVARG -5 // invalid argument
+#define ERR_TIMEOUT -6 // timeout
+
+#define PRODUCT_SIZE 64
+#define NAME_SIZE 64
+#define FIRMWARE_SIZE 64
+
+
+
+
+#define SPEED_DOWN 0
+#define SPEED_10 1
+#define SPEED_100 4
+#define SPEED_1000 5
+
+#define VLAN_PORT_BASIC 1
+#define VLAN_PORT_ADV 2
+#define VLAN_DOT_BASIC 3
+#define VLAN_DOT_ADV 4
+
+#define QOS_PORT 1
+#define QOS_DOT 2
+
+#define PRIO_HIGH 1
+#define PRIO_MED 2
+#define PRIO_NORM 3
+#define PRIO_LOW 4
+
+#define BITRATE_NOLIMIT 0
+#define BITRATE_512K 1
+#define BITRATE_1M 2
+#define BITRATE_2M 3
+#define BITRATE_4M 4
+#define BITRATE_8M 5
+#define BITRATE_16M 6
+#define BITRATE_32M 7
+#define BITRATE_64M 8
+#define BITRATE_128M 9
+#define BITRATE_256M 10
+#define BITRATE_512M 11
+
+
+
+
+// opaque type to clients
+struct ngadmin;
+
+
+struct net_conf {
+ struct in_addr ip; // IP
+ struct in_addr netmask; // netmask
+ struct in_addr gw; // gateway IP
+ bool dhcp; // DHCP enabled
+};
+
+
+struct swi_attr {
+ char product[PRODUCT_SIZE]; // product name (eg. GS108E)
+ char name[NAME_SIZE]; // custom name
+ char firmware[FIRMWARE_SIZE]; // firmware version string
+ unsigned char ports; // number of ports
+ struct ether_addr mac; // MAC address
+ struct net_conf nc; // network configuration
+};
+
+
+struct port_stats {
+ unsigned long long recv;
+ unsigned long long sent;
+ unsigned long long crc;
+};
+
+
+
+
+// initialize NgAdmin lib
+struct ngadmin* ngadmin_init (const char *iface) EXPORT;
+
+//
+int ngadmin_close (struct ngadmin *nga) EXPORT;
+
+
+// specify password to use for authenticating on switches
+int ngadmin_setPassword (struct ngadmin *nga, const char *pass) EXPORT;
+
+
+//
+int ngadmin_setTimeout (struct ngadmin *nga, const struct timeval *tv) EXPORT;
+
+
+//
+int ngadmin_scan (struct ngadmin *nga) EXPORT;
+
+
+//
+const struct swi_attr* ngadmin_getSwitchTab (struct ngadmin *nga, int *nb) EXPORT;
+
+
+//
+const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga) EXPORT;
+
+
+//
+int ngadmin_login (struct ngadmin *nga, int id) EXPORT;
+
+
+//
+int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) EXPORT;
+
+
+//
+int ngadmin_setName (struct ngadmin *nga, const char *name) EXPORT;
+
+
+//
+int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) EXPORT;
+
+
+//
+int ngadmin_resetPortsStatistics (struct ngadmin *nga) EXPORT;
+
+
+//
+int ngadmin_changePassword (struct ngadmin *nga, const char* pass) EXPORT;
+
+
+
+#endif
+
--- /dev/null
+
+CC=gcc
+CFLAGS=-DBUILD_LIB -D_REENTRANT -I.. -W -Wall -Wextra -Os -fomit-frame-pointer -fno-strict-aliasing -fvisibility=hidden -fPIC
+LDFLAGS=-lpthread -s
+EXEC=../libngadmin.so
+
+SRC=$(wildcard *.c)
+OBJ=$(SRC:.c=.o)
+
+
+
+$(EXEC): $(OBJ)
+ $(CC) $^ -shared -o $@ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) -c $^ -o $@ $(CFLAGS)
+
+
+clean:
+ @rm -f *.o
+
+mrproper: clean
+ @rm -f $(EXEC)
+
+
--- /dev/null
+
+#ifndef DEF_LIB
+#define DEF_LIB
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <net/if.h>
+
+#include <ngadmin.h>
+
+
+#define PASSWORD_MAX 32
+
+
+#define CLIENT_PORT 63321
+#define SWITCH_PORT 63322
+
+#define CODE_READ_REQ 1
+#define CODE_READ_REP 2
+#define CODE_WRITE_REQ 3
+#define CODE_WRITE_REP 4
+
+#define ATTR_PRODUCT 0x0001
+#define ATTR_UNK2 0x0002
+#define ATTR_NAME 0x0003
+#define ATTR_MAC 0x0004
+#define ATTR_UNK5 0x0005
+#define ATTR_IP 0x0006
+#define ATTR_NETMASK 0x0007
+#define ATTR_GATEWAY 0x0008
+#define ATTR_NEW_PASSWORD 0x0009
+#define ATTR_PASSWORD 0x000A
+#define ATTR_DHCP 0x000B
+#define ATTR_UNK12 0x000C
+#define ATTR_FIRM_VER 0x000D
+#define ATTR_UNK14 0x000E
+#define ATTR_UNK15 0x000F
+#define ATTR_RESTART 0x0013
+#define ATTR_DEFAULTS 0x0400
+#define ATTR_PORT_STATUS 0x0C00
+#define ATTR_PORT_STATISTICS 0x1000
+#define ATTR_STATS_RESET 0x1400
+#define ATTR_VLAN_TYPE 0x2000
+#define ATTR_VLAN_CONFIG 0x2400
+#define ATTR_QOS_TYPE 0x3400
+#define ATTR_QOS_CONFIG 0x3800
+#define ATTR_BITRATE_INPUT 0x4C00
+#define ATTR_BITRATE_OUTPUT 0x5000
+#define ATTR_STORM_ENABLE 0x5400
+#define ATTR_STORM_BITRATE 0x5800
+#define ATTR_MIRROR 0x5C00
+#define ATTR_PORTS_COUNT 0x6000
+#define ATTR_END 0xFFFF
+
+
+
+struct ngadmin {
+ // network
+ int sock; // socket
+ struct sockaddr_in local;
+ struct sockaddr_in remote;
+ char iface[IFNAMSIZ]; // interface
+ struct timeval timeout; // timeout
+ struct ether_addr localmac; // local MAC address
+ //
+ char password[PASSWORD_MAX]; // password to use to login on switches
+ struct swi_attr *swi_tab; // array of detected switches
+ int swi_count; // number of detected switches
+ struct swi_attr *current; // administred switch
+ int seq; // sequence number for packets
+};
+
+
+
+#endif
+
--- /dev/null
+
+#include "list.h"
+
+
+
+
+// -------------------------
+List* createEmptyList (void) {
+
+ List *l;
+
+
+ l=malloc(sizeof(List));
+ l->first=NULL;
+ l->last=NULL;
+ l->count=0;
+ pthread_cond_init(&l->cond, NULL);
+ pthread_mutex_init(&l->mutex, NULL);
+
+
+ return l;
+
+}
+
+
+
+// ------------------------------------------------
+void destroyList (List *l, void (*freefunc)(void*)) {
+
+ ListNode *pr, *ln;
+
+
+
+ if ( l==NULL ) {
+ return;
+ }
+
+
+ pthread_mutex_destroy(&l->mutex);
+ pthread_cond_destroy(&l->cond);
+
+ for (ln=l->first; ln!=NULL; ) {
+
+ pr=ln;
+
+ if ( freefunc!=NULL ) {
+ freefunc(pr->data);
+ }
+
+ ln=pr->next;
+ free(pr);
+
+ }
+
+
+ free(l);
+
+}
+
+
+
+// -------------------------------------
+void pushFrontList (List *l, void* data) {
+
+ ListNode *ln;
+
+
+ if ( l==NULL ) {
+ return;
+ }
+
+
+ pthread_mutex_lock(&l->mutex);
+
+ ln=malloc(sizeof(ListNode));
+ ln->data=data;
+ ln->prev=NULL;
+ ln->next=l->first;
+
+ if ( l->first==NULL ) {
+ l->last=ln;
+ } else {
+ l->first->prev=ln;
+ }
+
+ l->first=ln;
+ l->count++;
+
+ pthread_mutex_unlock(&l->mutex);
+ pthread_cond_broadcast(&l->cond);
+
+}
+
+
+
+// ------------------------------------
+void pushBackList (List *l, void* data) {
+
+ ListNode *ln;
+
+
+ if ( l==NULL ) {
+ return;
+ }
+
+
+ pthread_mutex_lock(&l->mutex);
+
+ ln=malloc(sizeof(ListNode));
+ ln->data=data;
+ ln->prev=l->last;
+ ln->next=NULL;
+
+ if ( l->last==NULL ) {
+ l->first=ln;
+ } else {
+ l->last->next=ln;
+ }
+
+ l->last=ln;
+ l->count++;
+
+ pthread_mutex_unlock(&l->mutex);
+ pthread_cond_broadcast(&l->cond);
+
+}
+
+
+
+// -------------------------
+void* popFrontList (List *l) {
+
+ ListNode *ln;
+ void* data;
+
+
+ if ( l==NULL ) {
+ return NULL;
+ }
+
+
+ pthread_mutex_lock(&l->mutex);
+
+ if ( (ln=l->first)==NULL ) {
+ pthread_mutex_unlock(&l->mutex);
+ return NULL;
+ }
+
+ data=ln->data;
+ l->first=ln->next;
+
+ if ( ln->next==NULL ) {
+ l->last=NULL;
+ } else {
+ ln->next->prev=NULL;
+ }
+
+ l->count--;
+ free(ln);
+
+ pthread_mutex_unlock(&l->mutex);
+ pthread_cond_broadcast(&l->cond);
+
+
+ return data;
+
+}
+
+
+
+// ------------------------
+void* popBackList (List *l) {
+
+ ListNode *ln;
+ void* data;
+
+
+
+ if ( l==NULL ) {
+ return NULL;
+ }
+
+
+ pthread_mutex_lock(&l->mutex);
+
+ if ( (ln=l->last)==NULL ) {
+ pthread_mutex_unlock(&l->mutex);
+ return NULL;
+ }
+
+ data=ln->data;
+ l->last=ln->prev;
+
+ if ( ln->prev==NULL ) {
+ l->first=NULL;
+ } else {
+ ln->prev->next=NULL;
+ }
+
+ l->count--;
+ free(ln);
+
+ pthread_mutex_unlock(&l->mutex);
+ pthread_cond_broadcast(&l->cond);
+
+
+
+ return data;
+
+}
+
+
+
+// ----------------------------------------------
+void clearList (List *l, void (*freefunc)(void*)) {
+
+ ListNode *ln, *pr;
+
+
+ if ( l==NULL ) {
+ return;
+ }
+
+
+ pthread_mutex_lock(&l->mutex);
+
+ for (ln=l->first; ln!=NULL; ) {
+
+ pr=ln;
+
+ if ( freefunc!=NULL ) {
+ freefunc(pr->data);
+ }
+
+ ln=pr->next;
+ free(pr);
+
+ }
+
+ l->first=NULL;
+ l->last=NULL;
+ l->count=0;
+
+ pthread_mutex_unlock(&l->mutex);
+ pthread_cond_broadcast(&l->cond);
+
+
+}
+
+
+
+// ---------------------------------------------------------------
+bool findAndDestroy (List *l, void* data, void (*freefunc)(void*)) {
+
+ ListNode *ln;
+
+
+
+ if ( l==NULL ) {
+ return false;
+ }
+
+
+ pthread_mutex_lock(&l->mutex);
+
+ for (ln=l->first; ln!=NULL && ln->data!=data; ln=ln->next);
+
+ if ( ln==NULL ) {
+
+ pthread_mutex_unlock(&l->mutex);
+
+ } else {
+
+ if ( ln->prev==NULL ) {
+ l->first=ln->next;
+ } else {
+ ln->prev->next=ln->next;
+ }
+
+ if ( ln->next==NULL ) {
+ l->last=ln->prev;
+ } else {
+ ln->next->prev=ln->prev;
+ }
+
+
+ if ( freefunc!=NULL ) {
+ freefunc(data);
+ }
+
+ l->count--;
+
+ pthread_mutex_unlock(&l->mutex);
+ pthread_cond_broadcast(&l->cond);
+
+ }
+
+
+
+ return true;
+
+}
+
+
+
+// -------------------------------------------------
+void browseList (List *l, void (*browsefunc)(void*)) {
+
+ ListNode *ln;
+
+
+
+ if ( l==NULL || browsefunc==NULL ) {
+ return;
+ }
+
+
+ pthread_mutex_lock(&l->mutex);
+
+ for (ln=l->first; ln!=NULL; ln=ln->next) {
+ browsefunc(ln->data);
+ }
+
+ pthread_mutex_unlock(&l->mutex);
+
+
+}
+
+
+// --------------------------------------
+void* convertToArray (List *l, size_t sz) {
+
+ ListNode *ln;
+ void *tab=NULL, *p;
+
+
+
+ if ( l==NULL || sz==0 ) {
+ return NULL;
+ }
+
+
+ pthread_mutex_lock(&l->mutex);
+
+ if ( l->count>0 ) {
+
+ tab=malloc(l->count*sz);
+ p=tab;
+
+ for (ln=l->first; ln!=NULL; ln=ln->next) {
+ memcpy(p, ln->data, sz);
+ p+=sz;
+ }
+
+ }
+
+ pthread_mutex_unlock(&l->mutex);
+
+
+ return tab;
+
+}
+
+
+
+
--- /dev/null
+
+#ifndef DEF_LIST
+#define DEF_LIST
+
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <pthread.h>
+
+
+
+
+typedef struct ListNode ListNode;
+
+struct ListNode {
+ void* data;
+ ListNode *prev, *next;
+};
+
+
+typedef struct {
+ ListNode *first, *last;
+ unsigned int count;
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+} List;
+
+
+
+
+// Creates an empty list
+List* createEmptyList (void);
+
+// Destroys a list, and eventually frees the elements
+// NOT MT SAFE
+void destroyList (List *l, void (*freefunc)(void*));
+
+// Adds an element at front of the list
+void pushFrontList (List *l, void* data);
+
+// Adds an element at back of the list
+void pushBackList (List *l, void* data);
+
+// Pops an element from the front of the list and returns its value
+void* popFrontList (List *l);
+
+// Pops an element from the back of the list and returns its value
+void* popBackList (List *l);
+
+// Clears all the items of the list, and eventually frees them
+void clearList (List *l, void (*freefunc)(void*));
+
+// Find and destroy a particular element of the list, and eventually frees it
+bool findAndDestroy (List *l, void* data, void (*freefunc)(void*));
+
+// Browse all the items of the list through the callback function
+void browseList (List *l, void (*browsefunc)(void*));
+
+//
+void* convertToArray (List *l, size_t sz);
+
+
+
+
+#endif
+
--- /dev/null
+
+#include "network.h"
+
+
+
+
+// -----------------------------------
+int startNetwork (struct ngadmin *nga) {
+
+ struct ifreq ifr;
+ int ret;
+
+
+ nga->local.sin_family=AF_INET;
+ nga->remote=nga->local;
+ nga->local.sin_port=htons(CLIENT_PORT);
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ-1);
+
+ if ( (nga->sock=socket(AF_INET, SOCK_DGRAM, 0))<0 ) {
+ perror("socket");
+ return nga->sock;
+ }
+
+ // get the interface IP address
+ if ( (ret=ioctl(nga->sock, SIOCGIFADDR, &ifr))<0 ) {
+ perror("ioctl(SIOCGIFADDR)");
+ close(nga->sock);
+ return ret;
+ }
+ //local.sin_addr=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; // FIXME
+
+ // get the interface MAC address
+ if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ close(nga->sock);
+ return ret;
+ }
+ memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ // bind
+ if ( (ret=bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)))<0 ) {
+ perror("bind");
+ close(nga->sock);
+ return ret;
+ }
+
+ // allow broadcasting
+ ret=1;
+ if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) {
+ perror("setsockopt(SO_BROADCAST)");
+ return ret;
+ }
+
+
+ return 0;
+
+}
+
+
+
+// ----------------------------------
+int stopNetwork (struct ngadmin *nga) {
+
+ return close(nga->sock);
+
+}
+
+
+
+// ------------------------------------
+int updateTimeout (struct ngadmin *nga) {
+
+ int ret;
+
+
+ // specify receive timeout
+ if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval)))<0 ) {
+ perror("setsockopt(SO_RCVTIMEO)");
+ return ret;
+ }
+
+
+ return 0;
+
+}
+
+
+
+// --------------------------------------------------------------------------------------------------------------------------
+int sendNgPacket (struct ngadmin *nga, char code, const struct ether_addr *switch_mac, unsigned int seqnum, const List *attr) {
+
+ char buffer[1500];
+ struct ng_packet np;
+ ListNode *ln;
+ struct attr *at;
+ int ret;
+
+
+
+ np.buffer=buffer;
+ np.maxlen=sizeof(buffer);
+ initNgPacket(&np);
+ initNgHeader(np.nh, code, &nga->localmac, switch_mac, seqnum);
+
+ if ( attr!=NULL ) {
+ for (ln=attr->first; ln!=NULL; ln=ln->next) {
+ at=ln->data;
+ addPacketAttr(&np, at->attr, at->size, at->data);
+ }
+ }
+
+
+ nga->remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
+ nga->remote.sin_port=htons(SWITCH_PORT);
+ if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&nga->remote, sizeof(struct sockaddr_in)))<0 ) {
+ perror("sendto");
+ }
+
+
+ return ret;
+
+}
+
+
+
+// ---------------------------------------------------------------------------------------------------------------------------------------------------
+List* recvNgPacket (struct ngadmin *nga, char code, char *error, unsigned short *attr_error, const struct ether_addr *switch_mac, unsigned int seqnum) {
+
+ char buffer[1500];
+ struct ng_packet np;
+ socklen_t slen=sizeof(struct sockaddr_in);
+ List *l=NULL;
+ int len;
+
+
+ np.buffer=buffer;
+ np.maxlen=sizeof(buffer);
+
+ while ( (len=recvfrom(nga->sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&nga->remote, &slen))>=0 ) {
+ if ( len>=(int)sizeof(struct ng_header) && validateNgHeader(np.nh, code, &nga->localmac, switch_mac, seqnum) ) {
+ initNgPacket(&np);
+ l=extractPacketAttributes(&np, error, attr_error);
+ break;
+ }
+ }
+
+
+ return l;
+
+}
+
+
--- /dev/null
+
+#ifndef DEF_NETWORK
+#define DEF_NETWORK
+
+
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/ether.h>
+#include <sys/ioctl.h>
+
+#include "list.h"
+#include "lib.h"
+#include "protocol.h"
+
+
+
+//
+int startNetwork (struct ngadmin *nga);
+
+//
+int stopNetwork (struct ngadmin *nga);
+
+//
+int updateTimeout (struct ngadmin *nga);
+
+//
+int sendNgPacket (struct ngadmin *nga, char code, const struct ether_addr *switch_mac, unsigned int seqnum, const List *attr);
+
+//
+List* recvNgPacket (struct ngadmin *nga, char code, char *error, unsigned short *attr_error, const struct ether_addr *switch_mac, unsigned int seqnum);
+
+
+
+#endif
+
--- /dev/null
+
+#include "lib.h"
+#include "network.h"
+
+
+
+static const struct timeval default_timeout={.tv_sec=3, .tv_usec=0};
+
+
+
+// ---------------------------------------------
+struct ngadmin* ngadmin_init (const char *iface) {
+
+ struct ngadmin *nga;
+
+
+ // allocate main structure
+ nga=malloc(sizeof(struct ngadmin));
+ memset(nga, 0, sizeof(struct ngadmin));
+
+ strncpy(nga->iface, iface, IFNAMSIZ-1);
+
+ if ( startNetwork(nga)<0 ) {
+ free(nga);
+ return NULL;
+ }
+
+ nga->timeout=default_timeout;
+ if ( updateTimeout(nga)<0 ) {
+ free(nga);
+ return NULL;
+ }
+
+
+ return nga;
+
+}
+
+
+
+// ------------------------------------
+int ngadmin_close (struct ngadmin *nga) {
+
+ if ( nga==NULL ) {
+ return ERR_INVARG;
+ }
+
+
+ stopNetwork(nga);
+ free(nga->swi_tab);
+ free(nga);
+
+
+ return ERR_OK;
+
+}
+
+
+
+// ------------------------------------------------------------
+int ngadmin_setPassword (struct ngadmin *nga, const char *pass) {
+
+ if ( nga==NULL ) {
+ return ERR_INVARG;
+ }
+
+
+ strncpy(nga->password, pass, PASSWORD_MAX);
+
+
+ return ERR_OK;
+
+}
+
+
+
+// -------------------------------------------------------------------
+int ngadmin_setTimeout (struct ngadmin *nga, const struct timeval *tv) {
+
+ int ret=ERR_OK;
+
+
+ if ( nga==NULL || tv==NULL ) {
+ return ERR_INVARG;
+ }
+
+
+ nga->timeout=*tv;
+ if ( updateTimeout(nga)<0 ) {
+ ret=ERR_NET;
+ }
+
+
+ return ret;
+
+}
+
+
+
+// -----------------------------------
+int ngadmin_scan (struct ngadmin *nga) {
+
+ int i;
+ List *attr, *swiList;
+ struct swi_attr *sa;
+ /*
+ sent by official win client:
+ ATTR_PRODUCT,
+ ATTR_UNK2,
+ ATTR_NAME,
+ ATTR_MAC,
+ ATTR_UNK5,
+ ATTR_IP,
+ ATTR_NETMASK,
+ ATTR_GATEWAY,
+ ATTR_DHCP,
+ ATTR_UNK12,
+ ATTR_FIRM_VER,
+ ATTR_UNK14,
+ ATTR_UNK15,
+ ATTR_END
+ */
+ static const unsigned short hello[]={
+ ATTR_PRODUCT,
+ ATTR_NAME,
+ ATTR_MAC,
+ ATTR_IP,
+ ATTR_NETMASK,
+ ATTR_GATEWAY,
+ ATTR_DHCP,
+ ATTR_FIRM_VER,
+ ATTR_PORTS_COUNT,
+ ATTR_END
+ };
+
+
+ if ( nga==NULL ) {
+ return ERR_INVARG;
+ }
+
+ free(nga->swi_tab);
+ nga->swi_count=0;
+ nga->current=NULL;
+
+
+ // create attributes for an "hello" request
+ attr=createEmptyList();
+ for (i=0; ; ++i) {
+ pushBackList(attr, newEmptyAttr(hello[i]));
+ if ( hello[i]==ATTR_END ) break;
+ }
+
+ // send request to all potential switches
+ i=sendNgPacket(nga, CODE_READ_REQ, NULL, ++nga->seq, attr);
+ destroyList(attr, (void(*)(void*))freeAttr);
+ if ( i<0 ) {
+ return ERR_NET;
+ }
+
+
+ // try to receive any packets until timeout
+ swiList=createEmptyList();
+ while ( (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL, NULL, nga->seq))!=NULL ) {
+ sa=malloc(sizeof(struct swi_attr));
+ extractSwitchAttributes(sa, attr);
+ destroyList(attr, (void(*)(void*))freeAttr);
+ pushBackList(swiList, sa);
+ }
+
+ nga->swi_count=swiList->count;
+ nga->swi_tab=convertToArray(swiList, sizeof(struct swi_attr));
+
+
+ return ERR_OK;
+
+}
+
+
+
+// -----------------------------------------------------------------------
+const struct swi_attr* ngadmin_getSwitchTab (struct ngadmin *nga, int *nb) {
+
+
+ if ( nga==NULL || nb==NULL ) {
+ return NULL;
+ }
+
+
+ *nb=nga->swi_count;
+
+
+ return nga->swi_tab;
+
+}
+
+
+
+// ------------------------------------------------------------------
+const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga) {
+
+
+ if ( nga==NULL ) {
+ return NULL;
+ }
+
+
+ return nga->current;
+
+}
+
+
+
+// --------------------------------------------
+int ngadmin_login (struct ngadmin *nga, int id) {
+
+ List *attr;
+ int ret=ERR_OK, i;
+ struct swi_attr *sa;
+ char err;
+ unsigned short attr_error;
+
+
+ if ( nga==NULL ) {
+ return ERR_INVARG;
+ } else if ( id<0 || id>=nga->swi_count ) {
+ return ERR_BADID;
+ }
+
+
+ nga->current=NULL;
+ sa=&nga->swi_tab[id];
+
+ attr=createEmptyList();
+ pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
+ pushBackList(attr, newEmptyAttr(ATTR_END));
+ i=sendNgPacket(nga, CODE_READ_REQ, &sa->mac, ++nga->seq, attr);
+ destroyList(attr, (void(*)(void*))freeAttr);
+ if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, &sa->mac, nga->seq))==NULL ) {
+ ret=ERR_NET;
+ goto end;
+ }
+
+
+ destroyList(attr, (void(*)(void*))freeAttr);
+ if ( err==7 && attr_error==ATTR_PASSWORD ) {
+ ret=ERR_BADPASS;
+ goto end;
+ }
+
+
+ // login successful
+ nga->current=sa;
+
+ end:
+
+
+ return ret;
+
+}
+
+
+
+// -------------------------------------------------------------------
+int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) {
+
+ List *attr;
+ ListNode *ln;
+ struct attr *at;
+ int ret=ERR_OK, i;
+ char *p;
+
+
+ if ( nga==NULL || ports==NULL ) {
+ return ERR_INVARG;
+ } else if ( nga->current==NULL ) {
+ return ERR_NOTLOG;
+ }
+
+
+ attr=createEmptyList();
+ pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
+ pushBackList(attr, newEmptyAttr(ATTR_END));
+ i=sendNgPacket(nga, CODE_READ_REQ, &nga->current->mac, ++nga->seq, attr);
+ destroyList(attr, (void(*)(void*))freeAttr);
+ if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL, &nga->current->mac, nga->seq))==NULL ) {
+ ret=ERR_NET;
+ goto end;
+ }
+
+ for (ln=attr->first; ln!=NULL; ln=ln->next) {
+ at=ln->data;
+ p=at->data;
+ if ( at->attr==ATTR_PORT_STATUS && at->size>=2 && (i=p[0]-1)>=0 && i<nga->current->ports ) {
+ ports[i]=p[1];
+ }
+ }
+
+ destroyList(attr, (void(*)(void*))freeAttr);
+
+
+ end:
+
+ return ret;
+
+}
+
+
+
+// --------------------------------------------------------
+int ngadmin_setName (struct ngadmin *nga, const char *name) {
+
+ List *attr;
+ int ret=ERR_OK, i;
+ char err;
+ unsigned short attr_error;
+
+
+ if ( nga==NULL ) {
+ return ERR_INVARG;
+ } else if ( nga->current==NULL ) {
+ return ERR_NOTLOG;
+ }
+
+
+ attr=createEmptyList();
+ pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
+ if ( name==NULL ) {
+ pushBackList(attr, newEmptyAttr(ATTR_NAME));
+ } else {
+ pushBackList(attr, newAttr(ATTR_NAME, strlen(name), strdup(name)));
+ }
+ pushBackList(attr, newEmptyAttr(ATTR_END));
+ i=sendNgPacket(nga, CODE_WRITE_REQ, &nga->current->mac, ++nga->seq, attr);
+ destroyList(attr, (void(*)(void*))freeAttr);
+ if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, &nga->current->mac, nga->seq))==NULL ) {
+ ret=ERR_NET;
+ goto end;
+ }
+
+ destroyList(attr, (void(*)(void*))freeAttr);
+ if ( err==7 && attr_error==ATTR_PASSWORD ) {
+ ret=ERR_BADPASS;
+ goto end;
+ }
+
+
+ // successful, also update local name
+ if ( name==NULL ) {
+ nga->current->name[0]=0;
+ } else {
+ strncpy(nga->current->name, name, NAME_SIZE);
+ }
+
+
+ end:
+
+ return ret;
+
+}
+
+
+
+// ------------------------------------------------------------------------
+int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) {
+
+ List *attr;
+ ListNode *ln;
+ struct attr *at;
+ int ret=ERR_OK, i;
+ int port;
+
+
+ if ( nga==NULL || ps==NULL ) {
+ return ERR_INVARG;
+ } else if ( nga->current==NULL ) {
+ return ERR_NOTLOG;
+ }
+
+
+ attr=createEmptyList();
+ pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
+ pushBackList(attr, newEmptyAttr(ATTR_END));
+ i=sendNgPacket(nga, CODE_READ_REQ, &nga->current->mac, ++nga->seq, attr);
+ destroyList(attr, (void(*)(void*))freeAttr);
+ if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL, &nga->current->mac, nga->seq))==NULL ) {
+ ret=ERR_NET;
+ goto end;
+ }
+
+ for (ln=attr->first; ln!=NULL; ln=ln->next) {
+ at=ln->data;
+ if ( at->attr==ATTR_PORT_STATISTICS && at->size>=49 && (port=(int)(*(char*)at->data)-1)>=0 && port<nga->current->ports ) {
+ ps[port].recv=be64toh(*(unsigned long long*)(at->data+1+8*0));
+ ps[port].sent=be64toh(*(unsigned long long*)(at->data+1+8*1));
+ ps[port].crc=be64toh(*(unsigned long long*)(at->data+1+8*5));
+ // all offsets between 2 and 4 inclusive are unknown values
+ }
+ }
+
+ destroyList(attr, (void(*)(void*))freeAttr);
+
+
+ end:
+
+ return ret;
+
+
+}
+
+
+
+// ---------------------------------------------------
+int ngadmin_resetPortsStatistics (struct ngadmin *nga) {
+
+ List *attr;
+ int ret=ERR_OK, i;
+ char err;
+ unsigned short attr_error;
+
+
+ if ( nga==NULL ) {
+ return ERR_INVARG;
+ } else if ( nga->current==NULL ) {
+ return ERR_NOTLOG;
+ }
+
+
+ attr=createEmptyList();
+ pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
+ pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
+ pushBackList(attr, newEmptyAttr(ATTR_END));
+ i=sendNgPacket(nga, CODE_WRITE_REQ, &nga->current->mac, ++nga->seq, attr);
+ destroyList(attr, (void(*)(void*))freeAttr);
+ if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, &nga->current->mac, nga->seq))==NULL ) {
+ ret=ERR_NET;
+ goto end;
+ }
+
+ destroyList(attr, (void(*)(void*))freeAttr);
+
+ if ( err==7 && attr_error==ATTR_PASSWORD ) {
+ ret=ERR_BADPASS;
+ goto end;
+ }
+
+
+
+ end:
+
+ return ret;
+
+}
+
+
+
+// ---------------------------------------------------------------
+int ngadmin_changePassword (struct ngadmin *nga, const char* pass) {
+
+ List *attr;
+ int ret=ERR_OK, i;
+ char err;
+ unsigned short attr_error;
+
+
+ if ( nga==NULL || pass==NULL ) {
+ return ERR_INVARG;
+ } else if ( nga->current==NULL ) {
+ return ERR_NOTLOG;
+ }
+
+
+ attr=createEmptyList();
+ pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
+ pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
+ pushBackList(attr, newEmptyAttr(ATTR_END));
+ i=sendNgPacket(nga, CODE_WRITE_REQ, &nga->current->mac, ++nga->seq, attr);
+ destroyList(attr, (void(*)(void*))freeAttr);
+ if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, &nga->current->mac, nga->seq))==NULL ) {
+ ret=ERR_NET;
+ goto end;
+ }
+
+ destroyList(attr, (void(*)(void*))freeAttr);
+
+ if ( err==7 && attr_error==ATTR_PASSWORD ) {
+ ret=ERR_BADPASS;
+ goto end;
+ }
+
+
+ // successful, also update local password
+ strncpy(nga->password, pass, PASSWORD_MAX);
+
+
+ end:
+
+ return ret;
+
+}
+
+
--- /dev/null
+
+#include "protocol.h"
+
+
+
+
+
+const struct ether_addr nullMac={.ether_addr_octet={0, 0, 0, 0, 0, 0}};
+
+
+
+// -------------------
+int min (int a, int b) {
+ return a<b ? a : b ;
+}
+
+
+
+// -----------------------------------------------------------------------------------------------------------------------------------------------
+void initNgHeader (struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum) {
+
+
+ memset(nh, 0, sizeof(struct ng_header));
+ nh->unk1=1;
+ nh->code=code;
+
+ memcpy(nh->client_mac, client_mac, ETH_ALEN);
+
+ if ( switch_mac!=NULL ) {
+ memcpy(nh->switch_mac, switch_mac, ETH_ALEN);
+ }
+
+ nh->seqnum=htonl(seqnum);
+ strcpy(nh->proto_id, "NSDP");
+
+
+}
+
+
+
+// ---------------------------------------------------------------------------------------------------------------------------------------------------------
+bool validateNgHeader (const struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum) {
+
+
+ if ( nh->unk1!=1 ) {
+ return false;
+ }
+
+ if ( code>0 && nh->code!=code ) {
+ return false;
+ }
+
+ if ( nh->unk2!=0 ) {
+ return false;
+ }
+
+ if ( *(unsigned short*)nh->unk3!=0 ) {
+ return false;
+ }
+
+ if ( client_mac!=NULL && memcmp(nh->client_mac, client_mac, ETH_ALEN)!=0 ) {
+ return false;
+ }
+
+ if ( switch_mac!=NULL && memcmp(nh->switch_mac, switch_mac, ETH_ALEN)!=0 ) {
+ return false;
+ }
+
+ if ( seqnum>0 && ntohl(nh->seqnum)!=seqnum ) {
+ return false;
+ }
+
+ if ( *(unsigned int*)nh->unk4!=0 ) {
+ return false;
+ }
+
+
+ return true;
+
+}
+
+
+
+// -------------------------------------
+void initNgPacket (struct ng_packet *np) {
+
+ np->ah=(struct attr_header*)np->nh->data;
+
+}
+
+
+
+// --------------------------------------------------------------------------------------------
+void addPacketAttr (struct ng_packet *np, unsigned short attr, unsigned short size, void* data) {
+
+ struct attr_header *ah=np->ah;
+
+
+ if ( (int)(getPacketTotalSize(np)+sizeof(struct attr_header)+size)>(np->maxlen) ) {
+ return;
+ }
+
+ ah->attr=htons(attr);
+ ah->size=htons(size);
+
+ if ( size>0 && data!=NULL ) {
+ memcpy(ah->data, data, size);
+ }
+
+ np->ah=(struct attr_header*)(ah->data+size);
+
+}
+
+
+
+// ----------------------------------------------------------------
+void addPacketEmptyAttr (struct ng_packet *np, unsigned short attr) {
+ addPacketAttr(np, attr, 0, NULL);
+}
+
+
+
+// -------------------------------------------------------------------------
+void addPacketByteAttr (struct ng_packet *np, unsigned short attr, char val) {
+ addPacketAttr(np, attr, 1, &val);
+}
+
+
+
+// ---------------------------------------------------------------------------
+void addPacketShortAttr (struct ng_packet *np, unsigned short attr, short val) {
+
+ short s=htons(val);
+
+
+ addPacketAttr(np, attr, 2, &s);
+
+}
+
+
+
+// ------------------------------------------------
+int getPacketTotalSize (const struct ng_packet *np) {
+ return ((char*)np->ah)-np->buffer;
+}
+
+
+
+// --------------------------------------------
+struct attr* newEmptyAttr (unsigned short attr) {
+ return newAttr(attr, 0, NULL);
+}
+
+
+
+// ------------------------------------------------------------------------
+struct attr* newAttr (unsigned short attr, unsigned short size, void *data) {
+
+ struct attr *at;
+
+
+ at=malloc(sizeof(struct attr));
+ at->attr=attr;
+ at->size=size;
+ at->data=data;
+
+
+ return at;
+
+}
+
+
+
+// ----------------------------------------------------------------
+struct attr* newByteAttr (unsigned short attr, unsigned char value) {
+
+ char *v=malloc(sizeof(char));
+
+ *v=value;
+
+ return newAttr(attr, 1, v);
+
+}
+
+
+
+// ----------------------------
+void freeAttr (struct attr *at) {
+
+ if ( at!=NULL ) {
+ free(at->data);
+ free(at);
+ }
+
+}
+
+
+
+// ------------------------------------------------------------------------------------------
+List* extractPacketAttributes (struct ng_packet *np, char *error, unsigned short *attr_error) {
+
+ List *l;
+ struct attr *at;
+
+
+ if ( error!=NULL ) {
+ *error=np->nh->error;
+ }
+
+ if ( attr_error!=NULL ) {
+ *attr_error=ntohs(np->nh->attr);
+ }
+
+ l=createEmptyList();
+
+ while ( getPacketTotalSize(np)<np->maxlen ) {
+
+ at=malloc(sizeof(struct attr));
+ at->attr=ntohs(np->ah->attr);
+ at->size=ntohs(np->ah->size);
+
+ if ( getPacketTotalSize(np)+at->size>np->maxlen ) {
+ free(at);
+ break;
+ }
+
+ if ( at->size==0 ) {
+ at->data=NULL;
+ } else {
+ at->data=malloc(at->size*sizeof(char));
+ memcpy(at->data, np->ah->data, at->size);
+ }
+
+ pushBackList(l, at);
+
+ if ( at->attr==ATTR_END ) {
+ break;
+ }
+
+ np->ah=(struct attr_header*)(np->ah->data+at->size);
+
+ }
+
+
+ return l;
+
+}
+
+
+
+// --------------------------------------------------------------
+void extractSwitchAttributes (struct swi_attr *sa, const List *l) {
+
+ const ListNode *ln;
+ const struct attr *at;
+ int len;
+
+
+ memset(sa, 0, sizeof(struct swi_attr));
+
+ // FIXME: mutex lock ?
+
+ for (ln=l->first; ln!=NULL; ln=ln->next) {
+ at=ln->data;
+
+ switch ( at->attr ) {
+
+ case ATTR_PRODUCT:
+ len=min(at->size, PRODUCT_SIZE);
+ memcpy(sa->product, at->data, len);
+ //trim(sa->product, len); // FIXME
+ break;
+
+ case ATTR_NAME:
+ len=min(at->size, NAME_SIZE);
+ memcpy(sa->name, at->data, len);
+ //trim(sa->name, len); // FIXME
+ break;
+
+ case ATTR_MAC:
+ memcpy(&sa->mac, at->data, ETH_ALEN);
+ break;
+
+ case ATTR_IP:
+ sa->nc.ip=*(struct in_addr*)at->data;
+ break;
+
+ case ATTR_NETMASK:
+ sa->nc.netmask=*(struct in_addr*)at->data;
+ break;
+
+ case ATTR_GATEWAY:
+ sa->nc.gw=*(struct in_addr*)at->data;
+ break;
+
+ case ATTR_DHCP:
+ sa->nc.dhcp=( ntohs(*(unsigned short*)at->data)==1 );
+ break;
+
+ case ATTR_FIRM_VER:
+ len=min(at->size, FIRMWARE_SIZE-1);
+ memcpy(sa->firmware, at->data, len);
+ sa->firmware[len]=0;
+ break;
+
+ case ATTR_PORTS_COUNT:
+ sa->ports=*(unsigned char*)at->data;
+ break;
+
+ case ATTR_END:
+ return;
+
+ }
+
+ }
+
+
+}
+
+
+
--- /dev/null
+
+#ifndef DEF_PROTOCOL
+#define DEF_PROTOCOL
+
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/ether.h>
+
+#include <ngadmin.h>
+#include "list.h"
+#include "lib.h"
+
+
+
+
+
+struct ng_header {
+ char unk1; // always 1
+ char code;
+ char error;
+ char unk2; // always 0
+ unsigned short attr; // attribute code which caused error
+ char unk3[2]; // always 0
+ char client_mac[6];
+ char switch_mac[6];
+ unsigned int seqnum;
+ char proto_id[4]; // always "NSDP"
+ char unk4[4]; // always 0
+ char data[0];
+} __attribute__((packed)) ;
+
+struct attr_header {
+ unsigned short attr;
+ unsigned short size;
+ char data[0];
+} __attribute__((packed)) ;
+
+
+struct ng_packet {
+ union {
+ char *buffer;
+ struct ng_header *nh;
+ };
+ int maxlen;
+ struct attr_header *ah;
+};
+
+
+struct attr {
+ unsigned short attr;
+ unsigned short size;
+ void *data;
+};
+
+
+
+extern const unsigned short helloRequest[];
+
+extern const struct ether_addr nullMac;
+
+
+
+//
+int min (int a, int b);
+
+//
+void initNgHeader (struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum);
+
+//
+bool validateNgHeader (const struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum);
+
+//
+void initNgPacket (struct ng_packet *np);
+
+//
+void addPacketAttr (struct ng_packet *np, unsigned short attr, unsigned short size, void* data);
+
+//
+void addPacketEmptyAttr (struct ng_packet *np, unsigned short attr);
+
+//
+void addPacketByteAttr (struct ng_packet *np, unsigned short attr, char val);
+
+//
+void addPacketShortAttr (struct ng_packet *np, unsigned short attr, short val);
+
+//
+int getPacketTotalSize (const struct ng_packet *np);
+
+//
+struct attr* newEmptyAttr (unsigned short attr);
+
+//
+struct attr* newAttr (unsigned short attr, unsigned short size, void *data);
+
+//
+struct attr* newByteAttr (unsigned short attr, unsigned char value);
+
+//
+void freeAttr (struct attr *at);
+
+//
+List* extractPacketAttributes (struct ng_packet *np, char *error, unsigned short *attr_error);
+
+//
+void extractSwitchAttributes (struct swi_attr *sa, const List *l);
+
+
+
+
+#endif
+
+++ /dev/null
-
-#include "list.h"
-
-
-
-
-// -------------------------
-List* createEmptyList (void) {
-
- List *l;
-
-
- l=malloc(sizeof(List));
- l->first=NULL;
- l->last=NULL;
- l->count=0;
- pthread_cond_init(&l->cond, NULL);
- pthread_mutex_init(&l->mutex, NULL);
-
-
- return l;
-
-}
-
-
-
-// ------------------------------------------------
-void destroyList (List *l, void (*freefunc)(void*)) {
-
- ListNode *pr, *ln;
-
-
-
- if ( l==NULL ) {
- return;
- }
-
-
- pthread_mutex_destroy(&l->mutex);
- pthread_cond_destroy(&l->cond);
-
- for (ln=l->first; ln!=NULL; ) {
-
- pr=ln;
-
- if ( freefunc!=NULL ) {
- freefunc(pr->data);
- }
-
- ln=pr->next;
- free(pr);
-
- }
-
-
- free(l);
-
-}
-
-
-
-// -------------------------------------
-void pushFrontList (List *l, void* data) {
-
- ListNode *ln;
-
-
- if ( l==NULL ) {
- return;
- }
-
-
- pthread_mutex_lock(&l->mutex);
-
- ln=malloc(sizeof(ListNode));
- ln->data=data;
- ln->prev=NULL;
- ln->next=l->first;
-
- if ( l->first==NULL ) {
- l->last=ln;
- } else {
- l->first->prev=ln;
- }
-
- l->first=ln;
- l->count++;
-
- pthread_mutex_unlock(&l->mutex);
- pthread_cond_broadcast(&l->cond);
-
-}
-
-
-
-// ------------------------------------
-void pushBackList (List *l, void* data) {
-
- ListNode *ln;
-
-
- if ( l==NULL ) {
- return;
- }
-
-
- pthread_mutex_lock(&l->mutex);
-
- ln=malloc(sizeof(ListNode));
- ln->data=data;
- ln->prev=l->last;
- ln->next=NULL;
-
- if ( l->last==NULL ) {
- l->first=ln;
- } else {
- l->last->next=ln;
- }
-
- l->last=ln;
- l->count++;
-
- pthread_mutex_unlock(&l->mutex);
- pthread_cond_broadcast(&l->cond);
-
-}
-
-
-
-// -------------------------
-void* popFrontList (List *l) {
-
- ListNode *ln;
- void* data;
-
-
- if ( l==NULL ) {
- return NULL;
- }
-
-
- pthread_mutex_lock(&l->mutex);
-
- if ( (ln=l->first)==NULL ) {
- pthread_mutex_unlock(&l->mutex);
- return NULL;
- }
-
- data=ln->data;
- l->first=ln->next;
-
- if ( ln->next==NULL ) {
- l->last=NULL;
- } else {
- ln->next->prev=NULL;
- }
-
- l->count--;
- free(ln);
-
- pthread_mutex_unlock(&l->mutex);
- pthread_cond_broadcast(&l->cond);
-
-
- return data;
-
-}
-
-
-
-// ------------------------
-void* popBackList (List *l) {
-
- ListNode *ln;
- void* data;
-
-
-
- if ( l==NULL ) {
- return NULL;
- }
-
-
- pthread_mutex_lock(&l->mutex);
-
- if ( (ln=l->last)==NULL ) {
- pthread_mutex_unlock(&l->mutex);
- return NULL;
- }
-
- data=ln->data;
- l->last=ln->prev;
-
- if ( ln->prev==NULL ) {
- l->first=NULL;
- } else {
- ln->prev->next=NULL;
- }
-
- l->count--;
- free(ln);
-
- pthread_mutex_unlock(&l->mutex);
- pthread_cond_broadcast(&l->cond);
-
-
-
- return data;
-
-}
-
-
-
-// ----------------------------------------------
-void clearList (List *l, void (*freefunc)(void*)) {
-
- ListNode *ln, *pr;
-
-
- if ( l==NULL ) {
- return;
- }
-
-
- pthread_mutex_lock(&l->mutex);
-
- for (ln=l->first; ln!=NULL; ) {
-
- pr=ln;
-
- if ( freefunc!=NULL ) {
- freefunc(pr->data);
- }
-
- ln=pr->next;
- free(pr);
-
- }
-
- l->first=NULL;
- l->last=NULL;
- l->count=0;
-
- pthread_mutex_unlock(&l->mutex);
- pthread_cond_broadcast(&l->cond);
-
-
-}
-
-
-
-// ---------------------------------------------------------------
-bool findAndDestroy (List *l, void* data, void (*freefunc)(void*)) {
-
- ListNode *ln;
-
-
-
- if ( l==NULL ) {
- return false;
- }
-
-
- pthread_mutex_lock(&l->mutex);
-
- for (ln=l->first; ln!=NULL && ln->data!=data; ln=ln->next);
-
- if ( ln==NULL ) {
-
- pthread_mutex_unlock(&l->mutex);
-
- } else {
-
- if ( ln->prev==NULL ) {
- l->first=ln->next;
- } else {
- ln->prev->next=ln->next;
- }
-
- if ( ln->next==NULL ) {
- l->last=ln->prev;
- } else {
- ln->next->prev=ln->prev;
- }
-
-
- if ( freefunc!=NULL ) {
- freefunc(data);
- }
-
- l->count--;
-
- pthread_mutex_unlock(&l->mutex);
- pthread_cond_broadcast(&l->cond);
-
- }
-
-
-
- return true;
-
-}
-
-
-
-// -------------------------------------------------
-void browseList (List *l, void (*browsefunc)(void*)) {
-
- ListNode *ln;
-
-
-
- if ( l==NULL || browsefunc==NULL ) {
- return;
- }
-
-
- pthread_mutex_lock(&l->mutex);
-
- for (ln=l->first; ln!=NULL; ln=ln->next) {
- browsefunc(ln->data);
- }
-
- pthread_mutex_unlock(&l->mutex);
-
-
-}
-
-
-
-
-
+++ /dev/null
-
-#ifndef DEF_LIST
-#define DEF_LIST
-
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <pthread.h>
-
-
-
-
-typedef struct ListNode ListNode;
-
-struct ListNode {
- void* data;
- ListNode *prev, *next;
-};
-
-
-typedef struct {
- ListNode *first, *last;
- unsigned int count;
- pthread_cond_t cond;
- pthread_mutex_t mutex;
-} List;
-
-
-
-
-// Creates an empty list
-List* createEmptyList (void);
-
-// Destroys a list, and eventually frees the elements
-// NOT MT SAFE
-void destroyList (List *l, void (*freefunc)(void*));
-
-// Adds an element at front of the list
-void pushFrontList (List *l, void* data);
-
-// Adds an element at back of the list
-void pushBackList (List *l, void* data);
-
-// Pops an element from the front of the list and returns its value
-void* popFrontList (List *l);
-
-// Pops an element from the back of the list and returns its value
-void* popBackList (List *l);
-
-// Clears all the items of the list, and eventually frees them
-void clearList (List *l, void (*freefunc)(void*));
-
-// Find and destroy a particular element of the list, and eventually frees it
-bool findAndDestroy (List *l, void* data, void (*freefunc)(void*));
-
-// Browse all the items of the list through the callback function
-void browseList (List *l, void (*browsefunc)(void*));
-
-
-
-
-#endif
-
+++ /dev/null
-
-CFLAGS=-W -Wall -Wextra -Os -fomit-frame-pointer -fno-strict-aliasing -pthread
-LDFLAGS=-s -pthread
-CC=gcc
-
-
-
-all: admin emu
-
-
-
-admin: admin.o protocol.o list.o command.o network.o controller.o
- $(CC) $^ -o $@ $(LDFLAGS)
-
-
-emu: emu.o protocol.o list.o command.o
- $(CC) $^ -o $@ $(LDFLAGS)
-
-
-%.o: %.c %.h
- $(CC) -c $< -o $@ $(CFLAGS)
-
-
-%.o: %.c
- $(CC) -c $^ -o $@ $(CFLAGS)
-
-
-.PHONY: clean mrproper
-
-
-
-clean:
- @rm -f *.o
-
-
-mrproper: clean
- @rm -f admin emu
-
-
-
+++ /dev/null
-
-#include "network.h"
-
-
-
-
-static struct timeval tv;
-static struct ether_addr localmac;
-
-static char buffer[1024];
-static int sock;
-static struct sockaddr_in local, remote;
-static socklen_t slen=sizeof(struct sockaddr_in);
-
-
-
-
-int startNetwork (const char *iface) {
-
- struct ifreq ifr;
- int ret;
-
-
-
-
- memset(&local, 0, sizeof(struct sockaddr_in));
- local.sin_family=AF_INET;
- remote=local;
- local.sin_port=htons(CLIENT_PORT);
-
- memset(&ifr, 0, sizeof(struct ifreq));
- strncpy(ifr.ifr_name, iface, IFNAMSIZ-1);
-
- if ( (sock=socket(AF_INET, SOCK_DGRAM, 0))<0 ) {
- perror("socket");
- return sock;
- } else if ( (ret=ioctl(sock, SIOCGIFADDR, &ifr))<0 ) {
- perror("ioctl(SIOCGIFADDR)");
- close(sock);
- return ret;
- }
- //local.sin_addr=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; // FIXME
-
- if ( (ret=ioctl(sock, SIOCGIFHWADDR, &ifr))<0 ) {
- perror("ioctl(SIOCGIFHWADDR)");
- close(sock);
- return ret;
- }
- memcpy(&localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
-
- if ( (ret=bind(sock, (struct sockaddr*)&local, sizeof(struct sockaddr_in)))<0 ) {
- perror("bind");
- close(sock);
- return ret;
- }
-
-
- ret=1;
- if ( (ret=setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) {
- perror("setsockopt(SO_BROADCAST)");
- return ret;
- }
-
- /*
- i=0;
- if ( setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &i, sizeof(i)) ) {
- perror("setsockopt(IP_MULTICAST_LOOP)");
- goto end;
- }
- */
-
-
- return setTimeout(1.);
-
-}
-
-
-int stopNetwork (void) {
-
- return close(sock);
-
-}
-
-
-
-
-int setTimeout (double sec) {
-
- int ret;
-
-
- tv.tv_sec=(int)sec;
- tv.tv_usec=(int)((sec-(double)tv.tv_sec)*1e6);
- if ( (ret=setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))<0 ) {
- perror("setsockopt(SO_RCVTIMEO)");
- return ret;
- }
-
-
- return 0;
-
-}
-
-
-int getTimeout (double *sec) {
-
-
- *sec=((double)tv.tv_sec)+1e-6*((double)tv.tv_usec);
-
-
- return 0;
-
-}
-
-
-
-
-int sendNgPacket (char code, const struct ether_addr *switch_mac, unsigned int seqnum, const List *attr) {
-
- struct ng_packet np;
- ListNode *ln;
- struct attr *at;
- int ret;
-
-
-
- np.buffer=buffer;
- np.maxlen=sizeof(buffer);
- initNgPacket(&np);
- initNgHeader(np.nh, code, &localmac, switch_mac, seqnum);
-
- if ( attr!=NULL ) {
- for (ln=attr->first; ln!=NULL; ln=ln->next) {
- at=ln->data;
- addPacketAttr(&np, at->attr, at->size, at->data);
- }
- }
-
-
- remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
- remote.sin_port=htons(SWITCH_PORT);
- if ( (ret=sendto(sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) {
- perror("sendto");
- }
-
-
- return ret;
-
-}
-
-
-List* recvNgPacket (char code, const struct ether_addr *switch_mac, unsigned int seqnum) {
-
- struct ng_packet np;
- List *l=NULL;
- int len;
-
-
- np.buffer=buffer;
- np.maxlen=sizeof(buffer);
-
- while ( (len=recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&remote, &slen))>=0 ) {
- if ( len>=(int)sizeof(struct ng_header) && validateNgHeader(np.nh, code, &localmac, switch_mac, seqnum) ) {
- initNgPacket(&np);
- l=extractPacketAttributes(&np);
- break;
- }
- }
-
-
- return l;
-
-}
-
-
+++ /dev/null
-
-#ifndef DEF_NETWORK
-#define DEF_NETWORK
-
-
-#include <string.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netinet/ether.h>
-#include <sys/ioctl.h>
-
-#include "list.h"
-#include "protocol.h"
-
-
-
-int startNetwork (const char *iface);
-
-int stopNetwork (void);
-
-
-
-int setTimeout (double sec);
-
-int getTimeout (double *sec);
-
-
-
-int sendNgPacket (char code, const struct ether_addr *switch_mac, unsigned int seqnum, const List *attr);
-
-List* recvNgPacket (char code, const struct ether_addr *switch_mac, unsigned int seqnum);
-
-
-
-#endif
-
+++ /dev/null
-
-#include "protocol.h"
-
-
-
-const unsigned short helloRequest[]={
- ATTR_PRODUCT,
- ATTR_UNK2,
- ATTR_NAME,
- ATTR_MAC,
- ATTR_UNK5,
- ATTR_IP,
- ATTR_NETMASK,
- ATTR_GATEWAY,
- ATTR_DHCP,
- ATTR_UNK12,
- ATTR_FIRM_VER,
- ATTR_UNK14,
- ATTR_UNK15,
- ATTR_END
-};
-
-
-const struct ether_addr nullMac={.ether_addr_octet={0, 0, 0, 0, 0, 0}};
-
-
-
-// -------------------
-int min (int a, int b) {
- return a<b ? a : b ;
-}
-
-
-
-// -----------------------------------------------------------------------------------------------------------------------------------------------
-void initNgHeader (struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum) {
-
-
- memset(nh, 0, sizeof(struct ng_header));
- nh->unk1=1;
- nh->code=code;
-
- memcpy(nh->client_mac, client_mac, ETH_ALEN);
-
- if ( switch_mac!=NULL ) {
- memcpy(nh->switch_mac, switch_mac, ETH_ALEN);
- }
-
- nh->seqnum=htonl(seqnum);
- strcpy(nh->proto_id, "NSDP");
-
-
-}
-
-
-
-// ----------------------------------------------------------------------------------------------------------------------------------------------
-bool validateNgHeader (const struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum) {
-
- int i;
-
-
- if ( nh->unk1!=1 ) {
- //printf("unk1 not 1\n");
- return false;
- }
-
- if ( code>0 && nh->code!=code ) {
- return false;
- }
-
- for (i=0; i<6; i++) {
- if ( nh->unk2[i]!=0 ) {
- //printf("unk2[%i] not 0\n", i);
- return false;
- }
- }
-
- if ( client_mac!=NULL && memcmp(nh->client_mac, client_mac, ETH_ALEN)!=0 ) {
- //printf("client_mac err\n");
- return false;
- }
-
- if ( switch_mac!=NULL && memcmp(nh->switch_mac, switch_mac, ETH_ALEN)!=0 ) {
- //printf("switch_mac err\n");
- return false;
- }
-
- if ( seqnum>0 && ntohl(nh->seqnum)!=seqnum ) {
- //printf("incorrect seqnum\n");
- return false;
- }
-
- if ( *(unsigned int*)nh->unk3!=0 ) {
- //printf("unk3 not 0\n");
- return false;
- }
-
-
- return true;
-
-}
-
-
-
-// -------------------------------------
-void initNgPacket (struct ng_packet *np) {
-
- np->ah=(struct attr_header*)np->nh->data;
-
-}
-
-
-
-// --------------------------------------------------------------------------------------------
-void addPacketAttr (struct ng_packet *np, unsigned short attr, unsigned short size, void* data) {
-
- struct attr_header *ah=np->ah;
-
-
- if ( (int)(getPacketTotalSize(np)+sizeof(struct attr_header)+size)>(np->maxlen) ) {
- return;
- }
-
- ah->attr=htons(attr);
- ah->size=htons(size);
-
- if ( size>0 && data!=NULL ) {
- memcpy(ah->data, data, size);
- }
-
- np->ah=(struct attr_header*)(ah->data+size);
-
-}
-
-
-
-// ----------------------------------------------------------------
-void addPacketEmptyAttr (struct ng_packet *np, unsigned short attr) {
- addPacketAttr(np, attr, 0, NULL);
-}
-
-
-
-// -------------------------------------------------------------------------
-void addPacketByteAttr (struct ng_packet *np, unsigned short attr, char val) {
- addPacketAttr(np, attr, 1, &val);
-}
-
-
-
-// ---------------------------------------------------------------------------
-void addPacketShortAttr (struct ng_packet *np, unsigned short attr, short val) {
-
- short s=htons(val);
-
-
- addPacketAttr(np, attr, 2, &s);
-
-}
-
-
-
-// ------------------------------------------------
-int getPacketTotalSize (const struct ng_packet *np) {
- return ((char*)np->ah)-np->buffer;
-}
-
-
-// --------------------------------------------
-struct attr* newEmptyAttr (unsigned short attr) {
-
- struct attr *at;
-
-
- at=malloc(sizeof(struct attr));
- at->attr=attr;
- at->size=0;
- at->data=NULL;
-
-
- return at;
-
-}
-
-
-// ----------------------------
-void freeAttr (struct attr *at) {
-
- if ( at!=NULL ) {
- free(at->data);
- free(at);
- }
-
-}
-
-
-
-// -------------------------------------------------
-List* extractPacketAttributes (struct ng_packet *np) {
-
- List *l;
- struct attr *at;
-
-
- l=createEmptyList();
-
- while ( getPacketTotalSize(np)<np->maxlen ) {
-
- at=malloc(sizeof(struct attr));
- at->attr=ntohs(np->ah->attr);
- at->size=ntohs(np->ah->size);
-
- if ( getPacketTotalSize(np)+at->size>np->maxlen ) {
- free(at);
- break;
- }
-
- if ( at->size==0 ) {
- at->data=NULL;
- } else {
- at->data=malloc(at->size*sizeof(char));
- memcpy(at->data, np->ah->data, at->size);
- }
-
- pushBackList(l, at);
-
- if ( at->attr==ATTR_END ) {
- break;
- }
-
- np->ah=(struct attr_header*)(np->ah->data+at->size);
-
- }
-
-
- return l;
-
-}
-
-
+++ /dev/null
-
-#ifndef DEF_PROTOCOL
-#define DEF_PROTOCOL
-
-
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <netinet/ether.h>
-
-#include "list.h"
-#include "command.h"
-
-
-
-
-#define CLIENT_PORT 63321
-#define SWITCH_PORT 63322
-
-#define CODE_READ_REQ 1
-#define CODE_READ_REP 2
-#define CODE_WRITE_REQ 3
-#define CODE_WRITE_REP 4
-
-#define ATTR_PRODUCT 0x0001
-#define ATTR_UNK2 0x0002
-#define ATTR_NAME 0x0003
-#define ATTR_MAC 0x0004
-#define ATTR_UNK5 0x0005
-#define ATTR_IP 0x0006
-#define ATTR_NETMASK 0x0007
-#define ATTR_GATEWAY 0x0008
-#define ATTR_NEW_PASSWORD 0x0009
-#define ATTR_PASSWORD 0x000A
-#define ATTR_DHCP 0x000B
-#define ATTR_UNK12 0x000C
-#define ATTR_FIRM_VER 0x000D
-#define ATTR_UNK14 0x000E
-#define ATTR_UNK15 0x000F
-#define ATTR_RESTART 0x0013
-#define ATTR_DEFAULTS 0x0400
-#define ATTR_PORT_STATUS 0x0C00
-#define ATTR_VLAN_TYPE 0x2000
-#define ATTR_VLAN_CONFIG 0x2400
-#define ATTR_QOS_TYPE 0x3400
-#define ATTR_QOS_CONFIG 0x3800
-#define ATTR_MIRROR 0x5C00
-#define ATTR_PORTS_NUMBER 0x6000
-#define ATTR_END 0xFFFF
-
-#define SPEED_DOWN 0
-#define SPEED_10 1
-#define SPEED_100 4
-#define SPEED_1000 5
-
-#define VLAN_PORT_BASIC 1
-#define VLAN_PORT_ADV 2
-#define VLAN_DOT_BASIC 3
-#define VLAN_DOT_ADV 4
-
-#define QOS_PORT 1
-#define QOS_DOT 2
-
-#define PRIO_HIGH 1
-#define PRIO_MED 2
-#define PRIO_NORM 3
-#define PRIO_LOW 4
-
-
-
-struct ng_header {
- char unk1; // always 1
- char code;
- char unk2[6]; // always 0
- char client_mac[6];
- char switch_mac[6];
- unsigned int seqnum;
- char proto_id[4]; // always "NSDP"
- char unk3[4]; // always 0
- char data[0];
-} __attribute__((packed)) ;
-
-struct attr_header {
- unsigned short attr;
- unsigned short size;
- char data[0];
-} __attribute__((packed)) ;
-
-
-struct ng_packet {
- union {
- char *buffer;
- struct ng_header *nh;
- };
- int maxlen;
- struct attr_header *ah;
-};
-
-
-struct attr {
- unsigned short attr;
- unsigned short size;
- void *data;
-};
-
-
-
-extern const unsigned short helloRequest[];
-
-extern const struct ether_addr nullMac;
-
-
-
-//
-int min (int a, int b);
-
-//
-void initNgHeader (struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum);
-
-//
-bool validateNgHeader (const struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum);
-
-//
-void initNgPacket (struct ng_packet *np);
-
-//
-void addPacketAttr (struct ng_packet *np, unsigned short attr, unsigned short size, void* data);
-
-//
-void addPacketEmptyAttr (struct ng_packet *np, unsigned short attr);
-
-//
-void addPacketByteAttr (struct ng_packet *np, unsigned short attr, char val);
-
-//
-void addPacketShortAttr (struct ng_packet *np, unsigned short attr, short val);
-
-//
-int getPacketTotalSize (const struct ng_packet *np);
-
-//
-struct attr* newEmptyAttr (unsigned short attr);
-
-//
-void freeAttr (struct attr *at);
-
-//
-List* extractPacketAttributes (struct ng_packet *np);
-
-
-
-
-
-#endif
-