]> git.sur5r.net Git - ngadmin/commitdiff
Lib: source refactor.
authordarkcoven <admin@darkcoven.tk>
Mon, 1 Apr 2013 16:49:13 +0000 (18:49 +0200)
committerdarkcoven <admin@darkcoven.tk>
Mon, 1 Apr 2013 16:49:13 +0000 (18:49 +0200)
Changed indentation rules.
Move attributes encoding and decoding in a separate file.
Reorganized functions and declarations in two groups: low and high level.

lib/ngadmin.h
lib/src/attr.c [new file with mode: 0644]
lib/src/attr.h [new file with mode: 0644]
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 81daf25a23169b813cc3f91dc3b0695acdb3deb7..1f48f2fd738f07a0d01bfe452e11e001676f39ea 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <stdbool.h>
 #include <arpa/inet.h>
+
 #include <netinet/ether.h>
 
 
  * This enum lists all the error codes the library can return to user. 
  **/
 enum {
- ERR_OK=0,                     /**< no error */
- ERR_NET=-1,                   /**< network error */
- ERR_NOTLOG=-2,                /**< not logged */
- ERR_DENIED=-3,                /**< access denied */
- ERR_BADPASS=-4,               /**< bad password */
- ERR_BADID=-5,                         /**< bad switch id */
- ERR_INVARG=-6,                /**< invalid argument */
- ERR_TIMEOUT=-7,               /**< timeout */
- ERR_NOTIMPL=-8                        /**< not implemented */
+       ERR_OK = 0,                     /**< no error */
+       ERR_NET = -1,                   /**< network error */
+       ERR_NOTLOG = -2,                /**< not logged */
+       ERR_DENIED = -3,                /**< access denied */
+       ERR_BADPASS = -4,               /**< bad password */
+       ERR_BADID = -5,                 /**< bad switch id */
+       ERR_INVARG = -6,                /**< invalid argument */
+       ERR_TIMEOUT = -7,               /**< timeout */
+       ERR_MEM = -8,                   /**< out of memory */
+       ERR_NOTIMPL = -8                /**< not implemented */
 };
 
 
