From 931564a7744fe0de3bb5b79af556ee8ff82a1774 Mon Sep 17 00:00:00 2001 From: darkcoven Date: Mon, 1 Apr 2013 18:49:13 +0200 Subject: [PATCH] Lib: source refactor. 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 | 127 ++- lib/src/attr.c | 465 ++++++++ lib/src/attr.h | 132 +++ lib/src/lib.h | 95 +- lib/src/network.c | 667 ++++++----- lib/src/network.h | 33 +- lib/src/ngadmin.c | 2670 ++++++++++++++++++++------------------------ lib/src/protocol.c | 600 ++++------ lib/src/protocol.h | 165 +-- 9 files changed, 2606 insertions(+), 2348 deletions(-) create mode 100644 lib/src/attr.c create mode 100644 lib/src/attr.h diff --git a/lib/ngadmin.h b/lib/ngadmin.h index 81daf25..1f48f2f 100644 --- a/lib/ngadmin.h +++ b/lib/ngadmin.h @@ -12,6 +12,7 @@ #include #include + #include @@ -45,15 +46,16 @@ * 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 index 0000000..3e12690 --- /dev/null +++ b/lib/src/attr.c @@ -0,0 +1,465 @@ + +#include + +#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 index 0000000..e297b49 --- /dev/null +++ b/lib/src/attr.h @@ -0,0 +1,132 @@ + +#ifndef DEF_ATTR +#define DEF_ATTR + + +#include + +#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 + diff --git a/lib/src/lib.h b/lib/src/lib.h index 93aaae9..b1552ec 100644 --- a/lib/src/lib.h +++ b/lib/src/lib.h @@ -3,93 +3,36 @@ #define DEF_LIB -#include -#include -#include +#include + #include +#include #include -#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 diff --git a/lib/src/network.c b/lib/src/network.c index 4df887e..fce65c3 100644 --- a/lib/src/network.c +++ b/lib/src/network.c @@ -1,335 +1,398 @@ -#include "network.h" +#include +#include +#include +#include +#include +#include +#include +#include +#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; + } + } } diff --git a/lib/src/network.h b/lib/src/network.h index 534ae31..7349278 100644 --- a/lib/src/network.h +++ b/lib/src/network.h @@ -3,47 +3,36 @@ #define DEF_NETWORK -#include -#include -//#include -#include -#include -#include -#include -//#include - #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 diff --git a/lib/src/ngadmin.c b/lib/src/ngadmin.c index f9d2610..4ab3306 100644 --- a/lib/src/ngadmin.c +++ b/lib/src/ngadmin.c @@ -1,1582 +1,1352 @@ -#include "lib.h" -#include "network.h" - +#include +#include -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 && icurrent->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 && portcurrent->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 && icurrent->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; icurrent->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->sizeport<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; icurrent->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 ( sQOS_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]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; icurrent->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=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; iports; ++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; iports; ++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; iports && 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; iports; ++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); } diff --git a/lib/src/protocol.c b/lib/src/protocol.c index 6c400f4..de2c451 100644 --- a/lib/src/protocol.c +++ b/lib/src/protocol.c @@ -1,379 +1,237 @@ -#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 aversion=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 +#include +#include +#include +#include - - -// ------------------------------------------------ -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)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; } - diff --git a/lib/src/protocol.h b/lib/src/protocol.h index cec182b..3064fd4 100644 --- a/lib/src/protocol.h +++ b/lib/src/protocol.h @@ -3,119 +3,154 @@ #define DEF_PROTOCOL -#include -#include -#include +#include #include + #include -#include #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 -- 2.39.5