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_useGlobalBroadcast (struct ngadmin *nga, bool value) {
106 nga->globalbroad=value;
115 // ------------------------------------------------------------
116 int ngadmin_setPassword (struct ngadmin *nga, const char *pass) {
123 strncpy(nga->password, pass, PASSWORD_MAX);
132 // -------------------------------------------------------------------
133 int ngadmin_setTimeout (struct ngadmin *nga, const struct timeval *tv) {
138 if ( nga==NULL || tv==NULL ) {
144 if ( updateTimeout(nga)<0 ) {
155 // -----------------------------------
156 int ngadmin_scan (struct ngadmin *nga) {
159 List *attr, *swiList;
162 sent by official win client:
178 static const unsigned short hello[]={
202 // create attributes for an "hello" request
203 attr=createEmptyList();
205 pushBackList(attr, newEmptyAttr(hello[i]));
206 if ( hello[i]==ATTR_END ) break;
209 // send request to all potential switches
210 i=sendNgPacket(nga, CODE_READ_REQ, attr);
211 clearList(attr, (void(*)(void*))freeAttr);
217 // try to receive any packets until timeout
218 swiList=createEmptyList();
219 // FIXME: end after timeout whatever received packet is good or not
220 while ( recvNgPacket(nga, CODE_READ_REP, NULL, NULL, attr)>=0 ) {
221 sa=malloc(sizeof(struct swi_attr));
222 extractSwitchAttributes(sa, attr);
223 clearList(attr, (void(*)(void*))freeAttr);
224 pushBackList(swiList, sa);
227 nga->swi_count=swiList->count;
228 nga->swi_tab=convertToArray(swiList, sizeof(struct swi_attr));
237 // -----------------------------------------------------------------------
238 const struct swi_attr* ngadmin_getSwitchTab (struct ngadmin *nga, int *nb) {
241 if ( nga==NULL || nb==NULL ) {
255 // ------------------------------------------------------------------
256 const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga) {
270 // --------------------------------------------
271 int ngadmin_login (struct ngadmin *nga, int id) {
280 } else if ( id<0 || id>=nga->swi_count ) {
285 sa=&nga->swi_tab[id];
288 attr=createEmptyList();
289 pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
290 if ( (ret=readRequest(nga, attr))==ERR_OK ) {
292 // TODO: if keep broadcasting is disabled, connect() the UDP socket so icmp errors messages (port unreachable, TTL exceeded in transit, ...) can be received
298 destroyList(attr, (void(*)(void*))freeAttr);
307 // --------------------------------------------------------------------
308 int ngadmin_upgradeFirmware (struct ngadmin *nga, const char *filename) {
311 if ( nga==NULL || filename==NULL || *filename==0 ) {
313 } else if ( nga->current==NULL ) {
319 Firmware upgrade is not yet implemented.
320 This would require much more work and the use of a TFTP client.
321 Overall, it could be quite dangerous, as the switch may not check the binary
331 // -------------------------------------------------------------------
332 int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) {
341 if ( nga==NULL || ports==NULL ) {
343 } else if ( nga->current==NULL ) {
348 attr=createEmptyList();
349 pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
350 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
354 for (ln=attr->first; ln!=NULL; ln=ln->next) {
357 if ( at->attr==ATTR_PORT_STATUS && at->size>=2 && (i=p[0]-1)>=0 && i<nga->current->ports ) {
364 destroyList(attr, (void(*)(void*))freeAttr);
372 // --------------------------------------------------------
373 int ngadmin_setName (struct ngadmin *nga, const char *name) {
381 } else if ( nga->current==NULL ) {
386 attr=createEmptyList();
387 pushBackList(attr, name==NULL ? newEmptyAttr(ATTR_NAME) : newAttr(ATTR_NAME, strlen(name), strdup(name)) );
388 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
393 // successful, also update local name
395 nga->current->name[0]=0;
397 strncpy(nga->current->name, name, NAME_SIZE);
409 // ------------------------------------------------------------------------
410 int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) {
419 if ( nga==NULL || ps==NULL ) {
421 } else if ( nga->current==NULL ) {
426 attr=createEmptyList();
427 pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
428 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
433 for (ln=attr->first; ln!=NULL; ln=ln->next) {
435 if ( at->attr==ATTR_PORT_STATISTICS && at->size>=49 && (port=(int)(*(char*)at->data)-1)>=0 && port<nga->current->ports ) {
436 ps[port].recv=be64toh(*(unsigned long long*)(at->data+1+8*0));
437 ps[port].sent=be64toh(*(unsigned long long*)(at->data+1+8*1));
438 ps[port].crc=be64toh(*(unsigned long long*)(at->data+1+8*5));
439 // all offsets between 2 and 4 inclusive are unknown values
445 destroyList(attr, (void(*)(void*))freeAttr);
453 // ---------------------------------------------------
454 int ngadmin_resetPortsStatistics (struct ngadmin *nga) {
459 attr=createEmptyList();
460 pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
463 return writeRequest(nga, attr);
469 // ---------------------------------------------------------------
470 int ngadmin_changePassword (struct ngadmin *nga, const char* pass) {
476 if ( nga==NULL || pass==NULL ) {
478 } else if ( nga->current==NULL ) {
483 attr=createEmptyList();
484 pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
485 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
490 // successful, also update local password
491 strncpy(nga->password, pass, PASSWORD_MAX);
502 // ----------------------------------------------------------
503 int ngadmin_getStormFilterState (struct ngadmin *nga, int *s) {
511 if ( nga==NULL || s==NULL ) {
513 } else if ( nga->current==NULL ) {
518 attr=createEmptyList();
519 pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
520 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
525 for (ln=attr->first; ln!=NULL; ln=ln->next) {
527 if ( at->attr==ATTR_STORM_ENABLE && at->size>=1 ) {
528 *s= *(char*)at->data!=0 ;
535 destroyList(attr, (void(*)(void*))freeAttr);
543 // ---------------------------------------------------------
544 int ngadmin_setStormFilterState (struct ngadmin *nga, int s) {
549 attr=createEmptyList();
550 pushBackList(attr, newByteAttr(ATTR_STORM_ENABLE, s!=0));
553 return writeRequest(nga, attr);
559 // ---------------------------------------------------------------
560 int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports) {
568 if ( nga==NULL || ports==NULL ) {
570 } else if ( nga->current==NULL ) {
575 attr=createEmptyList();
576 pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
577 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
582 for (ln=attr->first; ln!=NULL; ln=ln->next) {
584 if ( at->attr==ATTR_STORM_BITRATE && at->size>=5 && (i=(int)*(char*)(at->data)-1)>=0 && i<nga->current->ports ) {
585 ports[i]=ntohl(*(int*)(1+(char*)at->data));
591 destroyList(attr, (void(*)(void*))freeAttr);
599 // ---------------------------------------------------------------------
600 int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports) {
607 if ( nga==NULL || ports==NULL ) {
609 } else if ( nga->current==NULL ) {
614 attr=createEmptyList();
616 for (i=0; i<nga->current->ports; ++i) {
617 if ( ports[i]>=0 && ports[i]<=11 ) {
620 *(int*)(p+1)=htonl(ports[i]);
621 pushBackList(attr, newAttr(ATTR_STORM_BITRATE, 5, p));
626 return writeRequest(nga, attr);
632 // -----------------------------------------------------------
633 int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) {
642 } __attribute__((packed)) *p;
645 if ( nga==NULL || ports==NULL ) {
647 } else if ( nga->current==NULL ) {
652 attr=createEmptyList();
653 pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
654 pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
655 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
660 for (ln=attr->first; ln!=NULL; ln=ln->next) {
663 if ( at->size<sizeof(*p) || p->port<1 || p->port>nga->current->ports ) continue;
664 if ( at->attr==ATTR_BITRATE_INPUT ) {
665 ports[(p->port-1)*2+0]=ntohl(p->bitrate);
666 } else if ( at->attr==ATTR_BITRATE_OUTPUT ) {
667 ports[(p->port-1)*2+1]=ntohl(p->bitrate);
673 destroyList(attr, (void(*)(void*))freeAttr);
681 // -----------------------------------------------------------------
682 int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports) {
689 if ( nga==NULL || ports==NULL ) {
691 } else if ( nga->current==NULL ) {
696 attr=createEmptyList();
698 for (i=0; i<nga->current->ports; ++i) {
699 if ( ports[2*i+0]>=0 && ports[2*i+0]<=11 ) {
702 *(int*)(p+1)=htonl(ports[2*i+0]);
703 pushBackList(attr, newAttr(ATTR_BITRATE_INPUT, 5, p));
705 if ( ports[2*i+1]>=0 && ports[2*i+1]<=11 ) {
708 *(int*)(p+1)=htonl(ports[2*i+1]);
709 pushBackList(attr, newAttr(ATTR_BITRATE_OUTPUT, 5, p));
714 return writeRequest(nga, attr);
720 // -------------------------------------------------
721 int ngadmin_getQOSMode (struct ngadmin *nga, int *s) {
729 if ( nga==NULL || s==NULL ) {
731 } else if ( nga->current==NULL ) {
736 attr=createEmptyList();
737 pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
738 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
743 for (ln=attr->first; ln!=NULL; ln=ln->next) {
745 if ( at->attr==ATTR_QOS_TYPE && at->size>=1 ) {
746 *s= *(char*)at->data ;
753 destroyList(attr, (void(*)(void*))freeAttr);
760 // ------------------------------------------------
761 int ngadmin_setQOSMode (struct ngadmin *nga, int s) {
766 if ( s<QOS_PORT || s>QOS_DOT ) {
770 attr=createEmptyList();
771 pushBackList(attr, newByteAttr(ATTR_QOS_TYPE, s));
774 return writeRequest(nga, attr);
780 // -------------------------------------------------------
781 int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) {
790 if ( nga==NULL || ports==NULL ) {
792 } else if ( nga->current==NULL ) {
797 attr=createEmptyList();
798 pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
799 if ( (ret=readRequest(nga, attr))<0 ) {
803 for (ln=attr->first; ln!=NULL; ln=ln->next) {
806 if ( at->attr==ATTR_QOS_CONFIG && at->size>=2 && --p[0]>=0 && p[0]<nga->current->ports ) {
807 ports[(int)p[0]]=p[1];
813 destroyList(attr, (void(*)(void*))freeAttr);
822 // --------------------------------------------------------------
823 int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports) {
830 if ( nga==NULL || ports==NULL ) {
832 } else if ( nga->current==NULL ) {
837 attr=createEmptyList();
839 for (i=0; i<nga->current->ports; ++i) {
840 if ( ports[i]>=PRIO_HIGH && ports[i]<=PRIO_LOW ) {
844 pushBackList(attr, newAttr(ATTR_QOS_CONFIG, 2, p));
849 return writeRequest(nga, attr);
855 // --------------------------------------
856 int ngadmin_restart (struct ngadmin *nga) {
861 attr=createEmptyList();
862 pushBackList(attr, newByteAttr(ATTR_RESTART, 1));
865 return writeRequest(nga, attr);
871 // ---------------------------------------
872 int ngadmin_defaults (struct ngadmin *nga) {
878 attr=createEmptyList();
879 pushBackList(attr, newByteAttr(ATTR_DEFAULTS, 1));
880 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
885 // successful: delog and clean list
900 // -----------------------------------------------------
901 int ngadmin_getMirror (struct ngadmin *nga, char *ports) {
911 if ( nga==NULL || ports==NULL ) {
913 } else if ( (sa=nga->current)==NULL ) {
918 attr=createEmptyList();
919 pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
920 if ( (ret=readRequest(nga, attr))<0 ) {
924 for (ln=attr->first; ln!=NULL; ln=ln->next) {
927 if ( at->attr==ATTR_MIRROR && at->size>=3 && p[0]<=nga->current->ports ) {
929 for (i=1; i<=sa->ports; ++i) { // FIXME: if ports>8
930 ports[i]=(p[2]>>(8-i))&1;
938 destroyList(attr, (void(*)(void*))freeAttr);
947 // -----------------------------------------------------------
948 int ngadmin_setMirror (struct ngadmin *nga, const char *ports) {
958 } else if ( (sa=nga->current)==NULL ) {
963 p=malloc(3); // FIXME: if ports>8
966 if ( ports!=NULL && ports[0]>0 && ports[0]<=sa->ports ) {
968 for (i=1; i<=sa->ports; ++i) {
970 p[2]|=(ports[i]&1)<<(8-i);
975 attr=createEmptyList();
976 pushBackList(attr, newAttr(ATTR_MIRROR, 3, p));
979 return writeRequest(nga, attr);
985 // ----------------------------------------------------------------
986 int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic) {
997 if ( nga==NULL || ic==NULL ) {
999 } else if ( (sa=nga->current)==NULL ) {
1004 ATTR_IGMP_ENABLE_VLAN
1008 Apparently, read-querying these attributes at the same time causes the switch to reply garbage.
1009 Here we are forced to do like the official win app and send a separate request for each attribute.
1013 attr=createEmptyList();
1014 memset(ic, 0, sizeof(struct igmp_conf));
1017 pushBackList(attr, newEmptyAttr(ATTR_IGMP_ENABLE_VLAN));
1018 if ( (ret=readRequest(nga, attr))<0 ) {
1022 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1025 if ( at->attr==ATTR_IGMP_ENABLE_VLAN && at->size>=4 ) {
1026 ic->enable= ntohs(s[0])!=0 ;
1027 ic->vlan=htons(s[1]);
1032 clearList(attr, (void(*)(void*))freeAttr);
1035 pushBackList(attr, newEmptyAttr(ATTR_IGMP_BLOCK_UNK));
1036 if ( (ret=readRequest(nga, attr))<0 ) {
1040 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1043 if ( at->attr==ATTR_IGMP_BLOCK_UNK && at->size>=1 ) {
1044 ic->block= p[0]!=0 ;
1049 clearList(attr, (void(*)(void*))freeAttr);
1052 pushBackList(attr, newEmptyAttr(ATTR_IGMP_VALID_V3));
1053 if ( (ret=readRequest(nga, attr))<0 ) {
1057 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1060 if ( at->attr==ATTR_IGMP_VALID_V3 && at->size>=1 ) {
1061 ic->validate= p[0]!=0 ;
1069 destroyList(attr, (void(*)(void*))freeAttr);
1078 // ----------------------------------------------------------------------
1079 int ngadmin_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic) {
1083 struct swi_attr *sa;
1086 if ( nga==NULL || ic==NULL ) {
1088 } else if ( (sa=nga->current)==NULL ) {
1093 s=malloc(2*sizeof(short));
1094 s[0]=htons(ic->enable!=false);
1095 s[1]=htons(ic->vlan&0x0FFF);
1097 attr=createEmptyList();
1098 pushBackList(attr, newAttr(ATTR_IGMP_ENABLE_VLAN, 2*sizeof(short), s));
1099 pushBackList(attr, newByteAttr(ATTR_IGMP_BLOCK_UNK, ic->block!=false ));
1100 pushBackList(attr, newByteAttr(ATTR_IGMP_VALID_V3, ic->validate!=false ));
1103 return writeRequest(nga, attr);
1109 // ----------------------------------------------------------------------
1110 int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb) {
1116 struct swi_attr *sa;
1120 if ( nga==NULL || ct==NULL ) {
1122 } else if ( (sa=nga->current)==NULL ) {
1127 attr=createEmptyList();
1129 for (i=0; i<nb; ++i) {
1130 if ( ct[i].port>=1 && ct[i].port<=sa->ports ) {
1135 pushBackList(attr, newAttr(ATTR_CABLETEST_DO, 2, p));
1137 ret=writeRequest(nga, attr);
1139 if ( ret<0 ) goto end;
1141 // the list is destroyed by writeRequest, so we need to recreate it
1142 attr=createEmptyList();
1143 pushBackList(attr, newByteAttr(ATTR_CABLETEST_RESULT, ct[i].port));
1145 if ( (ret=readRequest(nga, attr))<0 ) goto end;
1147 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1150 if ( at->attr==ATTR_CABLETEST_RESULT && at->size>=9 && p[0]==ct[i].port ) {
1151 ct[i].v1=ntohl(*(int*)&p[1]);
1152 ct[i].v2=ntohl(*(int*)&p[5]);
1157 // just empty the list, it will be used at next iteration
1158 clearList(attr, (void(*)(void*))freeAttr);
1165 destroyList(attr, (void(*)(void*))freeAttr);
1173 // --------------------------------------------------------------------
1174 int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc) {
1177 struct swi_attr *sa;
1181 if ( nga==NULL || nc==NULL ) {
1183 } else if ( (sa=nga->current)==NULL ) {
1188 attr=createEmptyList();
1191 pushBackList(attr, newByteAttr(ATTR_DHCP, 1));
1193 pushBackList(attr, newByteAttr(ATTR_DHCP, 0));
1194 // only add non-null values
1195 if ( nc->ip.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_IP, nc->ip));
1196 if ( nc->netmask.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_NETMASK, nc->netmask));
1197 if ( nc->gw.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_GATEWAY, nc->gw));
1200 if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
1205 // update local values
1206 sa->nc.dhcp=nc->dhcp;
1208 if ( nc->ip.s_addr!=0 ) sa->nc.ip=nc->ip;
1209 if ( nc->netmask.s_addr!=0 ) sa->nc.netmask=nc->netmask;
1210 if ( nc->gw.s_addr!=0 ) sa->nc.gw=nc->gw;
1222 // --------------------------------------------------
1223 int ngadmin_getVLANType (struct ngadmin *nga, int *t) {
1231 if ( nga==NULL || t==NULL ) {
1233 } else if ( nga->current==NULL ) {
1238 attr=createEmptyList();
1239 pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
1240 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1245 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1247 if ( at->attr==ATTR_VLAN_TYPE && at->size>=1 ) {
1248 *t= (int)*(char*)at->data ;
1255 destroyList(attr, (void(*)(void*))freeAttr);
1263 // -------------------------------------------------
1264 int ngadmin_setVLANType (struct ngadmin *nga, int t) {
1267 struct swi_attr *sa;
1270 if ( nga==NULL || t<1 || t>4 ) {
1272 } else if ( (sa=nga->current)==NULL ) {
1277 attr=createEmptyList();
1278 pushBackList(attr, newByteAttr(ATTR_VLAN_TYPE, t));
1281 return writeRequest(nga, attr);
1287 // ------------------------------------------------------------------------------------------------------
1288 int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb) {
1293 struct swi_attr *sa;
1294 int ret=ERR_OK, total, i;
1298 if ( nga==NULL || vlans==NULL || ports==NULL || nb==NULL || *nb<=0 ) {
1300 } else if ( (sa=nga->current)==NULL ) {
1308 attr=createEmptyList();
1309 pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
1310 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1315 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1318 if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
1319 for (i=0; i<sa->ports; ++i) {
1320 if ( (p[3]>>(7-i))&1 ) ports[i]=VLAN_TAGGED; // tagged
1321 else if ( (p[2]>>(7-i))&1 ) ports[i]=VLAN_UNTAGGED; // untagged
1322 else ports[i]=VLAN_NO;
1324 *vlans++=ntohs(*(unsigned short*)p);
1326 if ( ++*nb>total ) break; // no more room
1332 destroyList(attr, (void(*)(void*))freeAttr);
1340 // ----------------------------------------------------------------------------------------
1341 int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned char *ports) {
1346 struct swi_attr *sa;
1351 if ( nga==NULL || vlan<1 || vlan>VLAN_MAX || ports==NULL ) {
1353 } else if ( (sa=nga->current)==NULL ) {
1358 attr=createEmptyList();
1359 pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
1360 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1365 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1368 if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
1369 for (i=0; i<sa->ports; ++i) {
1370 if ( (p[3]>>(7-i))&1 ) ports[i]=VLAN_TAGGED; // tagged
1371 else if ( (p[2]>>(7-i))&1 ) ports[i]=VLAN_UNTAGGED; // untagged
1372 else ports[i]=VLAN_NO;
1380 destroyList(attr, (void(*)(void*))freeAttr);
1388 // ----------------------------------------------------------------------------------------------
1389 int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsigned char *ports) {
1394 struct swi_attr *sa;
1399 if ( nga==NULL || vlan<1 || vlan>VLAN_MAX || ports==NULL ) {
1401 } else if ( (sa=nga->current)==NULL ) {
1406 // if nothing is to be changed, do nothing
1407 for (i=0; i<sa->ports && ports[i]==VLAN_UNSPEC; ++i);
1408 if ( i==sa->ports ) goto end;
1411 attr=createEmptyList();
1414 *(unsigned short*)p=htons(vlan);
1415 *(unsigned short*)&p[2]=0;
1417 // if all is to be changed, we do not need to read old config
1418 if ( memchr(ports, VLAN_UNSPEC, sa->ports)!=NULL ) {
1420 pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
1421 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1425 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1427 if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
1428 *(unsigned short*)&p[2]=*(unsigned short*)(at->data+2);
1433 clearList(attr, (void(*)(void*))freeAttr);
1439 for (i=0; i<sa->ports; ++i) {
1441 switch ( ports[i] ) {
1458 pushBackList(attr, newAttr(ATTR_VLAN_DOT_CONF, 4, p));
1459 ret=writeRequest(nga, attr);
1464 destroyList(attr, (void(*)(void*))freeAttr);
1473 // ---------------------------------------------------------------
1474 int ngadmin_VLANDestroy (struct ngadmin *nga, unsigned short vlan) {
1477 struct swi_attr *sa;
1480 if ( nga==NULL || vlan<1 || vlan>VLAN_MAX ) {
1482 } else if ( (sa=nga->current)==NULL ) {
1487 attr=createEmptyList();
1488 pushBackList(attr, newShortAttr(ATTR_VLAN_DESTROY, vlan));
1491 return writeRequest(nga, attr);
1497 // ----------------------------------------------------------------
1498 int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports) {
1503 struct swi_attr *sa;
1508 if ( nga==NULL || ports==NULL ) {
1510 } else if ( (sa=nga->current)==NULL ) {
1515 attr=createEmptyList();
1516 pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID));
1517 if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
1522 for (ln=attr->first; ln!=NULL; ln=ln->next) {
1525 if ( at->attr==ATTR_VLAN_PVID && at->size>=3 && p[0]>=1 && p[0]<=sa->ports ) {
1526 ports[p[0]-1]=htons(*(unsigned short*)&p[1]);
1532 destroyList(attr, (void(*)(void*))freeAttr);
1540 // -------------------------------------------------------------------------------
1541 int ngadmin_setPVID (struct ngadmin *nga, unsigned char port, unsigned short vlan) {
1544 struct swi_attr *sa;
1548 if ( nga==NULL || port<1 || vlan<1 || vlan>VLAN_MAX ) {
1550 } else if ( (sa=nga->current)==NULL ) {
1552 } else if ( port>sa->ports ) {
1557 attr=createEmptyList();
1560 *(unsigned short*)&p[1]=htons(vlan);
1562 pushBackList(attr, newAttr(ATTR_VLAN_PVID, 3, p));
1565 return writeRequest(nga, attr);