]> git.sur5r.net Git - ngadmin/commitdiff
Added the possibility to specify the command timeout.
authordarkcoven <admin@darkcoven.tk>
Sun, 20 Nov 2011 11:00:00 +0000 (12:00 +0100)
committerdarkcoven <admin@darkcoven.tk>
Sat, 29 Dec 2012 21:10:30 +0000 (22:10 +0100)
Added basic support for cable testing.
Added support of port mirroring.
Added support for IGMP parameters.
Lib: added comments to explain some restrictions in the network code.
Lib: improved network code by adding higher level helpers.

cli/admin.c
cli/commands.c
lib/ngadmin.h
lib/src/lib.h
lib/src/network.c
lib/src/network.h
lib/src/ngadmin.c
lib/src/protocol.c
lib/src/protocol.h

index 3318cbc55086779e91bfb009c5d54c20bc290f68..9e0aea6ac9478d20664bc58a77b43a85cec62e04 100644 (file)
@@ -129,10 +129,12 @@ int main (int argc, char **argv) {
   {"force-interface", no_argument, NULL, 'f'}, 
   {"interface", required_argument, NULL, 'i'}, 
   {"help", no_argument, NULL, 'h'}, 
+  {"timeout", required_argument, NULL, 't'}, 
   {0, 0, 0, 0}
  };
  char *line, *com[MAXCOM];
  const char *iface="eth0";
+ float timeout=0.f;
  bool kb=false, force=false;
  struct ngadmin *nga=NULL;
  struct timeval tv;
