From bffb5a818811fe4b7ee8d6c42b18281f36f9ebea Mon Sep 17 00:00:00 2001 From: darkcoven Date: Sat, 5 Nov 2011 12:00:00 +0100 Subject: [PATCH 1/1] Initial commit. Added basic client and switch emulator. --- .gitignore | 4 + admin.c | 404 +++++++++++++++++++++++++++++++++++++++++++++++++++ command.c | 56 +++++++ command.h | 20 +++ commandes | 52 +++++++ controller.c | 246 +++++++++++++++++++++++++++++++ controller.h | 112 ++++++++++++++ emu.c | 299 ++++++++++++++++++++++++++++++++++++++ list.c | 332 ++++++++++++++++++++++++++++++++++++++++++ list.h | 63 ++++++++ makefile | 40 +++++ network.c | 175 ++++++++++++++++++++++ network.h | 37 +++++ protocol.c | 241 ++++++++++++++++++++++++++++++ protocol.h | 156 ++++++++++++++++++++ 15 files changed, 2237 insertions(+) create mode 100644 .gitignore create mode 100644 admin.c create mode 100644 command.c create mode 100644 command.h create mode 100644 commandes create mode 100644 controller.c create mode 100644 controller.h create mode 100644 emu.c create mode 100644 list.c create mode 100644 list.h create mode 100644 makefile create mode 100644 network.c create mode 100644 network.h create mode 100644 protocol.c create mode 100644 protocol.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2c02531 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*~ +admin +emu diff --git a/admin.c b/admin.c new file mode 100644 index 0000000..01e7765 --- /dev/null +++ b/admin.c @@ -0,0 +1,404 @@ + +#include +#include +#include +#include +#include + + + +#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 \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=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 index 0000000..0689b22 --- /dev/null +++ b/command.h @@ -0,0 +1,20 @@ + +#ifndef DEF_COMMAND +#define DEF_COMMAND + + +#include +#include + + + +// +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 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 index 0000000..14b596f --- /dev/null +++ b/controller.c @@ -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 +#include +#include + +#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 index 0000000..d968ded --- /dev/null +++ b/emu.c @@ -0,0 +1,299 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 \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; idata[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 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 index 0000000..1088584 --- /dev/null +++ b/list.h @@ -0,0 +1,63 @@ + +#ifndef DEF_LIST +#define DEF_LIST + + +#include +#include +#include + + + + +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 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 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 index 0000000..9ba9f07 --- /dev/null +++ b/network.h @@ -0,0 +1,37 @@ + +#ifndef DEF_NETWORK +#define DEF_NETWORK + + +#include +#include +#include +#include +#include +#include + +#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 index 0000000..3afe35d --- /dev/null +++ b/protocol.c @@ -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 aunk1=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)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 index 0000000..2ffeec3 --- /dev/null +++ b/protocol.h @@ -0,0 +1,156 @@ + +#ifndef DEF_PROTOCOL +#define DEF_PROTOCOL + + +#include +#include +#include +#include +#include + +#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 + -- 2.39.5