@@ -63,10 +65,11 @@ enum {
  * This enum lists all the speeds a port can have. 
  **/
 enum {
- SPEED_DOWN=0,                         /**< link down */
- SPEED_10=1,                   /**< 10 Mb/s */
- SPEED_100=4,                  /**< 100 Mb/s */
- SPEED_1000=5                  /**< 1000 Mb/s */
+       SPEED_UNK = -1,                 /**< unknown status */
+       SPEED_DOWN = 0,                 /**< link down */
+       SPEED_10 = 1,                   /**< 10 Mb/s */
+       SPEED_100 = 4,                  /**< 100 Mb/s */
+       SPEED_1000 = 5                  /**< 1000 Mb/s */
 };
 
 
@@ -76,11 +79,11 @@ enum {
  * This enum lists all the VLAN types available
  **/
 enum {
VLAN_DISABLED=0,              /**< VLAN disabled */
VLAN_PORT_BASIC=1,            /**< port basic */
VLAN_PORT_ADV=2,              /**< port advanced */
VLAN_DOT_BASIC=3,             /**< 802.1q basic */
VLAN_DOT_ADV=4                        /**< 802.1q advanced */
      VLAN_DISABLED = 0,              /**< VLAN disabled */
      VLAN_PORT_BASIC = 1,            /**< port basic */
      VLAN_PORT_ADV = 2,              /**< port advanced */
      VLAN_DOT_BASIC = 3,             /**< 802.1q basic */
      VLAN_DOT_ADV = 4                /**< 802.1q advanced */
 };
 
 
@@ -89,10 +92,10 @@ enum {
  * This enum lists all the VLAN specifications a port can have. 
  **/
 enum {
VLAN_UNSPEC=0xFF,             /**< unspecified */
VLAN_NO=0,                    /**< not present */
VLAN_UNTAGGED=1,              /**< present, untagged */
VLAN_TAGGED=2                 /**< present, tagged */
      VLAN_UNSPEC = 0xFF,             /**< unspecified */
      VLAN_NO = 0,                    /**< not present */
      VLAN_UNTAGGED = 1,              /**< present, untagged */
      VLAN_TAGGED = 2                 /**< present, tagged */
 };
 
 
@@ -114,8 +117,8 @@ enum {
  * This enum lists all the availables QoS modes. 
  **/
 enum {
QOS_PORT=1,                   /**< port based */
QOS_DOT=2                     /**< 802.1p based */
      QOS_PORT = 1,                   /**< port based */
      QOS_DOT = 2                     /**< 802.1p based */
 };
 
 
@@ -124,11 +127,11 @@ enum {
  * This enum lists all the priorities a port can have. 
  **/
 enum {
PRIO_UNSPEC=-1,               /**< unspecified */
PRIO_HIGH=1,                  /**< high */
PRIO_MED=2,                   /**< medium */
PRIO_NORM=3,                  /**< normal */
PRIO_LOW=4                    /**< low */
      PRIO_UNSPEC = -1,               /**< unspecified */
      PRIO_HIGH = 1,                  /**< high */
      PRIO_MED = 2,                   /**< medium */
      PRIO_NORM = 3,                  /**< normal */
      PRIO_LOW = 4                    /**< low */
 };
 
 
@@ -139,19 +142,19 @@ enum {
  * This enum lists all the available bitrates. 
  **/
 enum {
BITRATE_UNSPEC=-1,    /**< unspecified */
- BITRATE_NOLIMIT=0,    /**< unlimited */ 
BITRATE_512K=1,       /**< 512 Kb/s */
BITRATE_1M=2,                 /**< 1 Mb/s */
BITRATE_2M=3,                 /**< 2 Mb/s */
BITRATE_4M=4,                 /**< 4 Mb/s */
BITRATE_8M=5,                 /**< 8 Mb/s */
BITRATE_16M=6,        /**< 16 Mb/s */
BITRATE_32M=7,        /**< 32 Mb/s */
BITRATE_64M=8,        /**< 64 Mb/s */
BITRATE_128M=9,       /**< 128 Mb/s */
BITRATE_256M=10,      /**< 256 Mb/s */
BITRATE_512M=11       /**< 512 Mb/s */
      BITRATE_UNSPEC = -1,    /**< unspecified */
+       BITRATE_NOLIMIT = 0,    /**< unlimited */
      BITRATE_512K = 1,       /**< 512 Kb/s */
      BITRATE_1M = 2,         /**< 1 Mb/s */
      BITRATE_2M = 3,         /**< 2 Mb/s */
      BITRATE_4M = 4,         /**< 4 Mb/s */
      BITRATE_8M = 5,         /**< 8 Mb/s */
      BITRATE_16M = 6,        /**< 16 Mb/s */
      BITRATE_32M = 7,        /**< 32 Mb/s */
      BITRATE_64M = 8,        /**< 64 Mb/s */
      BITRATE_128M = 9,       /**< 128 Mb/s */
      BITRATE_256M = 10,      /**< 256 Mb/s */
      BITRATE_512M = 11       /**< 512 Mb/s */
 };
 
 
@@ -171,10 +174,10 @@ struct ngadmin;
  * Represents the network configuration of a switch. 
  */
 struct net_conf {
struct in_addr ip;            /**< IP */
struct in_addr netmask;       /**< netmask */
struct in_addr gw;            /**< gateway IP */
bool dhcp;                    /**< DHCP enabled */
      struct in_addr ip;              /**< IP */
      struct in_addr netmask;         /**< netmask */
      struct in_addr gw;              /**< gateway IP */
      bool dhcp;                      /**< DHCP enabled */
 };
 
 
@@ -183,12 +186,12 @@ struct net_conf {
  * Represents the main characteristics of a switch. 
  */
 struct swi_attr {
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 */
struct ether_addr mac;                /**< MAC address */
struct net_conf nc;           /**< network configuration */
      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 */
      struct ether_addr mac;          /**< MAC address */
      struct net_conf nc;             /**< network configuration */
 };
 
 
@@ -197,9 +200,9 @@ struct swi_attr {
  * Represents statistics of a particular port. 
  */
 struct port_stats {
unsigned long long recv;      /**< packets received */
unsigned long long sent;      /**< packets sent */
unsigned long long crc;       /**< CRC errors */
      unsigned long long recv;        /**< packets received */
      unsigned long long sent;        /**< packets sent */
      unsigned long long crc;         /**< CRC errors */
 };
 
 
@@ -208,10 +211,10 @@ struct port_stats {
  * Represents the IGMP snooping configuration of a switch. 
  */
 struct igmp_conf {
bool enable;                  /**< IGMP snooping enabled */
unsigned short vlan;          /**< VLAN on which IGMP snooping is done */
bool validate;                        /**< validate IGMPv3 headers */
bool block;                   /**< block unknown multicast addresses */
      bool enable;                    /**< IGMP snooping enabled */
      unsigned short vlan;            /**< VLAN on which IGMP snooping is done */
      bool validate;                  /**< validate IGMPv3 headers */
      bool block;                     /**< block unknown multicast addresses */
 };
 
 
@@ -219,9 +222,9 @@ struct igmp_conf {
  * Cabletest result.
  */
 struct cabletest {
char port;                    /**< port */
int v1;                       /**< raw value 1 */
int v2;                       /**< raw value 2 */
      char port;              /**< port */
      int v1;                 /**< raw value 1 */
      int v2;                 /**< raw value 2 */
 };
 
 
diff --git a/lib/src/attr.c b/lib/src/attr.c
new file mode 100644 (file)
index 0000000..3e12690
--- /dev/null
@@ -0,0 +1,465 @@
+
+#include <ngadmin.h>
+
+#include "lib.h"
+#include "attr.h"
+#include "protocol.h"
+
+
+#define ATTR_HANDLER_ENTRY(at, sz, enc, dec)   {.attr = at, .size = sz, .encode = enc, .decode = dec}
+
+
+
+static bool bool_endecode (struct attr *at, unsigned char ports UNUSED)
+{
+       *(char*)at->data = (*(char*)at->data != 0);
+       
+       return true;
+}
+
+
+static bool ports_status_decode (struct attr *at, unsigned char ports)
+{
+       struct attr_port_status *ps = at->data;
+       
+       if (ps->port < 1 || ps->port > ports)
+               return false;
+       
+       switch (ps->status) {
+       case SPEED_DOWN:
+       case SPEED_10:
+       case SPEED_100:
+       case SPEED_1000:
+               break;
+       default:
+               return false;
+       }
+       
+       return true;
+}
+
+
+static bool port_stat_decode (struct attr *at, unsigned char ports)
+{
+       struct attr_port_stat *ps = at->data;
+       unsigned long long *v;
+       
+       if (ps->port < 1 || ps->port > ports)
+               return false;
+       
+       for (v = &ps->recv; ((char*)v) - ((char*)ps) < (int)sizeof(struct attr_port_stat); v++)
+               *v = be64toh(*v);
+       
+       
+       return true;
+}
+
+
+static bool bitrate_decode (struct attr *at, unsigned char ports)
+{
+       struct attr_bitrate *sb = at->data;
+       
+       if (sb->port < 1 || sb->port > ports)
+               return false;
+       
+       sb->bitrate = ntohl(sb->bitrate);
+       if (sb->bitrate < BITRATE_UNSPEC || sb->bitrate > BITRATE_512M)
+               return false;
+       
+       return true;
+}
+
+
+static bool bitrate_encode (struct attr *at, unsigned char ports)
+{
+       struct attr_bitrate *sb = at->data;
+       
+       if (sb->port < 1 || sb->port > ports)
+               return false;
+       
+       if (sb->bitrate < BITRATE_UNSPEC || sb->bitrate > BITRATE_512M)
+               return false;
+       sb->bitrate = htonl(sb->bitrate);
+       
+       return true;
+}
+
+
+static bool qos_mode_endecode (struct attr *at, unsigned char ports UNUSED)
+{
+       unsigned char v = *(char*)at->data;
+       
+       return (v == QOS_PORT || v == QOS_DOT);
+}
+
+
+static bool qos_endecode (struct attr *at, unsigned char ports)
+{
+       struct attr_qos *aq = at->data;
+       
+       if (aq->port < 1 || aq->port > ports)
+               return false;
+       
+       return (aq->prio >= PRIO_HIGH && aq->prio <= PRIO_LOW);
+}
+
+
+static bool pvid_decode (struct attr *at, unsigned char ports)
+{
+       struct attr_pvid *ap= at->data;
+       
+       if (ap->port < 1 || ap->port > ports)
+               return false;
+       
+       ap->vlan = ntohs(ap->vlan);
+       
+       return (ap->vlan >= VLAN_MIN && ap->vlan <= VLAN_MAX);
+}
+
+
+static bool pvid_encode (struct attr *at, unsigned char ports)
+{
+       struct attr_pvid *ap= at->data;
+       
+       if (ap->port < 1 || ap->port > ports)
+               return false;
+       
+       if (ap->vlan < VLAN_MIN || ap->vlan > VLAN_MAX)
+               return false;
+       
+       ap->vlan = htons(ap->vlan);
+       
+       return true;
+}
+
+
+static bool vlan_destroy_encode (struct attr *at, unsigned char ports UNUSED)
+{
+       unsigned short v = *(unsigned short*)at->data;
+       
+       if (v < VLAN_MIN || v > VLAN_MAX)
+               return false;
+       
+       *(unsigned short*)at->data = htons(v);
+       
+       return true;
+}
+
+
+static bool mirror_decode (struct attr *at, unsigned char ports)
+{
+       unsigned char *r = at->data, *p;
+       int port;
+       
+       
+       if (at->size != 3 + ((ports - 1) >> 3))
+               return false;
+       
+       /* r[0] == 0 is allowed and means mirroring is disabled */
+       if (r[0] > ports)
+               return false;
+       
+       p = malloc(1 + ports);
+       if (p == NULL)
+               return false;
+       
+       memset(p, 0, 1 + ports);
+       
+       if (r[0] == 0)
+               goto end;
+       
+       p[0] = r[0];
+       
+       for (port = 1; port <= ports; port++)
+               p[port] = (r[2] >> (8 - port)) & 1; /* FIXME: if ports > 8 */
+       
+end:
+       free(at->data);
+       at->data = p;
+       at->size = 1 + ports;
+       
+       
+       return true;
+}
+
+
+static bool mirror_encode (struct attr *at, unsigned char ports)
+{
+       unsigned char *p = at->data, *r;
+       int port;
+       
+       
+       if (at->size != 1 + ports)
+               return false;
+       
+       /* p[0] == 0 is allowed and means mirroring is disabled */
+       if (p[0] > ports)
+               return false;
+       
+       r = malloc(3 + ((ports - 1) >> 3));
+       if (r == NULL)
+               return false;
+       
+       memset(r, 0, 3 + ((ports - 1) >> 3));
+       
+       if (p[0] == 0)
+               goto end;
+       
+       r[0] = p[0];
+       
+       for (port = 1; port <= ports; port++) {
+               if (p[0] != port)
+                       r[2] |= (p[port] & 1) << (8 - port); /* FIXME: if ports > 8 */
+       }
+       
+end:
+       free(at->data);
+       at->data = r;
+       at->size = 3 + ((ports - 1) >> 3);
+       
+       
+       return true;
+}
+
+
+static bool igmp_vlan_decode (struct attr *at, unsigned char ports UNUSED)
+{
+       struct attr_igmp_vlan *aiv = at->data;
+       
+       aiv->enable = ntohs(aiv->enable);
+       if (aiv->enable != 0 && aiv->enable != 1)
+               return false;
+       
+       aiv->vlan = ntohs(aiv->vlan);
+       if (aiv->vlan < VLAN_MIN || aiv->vlan > VLAN_MAX)
+               return false;
+       
+       return true;
+}
+
+
+static bool igmp_vlan_encode (struct attr *at, unsigned char ports UNUSED)
+{
+       struct attr_igmp_vlan *aiv = at->data;
+       
+       if (aiv->enable != 0 && aiv->enable != 1)
+               return false;
+       aiv->enable = htons(aiv->enable);
+       
+       if (aiv->vlan < VLAN_MIN || aiv->vlan > VLAN_MAX)
+               return false;
+       aiv->vlan = htons(aiv->vlan);
+       
+       return true;
+}
+
+
+static bool cabletest_do_encode (struct attr *at, unsigned char ports)
+{
+       struct attr_cabletest_do *acd = at->data;
+       
+       if (acd->port < 1 || acd->port > ports)
+               return false;
+       
+       return (acd->action == 1);
+}
+
+
+static bool cabletest_result_encode (struct attr *at, unsigned char ports)
+{
+       unsigned char v = *(unsigned char*)at->data;
+       
+       return (v >= 1 && v <= ports);
+}
+
+
+static bool cabletest_result_decode (struct attr *at, unsigned char ports)
+{
+       struct attr_cabletest_result *acr = at->data;
+       
+       if (acr->port < 1 || acr->port > ports)
+               return false;
+       
+       acr->v1 = ntohl(acr->v1);
+       acr->v2 = ntohl(acr->v2);
+       
+       return true;
+}
+
+
+static bool cabletest_result_endecode (struct attr *at, unsigned char ports)
+{
+       switch (at->size) {
+       
+       case 1:
+               return cabletest_result_encode(at, ports);
+       
+       case sizeof(struct attr_cabletest_result):
+               return cabletest_result_decode(at, ports);
+       
+       default:
+               return false;
+       }
+}
+
+
+static bool vlan_type_endecode (struct attr *at, unsigned char ports UNUSED)
+{
+       char v = *(char*)at->data;
+       
+       return (v >= VLAN_DISABLED && v <= VLAN_DOT_ADV);
+}
+
+
+static bool vlan_dot_decode (struct attr *at, unsigned char ports)
+{
+       char *r = at->data;
+       struct attr_vlan_dot *avd;
+       int port;
+       
+       
+       if (at->size != (2 + 2 * (1 + ((ports - 1) >> 3))))
+               return false;
+       
+       avd = malloc(sizeof(struct attr_vlan_dot) + ports);
+       if (avd == NULL)
+               return false;
+       
+       avd->vlan = ntohs(*(unsigned short*)r);
+       r += 2;
+       
+       for (port = 0; port < ports; port++) {
+               /* FIXME: if ports > 8 */
+               if ((r[1] >> (7 - port)) & 1)
+                       avd->ports[port] = VLAN_TAGGED;
+               else if ((r[0] >> (7 - port)) & 1)
+                       avd->ports[port] = VLAN_UNTAGGED;
+               else
+                       avd->ports[port] = VLAN_NO;
+       }
+       
+       free(at->data);
+       at->data = avd;
+       at->size = sizeof(struct attr_vlan_dot) + ports;
+       
+       
+       return true;
+}
+
+
+static bool vlan_dot_encode (struct attr *at, unsigned char ports)
+{
+       struct attr_vlan_dot *avd = at->data;
+       char *r, fl;
+       unsigned int size, port;
+       
+       
+       if (avd->vlan < VLAN_MIN || avd->vlan > VLAN_MAX)
+               return false;
+       
+       /* just a header is valid */
+       if (at->size == sizeof(struct attr_vlan_dot))
+               size = 2;
+       else if (at->size == sizeof(struct attr_vlan_dot) + ports)
+               size = (2 + 2 * (1 + ((ports - 1) >> 3)));
+       else
+               return false;
+       
+       r = malloc(size);
+       if (r == NULL)
+               return false;
+       
+       memset(r, 0, size);
+       *(unsigned short*)r = htons(avd->vlan);
+       
+       if (size == 2)
+               goto end;
+       
+       r += 2;
+       
+       for (port = 0; port < ports; port++) {
+               /* FIXME: if ports > 8 */
+               fl = (1 << (7 - port));
+               switch (avd->ports[port]) {
+               case VLAN_TAGGED:
+                       r[1] |= fl;
+               case VLAN_UNTAGGED:
+                       r[0] |= fl;
+               }
+       }
+       
+       r -= 2;
+       
+end:
+       free(at->data);
+       at->data = r;
+       at->size = size;
+       
+       
+       return true;
+}
+
+
+
+/* WARNING: attributes codes MUST be in ascending order */
+static const struct attr_handler attrtab[] = {
+       ATTR_HANDLER_ENTRY(ATTR_MAC, 6, NULL, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_IP, 4, NULL, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_NETMASK, 4, NULL, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_GATEWAY, 4, NULL, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_DHCP, 2, NULL, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_RESTART, 1, NULL, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_DEFAULTS, 1, NULL, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_PORT_STATUS, sizeof(struct attr_port_status), NULL, ports_status_decode),
+       ATTR_HANDLER_ENTRY(ATTR_PORT_STATISTICS, sizeof(struct attr_port_stat), NULL, port_stat_decode),
+       ATTR_HANDLER_ENTRY(ATTR_STATS_RESET, 1, bool_endecode, bool_endecode),
+       ATTR_HANDLER_ENTRY(ATTR_CABLETEST_DO, sizeof(struct attr_cabletest_do), cabletest_do_encode, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_CABLETEST_RESULT, 0, cabletest_result_endecode, cabletest_result_endecode),
+       ATTR_HANDLER_ENTRY(ATTR_VLAN_TYPE, 1, vlan_type_endecode, vlan_type_endecode),
+       ATTR_HANDLER_ENTRY(ATTR_VLAN_DOT_CONF, 0, vlan_dot_encode, vlan_dot_decode),
+       ATTR_HANDLER_ENTRY(ATTR_VLAN_DESTROY, 2, vlan_destroy_encode, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_VLAN_PVID, sizeof(struct attr_pvid), pvid_encode, pvid_decode),
+       ATTR_HANDLER_ENTRY(ATTR_QOS_TYPE, 1, qos_mode_endecode, qos_mode_endecode),
+       ATTR_HANDLER_ENTRY(ATTR_QOS_CONFIG, sizeof(struct attr_qos), qos_endecode, qos_endecode),
+       ATTR_HANDLER_ENTRY(ATTR_BITRATE_INPUT, sizeof(struct attr_bitrate), bitrate_encode, bitrate_decode),
+       ATTR_HANDLER_ENTRY(ATTR_BITRATE_OUTPUT, sizeof(struct attr_bitrate), bitrate_encode, bitrate_decode),
+       ATTR_HANDLER_ENTRY(ATTR_STORM_ENABLE, 1, bool_endecode, bool_endecode),
+       ATTR_HANDLER_ENTRY(ATTR_STORM_BITRATE, sizeof(struct attr_bitrate), bitrate_encode, bitrate_decode),
+       ATTR_HANDLER_ENTRY(ATTR_MIRROR, 0, mirror_encode, mirror_decode),
+       ATTR_HANDLER_ENTRY(ATTR_PORTS_COUNT, 1, NULL, NULL),
+       ATTR_HANDLER_ENTRY(ATTR_IGMP_ENABLE_VLAN, sizeof(struct attr_igmp_vlan), igmp_vlan_encode, igmp_vlan_decode),
+       ATTR_HANDLER_ENTRY(ATTR_IGMP_BLOCK_UNK, 1, bool_endecode, bool_endecode),
+       ATTR_HANDLER_ENTRY(ATTR_IGMP_VALID_V3, 1, bool_endecode, bool_endecode)
+};
+
+
+
+const struct attr_handler* getAttrHandler (unsigned short attrcode)
+{
+       const struct attr_handler *ah;
+       const unsigned int tab_size = sizeof(attrtab) / sizeof(struct attr_handler);
+       unsigned int inf, sup, index;
+       
+       
+       inf = 0;
+       sup = tab_size;
+       index = tab_size >> 1;
+       while (index < sup) {
+               ah = &attrtab[index];
+               
+               if (ah->attr > attrcode) {
+                       sup = index;
+                       index -= ((index - inf) >> 1) + ((index - inf) & 1);
+               } else if (ah->attr < attrcode) {
+                       inf = index;
+                       index += ((sup - index) >> 1) + ((sup - index) & 1);
+               } else {
+                       return ah;
+               }
+       }
+       
+       
+       return NULL;
+}
+
+
diff --git a/lib/src/attr.h b/lib/src/attr.h
new file mode 100644 (file)
index 0000000..e297b49
--- /dev/null
@@ -0,0 +1,132 @@
+
+#ifndef DEF_ATTR
+#define DEF_ATTR
+
+
+#include <stdbool.h>
+
+#include "protocol.h"
+
+
+#define ATTR_PRODUCT           0x0001
+#define ATTR_UNK_0002          0x0002
+#define ATTR_NAME              0x0003
+#define ATTR_MAC               0x0004
+#define ATTR_UNK_0005          0x0005
+#define ATTR_IP                        0x0006
+#define ATTR_NETMASK           0x0007
+#define ATTR_GATEWAY           0x0008
+#define ATTR_NEW_PASSWORD      0x0009
+#define ATTR_PASSWORD          0x000A
+#define ATTR_DHCP              0x000B
+#define ATTR_UNK_000C          0x000C
+#define ATTR_FIRM_VER          0x000D
+#define ATTR_UNK_000E          0x000E
+#define ATTR_UNK_000F          0x000F
+#define ATTR_FIRM_UPGRADE      0x0010
+#define ATTR_RESTART           0x0013
+#define ATTR_DEFAULTS          0x0400
+#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
+#define ATTR_VLAN_DESTROY      0x2C00
+#define ATTR_VLAN_PVID         0x3000
+#define ATTR_QOS_TYPE          0x3400
+#define ATTR_QOS_CONFIG                0x3800
+#define ATTR_BITRATE_INPUT     0x4C00
+#define ATTR_BITRATE_OUTPUT    0x5000
+#define ATTR_STORM_ENABLE      0x5400
+#define ATTR_STORM_BITRATE     0x5800
+#define ATTR_MIRROR            0x5C00
+#define ATTR_PORTS_COUNT       0x6000
+#define ATTR_MAX_VLAN          0x6400
+#define ATTR_IGMP_ENABLE_VLAN  0x6800
+#define ATTR_IGMP_BLOCK_UNK    0x6C00
+#define ATTR_IGMP_VALID_V3     0x7000
+#define ATTR_TLV_BITMAP                0x7400
+#define ATTR_END               0xFFFF
+
+#define UNUSED                 __attribute__((unused))
+
+
+struct attr_handler {
+       unsigned short attr;                                    /* attribute code */
+       unsigned int size;                                      /* expected data size */
+       bool (*encode)(struct attr *at, unsigned char ports);   /* encode function */
+       bool (*decode)(struct attr *at, unsigned char ports);   /* decode function */
+};
+
+
+const struct attr_handler* getAttrHandler (unsigned short attrcode);
+
+
+
+
+struct attr_port_status {
+       unsigned char port;
+       unsigned char status;
+       unsigned char unk;
+} __attribute__((packed));
+
+
+struct attr_port_stat {
+       unsigned char port;
+       unsigned long long recv;
+       unsigned long long sent;
+       unsigned long long unk1;
+       unsigned long long unk2;
+       unsigned long long unk3;
+       unsigned long long crc;
+} __attribute__((packed));
+
+
+struct attr_bitrate {
+       unsigned char port;
+       int bitrate;
+} __attribute__((packed));
+
+
+struct attr_qos {
+       unsigned char port;
+       unsigned char prio;
+} __attribute__((packed));
+
+
+struct attr_pvid {
+       unsigned char port;
+       unsigned short vlan;
+} __attribute__((packed));
+
+
+struct attr_igmp_vlan {
+       unsigned short enable;
+       unsigned short vlan;
+} __attribute__((packed));
+
+
+struct attr_cabletest_do {
+       unsigned char port;
+       unsigned char action;
+} __attribute__((packed));
+
+
+struct attr_cabletest_result {
+       unsigned char port;
+       unsigned int v1;
+       unsigned int v2;
+} __attribute__((packed));
+
+
+struct attr_vlan_dot {
+       unsigned short vlan;
+       unsigned char ports[0];
+};
+
+
+#endif
+
index 93aaae9571c8ec89cfac80af980c7cf2778592e4..b1552ec1f098a9ede961dede83acc7d115590ec8 100644 (file)
@@ -3,93 +3,36 @@
 #define DEF_LIB
 
 
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
+#include <arpa/inet.h>
+
 #include <net/if.h>
+#include <netinet/ether.h>
 
 #include <ngadmin.h>
 
 
-#define PASSWORD_MAX   32
-
-
-#define CLIENT_PORT            63321
-#define SWITCH_PORT            63322
-
-#define CODE_READ_REQ          1
-#define CODE_READ_REP          2
-#define CODE_WRITE_REQ         3
-#define CODE_WRITE_REP         4
-
-#define ERROR_READONLY         3
-#define ERROR_INVALID_VALUE    5
-#define ERROR_DENIED           7
-
-#define ATTR_PRODUCT           0x0001
-#define ATTR_UNK_0002          0x0002
-#define ATTR_NAME              0x0003
-#define ATTR_MAC               0x0004
-#define ATTR_UNK_0005          0x0005
-#define ATTR_IP                        0x0006
-#define ATTR_NETMASK           0x0007
-#define ATTR_GATEWAY           0x0008
-#define ATTR_NEW_PASSWORD      0x0009
-#define ATTR_PASSWORD          0x000A
-#define ATTR_DHCP              0x000B
-#define ATTR_UNK_000C          0x000C
-#define ATTR_FIRM_VER          0x000D
-#define ATTR_UNK_000E          0x000E
-#define ATTR_UNK_000F          0x000F
-#define ATTR_FIRM_UPGRADE      0x0010
-#define ATTR_RESTART           0x0013
-#define ATTR_DEFAULTS          0x0400
-#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
-#define ATTR_VLAN_DESTROY      0x2C00
-#define ATTR_VLAN_PVID         0x3000
-#define ATTR_QOS_TYPE          0x3400
-#define ATTR_QOS_CONFIG                0x3800
-#define ATTR_BITRATE_INPUT     0x4C00
-#define ATTR_BITRATE_OUTPUT    0x5000
-#define ATTR_STORM_ENABLE      0x5400
-#define ATTR_STORM_BITRATE     0x5800
-#define ATTR_MIRROR            0x5C00
-#define ATTR_PORTS_COUNT       0x6000
-#define ATTR_MAX_VLAN          0x6400
-#define ATTR_IGMP_ENABLE_VLAN  0x6800
-#define ATTR_IGMP_BLOCK_UNK    0x6C00
-#define ATTR_IGMP_VALID_V3     0x7000
-#define ATTR_TLV_BITMAP                0x7400
-#define ATTR_END               0xFFFF
 
+#define PASSWORD_MAX           32
 
 
 struct ngadmin {
- // network
- int sock;                     // socket
- struct sockaddr_in local;     // local address & port
- struct in_addr brd;           // broadcast address
- char iface[IFNAMSIZ];         // interface
- struct timeval timeout;       // timeout
- struct ether_addr localmac;   // local MAC address
- bool keepbroad;               // keep broadcasting
- bool globalbroad;             // use global broadcast address (255.255.255.255)
- // 
- char password[PASSWORD_MAX];  // password to use to login on switches
- struct swi_attr *swi_tab;     // array of detected switches
- int swi_count;                        // number of detected switches
- struct swi_attr *current;     // administred switch
- int seq;                      // sequence number for packets
+       /* network */
+       int sock;                       /* socket */
+       struct sockaddr_in local;       /* local address & port */
+       struct in_addr brd;             /* broadcast address */
+       char iface[IFNAMSIZ];           /* interface */
+       struct timeval timeout;         /* timeout */
+       struct ether_addr localmac;     /* local MAC address */
+       bool keepbroad;                 /* keep broadcasting */
+       bool globalbroad;               /* use global broadcast address (255.255.255.255) */
+       /* switch properties */
+       char password[PASSWORD_MAX];    /* password to use to login on switches */
+       struct swi_attr *swi_tab;       /* array of detected switches */
+       int swi_count;                  /* number of detected switches */
+       struct swi_attr *current;       /* administred switch */
+       int seq;                        /* sequence number for packets */
 };
 
 
-
 #endif
 
index 4df887e7c4117929019abc497089f5e174c20daa..fce65c3a5db3a8be6b6bacf9a61eef4c5b1b9bb3 100644 (file)
 
-#include "network.h"
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <arpa/inet.h>
 
+#include <net/if.h>
+#include <netinet/ether.h>
+#include <sys/ioctl.h>
 
+#include "attr.h"
+#include "protocol.h"
+#include "network.h"
 
 
-// -----------------------------------
-int startNetwork (struct ngadmin *nga) {
- struct ifreq ifr;
- int ret;
- // create socket
- if ( (nga->sock=socket(AF_INET, SOCK_DGRAM, 0))<0 ) {
-  perror("socket");
-  return nga->sock;
- }
- memset(&ifr, 0, sizeof(struct ifreq));
- strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ-1);
- // get the interface broadcast address
- if ( (ret=ioctl(nga->sock, SIOCGIFBRDADDR, &ifr))<0 ) {
-  perror("ioctl(SIOCGIFBRDADDR)");
-  close(nga->sock);
-  return ret;
- }
- nga->brd=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
- // get the interface MAC address
- if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) {
-  perror("ioctl(SIOCGIFHWADDR)");
-  close(nga->sock);
-  return ret;
- }
- memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
- // bind
- memset(&nga->local, 0, sizeof(struct sockaddr_in));
- nga->local.sin_family=AF_INET;
- nga->local.sin_port=htons(CLIENT_PORT);
- if ( (ret=bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)))<0 ) {
-  perror("bind");
-  close(nga->sock);
-  return ret;
- }
- // allow broadcasting
- ret=1;
- if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) {
-  perror("setsockopt(SO_BROADCAST)");
-  return ret;
- }
- // prevent unicast packets from being routed by setting the TTL to 1
- ret=1;
- if ( (ret=setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)))<0 ) {
-  perror("setsockopt(IP_TTL)");
-  return ret;
- }
- return 0;
+int startNetwork (struct ngadmin *nga)
+{
+       struct ifreq ifr;
+       int ret;
+       
+       
+       /* create socket */
+       nga->sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (nga->sock < 0) {
+               perror("socket");
+               return nga->sock;
+       }
+       
+       memset(&ifr, 0, sizeof(struct ifreq));
+       strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
+       
+       /* get the interface broadcast address */
+       ret = ioctl(nga->sock, SIOCGIFBRDADDR, &ifr);
+       if (ret < 0) {
+               perror("ioctl(SIOCGIFBRDADDR)");
+               close(nga->sock);
+               return ret;
+       }
+       nga->brd = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
+       
+       /* get the interface MAC address */
+       ret = ioctl(nga->sock, SIOCGIFHWADDR, &ifr);
+       if (ret < 0) {
+               perror("ioctl(SIOCGIFHWADDR)");
+               close(nga->sock);
+               return ret;
+       }
+       memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+       
+       /* bind */
+       memset(&nga->local, 0, sizeof(struct sockaddr_in));
+       nga->local.sin_family = AF_INET;
+       nga->local.sin_port = htons(CLIENT_PORT);
+       
+       ret = bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in));
+       if (ret < 0) {
+               perror("bind");
+               close(nga->sock);
+               return ret;
+       }
+       
+       /* allow broadcasting */
+       ret = 1;
+       ret = setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret));
+       if (ret < 0) {
+               perror("setsockopt(SO_BROADCAST)");
+               return ret;
+       }
+       
+       /* prevent unicast packets from being routed by setting the TTL to 1 */
+       ret = 1;
+       ret = setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret));
+       if (ret < 0) {
+               perror("setsockopt(IP_TTL)");
+               return ret;
+       }
+       
+       
+       return 0;
 }
 
 