@@ -143,7 +145,7 @@ int main (int argc, char **argv) {
  
  opterr=0;
  
- while ( (n=getopt_long(argc, argv, "bfi:h", opts, NULL))!=-1 ) {
+ while ( (n=getopt_long(argc, argv, "bfi:ht:", opts, NULL))!=-1 ) {
   switch ( n ) {
    
    case 'b':
@@ -162,6 +164,10 @@ int main (int argc, char **argv) {
     printf("Usage: %s [-b] [-f] [-i <interface>]\n", argv[0]);
     goto end;
    
+   case 't':
+    timeout=strtof(optarg, NULL);
+   break;
+   
    case '?':
     printf("Unknown option: \"%s\"\n", argv[optind-1]);
     goto end;
@@ -187,9 +193,11 @@ int main (int argc, char **argv) {
  }
  
  // set timeout
- tv.tv_sec=3;
- tv.tv_usec=0;
- ngadmin_setTimeout(nga, &tv);
+ if ( timeout>0.f ) {
+  tv.tv_sec=(int)timeout;
+  tv.tv_usec=(int)((timeout-(float)tv.tv_sec)*1e6f);
+  ngadmin_setTimeout(nga, &tv);
+ }
  
  
  if ( kb && ngadmin_setKeepBroadcasting(nga, true)!=ERR_OK ) goto end;
index c50f531ad85d563722a7ad08b3195738b13de8d5..c1349055edbde2be69149412dd64163bb436b94f 100644 (file)
@@ -123,11 +123,64 @@ static bool do_bitrate_show (int nb UNUSED, const char **com UNUSED, struct ngad
 
 
 
+// =============================================================================
+// cabletest
+
+
+static bool do_cabletest (int nb, const char **com, struct ngadmin *nga) {
+ bool ret=true;
+ const struct swi_attr *sa;
+ struct cabletest *ct=NULL;
+ int i, j=0, k=0;
+ if ( nb<1 ) {
+  printf("Usage: cabletest <port1> [<port2> ...]\n");
+  goto end;
+ }
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+  printf("must be logged\n");
+  ret=false;
+  goto end;
+ }
+ ct=malloc(sa->ports*sizeof(struct cabletest));
+ memset(ct, 0, sa->ports*sizeof(struct cabletest));
+ while ( k<nb ) {
+  ct[j].port=strtol(com[k++], NULL, 0);
+  if ( ct[j].port>=1 && ct[j].port<=sa->ports ) ++j;
+ }
+ i=ngadmin_cabletest(nga, ct, j);
+ if ( i<0 ) {
+  printErrCode(i);
+  ret=false;
+  goto end;
+ }
+ for (i=0; i<j; ++i) {
+  printf("port %i: %08X %08X\n", ct[i].port, ct[i].v1, ct[i].v2);
+ }
+ end:
+ free(ct);
+ return ret;
+}
+
+
+
 // =============================================================================
 // defaults
 
 
-static bool do_defaults (int nb UNUSED, const char **com UNUSED, struct ngadmin *nga UNUSED) {
+static bool do_defaults (int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
  
  int i, ret=true;
  const struct swi_attr *sa;
@@ -213,6 +266,78 @@ static bool do_firmware_upgrade (int nb, const char **com UNUSED, struct ngadmin
 
 
 
+// =============================================================================
+// igmp
+
+
+static bool do_igmp_set (int nb, const char **com, struct ngadmin *nga) {
+ int i;
+ struct igmp_conf ic;
+ if ( nb!=4 ) {
+  printf("Usage: igmp set <enable> <vlan> <validate> <block>\n");
+  return false;
+ }
+ if ( ngadmin_getCurrentSwitch(nga)==NULL ) {
+  printf("must be logged\n");
+  return false;
+ }
+ ic.enable=strtol(com[0], NULL, 0);
+ ic.vlan=strtol(com[1], NULL, 0);
+ ic.validate=strtol(com[2], NULL, 0);
+ ic.block=strtol(com[3], NULL, 0);
+ i=ngadmin_setIGMPConf(nga, &ic);
+ printErrCode(i);
+ return true;
+}
+
+
+
+static bool do_igmp_show (int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+ int i;
+ const struct swi_attr *sa;
+ struct igmp_conf ic;
+ bool ret=true;
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+  printf("must be logged\n");
+  ret=false;
+  goto end;
+ }
+ i=ngadmin_getIGMPConf(nga, &ic);
+ if ( i!=ERR_OK ) {
+  printErrCode(i);
+  ret=false;
+  goto end;
+ }
+ printf("IGMP snooping enabled: %s\n", ic.enable ? "yes" : "no" );
+ printf("IGMP snooping vlan: %u\n", ic.vlan);
+ printf("Validate IGMPv3 headers: %s\n", ic.validate ? "yes" : "no" );
+ printf("Block unknown multicast addresses: %s\n", ic.block ? "yes" : "no" );
+ end:
+ return ret;
+}
+
+
+
 // =============================================================================
 // list
 
@@ -259,6 +384,136 @@ static bool do_login (int nb, const char **com, struct ngadmin *nga) {
 
 
 
+// =============================================================================
+// mirror
+
+
+static bool do_mirror_disable (int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+ int i;
+ if ( ngadmin_getCurrentSwitch(nga)==NULL ) {
+  printf("must be logged\n");
+  return false;
+ }
+ i=ngadmin_setMirror(nga, NULL);
+ printErrCode(i);
+ return true;
+}
+
+
+
+static bool do_mirror_set (int nb, const char **com, struct ngadmin *nga) {
+ const struct swi_attr *sa;
+ char *ports=NULL;
+ bool ret=true;
+ int i, k=0;
+ if ( nb<3 ) {
+  printf("Usage: mirror set <destination port> clone <port1> [<port2> ...]\n");
+  goto end;
+ }
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+  printf("must be logged\n");
+  ret=false;
+  goto end;
+ }
+ ports=malloc((sa->ports+1)*sizeof(char));
+ memset(ports, 0, sa->ports+1);
+ ports[0]=strtol(com[k++], NULL, 0);
+ if ( ports[0]<1 || ports[0]>sa->ports || strcasecmp(com[k++], "clone")!=0 ) {
+  printf("syntax error\n");
+  ret=false;
+  goto end;
+ }
+ while ( k<nb ) {
+  i=strtol(com[k++], NULL, 0);
+  if ( i<1 || i>sa->ports ) {
+   printf("port out of range\n");
+   ret=false;
+   goto end;
+  } else if ( i==ports[0] ) {
+   printf("destination port cannot be in port list\n");
+   ret=false;
+   goto end;
+  }
+  ports[i]=1;
+ }
+ i=ngadmin_setMirror(nga, ports);
+ printErrCode(i);
+ end:
+ free(ports);
+ return true;
+}
+
+
+
+static bool do_mirror_show (int nb UNUSED, const char **com UNUSED, struct ngadmin *nga) {
+ const struct swi_attr *sa;
+ char *ports=NULL;
+ int i;
+ if ( (sa=ngadmin_getCurrentSwitch(nga))==NULL ) {
+  printf("must be logged\n");
+  return false;
+ }
+ ports=malloc((sa->ports+1)*sizeof(char));
+ i=ngadmin_getMirror(nga, ports);
+ if ( i!=ERR_OK ) {
+  printErrCode(i);
+  goto end;
+ }
+ if ( ports[0]==0 ) {
+  printf("port mirroring is disabled\n");
+  goto end;
+ }
+ printf("destination: %i\n", ports[0]);
+ printf("ports: ");
+ for (i=1; i<=sa->ports; ++i) {
+  if ( ports[i] ) {
+   printf("%i ", i);
+  }
+ }
+ printf("\n");
+ end:
+ free(ports);
+ return true;
+}
+
+
+
 // =============================================================================
 // name
 
@@ -901,7 +1156,7 @@ COM_ROOT_START(coms)
   COM_TERM(show, do_bitrate_show, false)
  COM_END
  
- COM_TERM(cabletest, NULL, true)
+ COM_TERM(cabletest, do_cabletest, true)
  
  COM_TERM(defaults, do_defaults, false)
  
@@ -911,8 +1166,8 @@ COM_ROOT_START(coms)
  COM_END
  
  COM_START(igmp)
-  COM_TERM(set, NULL, false)
-  COM_TERM(show, NULL, false)
+  COM_TERM(set, do_igmp_set, true)
+  COM_TERM(show, do_igmp_show, false)
  COM_END
  
  COM_TERM(list, do_list, false)
@@ -920,10 +1175,9 @@ COM_ROOT_START(coms)
  COM_TERM(login, do_login, true)
  
  COM_START(mirror)
-  COM_TERM(enable, NULL, false)
-  COM_TERM(disable, NULL, false)
-  COM_TERM(set, NULL, true)
-  COM_TERM(show, NULL, false)
+  COM_TERM(disable, do_mirror_disable, false)
+  COM_TERM(set, do_mirror_set, true)
+  COM_TERM(show, do_mirror_show, false)
  COM_END
  
  COM_START(name)
index 1771a93cb597a03dece8c4aabd28df55c5a45875..50f0bc375439d62d25940504b828caf81bff62c5 100644 (file)
@@ -79,7 +79,7 @@ struct net_conf {
 
 
 struct swi_attr {
- char product[PRODUCT_SIZE];   // product name (eg. GS108E)
+ char product[PRODUCT_SIZE];   // product name (eg. GS108EV1)
  char name[NAME_SIZE];         // custom name
  char firmware[FIRMWARE_SIZE]; // firmware version string
  unsigned char ports;          // number of ports
@@ -95,6 +95,20 @@ struct port_stats {
 };
 
 
+struct igmp_conf {
+ bool enable;
+ unsigned short vlan;
+ bool validate;
+ bool block;
+};
+
+
+struct cabletest {
+ char port;
+ int v1;
+ int v2;
+};
+
 
 
 // initialize NgAdmin lib
@@ -204,6 +218,25 @@ int ngadmin_restart (struct ngadmin *nga) EXPORT;
 int ngadmin_defaults (struct ngadmin *nga) EXPORT;
 
 
+// 
+int ngadmin_getMirror (struct ngadmin *nga, char *ports) EXPORT;
+
+
+// 
+int ngadmin_setMirror (struct ngadmin *nga, const char *ports) EXPORT;
+
+
+// 
+int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic) EXPORT;
+
+
+// 
+int ngadmin_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic) EXPORT;
+
+
+// 
+int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb) EXPORT;
+
 
 
 #endif
index f71fb2b30f0f406f41eb567e66b584f06ea8f12b..30b654b2a83cdf60853239e030cb38f06f4a78a8 100644 (file)
@@ -41,6 +41,8 @@
 #define ATTR_PORT_STATUS       0x0C00
 #define ATTR_PORT_STATISTICS   0x1000
 #define ATTR_STATS_RESET       0x1400
+#define ATTR_CABLETEST_DO      0x1800
+#define ATTR_CABLETEST_RESULT  0x1C00
 #define ATTR_VLAN_TYPE         0x2000
 #define ATTR_VLAN_PORT_CONF    0x2400
 #define ATTR_VLAN_DOT_CONF     0x2800
@@ -52,9 +54,9 @@
 #define ATTR_STORM_BITRATE     0x5800
 #define ATTR_MIRROR            0x5C00
 #define ATTR_PORTS_COUNT       0x6000
-#define ATTR_UNK_6800          0x6800
-#define ATTR_UNK_6C00          0x6C00
-#define ATTR_UNK_7000          0x7000
+#define ATTR_IGMP_ENABLE_VLAN  0x6800
+#define ATTR_IGMP_BLOCK_UNK    0x6C00
+#define ATTR_IGMP_VALID_V3     0x7000
 #define ATTR_UNK_7400          0x7400
 #define ATTR_END               0xFFFF
 
index cf293d0360ef0fa6c46f5889ef70bc00d7b0cda8..e71515d6ed5090129d9fe5ba03c00dbd35f36197 100644 (file)
@@ -29,6 +29,13 @@ int startNetwork (struct ngadmin *nga) {
   close(nga->sock);
   return ret;
  }
+ /*
+ Here we have a problem: when you have multiple interfaces, sending a packet to 
+ 255.255.255.255 may not send it to the interface you want. If you bind() to 
+ the address of the interface, you will not be able to receive broadcasts. 
+ The only solution I have found yet is in this case to use 
+ setsockopt(SO_BINDTODEVICE) but this requires root priviledges. 
+ */
  //local.sin_addr=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; // FIXME
  
  // get the interface MAC address
@@ -76,12 +83,22 @@ int forceInterface (struct ngadmin *nga) {
  
  
  
+ /*
+ As described bellow, when you have multiple interfaces, this forces the packet 
+ to go to a particular interface. 
+ */
  ret=1;
  if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface)+1))<0 ) {
   perror("setsockopt(SO_BINDTODEVICE)");
   return ret;
  }
  
+ /*
+ If the switch's IP is not in your network range, for instance because you do 
+ not have DHCP  enabled or you started the switch after it, this allows to 
+ bypass the routing tables and consider every address is directly reachable on 
+ the interface. 
+ */
  ret=1;
  if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret)))<0 ) {
   perror("setsockopt(SO_DONTROUTE)");
@@ -155,15 +172,14 @@ int sendNgPacket (struct ngadmin *nga, char code, const List *attr) {
 
 
 
-// -----------------------------------------------------------------------------------------
-List* recvNgPacket (struct ngadmin *nga, char code, char *error, unsigned short *attr_error) {
+// ---------------------------------------------------------------------------------------------------
+int recvNgPacket (struct ngadmin *nga, char code, char *error, unsigned short *attr_error, List *attr) {
  
  char buffer[1500];
  struct ng_packet np;
  struct sockaddr_in remote;
  socklen_t slen=sizeof(struct sockaddr_in);
  const struct swi_attr *sa=nga->current;
- List *l=NULL;
  int len;
  
  
@@ -173,16 +189,120 @@ List* recvNgPacket (struct ngadmin *nga, char code, char *error, unsigned short
  memset(&remote, 0, sizeof(struct sockaddr_in));
  remote.sin_family=AF_INET;
  
- while ( (len=recvfrom(nga->sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&remote, &slen))>=0 ) {
+ while ( 1 ) {
+  
+  len=recvfrom(nga->sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&remote, &slen);
+  
+  if ( len<0 ) {
+   break;
+  }
+  
   if ( ntohs(remote.sin_port)==SWITCH_PORT && len>=(int)sizeof(struct ng_header) && validateNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , nga->seq) ) {
    initNgPacket(&np);
-   l=extractPacketAttributes(&np, error, attr_error);
+   extractPacketAttributes(&np, error, attr_error, attr);
+   len=0;
    break;
   }
+  
+ }
+ return len;
+}
+
+
+
+// ----------------------------------------------
+int readRequest (struct ngadmin *nga, List *attr) {
+ int i, ret=ERR_OK;
+ unsigned short attr_error;
+ char err;
+ if ( nga==NULL ) {
+  ret=ERR_INVARG;
+  goto end;
+ }
+ // add end attribute to end
+ pushBackList(attr, newEmptyAttr(ATTR_END));
+ i=sendNgPacket(nga, CODE_READ_REQ, attr);
+ // the list will be filled again by recvNgPacket
+ clearList(attr, (void(*)(void*))freeAttr);
+ if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) {
+  ret=ERR_NET;
+ }
+ if ( err==7 && attr_error==ATTR_PASSWORD ) {
+  ret=ERR_BADPASS;
+  goto end;
+ }
+ end:
+ return ret;
+}
+
+
+
+// -----------------------------------------------
+int writeRequest (struct ngadmin *nga, List *attr) {
+ int i, ret=ERR_OK;
+ unsigned short attr_error;
+ char err;
+ if ( nga==NULL ) {
+  ret=ERR_INVARG;
+  goto end;
+ } else if ( nga->current==NULL ) {
+  ret=ERR_NOTLOG;
+  goto end;
+ }
+ if ( attr==NULL ) {
+  attr=createEmptyList();
+ }
+ // add password attribute to start
+ pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
+ // add end attribute to end
+ pushBackList(attr, newEmptyAttr(ATTR_END));
+ i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
+ // the list will be filled again by recvNgPacket
+ // but normally it will be still empty
+ clearList(attr, (void(*)(void*))freeAttr);
+ if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) {
+  ret=ERR_NET;
+  goto end;
+ }
+ if ( err==7 && attr_error==ATTR_PASSWORD ) {
+  ret=ERR_BADPASS;
+  goto end;
  }
  
  
- return l;
+ end:
+ // the switch replies to write request by just a header (no attributes), so the list can be destroyed
+ destroyList(attr, (void(*)(void*))freeAttr);
+ return ret;
  
 }
 
index 1d6fc1fafd58d9d956e2200508f579d90463c004..a51992ea28aeef6b3b5c14613e73fcb907672290 100644 (file)
@@ -32,7 +32,13 @@ int updateTimeout (struct ngadmin *nga);
 int sendNgPacket (struct ngadmin *nga, char code, const List *attr);
 
 // 
-List* recvNgPacket (struct ngadmin *nga, char code, char *error, unsigned short *attr_error);
+int recvNgPacket (struct ngadmin *nga, char code, char *error, unsigned short *attr_error, List *attr);
+
+// 
+int readRequest (struct ngadmin *nga, List *attr);
+
+// 
+int writeRequest (struct ngadmin *nga, List *attr);
 
 
 
index 57b8e798dcf4b1a2757eae0448d56d04127230c4..d1e33d1cc566696faa6d9cf82c8a2ef64bd493ee 100644 (file)
@@ -4,7 +4,7 @@
 
 
 
-static const struct timeval default_timeout={.tv_sec=3, .tv_usec=0};
+static const struct timeval default_timeout={.tv_sec=4, .tv_usec=0};
 
 
 
@@ -190,7 +190,7 @@ int ngadmin_scan (struct ngadmin *nga) {
  
  // send request to all potential switches
  i=sendNgPacket(nga, CODE_READ_REQ, attr);
destroyList(attr, (void(*)(void*))freeAttr);
clearList(attr, (void(*)(void*))freeAttr);
  if ( i<0 ) {
   return ERR_NET;
  }
@@ -198,10 +198,10 @@ int ngadmin_scan (struct ngadmin *nga) {
  
  // try to receive any packets until timeout
  swiList=createEmptyList();
- while ( (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL))!=NULL ) {
+ while ( recvNgPacket(nga, CODE_READ_REP, NULL, NULL, attr)>=0 ) {
   sa=malloc(sizeof(struct swi_attr));
   extractSwitchAttributes(sa, attr);
-  destroyList(attr, (void(*)(void*))freeAttr);
+  clearList(attr, (void(*)(void*))freeAttr);
   pushBackList(swiList, sa);
  }
  
@@ -252,10 +252,8 @@ const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga) {
 int ngadmin_login (struct ngadmin *nga, int id) {
  
  List *attr;
- int ret=ERR_OK, i;
+ int ret=ERR_OK;
  struct swi_attr *sa;
- char err;
- unsigned short attr_error;
  
  
  if ( nga==NULL ) {
@@ -270,27 +268,14 @@ int ngadmin_login (struct ngadmin *nga, int id) {
  
  attr=createEmptyList();
  pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_READ_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
+ if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
+  // login failed
   nga->current=NULL;
-  goto end;
  }
  
  destroyList(attr, (void(*)(void*))freeAttr);
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
-  nga->current=NULL;
-  goto end;
- }
  
  
- end:
  return ret;
  
 }
@@ -316,11 +301,7 @@ int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) {
  
  attr=createEmptyList();
  pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_READ_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL))==NULL ) {
-  ret=ERR_NET;
+ if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
   goto end;
  }
  
@@ -332,10 +313,9 @@ int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) {
   }
  }
  
