7 static const struct timeval default_timeout={.tv_sec=4, .tv_usec=0};
11 // ---------------------------------------------
12 struct ngadmin* ngadmin_init (const char *iface) {
17 // allocate main structure
18 nga=malloc(sizeof(struct ngadmin));
19 memset(nga, 0, sizeof(struct ngadmin));
21 strncpy(nga->iface, iface, IFNAMSIZ-1);
23 if ( startNetwork(nga)<0 ) {
28 nga->timeout=default_timeout;
29 if ( updateTimeout(nga)<0 ) {
41 // ------------------------------------
42 int ngadmin_close (struct ngadmin *nga) {
60 // ---------------------------------------------
61 int ngadmin_forceInterface (struct ngadmin *nga) {
69 if ( forceInterface(nga)!=0 ) {
79 // --------------------------------------------------------------
80 int ngadmin_setKeepBroadcasting (struct ngadmin *nga, bool value) {
97 // ------------------------------------------------------------
98 int ngadmin_setPassword (struct ngadmin *nga, const char *pass) {
105 strncpy(nga->password, pass, PASSWORD_MAX);
114 // -------------------------------------------------------------------
115 int ngadmin_setTimeout (struct ngadmin *nga, const struct timeval *tv) {
120 if ( nga==NULL || tv==NULL ) {
126 if ( updateTimeout(nga)<0 ) {
137 // -----------------------------------
138 int ngadmin_scan (struct ngadmin *nga) {
141 List *attr, *swiList;
144 sent by official win client:
160 static const unsigned short hello[]={
184 // create attributes for an "hello" request
185 attr=createEmptyList();
187 pushBackList(attr, newEmptyAttr(hello[i]));
188 if ( hello[i]==ATTR_END ) break;
191 // send request to all potential switches
192 i=sendNgPacket(nga, CODE_READ_REQ, attr);
193 clearList(attr, (void(*)(void*))freeAttr);
199 // try to receive any packets until timeout
200 swiList=createEmptyList();
201 while ( recvNgPacket(nga, CODE_READ_REP, NULL, NULL, attr)>=0 ) {
202 sa=malloc(sizeof(struct swi_attr));
203 extractSwitchAttributes(sa, attr);
204 clearList(attr, (void(*)(void*))freeAttr);
205 pushBackList(swiList, sa);
208 nga->swi_count=swiList->count;
209 nga->swi_tab=convertToArray(swiList, sizeof(struct swi_attr));
218 // -----------------------------------------------------------------------
219 const struct swi_attr* ngadmin_getSwitchTab (struct ngadmin *nga, int *nb) {
222 if ( nga==NULL || nb==NULL ) {
236 // ------------------------------------------------------------------
237 const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga) {
251 // --------------------------------------------
252 int ngadmin_login (struct ngadmin *nga, int id) {
261 } else if ( id<0 || id>=nga->swi_count ) {
266 sa=&nga->swi_tab[id];
269 attr=createEmptyList();
270 pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
271 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
276 destroyList(attr, (void(*)(void*))freeAttr);
285 // -------------------------------------------------------------------
286 int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) {
295 if ( nga==NULL || ports==NULL ) {
297 } else if ( nga->current==NULL ) {
302 attr=createEmptyList();
303 pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
304 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
308 for (ln=attr->first; ln!=NULL; ln=ln->next) {
311 if ( at->attr==ATTR_PORT_STATUS && at->size>=2 && (i=p[0]-1)>=0 && i<nga->current->ports ) {
318 destroyList(attr, (void(*)(void*))freeAttr);
326 // --------------------------------------------------------
327 int ngadmin_setName (struct ngadmin *nga, const char *name) {
335 } else if ( nga->current==NULL ) {
340 attr=createEmptyList();
341 pushBackList(attr, name==NULL ? newEmptyAttr(ATTR_NAME) : newAttr(ATTR_NAME, strlen(name), strdup(name)) );
342 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
347 // successful, also update local name
349 nga->current->name[0]=0;
351 strncpy(nga->current->name, name, NAME_SIZE);
363 // ------------------------------------------------------------------------
364 int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) {
373 if ( nga==NULL || ps==NULL ) {
375 } else if ( nga->current==NULL ) {
380 attr=createEmptyList();
381 pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
382 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
387 for (ln=attr->first; ln!=NULL; ln=ln->next) {
389 if ( at->attr==ATTR_PORT_STATISTICS && at->size>=49 && (port=(int)(*(char*)at->data)-1)>=0 && port<nga->current->ports ) {
390 ps[port].recv=be64toh(*(unsigned long long*)(at->data+1+8*0));
391 ps[port].sent=be64toh(*(unsigned long long*)(at->data+1+8*1));
392 ps[port].crc=be64toh(*(unsigned long long*)(at->data+1+8*5));
393 // all offsets between 2 and 4 inclusive are unknown values
399 destroyList(attr, (void(*)(void*))freeAttr);
407 // ---------------------------------------------------
408 int ngadmin_resetPortsStatistics (struct ngadmin *nga) {
413 attr=createEmptyList();
414 pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
417 return writeRequest(nga, attr);
423 // ---------------------------------------------------------------
424 int ngadmin_changePassword (struct ngadmin *nga, const char* pass) {
430 if ( nga==NULL || pass==NULL ) {
432 } else if ( nga->current==NULL ) {
437 attr=createEmptyList();
438 pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
439 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
444 // successful, also update local password
445 strncpy(nga->password, pass, PASSWORD_MAX);
456 // ----------------------------------------------------------
457 int ngadmin_getStormFilterState (struct ngadmin *nga, int *s) {
465 if ( nga==NULL || s==NULL ) {
467 } else if ( nga->current==NULL ) {
472 attr=createEmptyList();
473 pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
474 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
479 for (ln=attr->first; ln!=NULL; ln=ln->next) {
481 if ( at->attr==ATTR_STORM_ENABLE && at->size>=1 ) {
482 *s= *(char*)at->data!=0 ;
489 destroyList(attr, (void(*)(void*))freeAttr);
497 // ---------------------------------------------------------
498 int ngadmin_setStormFilterState (struct ngadmin *nga, int s) {
503 attr=createEmptyList();
504 pushBackList(attr, newByteAttr(ATTR_STORM_ENABLE, s!=0));
507 return writeRequest(nga, attr);
513 // ---------------------------------------------------------------
514 int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports) {
522 if ( nga==NULL || ports==NULL ) {
524 } else if ( nga->current==NULL ) {
529 attr=createEmptyList();
530 pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
531 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
536 for (ln=attr->first; ln!=NULL; ln=ln->next) {
538 if ( at->attr==ATTR_STORM_BITRATE && at->size>=5 && (i=(int)*(char*)(at->data)-1)>=0 && i<nga->current->ports ) {
539 ports[i]=ntohl(*(int*)(1+(char*)at->data));
545 destroyList(attr, (void(*)(void*))freeAttr);
553 // ---------------------------------------------------------------------
554 int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports) {
561 if ( nga==NULL || ports==NULL ) {
563 } else if ( nga->current==NULL ) {
568 attr=createEmptyList();
570 for (i=0; i<nga->current->ports; ++i) {
571 if ( ports[i]>=0 && ports[i]<=11 ) {
574 *(int*)(p+1)=htonl(ports[i]);
575 pushBackList(attr, newAttr(ATTR_STORM_BITRATE, 5, p));
580 return writeRequest(nga, attr);
586 // -----------------------------------------------------------
587 int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) {
596 } __attribute__((packed)) *p;
599 if ( nga==NULL || ports==NULL ) {
601 } else if ( nga->current==NULL ) {
606 attr=createEmptyList();
607 pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
608 pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
609 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
614 for (ln=attr->first; ln!=NULL; ln=ln->next) {
617 if ( at->size<sizeof(*p) || p->port<1 || p->port>nga->current->ports ) continue;
618 if ( at->attr==ATTR_BITRATE_INPUT ) {
619 ports[(p->port-1)*2+0]=ntohl(p->bitrate);
620 } else if ( at->attr==ATTR_BITRATE_OUTPUT ) {
621 ports[(p->port-1)*2+1]=ntohl(p->bitrate);
627 destroyList(attr, (void(*)(void*))freeAttr);
635 // -----------------------------------------------------------------
636 int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports) {
643 if ( nga==NULL || ports==NULL ) {
645 } else if ( nga->current==NULL ) {
650 attr=createEmptyList();
652 for (i=0; i<nga->current->ports; ++i) {
653 if ( ports[2*i+0]>=0 && ports[2*i+0]<=11 ) {
656 *(int*)(p+1)=htonl(ports[2*i+0]);
657 pushBackList(attr, newAttr(ATTR_BITRATE_INPUT, 5, p));
659 if ( ports[2*i+1]>=0 && ports[2*i+1]<=11 ) {
662 *(int*)(p+1)=htonl(ports[2*i+1]);
663 pushBackList(attr, newAttr(ATTR_BITRATE_OUTPUT, 5, p));
668 return writeRequest(nga, attr);
674 // -------------------------------------------------
675 int ngadmin_getQOSMode (struct ngadmin *nga, int *s) {
683 if ( nga==NULL || s==NULL ) {
685 } else if ( nga->current==NULL ) {
690 attr=createEmptyList();
691 pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
692 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
697 for (ln=attr->first; ln!=NULL; ln=ln->next) {
699 if ( at->attr==ATTR_QOS_TYPE && at->size>=1 ) {
700 *s= *(char*)at->data ;
707 destroyList(attr, (void(*)(void*))freeAttr);
714 // ------------------------------------------------
715 int ngadmin_setQOSMode (struct ngadmin *nga, int s) {
720 if ( s<QOS_PORT || s>QOS_DOT ) {
724 attr=createEmptyList();
725 pushBackList(attr, newByteAttr(ATTR_QOS_TYPE, s));
728 return writeRequest(nga, attr);
734 // -------------------------------------------------------
735 int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) {
744 if ( nga==NULL || ports==NULL ) {
746 } else if ( nga->current==NULL ) {
751 attr=createEmptyList();
752 pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
753 if ( (ret=readRequest(nga, attr))<0 ) {
757 for (ln=attr->first; ln!=NULL; ln=ln->next) {
760 if ( at->attr==ATTR_QOS_CONFIG && at->size>=2 && --p[0]>=0 && p[0]<nga->current->ports ) {
761 ports[(int)p[0]]=p[1];
767 destroyList(attr, (void(*)(void*))freeAttr);
776 // --------------------------------------------------------------
777 int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports) {
784 if ( nga==NULL || ports==NULL ) {
786 } else if ( nga->current==NULL ) {
791 attr=createEmptyList();
793 for (i=0; i<nga->current->ports; ++i) {
794 if ( ports[i]>=PRIO_HIGH && ports[i]<=PRIO_LOW ) {
798 pushBackList(attr, newAttr(ATTR_QOS_CONFIG, 2, p));
803 return writeRequest(nga, attr);
809 // --------------------------------------
810 int ngadmin_restart (struct ngadmin *nga) {
815 attr=createEmptyList();
816 pushBackList(attr, newByteAttr(ATTR_RESTART, 1));
819 return writeRequest(nga, attr);
825 // ---------------------------------------
826 int ngadmin_defaults (struct ngadmin *nga) {
832 attr=createEmptyList();
833 pushBackList(attr, newByteAttr(ATTR_DEFAULTS, 1));
834 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
839 // successful: delog and clean list
854 // -----------------------------------------------------
855 int ngadmin_getMirror (struct ngadmin *nga, char *ports) {
865 if ( nga==NULL || ports==NULL ) {
867 } else if ( (sa=nga->current)==NULL ) {
872 attr=createEmptyList();
873 pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
874 if ( (ret=readRequest(nga, attr))<0 ) {
878 for (ln=attr->first; ln!=NULL; ln=ln->next) {
881 if ( at->attr==ATTR_MIRROR && at->size>=3 && p[0]<=nga->current->ports ) {
883 for (i=1; i<=sa->ports; ++i) { // FIXME: if ports>8
884 ports[i]=(p[2]>>(sa->ports-i))&1;
892 destroyList(attr, (void(*)(void*))freeAttr);
901 // -----------------------------------------------------------
902 int ngadmin_setMirror (struct ngadmin *nga, const char *ports) {
912 } else if ( (sa=nga->current)==NULL ) {
917 p=malloc(3); // FIXME: if ports>8
920 if ( ports!=NULL && ports[0]>0 && ports[0]<=sa->ports ) {
922 for (i=1; i<=sa->ports; ++i) {
924 p[2]|=(ports[i]&1)<<(sa->ports-i);
929 attr=createEmptyList();
930 pushBackList(attr, newAttr(ATTR_MIRROR, 3, p));
933 return writeRequest(nga, attr);
939 // ----------------------------------------------------------------
940 int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic) {
951 if ( nga==NULL || ic==NULL ) {
953 } else if ( (sa=nga->current)==NULL ) {
958 ATTR_IGMP_ENABLE_VLAN
962 Apparently, read-querying theses attributes at the same time causes the switch to reply garbage.
963 Here we are forced to do like the official win app and send a separate request for each attribute.
967 attr=createEmptyList();
968 memset(ic, 0, sizeof(struct igmp_conf));
971 pushBackList(attr, newEmptyAttr(ATTR_IGMP_ENABLE_VLAN));
972 if ( (ret=readRequest(nga, attr))<0 ) {
976 for (ln=attr->first; ln!=NULL; ln=ln->next) {
979 if ( at->attr==ATTR_IGMP_ENABLE_VLAN && at->size>=4 ) {
980 ic->enable= ntohs(s[0])!=0 ;
981 ic->vlan=htons(s[1]);
986 clearList(attr, (void(*)(void*))freeAttr);
989 pushBackList(attr, newEmptyAttr(ATTR_IGMP_BLOCK_UNK));
990 if ( (ret=readRequest(nga, attr))<0 ) {
994 for (ln=attr->first; ln!=NULL; ln=ln->next) {
997 if ( at->attr==ATTR_IGMP_BLOCK_UNK && at->size>=1 ) {
1003 clearList(attr, (void(*)(void*))freeAttr);
1006 pushBackList(attr, newEmptyAttr(ATTR_IGMP_VALID_V3));
1007 if ( (ret=readRequest(nga, attr))<0 ) {
1011 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1014 if ( at->attr==ATTR_IGMP_VALID_V3 && at->size>=1 ) {
1015 ic->validate= p[0]!=0 ;
1023 destroyList(attr, (void(*)(void*))freeAttr);
1032 // ----------------------------------------------------------------------
1033 int ngadmin_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic) {
1037 struct swi_attr *sa;
1040 if ( nga==NULL || ic==NULL ) {
1042 } else if ( (sa=nga->current)==NULL ) {
1047 s=malloc(2*sizeof(short));
1048 s[0]=htons(ic->enable!=false);
1049 s[1]=htons(ic->vlan&0x0FFF);
1051 attr=createEmptyList();
1052 pushBackList(attr, newAttr(ATTR_IGMP_ENABLE_VLAN, 2*sizeof(short), s));
1053 pushBackList(attr, newByteAttr(ATTR_IGMP_BLOCK_UNK, ic->block!=false ));
1054 pushBackList(attr, newByteAttr(ATTR_IGMP_VALID_V3, ic->validate!=false ));
1057 return writeRequest(nga, attr);
1063 // ----------------------------------------------------------------------
1064 int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb) {
1070 struct swi_attr *sa;
1074 if ( nga==NULL || ct==NULL ) {
1076 } else if ( (sa=nga->current)==NULL ) {
1081 attr=createEmptyList();
1083 for (i=0; i<nb; ++i) {
1084 if ( ct[i].port>=1 && ct[i].port<=sa->ports ) {
1089 pushBackList(attr, newAttr(ATTR_CABLETEST_DO, 2, p));
1091 ret=writeRequest(nga, attr);
1093 if ( ret<0 ) goto end;
1095 // the list is destroyed by writeRequest, so we need to recreate it
1096 attr=createEmptyList();
1097 pushBackList(attr, newByteAttr(ATTR_CABLETEST_RESULT, ct[i].port));
1099 if ( (ret=readRequest(nga, attr))<0 ) goto end;
1101 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1104 if ( at->attr==ATTR_CABLETEST_RESULT && at->size>=9 && p[0]==ct[i].port ) {
1105 ct[i].v1=ntohl(*(int*)&p[1]);
1106 ct[i].v2=ntohl(*(int*)&p[5]);
1111 // just empty the list, it will be used at next iteration
1112 clearList(attr, (void(*)(void*))freeAttr);
1119 destroyList(attr, (void(*)(void*))freeAttr);
1127 // --------------------------------------------------------------------
1128 int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc) {
1131 struct swi_attr *sa;
1135 if ( nga==NULL || nc==NULL ) {
1137 } else if ( (sa=nga->current)==NULL ) {
1142 attr=createEmptyList();
1145 pushBackList(attr, newByteAttr(ATTR_DHCP, 1));
1147 pushBackList(attr, newByteAttr(ATTR_DHCP, 0));
1148 if ( nc->ip.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_IP, nc->ip));
1149 if ( nc->netmask.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_NETMASK, nc->netmask));
1150 if ( nc->gw.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_GATEWAY, nc->gw));
1153 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
1161 memcpy(&sa->nc, nc, sizeof(struct net_conf));
1173 // --------------------------------------------------
1174 int ngadmin_getVLANType (struct ngadmin *nga, int *t) {
1182 if ( nga==NULL || t==NULL ) {
1184 } else if ( nga->current==NULL ) {
1189 attr=createEmptyList();
1190 pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
1191 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1196 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1198 if ( at->attr==ATTR_VLAN_TYPE && at->size>=1 ) {
1199 *t= (int)*(char*)at->data ;
1206 destroyList(attr, (void(*)(void*))freeAttr);
1214 // ------------------------------------------------------------------
1215 int ngadmin_getVLANDotConf (struct ngadmin *nga, char *buf, int *len) {
1220 struct swi_attr *sa;
1222 char *b=buf, *p=NULL;
1225 if ( nga==NULL || buf==NULL || len==NULL || *len<=0 ) {
1227 } else if ( (sa=nga->current)==NULL ) {
1232 attr=createEmptyList();
1233 pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
1234 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1239 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1242 if ( (b-buf)+2+sa->ports>*len ) break; // no more room
1243 if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
1244 *(unsigned short*)b=ntohs(*(unsigned short*)p);b+=2;
1245 for (i=1; i<=sa->ports; ++i) {
1246 if ( (p[3]>>(sa->ports-i))&1 ) *b++=VLAN_TAGGED; // tagged
1247 else if ( (p[2]>>(sa->ports-i))&1 ) *b++=VLAN_UNTAGGED; // untagged
1257 destroyList(attr, (void(*)(void*))freeAttr);