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 ) {
273 // TODO: if keep broadcasting is disabled, connect() the UDP socket so icmp errors messages (port unreachable, TTL exceeded in transit, ...)can be received
279 destroyList(attr, (void(*)(void*))freeAttr);
288 // -------------------------------------------------------------------
289 int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) {
298 if ( nga==NULL || ports==NULL ) {
300 } else if ( nga->current==NULL ) {
305 attr=createEmptyList();
306 pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
307 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
311 for (ln=attr->first; ln!=NULL; ln=ln->next) {
314 if ( at->attr==ATTR_PORT_STATUS && at->size>=2 && (i=p[0]-1)>=0 && i<nga->current->ports ) {
321 destroyList(attr, (void(*)(void*))freeAttr);
329 // --------------------------------------------------------
330 int ngadmin_setName (struct ngadmin *nga, const char *name) {
338 } else if ( nga->current==NULL ) {
343 attr=createEmptyList();
344 pushBackList(attr, name==NULL ? newEmptyAttr(ATTR_NAME) : newAttr(ATTR_NAME, strlen(name), strdup(name)) );
345 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
350 // successful, also update local name
352 nga->current->name[0]=0;
354 strncpy(nga->current->name, name, NAME_SIZE);
366 // ------------------------------------------------------------------------
367 int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) {
376 if ( nga==NULL || ps==NULL ) {
378 } else if ( nga->current==NULL ) {
383 attr=createEmptyList();
384 pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
385 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
390 for (ln=attr->first; ln!=NULL; ln=ln->next) {
392 if ( at->attr==ATTR_PORT_STATISTICS && at->size>=49 && (port=(int)(*(char*)at->data)-1)>=0 && port<nga->current->ports ) {
393 ps[port].recv=be64toh(*(unsigned long long*)(at->data+1+8*0));
394 ps[port].sent=be64toh(*(unsigned long long*)(at->data+1+8*1));
395 ps[port].crc=be64toh(*(unsigned long long*)(at->data+1+8*5));
396 // all offsets between 2 and 4 inclusive are unknown values
402 destroyList(attr, (void(*)(void*))freeAttr);
410 // ---------------------------------------------------
411 int ngadmin_resetPortsStatistics (struct ngadmin *nga) {
416 attr=createEmptyList();
417 pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
420 return writeRequest(nga, attr);
426 // ---------------------------------------------------------------
427 int ngadmin_changePassword (struct ngadmin *nga, const char* pass) {
433 if ( nga==NULL || pass==NULL ) {
435 } else if ( nga->current==NULL ) {
440 attr=createEmptyList();
441 pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
442 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
447 // successful, also update local password
448 strncpy(nga->password, pass, PASSWORD_MAX);
459 // ----------------------------------------------------------
460 int ngadmin_getStormFilterState (struct ngadmin *nga, int *s) {
468 if ( nga==NULL || s==NULL ) {
470 } else if ( nga->current==NULL ) {
475 attr=createEmptyList();
476 pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
477 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
482 for (ln=attr->first; ln!=NULL; ln=ln->next) {
484 if ( at->attr==ATTR_STORM_ENABLE && at->size>=1 ) {
485 *s= *(char*)at->data!=0 ;
492 destroyList(attr, (void(*)(void*))freeAttr);
500 // ---------------------------------------------------------
501 int ngadmin_setStormFilterState (struct ngadmin *nga, int s) {
506 attr=createEmptyList();
507 pushBackList(attr, newByteAttr(ATTR_STORM_ENABLE, s!=0));
510 return writeRequest(nga, attr);
516 // ---------------------------------------------------------------
517 int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports) {
525 if ( nga==NULL || ports==NULL ) {
527 } else if ( nga->current==NULL ) {
532 attr=createEmptyList();
533 pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
534 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
539 for (ln=attr->first; ln!=NULL; ln=ln->next) {
541 if ( at->attr==ATTR_STORM_BITRATE && at->size>=5 && (i=(int)*(char*)(at->data)-1)>=0 && i<nga->current->ports ) {
542 ports[i]=ntohl(*(int*)(1+(char*)at->data));
548 destroyList(attr, (void(*)(void*))freeAttr);
556 // ---------------------------------------------------------------------
557 int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports) {
564 if ( nga==NULL || ports==NULL ) {
566 } else if ( nga->current==NULL ) {
571 attr=createEmptyList();
573 for (i=0; i<nga->current->ports; ++i) {
574 if ( ports[i]>=0 && ports[i]<=11 ) {
577 *(int*)(p+1)=htonl(ports[i]);
578 pushBackList(attr, newAttr(ATTR_STORM_BITRATE, 5, p));
583 return writeRequest(nga, attr);
589 // -----------------------------------------------------------
590 int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) {
599 } __attribute__((packed)) *p;
602 if ( nga==NULL || ports==NULL ) {
604 } else if ( nga->current==NULL ) {
609 attr=createEmptyList();
610 pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
611 pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
612 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
617 for (ln=attr->first; ln!=NULL; ln=ln->next) {
620 if ( at->size<sizeof(*p) || p->port<1 || p->port>nga->current->ports ) continue;
621 if ( at->attr==ATTR_BITRATE_INPUT ) {
622 ports[(p->port-1)*2+0]=ntohl(p->bitrate);
623 } else if ( at->attr==ATTR_BITRATE_OUTPUT ) {
624 ports[(p->port-1)*2+1]=ntohl(p->bitrate);
630 destroyList(attr, (void(*)(void*))freeAttr);
638 // -----------------------------------------------------------------
639 int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports) {
646 if ( nga==NULL || ports==NULL ) {
648 } else if ( nga->current==NULL ) {
653 attr=createEmptyList();
655 for (i=0; i<nga->current->ports; ++i) {
656 if ( ports[2*i+0]>=0 && ports[2*i+0]<=11 ) {
659 *(int*)(p+1)=htonl(ports[2*i+0]);
660 pushBackList(attr, newAttr(ATTR_BITRATE_INPUT, 5, p));
662 if ( ports[2*i+1]>=0 && ports[2*i+1]<=11 ) {
665 *(int*)(p+1)=htonl(ports[2*i+1]);
666 pushBackList(attr, newAttr(ATTR_BITRATE_OUTPUT, 5, p));
671 return writeRequest(nga, attr);
677 // -------------------------------------------------
678 int ngadmin_getQOSMode (struct ngadmin *nga, int *s) {
686 if ( nga==NULL || s==NULL ) {
688 } else if ( nga->current==NULL ) {
693 attr=createEmptyList();
694 pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
695 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
700 for (ln=attr->first; ln!=NULL; ln=ln->next) {
702 if ( at->attr==ATTR_QOS_TYPE && at->size>=1 ) {
703 *s= *(char*)at->data ;
710 destroyList(attr, (void(*)(void*))freeAttr);
717 // ------------------------------------------------
718 int ngadmin_setQOSMode (struct ngadmin *nga, int s) {
723 if ( s<QOS_PORT || s>QOS_DOT ) {
727 attr=createEmptyList();
728 pushBackList(attr, newByteAttr(ATTR_QOS_TYPE, s));
731 return writeRequest(nga, attr);
737 // -------------------------------------------------------
738 int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) {
747 if ( nga==NULL || ports==NULL ) {
749 } else if ( nga->current==NULL ) {
754 attr=createEmptyList();
755 pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
756 if ( (ret=readRequest(nga, attr))<0 ) {
760 for (ln=attr->first; ln!=NULL; ln=ln->next) {
763 if ( at->attr==ATTR_QOS_CONFIG && at->size>=2 && --p[0]>=0 && p[0]<nga->current->ports ) {
764 ports[(int)p[0]]=p[1];
770 destroyList(attr, (void(*)(void*))freeAttr);
779 // --------------------------------------------------------------
780 int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports) {
787 if ( nga==NULL || ports==NULL ) {
789 } else if ( nga->current==NULL ) {
794 attr=createEmptyList();
796 for (i=0; i<nga->current->ports; ++i) {
797 if ( ports[i]>=PRIO_HIGH && ports[i]<=PRIO_LOW ) {
801 pushBackList(attr, newAttr(ATTR_QOS_CONFIG, 2, p));
806 return writeRequest(nga, attr);
812 // --------------------------------------
813 int ngadmin_restart (struct ngadmin *nga) {
818 attr=createEmptyList();
819 pushBackList(attr, newByteAttr(ATTR_RESTART, 1));
822 return writeRequest(nga, attr);
828 // ---------------------------------------
829 int ngadmin_defaults (struct ngadmin *nga) {
835 attr=createEmptyList();
836 pushBackList(attr, newByteAttr(ATTR_DEFAULTS, 1));
837 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
842 // successful: delog and clean list
857 // -----------------------------------------------------
858 int ngadmin_getMirror (struct ngadmin *nga, char *ports) {
868 if ( nga==NULL || ports==NULL ) {
870 } else if ( (sa=nga->current)==NULL ) {
875 attr=createEmptyList();
876 pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
877 if ( (ret=readRequest(nga, attr))<0 ) {
881 for (ln=attr->first; ln!=NULL; ln=ln->next) {
884 if ( at->attr==ATTR_MIRROR && at->size>=3 && p[0]<=nga->current->ports ) {
886 for (i=1; i<=sa->ports; ++i) { // FIXME: if ports>8
887 ports[i]=(p[2]>>(sa->ports-i))&1;
895 destroyList(attr, (void(*)(void*))freeAttr);
904 // -----------------------------------------------------------
905 int ngadmin_setMirror (struct ngadmin *nga, const char *ports) {
915 } else if ( (sa=nga->current)==NULL ) {
920 p=malloc(3); // FIXME: if ports>8
923 if ( ports!=NULL && ports[0]>0 && ports[0]<=sa->ports ) {
925 for (i=1; i<=sa->ports; ++i) {
927 p[2]|=(ports[i]&1)<<(sa->ports-i);
932 attr=createEmptyList();
933 pushBackList(attr, newAttr(ATTR_MIRROR, 3, p));
936 return writeRequest(nga, attr);
942 // ----------------------------------------------------------------
943 int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic) {
954 if ( nga==NULL || ic==NULL ) {
956 } else if ( (sa=nga->current)==NULL ) {
961 ATTR_IGMP_ENABLE_VLAN
965 Apparently, read-querying these attributes at the same time causes the switch to reply garbage.
966 Here we are forced to do like the official win app and send a separate request for each attribute.
970 attr=createEmptyList();
971 memset(ic, 0, sizeof(struct igmp_conf));
974 pushBackList(attr, newEmptyAttr(ATTR_IGMP_ENABLE_VLAN));
975 if ( (ret=readRequest(nga, attr))<0 ) {
979 for (ln=attr->first; ln!=NULL; ln=ln->next) {
982 if ( at->attr==ATTR_IGMP_ENABLE_VLAN && at->size>=4 ) {
983 ic->enable= ntohs(s[0])!=0 ;
984 ic->vlan=htons(s[1]);
989 clearList(attr, (void(*)(void*))freeAttr);
992 pushBackList(attr, newEmptyAttr(ATTR_IGMP_BLOCK_UNK));
993 if ( (ret=readRequest(nga, attr))<0 ) {
997 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1000 if ( at->attr==ATTR_IGMP_BLOCK_UNK && at->size>=1 ) {
1001 ic->block= p[0]!=0 ;
1006 clearList(attr, (void(*)(void*))freeAttr);
1009 pushBackList(attr, newEmptyAttr(ATTR_IGMP_VALID_V3));
1010 if ( (ret=readRequest(nga, attr))<0 ) {
1014 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1017 if ( at->attr==ATTR_IGMP_VALID_V3 && at->size>=1 ) {
1018 ic->validate= p[0]!=0 ;
1026 destroyList(attr, (void(*)(void*))freeAttr);
1035 // ----------------------------------------------------------------------
1036 int ngadmin_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic) {
1040 struct swi_attr *sa;
1043 if ( nga==NULL || ic==NULL ) {
1045 } else if ( (sa=nga->current)==NULL ) {
1050 s=malloc(2*sizeof(short));
1051 s[0]=htons(ic->enable!=false);
1052 s[1]=htons(ic->vlan&0x0FFF);
1054 attr=createEmptyList();
1055 pushBackList(attr, newAttr(ATTR_IGMP_ENABLE_VLAN, 2*sizeof(short), s));
1056 pushBackList(attr, newByteAttr(ATTR_IGMP_BLOCK_UNK, ic->block!=false ));
1057 pushBackList(attr, newByteAttr(ATTR_IGMP_VALID_V3, ic->validate!=false ));
1060 return writeRequest(nga, attr);
1066 // ----------------------------------------------------------------------
1067 int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb) {
1073 struct swi_attr *sa;
1077 if ( nga==NULL || ct==NULL ) {
1079 } else if ( (sa=nga->current)==NULL ) {
1084 attr=createEmptyList();
1086 for (i=0; i<nb; ++i) {
1087 if ( ct[i].port>=1 && ct[i].port<=sa->ports ) {
1092 pushBackList(attr, newAttr(ATTR_CABLETEST_DO, 2, p));
1094 ret=writeRequest(nga, attr);
1096 if ( ret<0 ) goto end;
1098 // the list is destroyed by writeRequest, so we need to recreate it
1099 attr=createEmptyList();
1100 pushBackList(attr, newByteAttr(ATTR_CABLETEST_RESULT, ct[i].port));
1102 if ( (ret=readRequest(nga, attr))<0 ) goto end;
1104 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1107 if ( at->attr==ATTR_CABLETEST_RESULT && at->size>=9 && p[0]==ct[i].port ) {
1108 ct[i].v1=ntohl(*(int*)&p[1]);
1109 ct[i].v2=ntohl(*(int*)&p[5]);
1114 // just empty the list, it will be used at next iteration
1115 clearList(attr, (void(*)(void*))freeAttr);
1122 destroyList(attr, (void(*)(void*))freeAttr);
1130 // --------------------------------------------------------------------
1131 int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc) {
1134 struct swi_attr *sa;
1138 if ( nga==NULL || nc==NULL ) {
1140 } else if ( (sa=nga->current)==NULL ) {
1145 attr=createEmptyList();
1148 pushBackList(attr, newByteAttr(ATTR_DHCP, 1));
1150 pushBackList(attr, newByteAttr(ATTR_DHCP, 0));
1151 if ( nc->ip.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_IP, nc->ip));
1152 if ( nc->netmask.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_NETMASK, nc->netmask));
1153 if ( nc->gw.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_GATEWAY, nc->gw));
1156 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
1164 memcpy(&sa->nc, nc, sizeof(struct net_conf));
1176 // --------------------------------------------------
1177 int ngadmin_getVLANType (struct ngadmin *nga, int *t) {
1185 if ( nga==NULL || t==NULL ) {
1187 } else if ( nga->current==NULL ) {
1192 attr=createEmptyList();
1193 pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
1194 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1199 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1201 if ( at->attr==ATTR_VLAN_TYPE && at->size>=1 ) {
1202 *t= (int)*(char*)at->data ;
1209 destroyList(attr, (void(*)(void*))freeAttr);
1217 // ------------------------------------------------------------------------------------------------------
1218 int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb) {
1223 struct swi_attr *sa;
1224 int ret=ERR_OK, total, i;
1228 if ( nga==NULL || vlans==NULL || ports==NULL || nb==NULL || *nb<=0 ) {
1230 } else if ( (sa=nga->current)==NULL ) {
1238 attr=createEmptyList();
1239 pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
1240 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1245 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1248 if ( *nb>=sa->ports ) break; // no more room
1249 if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
1250 for (i=1; i<=sa->ports; ++i) {
1251 if ( (p[3]>>(sa->ports-i))&1 ) ports[i-1]=VLAN_TAGGED; // tagged
1252 else if ( (p[2]>>(sa->ports-i))&1 ) ports[i-1]=VLAN_UNTAGGED; // untagged
1253 else ports[i-1]=VLAN_NO;
1255 *vlans++=ntohs(*(unsigned short*)p);
1263 destroyList(attr, (void(*)(void*))freeAttr);
1271 // ----------------------------------------------------------------------------------------
1272 int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned char *ports) {
1277 struct swi_attr *sa;
1282 if ( nga==NULL || ports==NULL ) {
1284 } else if ( (sa=nga->current)==NULL ) {
1290 attr=createEmptyList();
1291 pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
1292 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1297 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1300 if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
1301 for (i=1; i<=sa->ports; ++i) {
1302 if ( (p[3]>>(sa->ports-i))&1 ) ports[i-1]=VLAN_TAGGED; // tagged
1303 else if ( (p[2]>>(sa->ports-i))&1 ) ports[i-1]=VLAN_UNTAGGED; // untagged
1304 else ports[i-1]=VLAN_NO;
1312 destroyList(attr, (void(*)(void*))freeAttr);
1320 // -------------------------------------------------------------
1321 int ngadmin_getPVID (struct ngadmin *nga, unsigned short *ports) {
1326 struct swi_attr *sa;
1331 if ( nga==NULL || ports==NULL ) {
1333 } else if ( (sa=nga->current)==NULL ) {
1338 attr=createEmptyList();
1339 pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID));
1340 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1345 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1348 if ( at->attr==ATTR_VLAN_PVID && at->size>=3 && p[0]>=1 && p[0]<=sa->ports ) {
1349 ports[p[0]-1]=htons(*(unsigned short*)&p[1]);
1355 destroyList(attr, (void(*)(void*))freeAttr);