- destroyList(attr, (void(*)(void*))freeAttr);
  
  end:
+ destroyList(attr, (void(*)(void*))freeAttr);
  
  return ret;
  
@@ -347,9 +327,7 @@ int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) {
 int ngadmin_setName (struct ngadmin *nga, const char *name) {
  
  List *attr;
- int ret=ERR_OK, i;
- char err;
- unsigned short attr_error;
+ int ret=ERR_OK;
  
  
  if ( nga==NULL ) {
@@ -360,23 +338,8 @@ int ngadmin_setName (struct ngadmin *nga, const char *name) {
  
  
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
- if ( name==NULL ) {
-  pushBackList(attr, newEmptyAttr(ATTR_NAME));
- } else {
-  pushBackList(attr, newAttr(ATTR_NAME, strlen(name), strdup(name)));
- }
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
-  goto end;
- }
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
+ pushBackList(attr, name==NULL ? newEmptyAttr(ATTR_NAME) : newAttr(ATTR_NAME, strlen(name), strdup(name)) );
+ if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
   goto end;
  }
  
@@ -403,7 +366,7 @@ int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) {
  List *attr;
  ListNode *ln;
  struct attr *at;
- int ret=ERR_OK, i;
+ int ret=ERR_OK;
  int port;
  
  
@@ -416,14 +379,11 @@ int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) {
  
  attr=createEmptyList();
  pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_READ_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL))==NULL ) {
-  ret=ERR_NET;
+ if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
   goto end;
  }
  
  for (ln=attr->first; ln!=NULL; ln=ln->next) {
   at=ln->data;
   if ( at->attr==ATTR_PORT_STATISTICS && at->size>=49 && (port=(int)(*(char*)at->data)-1)>=0 && port<nga->current->ports ) {
@@ -434,10 +394,9 @@ int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) {
   }
  }
  