-
-// ----------------------------------
-int stopNetwork (struct ngadmin *nga) {
- return close(nga->sock);
+int stopNetwork (struct ngadmin *nga)
+{
+       return close(nga->sock);
 }
 
 
-
-// -------------------------------------
-int forceInterface (struct ngadmin *nga) {
- int ret;
- /*
- As described bellow, when you have multiple interfaces, this forces the packet 
- to go to a particular interface. 
- */
- 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)");
-  return ret;
- }
- return 0;
+int forceInterface (struct ngadmin *nga)
+{
+       int ret;
+       
+       
+       /*
+       As described bellow, when you have multiple interfaces, this forces the packet 
+       to go to a particular interface. 
+       */
+       ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1);
+       if (ret < 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;
+       ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret));
+       if (ret <0) {
+               perror("setsockopt(SO_DONTROUTE)");
+               return ret;
+       }
+       
+       
+       return 0;
 }
 
 
-
-// ------------------------------------
-int updateTimeout (struct ngadmin *nga) {
- int ret;
- // specify receive timeout
- if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval)))<0 ) {
-  perror("setsockopt(SO_RCVTIMEO)");
-  return ret;
- }
- return 0;
+int updateTimeout (struct ngadmin *nga)
+{
+       int ret;
+       
+       
+       /* specify receive timeout */
+       ret = setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval));
+       if (ret < 0) {
+               perror("setsockopt(SO_RCVTIMEO)");
+               return ret;
+       }
+       
+       
+       return 0;
 }
 
 
-
-// ----------------------------------------------------------------
-int sendNgPacket (struct ngadmin *nga, char code, const List *attr) {
- char buffer[1500];
- struct ng_packet np;
- ListNode *ln;
- struct attr *at;
- struct sockaddr_in remote;
- const struct swi_attr *sa=nga->current;
- int ret;
- np.buffer=buffer;
- np.maxlen=sizeof(buffer);
- initNgPacket(&np);
- initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , ++nga->seq);
- if ( attr!=NULL ) {
-  for (ln=attr->first; ln!=NULL; ln=ln->next) {
-   at=ln->data;
-   addPacketAttr(&np, at->attr, at->size, at->data);
-  }
- }
- memset(&remote, 0, sizeof(struct sockaddr_in));
- remote.sin_family=AF_INET;
- remote.sin_port=htons(SWITCH_PORT);
- if ( sa!=NULL && !nga->keepbroad ) remote.sin_addr=sa->nc.ip;
- else if ( nga->globalbroad ) remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
- else remote.sin_addr=nga->brd;
- if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) {
-  perror("sendto");
- }
- return ret;
+int sendNgPacket (struct ngadmin *nga, char code, const List *attr)
+{
+       char buffer[1500];
+       struct ng_packet np;
+       struct sockaddr_in remote;
+       const struct swi_attr *sa = nga->current;
+       int ret;
+       
+       
+       np.buffer = buffer;
+       np.maxlen = sizeof(buffer);
+       initNgPacket(&np);
+       initNgHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, ++nga->seq);
+       
+       ret = addPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports);
+       if (ret < 0)
+               return ret;
+       
+       memset(&remote, 0, sizeof(struct sockaddr_in));
+       remote.sin_family = AF_INET;
+       remote.sin_port = htons(SWITCH_PORT);
+       
+       /* destination address selection */
+       if (sa != NULL && !nga->keepbroad)
+               remote.sin_addr = sa->nc.ip;
+       else if (nga->globalbroad)
+               remote.sin_addr.s_addr = htonl(INADDR_BROADCAST);
+       else
+               remote.sin_addr = nga->brd;
+       
+       ret = sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in));
+       if (ret < 0)
+               perror("sendto");
+       
+       
+       return ret;
 }
 
 
-
-// ------------------------------------------------------------------------------------------------------------
-int recvNgPacket (struct ngadmin *nga, char code, unsigned 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;
- struct timeval rem;
- fd_set fs;
- int len=-1;
- np.buffer=buffer;
- memset(&remote, 0, sizeof(struct sockaddr_in));
- remote.sin_family=AF_INET;
- rem=nga->timeout;
- while ( 1 ) {
-  
-  FD_ZERO(&fs);
-  FD_SET(nga->sock, &fs);
-  select(nga->sock+1, &fs, NULL, NULL, &rem); // FIXME: non portable
-  
-  len=recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen);
-  
-  if ( len<0 ) break;
-  
-  np.maxlen=len;
-  initNgPacket(&np);
-  
-  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) || 
-      extractPacketAttributes(&np, error, attr_error, attr)<0
-     ) continue;
-  
-  len=0;
-  break;
-  
- }
- return len;
+int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr, unsigned short filter_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;
+       struct timeval rem;
+       fd_set fs;
+       int len = -1;
+       
+       
+       np.buffer = buffer;
+       
+       memset(&remote, 0, sizeof(struct sockaddr_in));
+       remote.sin_family = AF_INET;
+       
+       rem = nga->timeout;
+       
+       while (1) {
+               
+               FD_ZERO(&fs);
+               FD_SET(nga->sock, &fs);
+               select(nga->sock+1, &fs, NULL, NULL, &rem); /* FIXME: non portable */
+               
+               len = recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen);
+               
+               if (len < 0)
+                       break;
+               
+               np.maxlen = len;
+               initNgPacket(&np);
+               
+               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) ||
+                   extractPacketAttributes(&np, error, attr_error, attr, filter_attr, sa == NULL ? 0 : sa->ports) < 0)
+                       continue;
+               
+               len = 0;
+               break;
+       }
+       
+       
+       return len;
 }
 
 
-
-static int checkErrorCode (unsigned char err, unsigned short attr_error) {
- switch ( err ) {
-  
-  case ERROR_DENIED: return attr_error==ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED ;
-  case ERROR_INVALID_VALUE: return ERR_INVARG;
-  default: return ERR_OK;
-  
- }
+static int checkErrorCode (unsigned char err, unsigned short attr_error)
+{
+       switch (err) {
+       case ERROR_DENIED:
+               return attr_error == ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED;
+       case ERROR_INVALID_VALUE:
+               return ERR_INVARG;
+       default:
+               return ERR_OK;
+       }
 }
 
 
-
-// ----------------------------------------------
-int readRequest (struct ngadmin *nga, List *attr) {
- int i, ret=ERR_OK;
- unsigned char err;
- unsigned short attr_error;
- 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= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
-  goto end;
- }
- // check error code
- ret=checkErrorCode(err, attr_error);
- end:
- return ret;
+int readRequest (struct ngadmin *nga, List *attr, unsigned short filter_attr)
+{
+       int i, ret = ERR_OK;
+       unsigned char err;
+       unsigned short attr_error;
+       
+       
+       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, filter_attr);
+       
+       if (i == -EINVAL) {
+               ret = ERR_INVARG;
+               goto end;
+       } else if (i < 0) {
+               ret = ( errno == EAGAIN || errno == EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET;
+               goto end;
+       }
+       
+       
+       /* check the switch error code */
+       ret = checkErrorCode(err, attr_error);
+       
+       
+end:
+       return ret;
 }
 
 
+int writeRequest (struct ngadmin *nga, List *attr)
+{
+       int i, ret = ERR_OK;
+       unsigned char err;
+       unsigned short attr_error;
+       
+       
+       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, ATTR_END);
+       
+       if (i == -EINVAL) {
+               ret = ERR_INVARG;
+               goto end;
+       } else if (i < 0) {
+               ret = ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
+               goto end;
+       }
+       
+       /* check the switch error code */
+       ret = checkErrorCode(err, attr_error);
+       
+       
+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;
+}
+
 
