From: darkcoven Date: Sat, 5 Nov 2011 11:00:00 +0000 (+0100) Subject: Initial commit. X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=bffb5a818811fe4b7ee8d6c42b18281f36f9ebea;p=ngadmin Initial commit. Added basic client and switch emulator. --- bffb5a818811fe4b7ee8d6c42b18281f36f9ebea 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 +