- destroyList(attr, (void(*)(void*))freeAttr);
  
  end:
+ destroyList(attr, (void(*)(void*))freeAttr);
  
  return ret;
  
@@ -449,41 +408,13 @@ int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) {
 int ngadmin_resetPortsStatistics (struct ngadmin *nga) {
  
  List *attr;
- int ret=ERR_OK, i;
- char err;
- unsigned short attr_error;
- if ( nga==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
  
  
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
  pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
-  goto end;
- }
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
-  goto end;
- }
  
  
- end:
- return ret;
+ return writeRequest(nga, attr);
  
 }
 
@@ -493,9 +424,7 @@ int ngadmin_resetPortsStatistics (struct ngadmin *nga) {
 int ngadmin_changePassword (struct ngadmin *nga, const char* pass) {
  
  List *attr;
- int ret=ERR_OK, i;
- char err;
- unsigned short attr_error;
+ int ret=ERR_OK;
  
  
  if ( nga==NULL || pass==NULL ) {
@@ -506,20 +435,8 @@ int ngadmin_changePassword (struct ngadmin *nga, const char* pass) {
  
  
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
  pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
-  goto end;
- }
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
+ if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
   goto end;
  }
  
@@ -542,7 +459,7 @@ int ngadmin_getStormFilterState (struct ngadmin *nga, int *s) {
  List *attr;
  ListNode *ln;
  struct attr *at;
- int ret=ERR_OK, i;
+ int ret=ERR_OK;
  
  
  if ( nga==NULL || s==NULL ) {
@@ -554,14 +471,11 @@ int ngadmin_getStormFilterState (struct ngadmin *nga, int *s) {
  
  attr=createEmptyList();
  pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_READ_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL))==NULL ) {
-  ret=ERR_NET;
+ if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
   goto end;
  }
  
  for (ln=attr->first; ln!=NULL; ln=ln->next) {
   at=ln->data;
   if ( at->attr==ATTR_STORM_ENABLE && at->size>=1 ) {
@@ -570,10 +484,9 @@ int ngadmin_getStormFilterState (struct ngadmin *nga, int *s) {
   }
  }
  
- destroyList(attr, (void(*)(void*))freeAttr);
  
  end:
+ destroyList(attr, (void(*)(void*))freeAttr);
  
  return ret;
  
@@ -585,40 +498,13 @@ int ngadmin_getStormFilterState (struct ngadmin *nga, int *s) {
 int ngadmin_setStormFilterState (struct ngadmin *nga, int s) {
  
  List *attr;
- int ret=ERR_OK, i;
- char err;
- unsigned short attr_error;
- if ( nga==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
  
  
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
  pushBackList(attr, newByteAttr(ATTR_STORM_ENABLE, s!=0));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
-  goto end;
- }
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
-  goto end;
- }
  
  
- end:
- return ret;
+ return writeRequest(nga, attr);
  
 }
 
@@ -642,25 +528,21 @@ int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports) {
  
  attr=createEmptyList();
  pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_READ_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL))==NULL ) {
-  ret=ERR_NET;
+ if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
   goto end;
  }
  
  for (ln=attr->first; ln!=NULL; ln=ln->next) {
   at=ln->data;
-  if ( at->attr==ATTR_STORM_BITRATE && at->size>=5 && (i=*(char*)(at->data)-1)>=0 && i<nga->current->ports ) {
+  if ( at->attr==ATTR_STORM_BITRATE && at->size>=5 && (i=(int)*(char*)(at->data)-1)>=0 && i<nga->current->ports ) {
    ports[i]=ntohl(*(int*)(1+(char*)at->data));
   }
  }
  
- destroyList(attr, (void(*)(void*))freeAttr);
  
  end:
+ destroyList(attr, (void(*)(void*))freeAttr);
  
  return ret;
  
@@ -672,9 +554,7 @@ int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports) {
 int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports) {
  
  List *attr;
- int ret=ERR_OK, i;
- char err;
- unsigned short attr_error;
+ int i;
  char *p;
  
  
@@ -686,7 +566,6 @@ int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports) {
  
  
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
  
  for (i=0; i<nga->current->ports; ++i) {
   if ( ports[i]>=0 && ports[i]<=11 ) {
@@ -697,25 +576,8 @@ int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports) {
   }
  }
  
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
-  goto end;
- }
  
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
-  goto end;
- }
- end:
- return ret;
+ return writeRequest(nga, attr);
  
 }
 