-// -----------------------------------------------
-int writeRequest (struct ngadmin *nga, List *attr) {
- int i, ret=ERR_OK;
- unsigned char err;
- unsigned short attr_error;
- 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= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
-  goto end;
- }
- // check error code
- ret=checkErrorCode(err, attr_error);
- 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;
+void extractSwitchAttributes (struct swi_attr *sa, const List *l)
+{
+       const ListNode *ln;
+       const struct attr *at;
+       int len;
+       
+       
+       memset(sa, 0, sizeof(struct swi_attr));
+       
+       for (ln = l->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               
+               switch (at->attr) {
+               
+               case ATTR_PRODUCT:
+                       len = min(at->size, PRODUCT_SIZE);
+                       memcpy(sa->product, at->data, len);
+                       trim(sa->product, len);
+                       break;
+               
+               case ATTR_NAME:
+                       len = min(at->size, NAME_SIZE);
+                       memcpy(sa->name, at->data, len);
+                       trim(sa->name, len);
+                       break;
+               
+               case ATTR_MAC:
+                       memcpy(&sa->mac, at->data, ETH_ALEN);
+                       break;
+               
+               case ATTR_IP:
+                       sa->nc.ip = *(struct in_addr*)at->data;
+                       break;
+               
+               case ATTR_NETMASK:
+                       sa->nc.netmask = *(struct in_addr*)at->data;
+                       break;
+               
+               case ATTR_GATEWAY:
+                       sa->nc.gw = *(struct in_addr*)at->data;
+                       break;
+               
+               case ATTR_DHCP:
+                       sa->nc.dhcp = (ntohs(*(unsigned short*)at->data) == 1);
+                       break;
+               
+               case ATTR_FIRM_VER:
+                       len = min(at->size, FIRMWARE_SIZE - 1);
+                       memcpy(sa->firmware, at->data, len);
+                       sa->firmware[len] = '\0';
+                       break;
+               
+               case ATTR_PORTS_COUNT:
+                       sa->ports = *(unsigned char*)at->data;
+                       break;
+               
+               case ATTR_END:
+                       return;
+               }
+       }
 }
 
 
index 534ae31931e9432ac1db74eb3b1b2dfb1781c60e..7349278f30be26af8857e207ab4eff8a0e8f5751 100644 (file)
@@ -3,47 +3,36 @@
 #define DEF_NETWORK
 
 
-#include <string.h>
-#include <unistd.h>
-//#include <poll.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netinet/ether.h>
-#include <sys/ioctl.h>
-//#include <sys/time.h>
-
 #include "list.h"
 #include "lib.h"
-#include "protocol.h"
-
-
 
 
-// 
 int startNetwork (struct ngadmin *nga);
 
-// 
+
 int stopNetwork (struct ngadmin *nga);
 
-// 
+
 int forceInterface (struct ngadmin *nga);
 
-// 
+
 int updateTimeout (struct ngadmin *nga);
 
-// 
+
 int sendNgPacket (struct ngadmin *nga, char code, const List *attr);
 
-// 
-int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr);
 
-// 
-int readRequest (struct ngadmin *nga, List *attr);
+int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr, unsigned short filter_attr);
+
+
+int readRequest (struct ngadmin *nga, List *attr, unsigned short filter_attr);
+
 
-// 
 int writeRequest (struct ngadmin *nga, List *attr);
 
 
+void extractSwitchAttributes (struct swi_attr *sa, const List *l);
+
 
 #endif
 
index f9d26107f89757e42e158c44abcac588061fe1e0..4ab33060d1f95f5c02620681d53d69b90cccc88f 100644 (file)
 
-#include "lib.h"
-#include "network.h"
-
+#include <errno.h>
 
+#include <ngadmin.h>
 
