]> git.sur5r.net Git - ngadmin/commitdiff
Initial commit.
authordarkcoven <admin@darkcoven.tk>
Sat, 5 Nov 2011 11:00:00 +0000 (12:00 +0100)
committerdarkcoven <admin@darkcoven.tk>
Sat, 29 Dec 2012 20:27:37 +0000 (21:27 +0100)
Added basic client and switch emulator.

15 files changed:
.gitignore [new file with mode: 0644]
admin.c [new file with mode: 0644]
command.c [new file with mode: 0644]
command.h [new file with mode: 0644]
commandes [new file with mode: 0644]
controller.c [new file with mode: 0644]
controller.h [new file with mode: 0644]
emu.c [new file with mode: 0644]
list.c [new file with mode: 0644]
list.h [new file with mode: 0644]
makefile [new file with mode: 0644]
network.c [new file with mode: 0644]
network.h [new file with mode: 0644]
protocol.c [new file with mode: 0644]
protocol.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..2c02531
--- /dev/null
@@ -0,0 +1,4 @@
+*.o
+*~
+admin
+emu
diff --git a/admin.c b/admin.c
new file mode 100644 (file)
index 0000000..01e7765
--- /dev/null
+++ b/admin.c
@@ -0,0 +1,404 @@
+
+#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, &current->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, &current->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, &current->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, &current->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, &current->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;
+}
+
diff --git a/command.c b/command.c
new file mode 100644 (file)
index 0000000..943d148
--- /dev/null
+++ b/command.c
@@ -0,0 +1,56 @@
+
+#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;
+}
+
+
diff --git a/command.h b/command.h
new file mode 100644 (file)
index 0000000..0689b22
--- /dev/null
+++ b/command.h
@@ -0,0 +1,20 @@
+
+#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
+
diff --git a/commandes b/commandes
new file mode 100644 (file)
index 0000000..7ecd1e4
--- /dev/null
+++ b/commandes
@@ -0,0 +1,52 @@
+
+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
+
diff --git a/controller.c b/controller.c
new file mode 100644 (file)
index 0000000..14b596f
--- /dev/null
@@ -0,0 +1,246 @@
+
+#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);
+
+
+
diff --git a/controller.h b/controller.h
new file mode 100644 (file)
index 0000000..877901c
--- /dev/null
@@ -0,0 +1,112 @@
+
+#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
+
diff --git a/emu.c b/emu.c
new file mode 100644 (file)
index 0000000..d968ded
--- /dev/null
+++ b/emu.c
@@ -0,0 +1,299 @@
+
+#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);
+}
+
diff --git a/list.c b/list.c
new file mode 100644 (file)
index 0000000..491889e
--- /dev/null
+++ b/list.c
@@ -0,0 +1,332 @@
+
+#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);
+}
+
+
+
+
+
diff --git a/list.h b/list.h
new file mode 100644 (file)
index 0000000..1088584
--- /dev/null
+++ b/list.h
@@ -0,0 +1,63 @@
+
+#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
+
diff --git a/makefile b/makefile
new file mode 100644 (file)
index 0000000..54740e1
--- /dev/null
+++ b/makefile
@@ -0,0 +1,40 @@
+
+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
+
+
+
diff --git a/network.c b/network.c
new file mode 100644 (file)
index 0000000..431bfb1
--- /dev/null
+++ b/network.c
@@ -0,0 +1,175 @@
+
+#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;
+}
+
+
diff --git a/network.h b/network.h
new file mode 100644 (file)
index 0000000..9ba9f07
--- /dev/null
+++ b/network.h
@@ -0,0 +1,37 @@
+
+#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
+
diff --git a/protocol.c b/protocol.c
new file mode 100644 (file)
index 0000000..3afe35d
--- /dev/null
@@ -0,0 +1,241 @@
+
+#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;
+}
+
+
diff --git a/protocol.h b/protocol.h
new file mode 100644 (file)
index 0000000..2ffeec3
--- /dev/null
@@ -0,0 +1,156 @@
+
+#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
+