@@ -740,14 +602,11 @@ int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) {
  attr=createEmptyList();
  pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
  pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_READ_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL))==NULL ) {
-  ret=ERR_NET;
+ if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
   goto end;
  }
  
  for (ln=attr->first; ln!=NULL; ln=ln->next) {
   at=ln->data;
   if ( at->attr==ATTR_BITRATE_INPUT && at->size>=5 && (i=*(char*)(at->data)-1)>=0 && i<nga->current->ports ) {
@@ -757,10 +616,9 @@ int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) {
   }
  }
  
- destroyList(attr, (void(*)(void*))freeAttr);
  
  end:
+ destroyList(attr, (void(*)(void*))freeAttr);
  
  return ret;
  
@@ -772,9 +630,7 @@ int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) {
 int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports) {
  
  List *attr;
- int ret=ERR_OK, i;
- char err;
- unsigned short attr_error;
+ int i;
  char *p;
  
  
@@ -786,7 +642,6 @@ int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports) {
  
  
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
  
  for (i=0; i<nga->current->ports; ++i) {
   if ( ports[2*i+0]>=0 && ports[2*i+0]<=11 ) {
@@ -803,25 +658,8 @@ int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports) {
   }
  }
  
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
-  goto end;
- }
  
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
-  goto end;
- }
- end:
- return ret;
+ return writeRequest(nga, attr);
  
 }
 