-static const struct timeval default_timeout={.tv_sec=4, .tv_usec=0};
-
-
-
-// ---------------------------------------------
-struct ngadmin* ngadmin_init (const char *iface) {
- struct ngadmin *nga;
- // allocate main structure
- nga=malloc(sizeof(struct ngadmin));
- memset(nga, 0, sizeof(struct ngadmin));
- strncpy(nga->iface, iface, IFNAMSIZ-1);
- if ( startNetwork(nga)<0 ) {
-  free(nga);
-  return NULL;
- }
- nga->timeout=default_timeout;
- if ( updateTimeout(nga)<0 ) {
-  free(nga);
-  return NULL;
- }
- return nga;
+#include "lib.h"
+#include "network.h"
+#include "attr.h"
+#include "protocol.h"
+
+
+
+static const struct timeval default_timeout = {.tv_sec = 4, .tv_usec = 0};
+
+
+
+struct ngadmin* ngadmin_init (const char *iface)
+{
+       struct ngadmin *nga;
+       
+       
+       /* allocate main structure */
+       nga = malloc(sizeof(struct ngadmin));
+       memset(nga, 0, sizeof(struct ngadmin));
+       
+       strncpy(nga->iface, iface, IFNAMSIZ - 1);
+       
+       if (startNetwork(nga) < 0) {
+               free(nga);
+               return NULL;
+       }
+       
+       nga->timeout = default_timeout;
+       if (updateTimeout(nga) < 0) {
+               free(nga);
+               return NULL;
+       }
+       
+       
+       return nga;
 }
 
 
-
-// ------------------------------------
-int ngadmin_close (struct ngadmin *nga) {
- if ( nga==NULL ) {
-  return ERR_INVARG;
- }
- stopNetwork(nga);
- free(nga->swi_tab);
- free(nga);
- return ERR_OK;
+int ngadmin_close (struct ngadmin *nga)
+{
+       if (nga == NULL)
+               return ERR_INVARG;
+               
+       stopNetwork(nga);
+       free(nga->swi_tab);
+       free(nga);
+       
+       return ERR_OK;
 }
 
 
-
-// ---------------------------------------------
-int ngadmin_forceInterface (struct ngadmin *nga) {
- if ( nga==NULL ) {
-  return ERR_INVARG;
- }
- if ( forceInterface(nga)!=0 ) {
-  return ERR_NET;
- } else {
-  return ERR_OK;
- }
+int ngadmin_forceInterface (struct ngadmin *nga)
+{
+       if (nga == NULL)
+               return ERR_INVARG;
+       
+       return forceInterface(nga) == 0 ? ERR_OK : ERR_NET;
 }
 
 
-
-// --------------------------------------------------------------
-int ngadmin_setKeepBroadcasting (struct ngadmin *nga, bool value) {
- if ( nga==NULL ) {
-  return ERR_INVARG;
- }
- nga->keepbroad=value;
- return ERR_OK;
+int ngadmin_setKeepBroadcasting (struct ngadmin *nga, bool value)
+{
+       if (nga == NULL)
+               return ERR_INVARG;
+       
+       nga->keepbroad = value;
+       
+       return ERR_OK;
 }
 
 
-
-// -------------------------------------------------------------
-int ngadmin_useGlobalBroadcast (struct ngadmin *nga, bool value) {
- if ( nga==NULL ) {
-  return ERR_INVARG;
- }
- nga->globalbroad=value;
- return ERR_OK;
+int ngadmin_useGlobalBroadcast (struct ngadmin *nga, bool value)
+{
+       if (nga == NULL)
+               return ERR_INVARG;
+       
+       nga->globalbroad = value;
+       
+       return ERR_OK;
 }
 
 
-
-// ------------------------------------------------------------
-int ngadmin_setPassword (struct ngadmin *nga, const char *pass) {
- if ( nga==NULL ) {
-  return ERR_INVARG;
- }
- strncpy(nga->password, pass, PASSWORD_MAX);
- return ERR_OK;
+int ngadmin_setPassword (struct ngadmin *nga, const char *pass)
+{
+       if (nga == NULL)
+               return ERR_INVARG;
+       
+       strncpy(nga->password, pass, PASSWORD_MAX);
+       
+       return ERR_OK;
 }
 
 
-
-// -------------------------------------------------------------------
-int ngadmin_setTimeout (struct ngadmin *nga, const struct timeval *tv) {
- int ret=ERR_OK;
- if ( nga==NULL || tv==NULL ) {
-  return ERR_INVARG;
- }
- nga->timeout=*tv;
- if ( updateTimeout(nga)<0 ) {
-  ret=ERR_NET;
- }
- return ret;
+int ngadmin_setTimeout (struct ngadmin *nga, const struct timeval *tv)
+{
+       int ret = ERR_OK;
+       
+       
+       if (nga == NULL || tv == NULL)
+               return ERR_INVARG;
+       
+       nga->timeout = *tv;
+       if (updateTimeout(nga) < 0)
+               ret = ERR_NET;
+       
+       
+       return ret;
 }
 
 
-
-// -----------------------------------
-int ngadmin_scan (struct ngadmin *nga) {
- int i;
- List *attr, *swiList;
- struct swi_attr *sa;
- /*
- sent by official win client:
-  ATTR_PRODUCT, 
-  ATTR_UNK2, 
-  ATTR_NAME, 
-  ATTR_MAC, 
-  ATTR_UNK5, 
-  ATTR_IP, 
-  ATTR_NETMASK, 
-  ATTR_GATEWAY, 
-  ATTR_DHCP, 
-  ATTR_UNK12, 
-  ATTR_FIRM_VER, 
-  ATTR_UNK14, 
-  ATTR_UNK15, 
-  ATTR_END
- */
- static const unsigned short hello[]={
-  ATTR_PRODUCT, 
-  ATTR_NAME, 
-  ATTR_MAC, 
-  ATTR_IP, 
-  ATTR_NETMASK, 
-  ATTR_GATEWAY, 
-  ATTR_DHCP, 
-  ATTR_FIRM_VER, 
-  ATTR_PORTS_COUNT, 
-  ATTR_END
- };
- if ( nga==NULL ) {
-  return ERR_INVARG;
- }
- free(nga->swi_tab);
- nga->swi_tab=NULL;
- nga->swi_count=0;
- nga->current=NULL;
- // create attributes for an "hello" request
- attr=createEmptyList();
- for (i=0; ; ++i) {
-  pushBackList(attr, newEmptyAttr(hello[i]));
-  if ( hello[i]==ATTR_END ) break;
- }
- // send request to all potential switches
- i=sendNgPacket(nga, CODE_READ_REQ, attr);
- clearList(attr, (void(*)(void*))freeAttr);
- if ( i<0 ) {
-  return ERR_NET;
- }
- // try to receive any packets until timeout
- swiList=createEmptyList();
- // FIXME: end after timeout whatever received packet is good or not
- while ( recvNgPacket(nga, CODE_READ_REP, NULL, NULL, attr)>=0 ) {
-  sa=malloc(sizeof(struct swi_attr));
-  extractSwitchAttributes(sa, attr);
-  clearList(attr, (void(*)(void*))freeAttr);
-  pushBackList(swiList, sa);
- }
- nga->swi_count=swiList->count;
- nga->swi_tab=convertToArray(swiList, sizeof(struct swi_attr));
- destroyList(swiList, free);
- destroyList(attr, (void(*)(void*))freeAttr);
- return ERR_OK;
+int ngadmin_scan (struct ngadmin *nga)
+{
+       int i;
+       List *attr, *swiList;
+       struct swi_attr *sa;
+       /*
+       sent by official win client:
+       ATTR_PRODUCT,
+       ATTR_UNK2,
+       ATTR_NAME,
+       ATTR_MAC,
+       ATTR_UNK5,
+       ATTR_IP,
+       ATTR_NETMASK,
+       ATTR_GATEWAY,
+       ATTR_DHCP,
+       ATTR_UNK12,
+       ATTR_FIRM_VER,
+       ATTR_UNK14,
+       ATTR_UNK15,
+       ATTR_END
+       */
+       static const unsigned short hello[] = {
+               ATTR_PRODUCT,
+               ATTR_NAME,
+               ATTR_MAC,
+               ATTR_IP,
+               ATTR_NETMASK,
+               ATTR_GATEWAY,
+               ATTR_DHCP,
+               ATTR_FIRM_VER,
+               ATTR_PORTS_COUNT,
+               ATTR_END
+       };
+       
+       
+       if (nga == NULL)
+               return ERR_INVARG;
+       
+       free(nga->swi_tab);
+       nga->swi_tab = NULL;
+       nga->swi_count = 0;
+       nga->current = NULL;
+       
+       
+       /* create attributes for an "hello" request */
+       attr = createEmptyList();
+       for (i = 0; ; i++) {
+               pushBackList(attr, newEmptyAttr(hello[i]));
+               if (hello[i] == ATTR_END)
+                       break;
+       }
+       
+       /* send request to all potential switches */
+       i = sendNgPacket(nga, CODE_READ_REQ, attr);
+       clearList(attr, (void(*)(void*))freeAttr);
+       if (i == -EINVAL)
+               return ERR_INVARG;
+       else if (i < 0)
+               return ERR_NET;
+       
+       /* try to receive any packets until timeout */
+       swiList = createEmptyList();
+       /* FIXME: end after timeout whatever received packet is good or not */
+       while (recvNgPacket(nga, CODE_READ_REP, NULL, NULL, attr, ATTR_END) >= 0) {
+               sa = malloc(sizeof(struct swi_attr));
+               if (sa == NULL)
+                       return ERR_MEM;
+               extractSwitchAttributes(sa, attr);
+               clearList(attr, (void(*)(void*))freeAttr);
+               pushBackList(swiList, sa);
+       }
+       
+       nga->swi_count = swiList->count;
+       nga->swi_tab = convertToArray(swiList, sizeof(struct swi_attr));
+       destroyList(swiList, free);
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ERR_OK;
 }
 
 
-
-// -----------------------------------------------------------------------
-const struct swi_attr* ngadmin_getSwitchTab (struct ngadmin *nga, int *nb) {
- if ( nga==NULL || nb==NULL ) {
-  return NULL;
- }
- *nb=nga->swi_count;
- return nga->swi_tab;
+const struct swi_attr* ngadmin_getSwitchTab (struct ngadmin *nga, int *nb)
+{
+       if (nga == NULL || nb == NULL)
+               return NULL;
+       
+       *nb = nga->swi_count;
+       
+       return nga->swi_tab;
 }
 
 
-
-// ------------------------------------------------------------------
-const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga) {
- if ( nga==NULL ) {
-  return NULL;
- }
- return nga->current;
+const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga)
+{
+       if (nga == NULL)
+               return NULL;
+       
+       return nga->current;
 }
 
 
-
-// --------------------------------------------
-int ngadmin_login (struct ngadmin *nga, int id) {
- List *attr;
- int ret=ERR_OK;
- struct swi_attr *sa;
- if ( nga==NULL ) {
-  return ERR_INVARG;
- } else if ( id<0 || id>=nga->swi_count ) {
-  return ERR_BADID;
- }
- sa=&nga->swi_tab[id];
- nga->current=sa;
- attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
- if ( (ret=readRequest(nga, attr))==ERR_OK ) {
-  // login succeeded
-  // TODO: if keep broadcasting is disabled, connect() the UDP socket so icmp errors messages (port unreachable, TTL exceeded in transit, ...) can be received
- } else {
-  // login failed
-  nga->current=NULL;
- }
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_login (struct ngadmin *nga, int id)
+{
+       List *attr;
+       int ret = ERR_OK;
+       struct swi_attr *sa;
+       
+       
+       if (nga == NULL)
+               return ERR_INVARG;
+       else if (id < 0 || id >= nga->swi_count)
+               return ERR_BADID;
+       
+       sa = &nga->swi_tab[id];
+       nga->current = sa;
+       
+       attr = createEmptyList();
+       pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
+       ret = readRequest(nga, attr, ATTR_END);
+       if (ret == ERR_OK ) {
+               /* login succeeded */
+               /* TODO: if keep broadcasting is disabled, connect() the UDP 
+               socket so icmp errors messages (port unreachable, TTL exceeded 
+               in transit, ...) can be received */
+       } else {
+               /* login failed */
+               nga->current = NULL;
+       }
+       
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// --------------------------------------------------------------------
-int ngadmin_upgradeFirmware (struct ngadmin *nga, const char *filename) {
- if ( nga==NULL || filename==NULL || *filename==0 ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- /*
- Firmware upgrade is not yet implemented. 
- This would require much more work and the use of a TFTP client. 
- Overall, it could be quite dangerous, as the switch may not check the binary 
- content sent to it. 
- */
- return ERR_NOTIMPL;
+int ngadmin_upgradeFirmware (struct ngadmin *nga, const char *filename)
+{
+       if (nga == NULL || filename == NULL || *filename == 0)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       /*
+       Firmware upgrade is not yet implemented. 
+       This would require much more work and the use of a TFTP client. 
+       Overall, it could be quite dangerous, as the switch may not check the binary 
+       content sent to it. 
+       */
+       
+       return ERR_NOTIMPL;
 }
 
 
-
-// -------------------------------------------------------------------
-int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- int ret=ERR_OK, i;
- char *p;
- if ( nga==NULL || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
- if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
-  goto end;
- }
- for (ln=attr->first; ln!=NULL; ln=ln->next) {
-  at=ln->data;
-  p=at->data;
-  if ( at->attr==ATTR_PORT_STATUS && at->size>=2 && (i=p[0]-1)>=0 && i<nga->current->ports ) {
-   ports[i]=p[1];
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK;
+       struct attr_port_status *ps;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
+       ret = readRequest(nga, attr, ATTR_PORT_STATUS);
+       if (ret != ERR_OK)
+               goto end;
+       
+       memset(ports, SPEED_UNK, nga->current->ports);
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               ps = at->data;
+               ports[ps->port - 1] = ps->status;
+       }
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// --------------------------------------------------------
-int ngadmin_setName (struct ngadmin *nga, const char *name) {
- List *attr;
- int ret=ERR_OK;
- if ( nga==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, name==NULL ? newEmptyAttr(ATTR_NAME) : newAttr(ATTR_NAME, strlen(name), strdup(name)) );
- if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
-  goto end;
- }
- // successful, also update local name
- if ( name==NULL ) {
-  nga->current->name[0]=0;
- } else {
-  strncpy(nga->current->name, name, NAME_SIZE);
- }
- end:
- return ret;
+int ngadmin_setName (struct ngadmin *nga, const char *name)
+{
+       List *attr;
+       int ret = ERR_OK;
+       
+       
+       if (nga == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, name == NULL ? newEmptyAttr(ATTR_NAME) : newAttr(ATTR_NAME, strlen(name), strdup(name)) );
+       ret = writeRequest(nga, attr);
+       if (ret != ERR_OK)
+               goto end;
+        
+       /* successful, also update local name */
+       if (name == NULL)
+               memset(nga->current->name, '\0', NAME_SIZE);
+       else
+               strncpy(nga->current->name, name, NAME_SIZE);
+       
+end:
+       return ret;
 }
 
 
-
-// ------------------------------------------------------------------------
-int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- int ret=ERR_OK;
- int port;
- if ( nga==NULL || ps==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
- 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 ) {
-   ps[port].recv=be64toh(*(unsigned long long*)(at->data+1+8*0));
-   ps[port].sent=be64toh(*(unsigned long long*)(at->data+1+8*1));
-   ps[port].crc=be64toh(*(unsigned long long*)(at->data+1+8*5));
-   // all offsets between 2 and 4 inclusive are unknown values
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK;
+       struct attr_port_stat *aps;
+       
+       
+       if (nga == NULL || ps == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
+       ret = readRequest(nga, attr, ATTR_PORT_STATISTICS);
+       if (ret != ERR_OK)
+               goto end;
+       
+       memset(ps, 0, nga->current->ports * sizeof(struct port_stats));
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               aps = at->data;
+               ps[aps->port -1].recv = aps->recv;
+               ps[aps->port -1].sent = aps->sent;
+               ps[aps->port -1].crc = aps->crc;
+       }
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// ---------------------------------------------------
-int ngadmin_resetPortsStatistics (struct ngadmin *nga) {
- List *attr;
- attr=createEmptyList();
- pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
- return writeRequest(nga, attr);
+int ngadmin_resetPortsStatistics (struct ngadmin *nga)
+{
+       List *attr;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
+       
+       
+       return writeRequest(nga, attr);
 }
 
 
-
-// ---------------------------------------------------------------
-int ngadmin_changePassword (struct ngadmin *nga, const char* pass) {
- List *attr;
- int ret=ERR_OK;
- if ( nga==NULL || pass==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
- if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
-  goto end;
- }
- // successful, also update local password
- strncpy(nga->password, pass, PASSWORD_MAX);
- end:
- return ret;
+int ngadmin_changePassword (struct ngadmin *nga, const char* pass)
+{
+       List *attr;
+       int ret = ERR_OK;
+       
+       
+       if (nga == NULL || pass == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
+       ret = writeRequest(nga, attr);
+       if (ret != ERR_OK)
+               goto end;
+       
+       
+       /* successful, also update local password */
+       strncpy(nga->password, pass, PASSWORD_MAX);
+       
+end:
+       
+       return ret;
 }
 
 
-
-// ----------------------------------------------------------
-int ngadmin_getStormFilterState (struct ngadmin *nga, int *s) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- int ret=ERR_OK;
- if ( nga==NULL || s==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
- 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 ) {
-   *s= *(char*)at->data!=0 ;
-   break;
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getStormFilterState (struct ngadmin *nga, int *s)
+{
+       List *attr;
+       struct attr *at;
+       int ret = ERR_OK;
+       
+       
+       if (nga == NULL || s == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
+       ret = readRequest(nga, attr, ATTR_STORM_ENABLE);
+       if (ret != ERR_OK)
+               goto end;
+       
+       *s = 0;
+       
+       if (attr->first != NULL) {
+               at = attr->first->data;
+               *s = *(char*)at->data;
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// ---------------------------------------------------------
-int ngadmin_setStormFilterState (struct ngadmin *nga, int s) {
- List *attr;
- attr=createEmptyList();
- pushBackList(attr, newByteAttr(ATTR_STORM_ENABLE, s!=0));
- return writeRequest(nga, attr);
+int ngadmin_setStormFilterState (struct ngadmin *nga, int s)
+{
+       List *attr;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newByteAttr(ATTR_STORM_ENABLE, s != 0));
+       
+       
+       return writeRequest(nga, attr);
 }
 
 
-
-// ---------------------------------------------------------------
-int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- int ret=ERR_OK, i;
- if ( nga==NULL || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
- 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=(int)*(char*)(at->data)-1)>=0 && i<nga->current->ports ) {
-   ports[i]=ntohl(*(int*)(1+(char*)at->data));
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK, port;
+       struct attr_bitrate *sb;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
+       ret = readRequest(nga, attr, ATTR_STORM_BITRATE);
+       if (ret != ERR_OK)
+               goto end;
+       
+       for (port = 0; port < nga->current->ports; port++)
+               ports[port] = BITRATE_UNSPEC;
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               sb = at->data;
+               ports[sb->port - 1] = sb->bitrate;
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// ---------------------------------------------------------------------
-int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports) {
- List *attr;
- int i;
- char *p;
- if ( nga==NULL || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- for (i=0; i<nga->current->ports; ++i) {
-  if ( ports[i]>=0 && ports[i]<=11 ) {
-   p=malloc(5);
-   *p=i+1;
-   *(int*)(p+1)=htonl(ports[i]);
-   pushBackList(attr, newAttr(ATTR_STORM_BITRATE, 5, p));
-  }
- }
- return writeRequest(nga, attr);
+int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports)
+{
+       List *attr;
+       int port;
+       struct attr_bitrate *sb;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       
+       for (port = 0; port < nga->current->ports; port++) {
+               if (ports[port] != BITRATE_UNSPEC) {
+                       sb = malloc(sizeof(struct attr_bitrate));
+                       if (sb == NULL)
+                               return ERR_MEM;
+                       sb->port = port + 1;
+                       sb->bitrate = ports[port];
+                       pushBackList(attr, newAttr(ATTR_STORM_BITRATE, sizeof(struct attr_bitrate), sb));
+               }
+       }
+       
+       return writeRequest(nga, attr);
 }
 
 
-
-// -----------------------------------------------------------
-int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- int ret=ERR_OK;
- struct {
-  char port;
-  int bitrate;
- } __attribute__((packed)) *p;
- if ( nga==NULL || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
- pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
- if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
-  goto end;
- }
- for (ln=attr->first; ln!=NULL; ln=ln->next) {
-  at=ln->data;
-  p=at->data;
-  if ( at->size<sizeof(*p) || p->port<1 || p->port>nga->current->ports ) continue;
-  if ( at->attr==ATTR_BITRATE_INPUT ) {
-   ports[(p->port-1)*2+0]=ntohl(p->bitrate);
-  } else if ( at->attr==ATTR_BITRATE_OUTPUT ) {
-   ports[(p->port-1)*2+1]=ntohl(p->bitrate);
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK, port;
+       struct attr_bitrate *pb;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
+       pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
+       ret = readRequest(nga, attr, ATTR_END);
+       if (ret != ERR_OK)
+               goto end;
+       
+       
+       for (port = 0; port < nga->current->ports; port++) {
+               ports[2 * port + 0] = BITRATE_UNSPEC;
+               ports[2 * port + 1] = BITRATE_UNSPEC;
+       }
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               pb = at->data;
+               if (at->attr == ATTR_BITRATE_INPUT)
+                       ports[(pb->port - 1) * 2 + 0] = pb->bitrate;
+               else if (at->attr == ATTR_BITRATE_OUTPUT)
+                       ports[(pb->port - 1) * 2 + 1] = pb->bitrate;
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       return ret;
 }
 
 
-
-// -----------------------------------------------------------------
-int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports) {
List *attr;
- int i;
- char *p;
- if ( nga==NULL || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- for (i=0; i<nga->current->ports; ++i) {
-  if ( ports[2*i+0]>=0 && ports[2*i+0]<=11 ) {
-   p=malloc(5);
-   *p=i+1;
-   *(int*)(p+1)=htonl(ports[2*i+0]);
-   pushBackList(attr, newAttr(ATTR_BITRATE_INPUT, 5, p));
-  }
-  if ( ports[2*i+1]>=0 && ports[2*i+1]<=11 ) {
-   p=malloc(5);
-   *p=i+1;
-   *(int*)(p+1)=htonl(ports[2*i+1]);
-   pushBackList(attr, newAttr(ATTR_BITRATE_OUTPUT, 5, p));
-  }
- }
- return writeRequest(nga, attr);
+int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports)
+{
+       List *attr;
+       int port;
      struct attr_bitrate *pb;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       
+       for (port = 0; port < nga->current->ports; port++) {
+               if (ports[2 * port + 0] >= BITRATE_NOLIMIT && ports[2 * port + 0] <= BITRATE_512M) {
+                       pb = malloc(sizeof(struct attr_bitrate));
+                       if (pb == NULL)
+                               return ERR_MEM;
+                       pb->port = port + 1;
+                       pb->bitrate = ports[2 * port + 0];
+                       pushBackList(attr, newAttr(ATTR_BITRATE_INPUT, sizeof(struct attr_bitrate), pb));
+               }
+               if (ports[2 * port + 1] >= BITRATE_NOLIMIT && ports[2 * port + 1] <= BITRATE_512M) {
+                       pb = malloc(sizeof(struct attr_bitrate));
+                       if (pb == NULL)
+                               return ERR_MEM;
+                       pb->port = port + 1;
+                       pb->bitrate = ports[2 * port + 1];
+                       pushBackList(attr, newAttr(ATTR_BITRATE_OUTPUT, sizeof(struct attr_bitrate), pb));
              }
+       }
+       
+       
+       return writeRequest(nga, attr);
 }
 
 
-
-// -------------------------------------------------
-int ngadmin_getQOSMode (struct ngadmin *nga, int *s) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- int ret=ERR_OK;
- if ( nga==NULL || s==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
- 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 ) {
-   *s= *(char*)at->data ;
-   break;
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getQOSMode (struct ngadmin *nga, int *s)
+{
+       List *attr;
+       struct attr *at;
+       int ret = ERR_OK;
+       
+       
+       if (nga == NULL || s == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
+       ret = readRequest(nga, attr, ATTR_QOS_TYPE);
+       if (ret != ERR_OK)
+               goto end;
+       
+       *s = 0;
+       
+       if (attr->first != NULL) {
+               at = attr->first->data;
+               *s = *(char*)at->data;
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-// ------------------------------------------------
-int ngadmin_setQOSMode (struct ngadmin *nga, int s) {
- List *attr;
- if ( s<QOS_PORT || s>QOS_DOT ) {
-  return ERR_INVARG;
- }
- attr=createEmptyList();
- pushBackList(attr, newByteAttr(ATTR_QOS_TYPE, s));
- return writeRequest(nga, attr);
+int ngadmin_setQOSMode (struct ngadmin *nga, int s)
+{
+       List *attr;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newByteAttr(ATTR_QOS_TYPE, s));
+       
+       
+       return writeRequest(nga, attr);
 }
 
 
-
-// -------------------------------------------------------
-int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- int ret=ERR_OK;
- char *p;
- if ( nga==NULL || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
- 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_QOS_CONFIG && at->size>=2 && --p[0]>=0 && p[0]<nga->current->ports ) {
-   ports[(int)p[0]]=p[1];
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getQOSValues (struct ngadmin *nga, char *ports)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK, port;
+       struct attr_qos *aq;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
+       ret = readRequest(nga, attr, ATTR_QOS_CONFIG);
+       if (ret < 0)
+               goto end;
+       
+       for (port = 0; port < nga->current->ports; port++)
+               ports[port] = PRIO_UNSPEC;
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               aq = at->data;
+               ports[aq->port - 1] = aq->prio;
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// --------------------------------------------------------------
-int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports) {
- List *attr;
- int i;
- char *p;
- if ( nga==NULL || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- for (i=0; i<nga->current->ports; ++i) {
-  if ( ports[i]>=PRIO_HIGH && ports[i]<=PRIO_LOW ) {
-   p=malloc(2);
-   p[0]=i+1;
-   p[1]=ports[i];
-   pushBackList(attr, newAttr(ATTR_QOS_CONFIG, 2, p));
-  }
- }
- return writeRequest(nga, attr);
+int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports)
+{
+       List *attr;
+       int port;
+       struct attr_qos *aq;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       
+       for (port = 0; port < nga->current->ports; port++) {
+               if (ports[port] >= PRIO_HIGH && ports[port] <= PRIO_LOW) {
+                       aq = malloc(sizeof(struct attr_qos));
+                       if (aq == NULL)
+                               return ERR_MEM;
+                       aq->port = port + 1;
+                       aq->prio = ports[port];
+                       pushBackList(attr, newAttr(ATTR_QOS_CONFIG, sizeof(struct attr_qos), aq));
+               }
+       }
+       
+       
+       return writeRequest(nga, attr);
 }
 
 
-
-// --------------------------------------
-int ngadmin_restart (struct ngadmin *nga) {
- List *attr;
- attr=createEmptyList();
- pushBackList(attr, newByteAttr(ATTR_RESTART, 1));
- return writeRequest(nga, attr);
+int ngadmin_restart (struct ngadmin *nga)
+{
+       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;
+int ngadmin_defaults (struct ngadmin *nga)
+{
+       List *attr;
+       int ret = ERR_OK;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newByteAttr(ATTR_DEFAULTS, 1));
+       ret = writeRequest(nga, attr);
+       if (ret != 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;
 }
 
 
-
-// -----------------------------------------------------
-int ngadmin_getMirror (struct ngadmin *nga, char *ports) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- struct swi_attr *sa;
- int ret=ERR_OK, i;
- unsigned char *p;
- if ( nga==NULL || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( (sa=nga->current)==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
- 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_MIRROR && at->size>=3 && p[0]<=nga->current->ports ) {
-   ports[0]=p[0];
-   for (i=1; i<=sa->ports; ++i) { // FIXME: if ports>8
-    ports[i]=(p[2]>>(8-i))&1;
-   }
-   break;
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getMirror (struct ngadmin *nga, char *ports)
+{
+       List *attr;
+       struct attr *at;
+       int ret = ERR_OK;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
+       ret = readRequest(nga, attr, ATTR_MIRROR);
+       if (ret < 0)
+               goto end;
+       
+       memset(ports, 0, 1 + nga->current->ports);
+       
+       if (attr->first != NULL) {
+               at = attr->first->data;
+               memcpy(ports, at->data, 1 + nga->current->ports);
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// -----------------------------------------------------------
-int ngadmin_setMirror (struct ngadmin *nga, const char *ports) {
- List *attr;
- int i;
- char *p;
- struct swi_attr *sa;
- if ( nga==NULL ) {
-  return ERR_INVARG;
- } 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)<<(8-i);
-   }
-  }
- }
- attr=createEmptyList();
- pushBackList(attr, newAttr(ATTR_MIRROR, 3, p));
- return writeRequest(nga, attr);
+int ngadmin_setMirror (struct ngadmin *nga, const char *ports)
+{
+       List *attr;
+       char *p;
+       
+       
+       if (nga == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       p = malloc(1 + nga->current->ports);
+       if (p == NULL)
+               return ERR_MEM;
+       
+       if (ports == NULL)
+               memset(p, 0, 1 + nga->current->ports);
+       else
+               memcpy(p, ports, 1 + nga->current->ports);
+       
+       attr = createEmptyList();
+       pushBackList(attr, newAttr(ATTR_MIRROR, 1 + nga->current->ports, 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 these 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;
- }
- 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);
- 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;
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic)
+{
+       List *attr;
+       struct attr *at;
+       int ret = ERR_OK;
+       struct attr_igmp_vlan *aiv;
+       
+       
+       if (nga == NULL || ic == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       /*
+       ATTR_IGMP_ENABLE_VLAN
+       ATTR_IGMP_BLOCK_UNK
+       ATTR_IGMP_VALID_V3
+       
+       Apparently, read-querying these 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));
+       ret = readRequest(nga, attr, ATTR_IGMP_ENABLE_VLAN);
+       if (ret < 0)
+               goto end;
+       
+       if (attr->first != NULL) {
+               at = attr->first->data;
+               aiv = at->data;
+               ic->enable = aiv->enable;
+               ic->vlan = aiv->vlan;
+       }
+       
+       clearList(attr, (void(*)(void*))freeAttr);
+       
+       
+       pushBackList(attr, newEmptyAttr(ATTR_IGMP_BLOCK_UNK));
+       ret = readRequest(nga, attr, ATTR_IGMP_BLOCK_UNK);
+       if (ret < 0)
+               goto end;
+       
+       if (attr->first != NULL) {
+               at = attr->first->data;
+               ic->block = *(char*)at->data;
+       }
+       
+       clearList(attr, (void(*)(void*))freeAttr);
+       
+       
+       pushBackList(attr, newEmptyAttr(ATTR_IGMP_VALID_V3));
+       ret = readRequest(nga, attr, ATTR_IGMP_VALID_V3);
+       if (ret < 0)
+               goto end;
+       
+       if (attr->first != NULL) {
+               at = attr->first->data;
+               ic->validate = *(char*)at->data;
+       }
+       
+       
+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_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic)
+{
+       List *attr;
+       struct attr_igmp_vlan *aiv;
+       
+       
+       if (nga == NULL || ic == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       aiv = malloc(sizeof(struct attr_igmp_vlan));
+       if (aiv == NULL)
+               return ERR_MEM;
+       aiv->enable = ic->enable;
+       aiv->vlan = ic->vlan;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newAttr(ATTR_IGMP_ENABLE_VLAN, sizeof(struct attr_igmp_vlan), aiv));
+       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;
+int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK, i;
+       struct attr_cabletest_do *acd;
+       struct attr_cabletest_result *acr;
+       
+       
+       if (nga == NULL || ct == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       
+       for (i = 0; i < nb; i++) {
+               
+               acd = malloc(sizeof(struct attr_cabletest_do));
+               if (acd == NULL)
+                       return ERR_MEM;
+               acd->port = ct[i].port;
+               acd->action = 1;
+               pushBackList(attr, newAttr(ATTR_CABLETEST_DO, sizeof(struct attr_cabletest_do), acd));
+               
+               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));
+               ret = readRequest(nga, attr, ATTR_CABLETEST_RESULT);
+               if (ret < 0)
+                       goto end;
+               
+               for (ln = attr->first; ln != NULL; ln = ln->next) {
+                       at = ln->data;
+                       acr = at->data;
+                       if (at->size == sizeof(struct attr_cabletest_result) && acr->port == ct[i].port) {
+                               ct[i].v1 = acr->v1;
+                               ct[i].v2 = acr->v2;
+                               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;
 }
 
 
-
-// --------------------------------------------------------------------
-int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc) {
- List *attr;
- struct swi_attr *sa;
- int ret=ERR_OK;
- if ( nga==NULL || nc==NULL ) {
-  return ERR_INVARG;
- } else if ( (sa=nga->current)==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- if ( nc->dhcp ) {
-  pushBackList(attr, newByteAttr(ATTR_DHCP, 1));
- } else {
-  pushBackList(attr, newByteAttr(ATTR_DHCP, 0));
-  // only add non-null values
-  if ( nc->ip.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_IP, nc->ip));
-  if ( nc->netmask.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_NETMASK, nc->netmask));
-  if ( nc->gw.s_addr!=0 ) pushBackList(attr, newAddrAttr(ATTR_GATEWAY, nc->gw));
- }
- if ( (ret=writeRequest(nga, attr))!=ERR_OK ) {
-  goto end;
- }
- // update local values
- sa->nc.dhcp=nc->dhcp;
- if ( !nc->dhcp ) {
-  if ( nc->ip.s_addr!=0 ) sa->nc.ip=nc->ip;
-  if ( nc->netmask.s_addr!=0 ) sa->nc.netmask=nc->netmask;
-  if ( nc->gw.s_addr!=0 ) sa->nc.gw=nc->gw;
- }
- end:
- return ret;
+int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc)
+{
+       List *attr;
+       int ret = ERR_OK;
+       struct swi_attr *sa;
+       
+       
+       if (nga == NULL || nc == NULL)
+               return ERR_INVARG;
+       
+       sa = nga->current;
+       if (sa == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       
+       if (nc->dhcp) {
+               pushBackList(attr, newShortAttr(ATTR_DHCP, 1));
+       } else {
+               pushBackList(attr, newShortAttr(ATTR_DHCP, 0));
+               /* only add non-null values */
+               if (nc->ip.s_addr != 0)
+                       pushBackList(attr, newAddrAttr(ATTR_IP, nc->ip));
+               if (nc->netmask.s_addr != 0)
+                       pushBackList(attr, newAddrAttr(ATTR_NETMASK, nc->netmask));
+               if (nc->gw.s_addr != 0)
+                       pushBackList(attr, newAddrAttr(ATTR_GATEWAY, nc->gw));
+       }
+       
+       ret = writeRequest(nga, attr);
+       if (ret != ERR_OK)
+               goto end;
+       
+       
+       /* update local values */
+       sa->nc.dhcp = nc->dhcp;
+       if (!nc->dhcp) {
+               if (nc->ip.s_addr !=0)
+                       sa->nc.ip = nc->ip;
+               if (nc->netmask.s_addr != 0)
+                       sa->nc.netmask = nc->netmask;
+               if (nc->gw.s_addr != 0)
+                       sa->nc.gw = nc->gw;
+       }
+       
+       
+end:
+       
+       return ret;
 }
 
 
-
-// --------------------------------------------------
-int ngadmin_getVLANType (struct ngadmin *nga, int *t) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- int ret=ERR_OK;
- if ( nga==NULL || t==NULL ) {
-  return ERR_INVARG;
- } else if ( nga->current==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
- 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_VLAN_TYPE && at->size>=1 ) {
-   *t= (int)*(char*)at->data ;
-   break;
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getVLANType (struct ngadmin *nga, int *t)
+{
+       List *attr;
+       struct attr *at;
+       int ret = ERR_OK;
+       
+       
+       if (nga == NULL || t == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
+       ret=readRequest(nga, attr, ATTR_VLAN_TYPE);
+       if (ret != ERR_OK)
+               goto end;
+       
+       *t = VLAN_DISABLED;
+       
+       if (attr->first != NULL) {
+               at = attr->first->data;
+               *t =(int)*(char*)at->data;
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// -------------------------------------------------
-int ngadmin_setVLANType (struct ngadmin *nga, int t) {
- List *attr;
- struct swi_attr *sa;
- if ( nga==NULL || t<1 || t>4 ) {
-  return ERR_INVARG;
- } else if ( (sa=nga->current)==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newByteAttr(ATTR_VLAN_TYPE, t));
- return writeRequest(nga, attr);
+int ngadmin_setVLANType (struct ngadmin *nga, int t)
+{
+       List *attr;
+       
+       
+       if (nga == NULL || t < 1 || t > 4)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newByteAttr(ATTR_VLAN_TYPE, t));
+       
+       
+       return writeRequest(nga, attr);
 }
 
 
-
-// ------------------------------------------------------------------------------------------------------
-int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- struct swi_attr *sa;
- int ret=ERR_OK, total, i;
- char *p=NULL;
- if ( nga==NULL || vlans==NULL || ports==NULL || nb==NULL || *nb<=0 ) {
-  return ERR_INVARG;
- } else if ( (sa=nga->current)==NULL ) {
-  return ERR_NOTLOG;
- }
- total=*nb;
- *nb=0;
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
- if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
-  goto end;
- }
- for (ln=attr->first; ln!=NULL; ln=ln->next) {
-  at=ln->data;
-  p=at->data;
-  if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
-   for (i=0; i<sa->ports; ++i) {
-    if ( (p[3]>>(7-i))&1 ) ports[i]=VLAN_TAGGED; // tagged
-    else if ( (p[2]>>(7-i))&1 ) ports[i]=VLAN_UNTAGGED; // untagged
-    else ports[i]=VLAN_NO;
-   }
-   *vlans++=ntohs(*(unsigned short*)p);
-   ports+=sa->ports;
-   if ( ++*nb>total ) break; // no more room
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK, total;
+       struct attr_vlan_dot *avd;
+       
+       
+       if (nga == NULL || vlans == NULL || ports== NULL || nb == NULL || *nb <= 0)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       total = *nb;
+       *nb = 0;
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
+       ret = readRequest(nga, attr, ATTR_VLAN_DOT_CONF);
+       if (ret != ERR_OK)
+               goto end;
+       
+       memset(vlans, 0, total * sizeof(unsigned short));
+       memset(ports, 0, total * nga->current->ports);
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               avd = at->data;
+               
+               *vlans = avd->vlan;
+               memcpy(ports, avd->ports, nga->current->ports);
+               
+               vlans++;
+               ports += nga->current->ports;
+               (*nb)++;
+               
+               if (*nb > total)
+                       break; /* no more room */
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// ----------------------------------------------------------------------------------------
-int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned char *ports) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- struct swi_attr *sa;
- int ret=ERR_OK, i;
- char *p=NULL;
- if ( nga==NULL || vlan<1 || vlan>VLAN_MAX || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( (sa=nga->current)==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
- if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
-  goto end;
- }
- for (ln=attr->first; ln!=NULL; ln=ln->next) {
-  at=ln->data;
-  p=at->data;
-  if ( at->attr==ATTR_VLAN_DOT_CONF && at->size>=4 ) {
-   for (i=0; i<sa->ports; ++i) {
-    if ( (p[3]>>(7-i))&1 ) ports[i]=VLAN_TAGGED; // tagged
-    else if ( (p[2]>>(7-i))&1 ) ports[i]=VLAN_UNTAGGED; // untagged
-    else ports[i]=VLAN_NO;
-   }
-   break;
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned char *ports)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK;
+       struct attr_vlan_dot *avd;
+       
+       
+       if (nga == NULL || vlan < 1 || vlan > VLAN_MAX || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
+       ret = readRequest(nga, attr, ATTR_END);
+       if (ret != ERR_OK)
+               goto end;
+       
+       memset(ports, 0, nga->current->ports);
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               avd = at->data;
+               if (avd->vlan == vlan) {
+                       memcpy(ports, avd->ports, nga->current->ports);
+                       break;
+               }
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// ----------------------------------------------------------------------------------------------
-int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsigned char *ports) {
- List *attr=NULL;
- ListNode *ln;
- struct attr *at;
- struct swi_attr *sa;
- char *p, fl;
- int ret=ERR_OK, i;
- if ( nga==NULL || vlan<1 || vlan>VLAN_MAX || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( (sa=nga->current)==NULL ) {
-  return ERR_NOTLOG;
- }
- // if nothing is to be changed, do nothing
- for (i=0; i<sa->ports && ports[i]==VLAN_UNSPEC; ++i);
- if ( i==sa->ports ) goto end;
- attr=createEmptyList();
- p=malloc(4);
- *(unsigned short*)p=htons(vlan);
- *(unsigned short*)&p[2]=0;
- // if all is to be changed, we do not need to read old config
- if ( memchr(ports, VLAN_UNSPEC, sa->ports)!=NULL ) {
-  
-  pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
-  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_VLAN_DOT_CONF && at->size>=4 ) {
-    *(unsigned short*)&p[2]=*(unsigned short*)(at->data+2);
-    break;
-   }
-  }
-  
-  clearList(attr, (void(*)(void*))freeAttr);
-  
- }
- // apply changes
- for (i=0; i<sa->ports; ++i) {
-  fl=(1<<(7-i));
-  switch ( ports[i] ) {
-   case VLAN_NO:
-    p[2]&=~fl;
-    p[3]&=~fl;
-   break;
-   case VLAN_UNTAGGED:
-    p[2]|=fl;
-    p[3]&=~fl;
-   break;
-   case VLAN_TAGGED:
-    p[2]|=fl;
-    p[3]|=fl;
-  }
- }
- pushBackList(attr, newAttr(ATTR_VLAN_DOT_CONF, 4, p));
- ret=writeRequest(nga, attr);
- attr=NULL;
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsigned char *ports)
+{
+       List *attr = NULL;
+       struct attr *at;
+       struct swi_attr *sa;
+       struct attr_vlan_dot *avd;
+       int ret = ERR_OK, port;
+       
+       
+       if (nga == NULL || vlan < 1 || vlan > VLAN_MAX || ports == NULL)
+               return ERR_INVARG;
+       
+       sa = nga->current;
+       if (sa == NULL)
+               return ERR_NOTLOG;
+       
+       
+       /* if nothing is to be changed, do nothing */
+       for (port = 0; port < sa->ports && ports[port] == VLAN_UNSPEC; port++);
+       if (port == sa->ports )
+               goto end;
+       
+       
+       attr = createEmptyList();
+       avd = malloc(sizeof(struct attr_vlan_dot) + sa->ports);
+       if (avd == NULL)
+               return ERR_MEM;
+       
+       avd->vlan = vlan;
+       
+       /* if all is to be changed, we do not need to read old config */
+       if (memchr(ports, VLAN_UNSPEC, sa->ports) != NULL) {
+               
+               pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
+               ret = readRequest(nga, attr, ATTR_VLAN_DOT_CONF);
+               if (ret != ERR_OK)
+                       goto end;
+               
+               if (attr->first != NULL) {
+                       at = attr->first->data;
+                       memcpy(avd, at->data, sizeof(struct attr_vlan_dot) + sa->ports);
+               }
+               
+               clearList(attr, (void(*)(void*))freeAttr);
+       }
+       
+       
+       /* apply changes */
+       for (port = 0; port < sa->ports; port++) {
+               if (ports[port] != VLAN_UNSPEC)
+                       avd->ports[port] = ports[port];
+       }
+       
+       
+       pushBackList(attr, newAttr(ATTR_VLAN_DOT_CONF, sizeof(struct attr_vlan_dot) + sa->ports, avd));
+       ret = writeRequest(nga, attr);
+       attr = NULL;
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// ---------------------------------------------------------------
-int ngadmin_VLANDestroy (struct ngadmin *nga, unsigned short vlan) {
- List *attr;
- struct swi_attr *sa;
- if ( nga==NULL || vlan<1 || vlan>VLAN_MAX ) {
-  return ERR_INVARG;
- } else if ( (sa=nga->current)==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newShortAttr(ATTR_VLAN_DESTROY, vlan));
- return writeRequest(nga, attr);
+int ngadmin_VLANDestroy (struct ngadmin *nga, unsigned short vlan)
+{
+       List *attr;
+       
+       
+       if (nga == NULL || vlan < 1 || vlan > VLAN_MAX)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newShortAttr(ATTR_VLAN_DESTROY, vlan));
+       
+       
+       return writeRequest(nga, attr);
 }
 
 
-
-// ----------------------------------------------------------------
-int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports) {
- List *attr;
- ListNode *ln;
- struct attr *at;
- struct swi_attr *sa;
- int ret=ERR_OK;
- char *p;
- if ( nga==NULL || ports==NULL ) {
-  return ERR_INVARG;
- } else if ( (sa=nga->current)==NULL ) {
-  return ERR_NOTLOG;
- }
- attr=createEmptyList();
- pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID));
- if ( (ret=readRequest(nga, attr))!=ERR_OK ) {
-  goto end;
- }
- for (ln=attr->first; ln!=NULL; ln=ln->next) {
-  at=ln->data;
-  p=at->data;
-  if ( at->attr==ATTR_VLAN_PVID && at->size>=3 && p[0]>=1 && p[0]<=sa->ports ) {
-   ports[p[0]-1]=htons(*(unsigned short*)&p[1]);
-  }
- }
- end:
- destroyList(attr, (void(*)(void*))freeAttr);
- return ret;
+int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK;
+       struct attr_pvid *ap;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID));
+       ret = readRequest(nga, attr, ATTR_VLAN_PVID);
+       if (ret != ERR_OK)
+               goto end;
+       
+       memset(ports, 0, nga->current->ports * sizeof(unsigned short));
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               ap = at->data;
+               ports[ap->port - 1] = ap->vlan;
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
 }
 
 
-
-// -------------------------------------------------------------------------------
-int ngadmin_setPVID (struct ngadmin *nga, unsigned char port, unsigned short vlan) {
- List *attr;
- struct swi_attr *sa;
- char *p;
- if ( nga==NULL || port<1 || vlan<1 || vlan>VLAN_MAX ) {
-  return ERR_INVARG;
- } else if ( (sa=nga->current)==NULL ) {
-  return ERR_NOTLOG;
- } else if ( port>sa->ports ) {
-  return ERR_INVARG;
- }
- attr=createEmptyList();
- p=malloc(3);
- p[0]=port;
- *(unsigned short*)&p[1]=htons(vlan);
- pushBackList(attr, newAttr(ATTR_VLAN_PVID, 3, p));
- return writeRequest(nga, attr);
+int ngadmin_setPVID (struct ngadmin *nga, unsigned char port, unsigned short vlan)
+{
+       List *attr;
+       struct attr_pvid *ap;
+       
+       
+       if (nga == NULL || port < 1 || vlan < 1 || vlan > VLAN_MAX)
+               return ERR_INVARG;
+       else if (nga->current == NULL)
+               return ERR_NOTLOG;
+       else if (port > nga->current->ports)
+               return ERR_INVARG;
+       
+       
+       attr = createEmptyList();
+       ap = malloc(sizeof(struct attr_pvid));
+       if (ap == NULL)
+               return ERR_MEM;
+       ap->port = port;
+       ap->vlan = vlan;
+       
+       pushBackList(attr, newAttr(ATTR_VLAN_PVID, sizeof(struct attr_pvid), ap));
+       
+       
+       return writeRequest(nga, attr);
 }
 
 
index 6c400f437a5986491906583d27ee3c653c46007d..de2c4519c87596ab385f461b5a67140f27159d83 100644 (file)
 
-#include "protocol.h"
-
-
-
-
-// ----------------------------
-int trim (char *txt, int start) {
- char *p, c;
- if ( txt==NULL ) {
-  return 0;
- }
- //for (p=txt; *p!=0; p++);
- p=txt+start;
- for (p--; p>=txt && ( (c=*p)==' ' || c=='\n' ); *p--=0);
- return p-txt+1;
-}
-
-
-
-// -------------------
-int min (int a, int b) {
- return a<b ? a : b ;
-}
-
-
-
-// -----------------------------------------------------------------------------------------------------------------------------------------------
-void initNgHeader (struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum) {
- memset(nh, 0, sizeof(struct ng_header));
- nh->version=1;
- nh->code=code;
- memcpy(nh->client_mac, client_mac, ETH_ALEN);
- if ( switch_mac!=NULL ) {
-  memcpy(nh->switch_mac, switch_mac, ETH_ALEN);
- }
- nh->seqnum=htonl(seqnum);
- memcpy(nh->proto_id, "NSDP", 4);
-}
-
-
-
-// ---------------------------------------------------------------------------------------------------------------------------------------------------------
-bool validateNgHeader (const struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum) {
- if ( nh->version!=1 ) {
-  return false;
- }
- if ( code>0 && nh->code!=code ) {
-  return false;
- }
- if ( nh->unk1!=0 ) {
-  return false;
- }
- if ( *(unsigned short*)nh->unk2!=0 ) {
-  return false;
- }
- if ( client_mac!=NULL && memcmp(nh->client_mac, client_mac, ETH_ALEN)!=0 ) {
-  return false;
- }
- if ( switch_mac!=NULL && memcmp(nh->switch_mac, switch_mac, ETH_ALEN)!=0 ) {
-  return false;
- }
- if ( seqnum>0 && ntohl(nh->seqnum)!=seqnum ) {
-  return false;
- }
- if ( memcmp(nh->proto_id, "NSDP", 4)!=0 ) {
-  return false;
- }
- if ( *(unsigned int*)nh->unk3!=0 ) {
-  return false;
- }
- return true;
-}
-
-
-
-// -------------------------------------
-void initNgPacket (struct ng_packet *np) {
- np->ah=(struct attr_header*)np->nh->data;
-}
-
-
-
-// --------------------------------------------------------------------------------------------
-void addPacketAttr (struct ng_packet *np, unsigned short attr, unsigned short size, void* data) {
- struct attr_header *ah=np->ah;
- if ( (int)(getPacketTotalSize(np)+sizeof(struct attr_header)+size)>(np->maxlen) ) {
-  return;
- }
- ah->attr=htons(attr);
- ah->size=htons(size);
- if ( size>0 && data!=NULL ) {
-  memcpy(ah->data, data, size);
- }
- np->ah=(struct attr_header*)(ah->data+size);
-}
-
-
-
-// ----------------------------------------------------------------
-void addPacketEmptyAttr (struct ng_packet *np, unsigned short attr) {
- addPacketAttr(np, attr, 0, NULL);
-}
-
-
-
-// -------------------------------------------------------------------------
-void addPacketByteAttr (struct ng_packet *np, unsigned short attr, char val) {
- addPacketAttr(np, attr, 1, &val);
-}
-
-
-
-// ---------------------------------------------------------------------------
-void addPacketShortAttr (struct ng_packet *np, unsigned short attr, short val) {
- short s=htons(val);
- addPacketAttr(np, attr, 2, &s);
-}
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
 
-
-
-// ------------------------------------------------
-int getPacketTotalSize (const struct ng_packet *np) {
- return ((char*)np->ah)-np->buffer;
-}
-
-
-
-// --------------------------------------------
-struct attr* newEmptyAttr (unsigned short attr) {
- return newAttr(attr, 0, NULL);
-}
-
-
-
-// ------------------------------------------------------------------------
-struct attr* newAttr (unsigned short attr, unsigned short size, void *data) {
- struct attr *at;
- at=malloc(sizeof(struct attr));
- at->attr=attr;
- at->size=size;
- at->data=data;
- return at;
-}
-
-
-
-// ----------------------------------------------------------------
-struct attr* newByteAttr (unsigned short attr, unsigned char value) {
- char *v=malloc(sizeof(char));
- *v=value;
- return newAttr(attr, sizeof(char), v);
-}
-
-
-
-// ---------------------------------------------------------
-struct attr* newShortAttr (unsigned short attr, short value) {
- short *v=malloc(sizeof(short));
- *v=htons(value);
- return newAttr(attr, sizeof(short), v);
-}
-
-
-
-// -----------------------------------------------------
-struct attr* newIntAttr (unsigned short attr, int value) {
- int *v=malloc(sizeof(int));
- *v=htonl(value);
- return newAttr(attr, sizeof(int), v);
-}
-
-
-
-// -----------------------------------------------------------------
-struct attr* newAddrAttr (unsigned short attr, struct in_addr value) {
- struct in_addr *v=malloc(sizeof(struct in_addr));
- *v=value;
- return newAttr(attr, sizeof(struct in_addr), v);
-}
-
-
-
-// ----------------------------
-void freeAttr (struct attr *at) {
- if ( at!=NULL ) {
-  free(at->data);
-  free(at);
- }
-}
-
-
-
-// --------------------------------------------------------------------------------------------------------------
-int extractPacketAttributes (struct ng_packet *np, unsigned char *error, unsigned short *attr_error, List *attr) {
- struct attr *at;
- int ret=0;
- if ( error!=NULL ) *error=np->nh->error;
- if ( attr_error!=NULL ) *attr_error=ntohs(np->nh->attr);
- while ( getPacketTotalSize(np)<np->maxlen ) {
-  
-  // no room for an attribute header: error
-  if ( getPacketTotalSize(np)+(int)sizeof(struct attr_header)>np->maxlen ) {
-   ret=-1;
-   break;
-  }
-  
-  at=malloc(sizeof(struct attr));
-  at->attr=ntohs(np->ah->attr);
-  at->size=ntohs(np->ah->size);
-  
-  // attribute data bigger than the remaining size: error
-  if ( getPacketTotalSize(np)+(int)sizeof(struct attr_header)+at->size>np->maxlen ) {
-   free(at);
-   ret=-1;
-   break;
-  }
-  
-  if ( at->size==0 ) {
-   at->data=NULL;
-  } else {
-   at->data=malloc(at->size*sizeof(char));
-   memcpy(at->data, np->ah->data, at->size);
-  }
-  
-  pushBackList(attr, at);
-  
-  // stop on an END attribute
-  if ( at->attr==ATTR_END ) break;
-  
-  // move to next attribute
-  np->ah=(struct attr_header*)(np->ah->data+at->size);
-  
- }
- return ret;
-}
+#include "attr.h"
+#include "protocol.h"
 
 
 
-// --------------------------------------------------------------
-void extractSwitchAttributes (struct swi_attr *sa, const List *l) {
- const ListNode *ln;
- const struct attr *at;
- int len;
- memset(sa, 0, sizeof(struct swi_attr));
- for (ln=l->first; ln!=NULL; ln=ln->next) {
-  at=ln->data;
-  
-  switch ( at->attr ) {
-   
-   case ATTR_PRODUCT:
-    len=min(at->size, PRODUCT_SIZE);
-    memcpy(sa->product, at->data, len);
-    trim(sa->product, len);
-   break;
-   
-   case ATTR_NAME:
-    len=min(at->size, NAME_SIZE);
-    memcpy(sa->name, at->data, len);
-    trim(sa->name, len);
-   break;
-   
-   case ATTR_MAC:
-    memcpy(&sa->mac, at->data, ETH_ALEN);
-   break;
-   
-   case ATTR_IP:
-    sa->nc.ip=*(struct in_addr*)at->data;
-   break;
-   
-   case ATTR_NETMASK:
-    sa->nc.netmask=*(struct in_addr*)at->data;
-   break;
-   
-   case ATTR_GATEWAY:
-    sa->nc.gw=*(struct in_addr*)at->data;
-   break;
-   
-   case ATTR_DHCP:
-    sa->nc.dhcp=( ntohs(*(unsigned short*)at->data)==1 );
-   break;
-   
-   case ATTR_FIRM_VER:
-    len=min(at->size, FIRMWARE_SIZE-1);
-    memcpy(sa->firmware, at->data, len);
-    sa->firmware[len]=0;
-   break;
-   
-   case ATTR_PORTS_COUNT:
-    sa->ports=*(unsigned char*)at->data;
-   break;
-   
-   case ATTR_END:
-    return;
-   
-  }
-  
- }
+int trim (char *txt, int start)
+{
+       char *p;
+       
+       if (txt == NULL)
+               return 0;
+       
+       p = txt + start;
+       while (p >= txt && (*p == ' ' || *p == '\n')) {
+               *p = '\0';
+               p--;
+       }
+       
+       return p - txt + 1;
+}
+
+
+void initNgHeader (struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum)
+{
+       memset(nh, 0, sizeof(struct ng_header));
+       nh->version = 1;
+       nh->code = code;
+       
+       memcpy(nh->client_mac, client_mac, ETH_ALEN);
+       
+       if (switch_mac != NULL)
+               memcpy(nh->switch_mac, switch_mac, ETH_ALEN);
+       
+       nh->seqnum = htonl(seqnum);
+       memcpy(nh->proto_id, "NSDP", 4);
+}
+
+
+bool validateNgHeader (const struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum)
+{
+       if (nh->version != 1)
+               return false;
+       
+       if (code > 0 && nh->code != code)
+               return false;
+       
+       if (nh->unk1 != 0)
+               return false;
+       
+       if (*(unsigned short*)nh->unk2 != 0)
+               return false;
+       
+       if (client_mac != NULL && memcmp(nh->client_mac, client_mac, ETH_ALEN) != 0)
+               return false;
+       
+       if (switch_mac != NULL && memcmp(nh->switch_mac, switch_mac, ETH_ALEN) != 0)
+               return false;
+       
+       if (seqnum > 0 && ntohl(nh->seqnum) != seqnum)
+               return false;
+       
+       if (memcmp(nh->proto_id, "NSDP", 4) != 0)
+               return false;
+       
+       if (*(unsigned int*)nh->unk3 != 0)
+               return false;
+       
+       return true;
+}
+
+
+void addPacketAttr (struct ng_packet *np, struct attr *at)
+{
+       struct attr_header *ah = np->ah;
+       
+       
+       if ((int)(getPacketTotalSize(np) + sizeof(struct attr_header) + at->size) > np->maxlen)
+               return;
+       
+       ah->attr = htons(at->attr);
+       ah->size = htons(at->size);
+       
+       if (at->size > 0 && at->data != NULL)
+               memcpy(ah->data, at->data, at->size);
+       
+       np->ah = (struct attr_header*)(ah->data + at->size);
+}
+
+
+struct attr* newAttr (unsigned short attr, unsigned short size, void *data)
+{
+       struct attr *at;
+       
+       
+       at = malloc(sizeof(struct attr));
+       if (at == NULL)
+               return NULL;
+       
+       at->attr = attr;
+       at->size = size;
+       at->data = data;
+       
+       
+       return at;
+}
+
+
+void freeAttr (struct attr *at)
+{
+       if (at != NULL) {
+               free(at->data);
+               free(at);
+       }
+}
+
+
+int addPacketAttributes (struct ng_packet *np, const List* attr, unsigned char ports)
+{
+       ListNode *ln;
+       struct attr *at;
+       const struct attr_handler *ah;
+       
+       
+       if (attr == NULL)
+               return 0;
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               ah = getAttrHandler(at->attr);
+               if (ah != NULL) {
+                       if (ah->size > 0 && at->size > 0 && at->size != ah->size)
+                               return -EINVAL;
+                       if (at->size > 0 && ah->encode != NULL && !ah->encode(at, ports))
+                               return -EINVAL;
+               }
+               
+               addPacketAttr(np, at);
+       }
+       
+       
+       return 0;
+}
+
+
+int extractPacketAttributes (struct ng_packet *np, unsigned char *error, unsigned short *attr_error, List *attr, unsigned short filter_attr, unsigned char ports)
+{
+       struct attr *at;
+       const struct attr_handler *ah;
+       int ret = 0;
+       unsigned short size;
+       bool valid;
+       
+       
+       if (error != NULL)
+               *error = np->nh->error;
+       if (attr_error != NULL)
+               *attr_error = ntohs(np->nh->attr);
+       
+       while (getPacketTotalSize(np) < np->maxlen) {
+               
+               /* no room for an attribute header: error */
+               if (getPacketTotalSize(np) + (int)sizeof(struct attr_header) > np->maxlen) {
+                       ret = -1;
+                       break;
+               }
+               
+               /* create new attribute */
+               size = ntohs(np->ah->size);
+               at = newAttr(ntohs(np->ah->attr), size, NULL);
+               if (at == NULL) {
+                       ret = -1;
+                       break;
+               }
+               
+               /* attribute data bigger than the remaining size: error */
+               if (getPacketTotalSize(np) + (int)sizeof(struct attr_header) + size > np->maxlen) {
+                       free(at);
+                       ret = -1;
+                       break;
+               }
+               
+               /* copy attribute raw data */
+               if (size == 0) {
+                       at->data = NULL;
+               } else {
+                       at->data = malloc(size * sizeof(char));
+                       memcpy(at->data, np->ah->data, size);
+               }
+               
+               /* decode attribute data */
+               valid = true;
+               
+               if (filter_attr != ATTR_END && at->attr != filter_attr) {
+                       valid = false;
+                       goto next;
+               }
+               
+               ah = getAttrHandler(at->attr);
+               if (at->data == NULL || ah == NULL)
+                       goto next;
+               
+               if (ah->size > 0 && size != ah->size) {
+                       valid = false;
+                       goto next;
+               }
+               
+               if (ah->decode != NULL)
+                       valid = ah->decode(at, ports);
+               
+next:
+               /* stop on an END attribute */
+               if (at->attr == ATTR_END) {
+                       free(at);
+                       break;
+               }
+               
+               /* move to next attribute */
+               np->ah = (struct attr_header*)(np->ah->data + size);
+               
+               if (valid)
+                       pushBackList(attr, at);
+               else
+                       free(at);
+       }
+       
+       
+       return ret;
 }
 
 
-
index cec182bbd77bd22de1455a647c0cc449c0a051d8..3064fd4f797578f7ef3acd55990bd4298bcafc34 100644 (file)
 #define DEF_PROTOCOL
 
 
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
+#include <stdlib.h>
 #include <arpa/inet.h>
+
 #include <netinet/ether.h>
 
-#include <ngadmin.h>
 #include "list.h"
-#include "lib.h"
 
 
+#define CLIENT_PORT            63321
+#define SWITCH_PORT            63322
+
+#define CODE_READ_REQ          1
+#define CODE_READ_REP          2
+#define CODE_WRITE_REQ         3
+#define CODE_WRITE_REP         4
 
+#define ERROR_READONLY         3
+#define ERROR_INVALID_VALUE    5
+#define ERROR_DENIED           7
 
 
 struct ng_header {
- char version;                 // always 1, maybe version
- char code;                    // request code: read request, read reply, write request, write reply
- unsigned char error;          // error code, 0 when no error
- unsigned char unk1;           // always 0, unknown
- unsigned short attr;          // attribute code which caused error, 0 when no error
- char unk2[2];                         // always 0, unknown
- char client_mac[ETH_ALEN];    // client MAC address
- char switch_mac[ETH_ALEN];    // switch MAC address
- unsigned int seqnum;          // sequence number
- char proto_id[4];             // always "NSDP", maybe short for "Netgear Switch Description Protocol"
- char unk3[4];                         // always 0, unknown
- char data[0];
-} __attribute__((packed)) ;
+       char version;                   /* always 1, maybe version */
+       char code;                      /* request code: read request, read reply, write request, write reply */
+       unsigned char error;            /* error code, 0 when no error */
+       unsigned char unk1;             /* always 0, unknown */
+       unsigned short attr;            /* attribute code which caused error, 0 when no error */
+       char unk2[2];                   /* always 0, unknown */
+       char client_mac[ETH_ALEN];      /* client MAC address */
+       char switch_mac[ETH_ALEN];      /* switch MAC address */
+       unsigned int seqnum;            /* sequence number */
+       char proto_id[4];               /* always "NSDP", maybe short for "Netgear Switch Description Protocol" */
+       char unk3[4];                   /* always 0, unknown */
+       char data[0];
+} __attribute__((packed));
+
 
 struct attr_header {
- unsigned short attr;
- unsigned short size;
- char data[0];
-} __attribute__((packed)) ;
      unsigned short attr;
      unsigned short size;
      char data[0];
+} __attribute__((packed));
 
 
 struct ng_packet {
- union {
-  char *buffer;
-  struct ng_header *nh;
- };
- int maxlen;
- struct attr_header *ah;
      union {
+               char *buffer;
+               struct ng_header *nh;
      };
      int maxlen;
      struct attr_header *ah;
 };
 
 
 struct attr {
- unsigned short attr;
- unsigned short size;
- void *data;
      unsigned short attr;
      unsigned short size;
      void *data;
 };
 
 
 
-
-// 
 int trim (char *txt, int start);
 
-// 
-int min (int a, int b);
 
-// 
+static inline int min (int a, int b)
+{
+       return a < b ? a : b;
+}
+
+
 void initNgHeader (struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum);
 
-// 
+
 bool validateNgHeader (const struct ng_header *nh, char code, const struct ether_addr *client_mac, const struct ether_addr *switch_mac, unsigned int seqnum);
 
-// 
-void initNgPacket (struct ng_packet *np);
 
-// 
-void addPacketAttr (struct ng_packet *np, unsigned short attr, unsigned short size, void* data);
+static inline void initNgPacket (struct ng_packet *np)
+{
+       np->ah = (struct attr_header*)np->nh->data;
+}
 
-// 
-void addPacketEmptyAttr (struct ng_packet *np, unsigned short attr);
 
-// 
-void addPacketByteAttr (struct ng_packet *np, unsigned short attr, char val);
+void addPacketAttr (struct ng_packet *np, struct attr *at);
 
-// 
-void addPacketShortAttr (struct ng_packet *np, unsigned short attr, short val);
 
-// 
-int getPacketTotalSize (const struct ng_packet *np);
+static inline int getPacketTotalSize (const struct ng_packet *np)
+{
+       return ((char*)np->ah) - np->buffer;
+}
 
-// 
-struct attr* newEmptyAttr (unsigned short attr);
 
-// 
 struct attr* newAttr (unsigned short attr, unsigned short size, void *data);
 
-// 
-struct attr* newByteAttr (unsigned short attr, unsigned char value);
 
-// 
-struct attr* newShortAttr (unsigned short attr, short value);
+static inline struct attr* newEmptyAttr (unsigned short attr)
+{
+       return newAttr(attr, 0, NULL);
+}
+
+
+static inline struct attr* newByteAttr (unsigned short attr, unsigned char value)
+{
+       char *v = malloc(sizeof(char));
+       
+       *v = value;
+       
+       return newAttr(attr, sizeof(char), v);
+}
+
+
+static inline struct attr* newShortAttr (unsigned short attr, short value)
+{
+       short *v = malloc(sizeof(short));
+       
+       *v = value;
+       
+       return newAttr(attr, sizeof(short), v);
+}
+
+
+static inline struct attr* newIntAttr (unsigned short attr, int value)
+{
+       int *v = malloc(sizeof(int));
+       
+       *v = value;
+       
+       return newAttr(attr, sizeof(int), v);
+}
+
 
-// 
-struct attr* newIntAttr (unsigned short attr, int value);
+static inline struct attr* newAddrAttr (unsigned short attr, struct in_addr value)
+{
+       struct in_addr *v = malloc(sizeof(struct in_addr));
+       
+       *v = value;
+       
+       return newAttr(attr, sizeof(struct in_addr), v);
+}
 
-// 
-struct attr* newAddrAttr (unsigned short attr, struct in_addr value);
 
-// 
 void freeAttr (struct attr *at);
 
-// 
-int extractPacketAttributes (struct ng_packet *np, unsigned char *error, unsigned short *attr_error, List *attr);
 
-// 
-void extractSwitchAttributes (struct swi_attr *sa, const List *l);
+int addPacketAttributes (struct ng_packet *np, const List* attr, unsigned char ports);
 
 
+int extractPacketAttributes (struct ng_packet *np, unsigned char *error, unsigned short *attr_error, List *attr, unsigned short filter_attr, unsigned char ports);
 
 
 #endif