Added basic client and switch emulator.
--- /dev/null
+*.o
+*~
+admin
+emu
--- /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
+
+#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
+
+#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
+