@@ -833,7 +671,7 @@ int ngadmin_getQOSMode (struct ngadmin *nga, int *s) {
  List *attr;
  ListNode *ln;
  struct attr *at;
- int ret=ERR_OK, i;
+ int ret=ERR_OK;
  
  
  if ( nga==NULL || s==NULL ) {
@@ -845,14 +683,11 @@ int ngadmin_getQOSMode (struct ngadmin *nga, int *s) {
  
  attr=createEmptyList();
  pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_READ_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL))==NULL ) {
-  ret=ERR_NET;
+ if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
   goto end;
  }
  
  for (ln=attr->first; ln!=NULL; ln=ln->next) {
   at=ln->data;
   if ( at->attr==ATTR_QOS_TYPE && at->size>=1 ) {
@@ -861,10 +696,9 @@ int ngadmin_getQOSMode (struct ngadmin *nga, int *s) {
   }
  }
  
- destroyList(attr, (void(*)(void*))freeAttr);
  
  end:
+ destroyList(attr, (void(*)(void*))freeAttr);
  
  return ret;
  
@@ -875,40 +709,17 @@ int ngadmin_getQOSMode (struct ngadmin *nga, int *s) {
 int ngadmin_setQOSMode (struct ngadmin *nga, int s) {
  
  List *attr;
- int ret=ERR_OK, i;
- char err;
- unsigned short attr_error;
  
  
- if ( nga==NULL || s<1 || s>2 ) {
+ if ( s<QOS_PORT || s>QOS_DOT ) {
   return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
  }
  
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
  pushBackList(attr, newByteAttr(ATTR_QOS_TYPE, s));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
-  goto end;
- }
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
-  goto end;
- }
  
- end:
  
- return ret;
+ return writeRequest(nga, attr);
  
 }
 
@@ -920,7 +731,7 @@ int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) {
  List *attr;
  ListNode *ln;
  struct attr *at;
- int ret=ERR_OK, i;
+ int ret=ERR_OK;
  char *p;
  
  
@@ -933,11 +744,7 @@ int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) {
  
  attr=createEmptyList();
  pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_READ_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_READ_REP, NULL, NULL))==NULL ) {
-  ret=ERR_NET;
+ if ( (ret=readRequest(nga, attr))<0 ) {
   goto end;
  }
  
@@ -949,10 +756,10 @@ int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) {
   }
  }
  
- destroyList(attr, (void(*)(void*))freeAttr);
  
  end:
+ destroyList(attr, (void(*)(void*))freeAttr);
  
  return ret;
  
@@ -964,9 +771,7 @@ int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) {
 int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports) {
  
  List *attr;
- int ret=ERR_OK, i;
- char err;
- unsigned short attr_error;
+ int i;
  char *p;
  
  
@@ -978,7 +783,6 @@ int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports) {
  
  
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
  
  for (i=0; i<nga->current->ports; ++i) {
   if ( ports[i]>=PRIO_HIGH && ports[i]<=PRIO_LOW ) {
@@ -989,22 +793,50 @@ int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports) {
   }
  }
  
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
-  goto end;
- }
  
- destroyList(attr, (void(*)(void*))freeAttr);
+ return writeRequest(nga, attr);
+}
+
+
+
+// --------------------------------------
+int ngadmin_restart (struct ngadmin *nga) {
  
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
+ List *attr;
+ attr=createEmptyList();
+ pushBackList(attr, newByteAttr(ATTR_RESTART, 1));
+ return writeRequest(nga, attr);
+}
+
+
+
+// ---------------------------------------
+int ngadmin_defaults (struct ngadmin *nga) {
+ List *attr;
+ int ret=ERR_OK;
+ attr=createEmptyList();
+ pushBackList(attr, newByteAttr(ATTR_DEFAULTS, 1));
+ if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
   goto end;
  }
  
  
+ // successful: delog and clean list
+ free(nga->swi_tab);
+ nga->swi_tab=NULL;
+ nga->swi_count=0;
+ nga->current=NULL;
  end:
  
  return ret;
@@ -1013,42 +845,46 @@ int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports) {
 
 
 
-// --------------------------------------
-int ngadmin_restart (struct ngadmin *nga) {
+// -----------------------------------------------------
+int ngadmin_getMirror (struct ngadmin *nga, char *ports) {
  
  List *attr;
+ ListNode *ln;
+ struct attr *at;
+ struct swi_attr *sa;
  int ret=ERR_OK, i;
- char err;
- unsigned short attr_error;
+ unsigned char *p;
  
  
- if ( nga==NULL ) {
+ if ( nga==NULL || ports==NULL ) {
   return ERR_INVARG;
- } else if ( nga->current==NULL ) {
+ } else if ( (sa=nga->current)==NULL ) {
   return ERR_NOTLOG;
  }
  
  
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
- pushBackList(attr, newByteAttr(ATTR_RESTART, 1));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
+ pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
+ if ( (ret=readRequest(nga, attr))<0 ) {
   goto end;
  }
  
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
-  goto end;
+ for (ln=attr->first; ln!=NULL; ln=ln->next) {
+  at=ln->data;
+  p=at->data;
+  if ( at->attr==ATTR_MIRROR && at->size>=2+sa->ports/8 && p[0]<=nga->current->ports ) {
+   ports[0]=p[0];
+   for (i=1; i<=sa->ports; ++i) { // FIXME: if ports>8
+    ports[i]=(p[2]>>(sa->ports-i))&1;
+   }
+   break;
+  }
  }
  
  
  end:
+ destroyList(attr, (void(*)(void*))freeAttr);
  
  return ret;
  
@@ -1056,52 +892,229 @@ int ngadmin_restart (struct ngadmin *nga) {
 
 
 
-// ---------------------------------------
-int ngadmin_defaults (struct ngadmin *nga) {
+// -----------------------------------------------------------
+int ngadmin_setMirror (struct ngadmin *nga, const char *ports) {
  
  List *attr;
- int ret=ERR_OK, i;
- char err;
unsigned short attr_error;
+ int i;
+ char *p;
struct swi_attr *sa;
  
  
  if ( nga==NULL ) {
   return ERR_INVARG;
- } else if ( nga->current==NULL ) {
+ } else if ( (sa=nga->current)==NULL ) {
   return ERR_NOTLOG;
  }
  
  
+ p=malloc(3); // FIXME: if ports>8
+ memset(p, 0, 3);
+ if ( ports!=NULL && ports[0]>0 && ports[0]<=sa->ports ) {
+  p[0]=ports[0];
+  for (i=1; i<=sa->ports; ++i) {
+   if ( i!=p[0] ) {
+    p[2]|=(ports[i]&1)<<(sa->ports-i);
+   }
+  }
+ }
  attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
- pushBackList(attr, newByteAttr(ATTR_DEFAULTS, 1));
- pushBackList(attr, newEmptyAttr(ATTR_END));
- i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
- destroyList(attr, (void(*)(void*))freeAttr);
- if ( i<0 || (attr=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error))==NULL ) {
-  ret=ERR_NET;
+ pushBackList(attr, newAttr(ATTR_MIRROR, 3, p));
+ return writeRequest(nga, attr);
+}
+
+
+
+// ----------------------------------------------------------------
+int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic) {
+ List *attr;
+ ListNode *ln;
+ struct attr *at;
+ struct swi_attr *sa;
+ int ret=ERR_OK;
+ unsigned char *p;
+ unsigned short *s;
+ if ( nga==NULL || ic==NULL ) {
+  return ERR_INVARG;
+ } else if ( (sa=nga->current)==NULL ) {
+  return ERR_NOTLOG;
+ }
+ /*
+ ATTR_IGMP_ENABLE_VLAN
+ ATTR_IGMP_BLOCK_UNK
+ ATTR_IGMP_VALID_V3
+ Apparently, read-querying theses attributes at the same time causes the switch to reply garbage. 
+ Here we are forced to do like the official win app and send a separate request for each attribute. 
+ */
+ attr=createEmptyList();
+ memset(ic, 0, sizeof(struct igmp_conf));
+ pushBackList(attr, newEmptyAttr(ATTR_IGMP_ENABLE_VLAN));
+ if ( (ret=readRequest(nga, attr))<0 ) {
   goto end;
  }
  
- destroyList(attr, (void(*)(void*))freeAttr);
+ for (ln=attr->first; ln!=NULL; ln=ln->next) {
+  at=ln->data;
+  s=at->data;
+  if ( at->attr==ATTR_IGMP_ENABLE_VLAN && at->size>=4 ) {
+   ic->enable= ntohs(s[0])!=0 ;
+   ic->vlan=htons(s[1]);
+   break;
+  }
+ }
+ clearList(attr, (void(*)(void*))freeAttr);
  
- if ( err==7 && attr_error==ATTR_PASSWORD ) {
-  ret=ERR_BADPASS;
+ pushBackList(attr, newEmptyAttr(ATTR_IGMP_BLOCK_UNK));
+ if ( (ret=readRequest(nga, attr))<0 ) {
   goto end;
  }
  
+ for (ln=attr->first; ln!=NULL; ln=ln->next) {
+  at=ln->data;
+  p=at->data;
+  if ( at->attr==ATTR_IGMP_BLOCK_UNK && at->size>=1 ) {
+   ic->block= p[0]!=0 ;
+   break;
+  }
+ }
+ clearList(attr, (void(*)(void*))freeAttr);
+ pushBackList(attr, newEmptyAttr(ATTR_IGMP_VALID_V3));
+ if ( (ret=readRequest(nga, attr))<0 ) {
+  goto end;
+ }
+ for (ln=attr->first; ln!=NULL; ln=ln->next) {
+  at=ln->data;
+  p=at->data;
+  if ( at->attr==ATTR_IGMP_VALID_V3 && at->size>=1 ) {
+   ic->validate= p[0]!=0 ;
+   break;
+  }
+ }
  
- // successful: delog and clean list
- free(nga->swi_tab);
- nga->swi_tab=NULL;
- nga->swi_count=0;
- nga->current=NULL;
  
  
  end:
+ destroyList(attr, (void(*)(void*))freeAttr);
  
  return ret;
  
 }
 
 
+
+// ----------------------------------------------------------------------
+int ngadmin_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic) {
+ List *attr;
+ short *s;
+ struct swi_attr *sa;
+ if ( nga==NULL || ic==NULL ) {
+  return ERR_INVARG;
+ } else if ( (sa=nga->current)==NULL ) {
+  return ERR_NOTLOG;
+ }
+ s=malloc(2*sizeof(short));
+ s[0]=htons(ic->enable!=false);
+ s[1]=htons(ic->vlan&0x0FFF);
+ attr=createEmptyList();
+ pushBackList(attr, newAttr(ATTR_IGMP_ENABLE_VLAN, 2*sizeof(short), s));
+ pushBackList(attr, newByteAttr(ATTR_IGMP_BLOCK_UNK, ic->block!=false ));
+ pushBackList(attr, newByteAttr(ATTR_IGMP_VALID_V3, ic->validate!=false ));
+ return writeRequest(nga, attr);
+}
+
+
+
+// ----------------------------------------------------------------------
+int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb) {
+ List *attr;
+ ListNode *ln;
+ struct attr *at;
+ int i, ret=ERR_OK;
+ struct swi_attr *sa;
+ char *p;
+ if ( nga==NULL || ct==NULL ) {
+  return ERR_INVARG;
+ } else if ( (sa=nga->current)==NULL ) {
+  return ERR_NOTLOG;
+ }
+ attr=createEmptyList();
+ for (i=0; i<nb; ++i) {
+  if ( ct[i].port>=1 && ct[i].port<=sa->ports ) {
+   
+   p=malloc(2);
+   p[0]=ct[i].port;
+   p[1]=1;
+   pushBackList(attr, newAttr(ATTR_CABLETEST_DO, 2, p));
+   
+   ret=writeRequest(nga, attr);
+   attr=NULL;
+   if ( ret<0 ) goto end;
+   
+   // the list is destroyed by writeRequest, so we need to recreate it
+   attr=createEmptyList();
+   pushBackList(attr, newByteAttr(ATTR_CABLETEST_RESULT, ct[i].port));
+   
+   if ( (ret=readRequest(nga, attr))<0 ) goto end;
+   
+   for (ln=attr->first; ln!=NULL; ln=ln->next) {
+    at=ln->data;
+    p=at->data;
+    if ( at->attr==ATTR_CABLETEST_RESULT && at->size>=9 && p[0]==ct[i].port ) {
+     ct[i].v1=ntohl(*(int*)&p[1]);
+     ct[i].v2=ntohl(*(int*)&p[5]);
+     break;
+    }
+   }
+   
+   // just empty the list, it will be used at next iteration
+   clearList(attr, (void(*)(void*))freeAttr);
+   
+  }
+ }
+ end:
+ destroyList(attr, (void(*)(void*))freeAttr);
+ return ret;
+}
+
+
+
index b5d930e4dbecc74f68964343357e7794c1fc13fe..a71df2eaa9740bf2b80c06a103a0025828e80484 100644 (file)
@@ -189,7 +189,7 @@ struct attr* newIntAttr (unsigned short attr, int value) {
  
  int *v=malloc(sizeof(int));
  
- *v=value;
+ *v=htonl(value);
  
  return newAttr(attr, sizeof(int), v);
  
@@ -209,10 +209,9 @@ void freeAttr (struct attr *at) {
 
 
 
-// ------------------------------------------------------------------------------------------
-List* extractPacketAttributes (struct ng_packet *np, char *error, unsigned short *attr_error) {
+// -----------------------------------------------------------------------------------------------------
+void extractPacketAttributes (struct ng_packet *np, char *error, unsigned short *attr_error, List *attr) {
  
- List *l;
  struct attr *at;
  
  
@@ -224,8 +223,6 @@ List* extractPacketAttributes (struct ng_packet *np, char *error, unsigned short
   *attr_error=ntohs(np->nh->attr);
  }
  
- l=createEmptyList();
  while ( getPacketTotalSize(np)<np->maxlen ) {
   
   at=malloc(sizeof(struct attr));
@@ -244,7 +241,7 @@ List* extractPacketAttributes (struct ng_packet *np, char *error, unsigned short
    memcpy(at->data, np->ah->data, at->size);
   }
   
-  pushBackList(l, at);
+  pushBackList(attr, at);
   
   if ( at->attr==ATTR_END ) {
    break;
@@ -255,8 +252,6 @@ List* extractPacketAttributes (struct ng_packet *np, char *error, unsigned short
  }
  
  
- return l;
 }
 
 
index ee832f8ef8954afcbdf7391f81e6bf368b35cb5e..4b4407b094ec82456f28ff689a5605389a0514aa 100644 (file)
@@ -24,8 +24,8 @@ struct ng_header {
  char unk2; // always 0
  unsigned short attr; // attribute code which caused error
  char unk3[2]; // always 0
- char client_mac[6];
- char switch_mac[6];
+ char client_mac[ETH_ALEN];
+ char switch_mac[ETH_ALEN];
  unsigned int seqnum;
  char proto_id[4]; // always "NSDP"
  char unk4[4]; // always 0
@@ -106,7 +106,7 @@ struct attr* newIntAttr (unsigned short attr, int value);
 void freeAttr (struct attr *at);
 
 // 
-List* extractPacketAttributes (struct ng_packet *np, char *error, unsigned short *attr_error);
+void extractPacketAttributes (struct ng_packet *np, char *error, unsigned short *attr_error, List *attr);
 
 // 
 void extractSwitchAttributes (struct swi_attr *sa, const List *l);