From: darkcoven Date: Sun, 13 Oct 2013 15:06:09 +0000 (+0200) Subject: Raw: refactor attribute encoding and decoding X-Git-Url: https://git.sur5r.net/?p=ngadmin;a=commitdiff_plain;h=37f89190b48ac9b483286caa0534fba00bb6f7a9 Raw: refactor attribute encoding and decoding --- diff --git a/lib/src/Makefile.am b/lib/src/Makefile.am index e80b991..e381747 100644 --- a/lib/src/Makefile.am +++ b/lib/src/Makefile.am @@ -3,6 +3,7 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libngadmin.pc lib_LTLIBRARIES = libngadmin.la +noinst_HEADERS = lib.h network.h libngadmin_la_SOURCES = network.c bitrate.c firmware.c libconf.c mirror.c misc.c \ netconf.c ports.c qos.c session.c vlan.c diff --git a/lib/src/bitrate.c b/lib/src/bitrate.c index 50dfb76..82ec14c 100644 --- a/lib/src/bitrate.c +++ b/lib/src/bitrate.c @@ -65,11 +65,14 @@ int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports) struct attr *at; int ret = ERR_OK, port; struct attr_bitrate *sb; + struct swi_attr *sa; if (nga == NULL || ports == NULL) return ERR_INVARG; - else if (nga->current == NULL) + + sa = nga->current; + if (sa == NULL) return ERR_NOTLOG; @@ -81,13 +84,14 @@ int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports) filterAttributes(attr, ATTR_STORM_BITRATE, ATTR_END); - for (port = 0; port < nga->current->ports; port++) + for (port = 0; port < sa->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; + if (sb->port <= sa->ports) + ports[sb->port - 1] = sb->bitrate; } @@ -136,11 +140,14 @@ int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) struct attr *at; int ret = ERR_OK, port; struct attr_bitrate *pb; + struct swi_attr *sa; if (nga == NULL || ports == NULL) return ERR_INVARG; - else if (nga->current == NULL) + + sa = nga->current; + if (sa == NULL) return ERR_NOTLOG; @@ -151,8 +158,9 @@ int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) if (ret != ERR_OK) goto end; + filterAttributes(attr, ATTR_BITRATE_INPUT, ATTR_BITRATE_OUTPUT, ATTR_END); - for (port = 0; port < nga->current->ports; port++) { + for (port = 0; port < sa->ports; port++) { ports[2 * port + 0] = BITRATE_UNSPEC; ports[2 * port + 1] = BITRATE_UNSPEC; } @@ -160,9 +168,11 @@ int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports) for (ln = attr->first; ln != NULL; ln = ln->next) { at = ln->data; pb = at->data; - if (at->attr == ATTR_BITRATE_INPUT) + if (pb->port > sa->ports) + continue; + else if (at->attr == ATTR_BITRATE_INPUT) ports[(pb->port - 1) * 2 + 0] = pb->bitrate; - else if (at->attr == ATTR_BITRATE_OUTPUT) + else ports[(pb->port - 1) * 2 + 1] = pb->bitrate; } diff --git a/lib/src/firmware.c b/lib/src/firmware.c index efe9ad8..03bb3ee 100644 --- a/lib/src/firmware.c +++ b/lib/src/firmware.c @@ -15,12 +15,11 @@ int ngadmin_upgradeFirmware (struct ngadmin *nga, const char *filename) 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. - */ + /* 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; } diff --git a/lib/src/mirror.c b/lib/src/mirror.c index daa7f47..be40738 100644 --- a/lib/src/mirror.c +++ b/lib/src/mirror.c @@ -13,11 +13,15 @@ int ngadmin_getMirror (struct ngadmin *nga, char *ports) List *attr; struct attr *at; int ret = ERR_OK; + struct swi_attr *sa; + struct attr_mirror *am; if (nga == NULL || ports == NULL) return ERR_INVARG; - else if (nga->current == NULL) + + sa = nga->current; + if (sa == NULL) return ERR_NOTLOG; @@ -29,11 +33,22 @@ int ngadmin_getMirror (struct ngadmin *nga, char *ports) filterAttributes(attr, ATTR_MIRROR, ATTR_END); - memset(ports, 0, 1 + nga->current->ports); + memset(ports, 0, 1 + sa->ports); if (attr->first != NULL) { at = attr->first->data; - memcpy(ports, at->data, 1 + nga->current->ports); + am = at->data; + + if (am->outport == 0) { + memset(ports, 0, 1 + sa->ports); + } else if (am->outport > 0 && at->size >= 1 + sa->ports) { + if (at->size < sizeof(struct attr_mirror) + sa->ports) { + ret = ERR_INVARG; + goto end; + } + ports[0] = am->outport; + memcpy(ports + 1, am->ports, sa->ports); + } } @@ -48,8 +63,8 @@ end: int ngadmin_setMirror (struct ngadmin *nga, const char *ports) { List *attr; - char *p; struct swi_attr *sa; + struct attr_mirror *am; if (nga == NULL) @@ -60,17 +75,19 @@ int ngadmin_setMirror (struct ngadmin *nga, const char *ports) return ERR_NOTLOG; - p = malloc(1 + sa->ports); - if (p == NULL) + am = malloc(sizeof(struct attr_mirror) + sa->ports); + if (am == NULL) return ERR_MEM; - if (ports == NULL) - memset(p, 0, 1 + sa->ports); - else - memcpy(p, ports, 1 + sa->ports); + if (ports == NULL) { + am->outport = 0; + } else { + am->outport = ports[0]; + memcpy(am->ports, ports + 1, sa->ports); + } attr = createEmptyList(); - pushBackList(attr, newAttr(ATTR_MIRROR, 1 + sa->ports, p)); + pushBackList(attr, newAttr(ATTR_MIRROR, sizeof(struct attr_mirror) + sa->ports, am)); return writeRequest(nga, attr); diff --git a/lib/src/netconf.c b/lib/src/netconf.c index 9349772..15d0c90 100644 --- a/lib/src/netconf.c +++ b/lib/src/netconf.c @@ -21,15 +21,15 @@ int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic) 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_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)); diff --git a/lib/src/network.c b/lib/src/network.c index 0ad9056..e106596 100644 --- a/lib/src/network.c +++ b/lib/src/network.c @@ -116,22 +116,20 @@ 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. - */ + /* 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. - */ + /* 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 your DHCP server, 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) { @@ -169,10 +167,8 @@ void prepareSend (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code) memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN); nc->remote_addr.sin_family = AF_INET; nc->remote_addr.sin_port = htons(SWITCH_PORT); - if (sa != NULL) { + if (sa != NULL) memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN); - nc->ports = sa->ports; - } /* destination address selection */ if (sa != NULL && !nga->keepbroad) @@ -196,10 +192,8 @@ void prepareRecv (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code) memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN); nc->remote_addr.sin_family = AF_INET; nc->remote_addr.sin_port = htons(SWITCH_PORT); - if (sa != NULL) { + if (sa != NULL) memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN); - nc->ports = sa->ports; - } /* set filter on switch IP */ if (sa == NULL) @@ -287,7 +281,8 @@ int writeRequest (struct ngadmin *nga, List *attr) i = sendNsdpPacket(nga->sock, &nc, attr); /* the list will be filled again by recvNgPacket - but normally it will be still empty */ + * but normally it will be still empty + */ clearList(attr, (void(*)(void*))freeAttr); if (i >= 0) { diff --git a/lib/src/ports.c b/lib/src/ports.c index 0b4afc2..0c73533 100644 --- a/lib/src/ports.c +++ b/lib/src/ports.c @@ -15,13 +15,15 @@ int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) struct attr *at; int ret = ERR_OK; struct attr_port_status *ps; + struct swi_attr *sa; if (nga == NULL || ports == NULL) return ERR_INVARG; - else if (nga->current == NULL) - return ERR_NOTLOG; + sa = nga->current; + if (sa == NULL) + return ERR_NOTLOG; attr = createEmptyList(); pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS)); @@ -31,12 +33,13 @@ int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports) filterAttributes(attr, ATTR_PORT_STATUS, ATTR_END); - memset(ports, SPEED_UNK, nga->current->ports); + memset(ports, SPEED_UNK, sa->ports); for (ln = attr->first; ln != NULL; ln = ln->next) { at = ln->data; ps = at->data; - ports[ps->port - 1] = ps->status; + if (ps->port <= sa->ports) + ports[ps->port - 1] = ps->status; } end: @@ -47,7 +50,6 @@ end: } - int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) { List *attr; @@ -55,11 +57,14 @@ int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) struct attr *at; int ret = ERR_OK; struct attr_port_stat *aps; + struct swi_attr *sa; if (nga == NULL || ps == NULL) return ERR_INVARG; - else if (nga->current == NULL) + + sa = nga->current; + if (sa == NULL) return ERR_NOTLOG; attr = createEmptyList(); @@ -70,14 +75,16 @@ int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps) filterAttributes(attr, ATTR_PORT_STATISTICS, ATTR_END); - memset(ps, 0, nga->current->ports * sizeof(struct port_stats)); + memset(ps, 0, sa->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; + if (aps->port <= sa->ports) { + ps[aps->port -1].recv = aps->recv; + ps[aps->port -1].sent = aps->sent; + ps[aps->port -1].crc = aps->crc; + } } end: @@ -101,7 +108,6 @@ int ngadmin_resetPortsStatistics (struct ngadmin *nga) } - int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb) { List *attr; diff --git a/lib/src/qos.c b/lib/src/qos.c index 553c878..e31648a 100644 --- a/lib/src/qos.c +++ b/lib/src/qos.c @@ -65,13 +65,15 @@ int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) struct attr *at; int ret = ERR_OK, port; struct attr_qos *aq; + struct swi_attr *sa; if (nga == NULL || ports == NULL) return ERR_INVARG; - else if (nga->current == NULL) - return ERR_NOTLOG; + sa = nga->current; + if (sa == NULL) + return ERR_NOTLOG; attr = createEmptyList(); pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG)); @@ -81,13 +83,14 @@ int ngadmin_getQOSValues (struct ngadmin *nga, char *ports) filterAttributes(attr, ATTR_QOS_CONFIG, ATTR_END); - for (port = 0; port < nga->current->ports; port++) + for (port = 0; port < sa->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; + if (aq->port <= sa->ports) + ports[aq->port - 1] = aq->prio; } diff --git a/lib/src/session.c b/lib/src/session.c index 43da030..667464c 100644 --- a/lib/src/session.c +++ b/lib/src/session.c @@ -16,23 +16,27 @@ int ngadmin_scan (struct ngadmin *nga) List *attr, *swiList; struct swi_attr *sa; struct nsdp_cmd nc; - /* - 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 - */ + /* 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 + * + * one may be tempted to add ATTR_ENCPASS so we can now early if the + * switch uses password encryption, but this would cause (at least) + * switches that do not support this feature not to reply to the + * discovery request at all + */ static const unsigned short hello[] = { ATTR_PRODUCT, ATTR_NAME, @@ -137,6 +141,10 @@ int ngadmin_login (struct ngadmin *nga, int id) nga->current = sa; nga->encrypt_pass = false; + /* determine if the switch uses password encryption + * as explained in ngadmin_scan, it cannot be done at discovery + * stage + */ attr = createEmptyList(); pushBackList(attr, newEmptyAttr(ATTR_ENCPASS)); ret = readRequest(nga, attr); @@ -146,19 +154,21 @@ int ngadmin_login (struct ngadmin *nga, int id) filterAttributes(attr, ATTR_ENCPASS, ATTR_END); if (attr->first != NULL) { at = attr->first->data; - nga->encrypt_pass = (at->size == 4 && ntohl(*(unsigned int*)at->data) == 1); + nga->encrypt_pass = (at->size == 4 && *(unsigned int*)at->data == 1); } clearList(attr, (void(*)(void*))freeAttr); - /* Strangely, passwords must never be encrypted inside a read request, - * or it will be rejected. Seems more to be a firmware bug. */ + /* strangely, passwords must never be encrypted inside a read request, + * or it will be rejected. Seems more to be a firmware bug + */ pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password))); ret = readRequest(nga, attr); 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 */ + /* 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; diff --git a/lib/src/vlan.c b/lib/src/vlan.c index 2d3d536..441e142 100644 --- a/lib/src/vlan.c +++ b/lib/src/vlan.c @@ -103,7 +103,7 @@ int ngadmin_getVLANPortConf (struct ngadmin *nga, unsigned char *ports) at = ln->data; avc = at->data; - if (at->size != sizeof(struct attr_vlan_conf) + sa->ports) { + if (at->size < sizeof(struct attr_vlan_conf) + sa->ports) { ret = ERR_INVARG; goto end; } @@ -167,7 +167,7 @@ int ngadmin_setVLANPortConf (struct ngadmin *nga, const unsigned char *ports) at = ln->data; avc_old = at->data; - if (at->size != sizeof(struct attr_vlan_conf) + sa->ports) { + if (at->size < sizeof(struct attr_vlan_conf) + sa->ports) { ret = ERR_INVARG; free(avc_new); goto end; @@ -252,7 +252,7 @@ int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsig at = ln->data; avc = at->data; - if (at->size != sizeof(struct attr_vlan_conf) + sa->ports) { + if (at->size < sizeof(struct attr_vlan_conf) + sa->ports) { ret = ERR_INVARG; goto end; } @@ -313,7 +313,7 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned c at = ln->data; avc = at->data; - if (at->size != sizeof(struct attr_vlan_conf) + sa->ports) { + if (at->size < sizeof(struct attr_vlan_conf) + sa->ports) { ret = ERR_INVARG; goto end; } @@ -379,7 +379,7 @@ int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsi goto end; } else { at = attr->first->data; - if (at->size != sizeof(struct attr_vlan_conf) + sa->ports) { + if (at->size < sizeof(struct attr_vlan_conf) + sa->ports) { ret = ERR_INVARG; goto end; } @@ -436,11 +436,14 @@ int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports) struct attr *at; int ret = ERR_OK; struct attr_pvid *ap; + struct swi_attr *sa; if (nga == NULL || ports == NULL) return ERR_INVARG; - else if (nga->current == NULL) + + sa = nga->current; + if (sa == NULL) return ERR_NOTLOG; @@ -452,12 +455,13 @@ int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports) filterAttributes(attr, ATTR_VLAN_PVID, ATTR_END); - memset(ports, 0, nga->current->ports * sizeof(unsigned short)); + memset(ports, 0, sa->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; + if (ap->port <= sa->ports) + ports[ap->port - 1] = ap->vlan; } diff --git a/raw/include/nsdp/Makefile.am b/raw/include/nsdp/Makefile.am index ccce647..5a903a8 100644 --- a/raw/include/nsdp/Makefile.am +++ b/raw/include/nsdp/Makefile.am @@ -1,3 +1,3 @@ -noinst_HEADERS = attr.h encoding.h list.h misc.h net.h protocol.h +noinst_HEADERS = attr.h list.h misc.h net.h packet.h protocol.h diff --git a/raw/include/nsdp/attr.h b/raw/include/nsdp/attr.h index 75ce384..e85a002 100644 --- a/raw/include/nsdp/attr.h +++ b/raw/include/nsdp/attr.h @@ -73,5 +73,11 @@ void freeAttr (struct attr *at); void filterAttributes (List *attr, ...); +int encodeAttr (struct attr *at); + + +int decodeAttr (struct attr *at); + + #endif diff --git a/raw/include/nsdp/encoding.h b/raw/include/nsdp/encoding.h deleted file mode 100644 index 27ec812..0000000 --- a/raw/include/nsdp/encoding.h +++ /dev/null @@ -1,51 +0,0 @@ - -#ifndef DEF_ENCODING -#define DEF_ENCODING - - -#include - -#include - -#include -#include -#include - - -struct nsdp_packet { - union { - unsigned char *buffer; - struct nsdp_header *nh; - }; - int maxlen; - struct attr_header *ah; -}; - - - -void initNsdpHeader (struct nsdp_header *nh, const struct nsdp_cmd *nc); - - -bool extractNsdpHeader (const struct nsdp_header *nh, struct nsdp_cmd *nc); - - -static inline void initNsdpPacket (struct nsdp_packet *np) -{ - np->ah = (struct attr_header*)np->nh->data; -} - - -static inline int getPacketTotalSize (const struct nsdp_packet *np) -{ - return ((unsigned char*)np->ah) - np->buffer; -} - - -int addPacketAttributes (struct nsdp_packet *np, const List* attr, unsigned char ports); - - -int extractPacketAttributes (struct nsdp_packet *np, List *attr, unsigned char ports); - - -#endif - diff --git a/raw/include/nsdp/net.h b/raw/include/nsdp/net.h index 401a1fb..8620dd3 100644 --- a/raw/include/nsdp/net.h +++ b/raw/include/nsdp/net.h @@ -15,7 +15,6 @@ struct nsdp_cmd { struct ether_addr switch_mac; struct sockaddr_in remote_addr; unsigned int seqnum; - unsigned int ports; unsigned char code; unsigned char error; unsigned short attr_error; diff --git a/raw/include/nsdp/packet.h b/raw/include/nsdp/packet.h new file mode 100644 index 0000000..21c1569 --- /dev/null +++ b/raw/include/nsdp/packet.h @@ -0,0 +1,51 @@ + +#ifndef DEF_ENCODING +#define DEF_ENCODING + + +#include + +#include + +#include +#include +#include + + +struct nsdp_packet { + union { + unsigned char *buffer; + struct nsdp_header *nh; + }; + int maxlen; + struct attr_header *ah; +}; + + + +void initNsdpHeader (struct nsdp_header *nh, const struct nsdp_cmd *nc); + + +bool extractNsdpHeader (const struct nsdp_header *nh, struct nsdp_cmd *nc); + + +static inline void initNsdpPacket (struct nsdp_packet *np) +{ + np->ah = (struct attr_header*)np->nh->data; +} + + +static inline int getPacketTotalSize (const struct nsdp_packet *np) +{ + return ((unsigned char*)np->ah) - np->buffer; +} + + +int addPacketAttributes (struct nsdp_packet *np, const List* attr); + + +int extractPacketAttributes (struct nsdp_packet *np, List *attr); + + +#endif + diff --git a/raw/include/nsdp/protocol.h b/raw/include/nsdp/protocol.h index a785e2c..e346de5 100644 --- a/raw/include/nsdp/protocol.h +++ b/raw/include/nsdp/protocol.h @@ -147,14 +147,23 @@ struct attr_cabletest_result { } __attribute__((packed)); -/** - * Note: this structure is not sent "as-is" on the wire. +/* Note: this structure is not sent "as-is" on the wire. * A translation is done between the wire format (which uses somewhat not - * trivial bitmap) and this simpler format. See encoding_attr.c for more details. + * trivial bitmap) and this simpler format. See attr.c for more details. */ struct attr_vlan_conf { - unsigned short vlan; /* port number */ - unsigned char ports[0]; /* array, maps each port to a VLAN */ + unsigned short vlan; /* VLAN number */ + unsigned char ports[0]; /* array, maps each port association with the VLAN */ +}; + + +/* Note: this structure is not sent "as-is" on the wire. + * A translation is done between the wire format (which uses somewhat not + * trivial bitmap) and this simpler format. See attr.c for more details. + */ +struct attr_mirror { + unsigned char outport; /* port number on which traffic is sent */ + unsigned char ports[0]; /* array, maps each port source mirror traffic */ }; diff --git a/raw/src/Makefile.am b/raw/src/Makefile.am index cc047c9..f0c2a91 100644 --- a/raw/src/Makefile.am +++ b/raw/src/Makefile.am @@ -1,8 +1,7 @@ noinst_LTLIBRARIES = librawnsdp.la -noinst_HEADERS = encoding_attr.h -librawnsdp_la_SOURCES = attr.c encoding.c encoding_attr.c list.c misc.c net.c +librawnsdp_la_SOURCES = attr.c list.c misc.c net.c packet.c librawnsdp_la_CPPFLAGS = -I$(top_srcdir)/raw/include/ -I$(top_srcdir)/lib/include/ librawnsdp_la_CFLAGS = -fno-strict-aliasing librawnsdp_la_LIBADD = $(RT_LIBS) diff --git a/raw/src/attr.c b/raw/src/attr.c index c8f2fcc..70f3a18 100644 --- a/raw/src/attr.c +++ b/raw/src/attr.c @@ -1,16 +1,16 @@ #include +#include +#include /* FIXME */ #include #include - struct attr* newAttr (unsigned short attr, unsigned short size, void *data) { struct attr *at; - at = malloc(sizeof(struct attr)); if (at == NULL) return NULL; @@ -19,7 +19,6 @@ struct attr* newAttr (unsigned short attr, unsigned short size, void *data) at->size = size; at->data = data; - return at; } @@ -42,8 +41,7 @@ void filterAttributes (List *attr, ...) bool keep; - ln = attr->first; - while (ln != NULL) { + for (ln = attr->first; ln != NULL; ) { at = ln->data; va_start(ap, attr); @@ -63,7 +61,623 @@ void filterAttributes (List *attr, ...) destroyElement(attr, pr, (void(*)(void*))freeAttr); } } +} + + +static int ports_status_endecode (struct attr *at) +{ + struct attr_port_status *ps = at->data; + + if (at->size != sizeof(struct attr_port_status)) + return -EMSGSIZE; + + if (ps->port < 1) + return -EINVAL; + + switch (ps->status) { + + case SPEED_DOWN: + case SPEED_10: + case SPEED_100: + case SPEED_1000: + return 0; + + default: + return -EINVAL; + } +} + + +static int port_stat_endecode (struct attr *at, bool encode) +{ + struct attr_port_stat *ps = at->data; + unsigned long long *v; + + if (at->size != sizeof(struct attr_port_stat)) + return -EMSGSIZE; + + if (ps->port < 1) + return -EINVAL; + + for (v = &ps->recv; ((void*)v) - ((void*)ps) < (int)sizeof(struct attr_port_stat); v++) + *v = encode ? htobe64(*v) : be64toh(*v); + + return 0; +} + + +static int qos_endecode (struct attr *at) +{ + struct attr_qos *aq = at->data; + + if (at->size != sizeof(struct attr_qos)) + return -EMSGSIZE; + + if (aq->port < 1) + return -EINVAL; + + if (aq->prio < PRIO_HIGH || aq->prio > PRIO_LOW) + return -EINVAL; + + return 0; +} + + +static int bitrate_endecode (struct attr *at, bool encode) +{ + struct attr_bitrate *sb = at->data; + + if (at->size != sizeof(struct attr_bitrate)) + return -EMSGSIZE; + + if (sb->port < 1) + return -EINVAL; + + if (!encode) + sb->bitrate = ntohl(sb->bitrate); + + if (sb->bitrate < BITRATE_UNSPEC || sb->bitrate > BITRATE_512M) + return -EINVAL; + + if (encode) + sb->bitrate = htonl(sb->bitrate); + + return 0; +} + + +static int pvid_endecode (struct attr *at, bool encode) +{ + struct attr_pvid *ap = at->data; + + if (at->size != sizeof(struct attr_pvid)) + return -EMSGSIZE; + + if (ap->port < 1) + return -EINVAL; + + if (!encode) + ap->vlan = ntohs(ap->vlan); + + if (ap->vlan < VLAN_MIN || ap->vlan > VLAN_DOT_MAX) + return -EINVAL; + + if (encode) + ap->vlan = htons(ap->vlan); + + return 0; +} + + +static int cabletest_do_endecode (struct attr *at) +{ + struct attr_cabletest_do *acd = at->data; + + if (at->size != sizeof(struct attr_cabletest_do)) + return -EMSGSIZE; + + if (acd->port < 1 || acd->action != 1) + return -EINVAL; + + return 0; +} + + +static int cabletest_result_endecode (struct attr *at, bool encode) +{ + struct attr_cabletest_result *acr = at->data; + + /* Note: this attribute is special + * - when sent by the client, it contains the port number whe want to + * get cabletest results from + * - when the switch replies, it contains the actual test results data + */ + + /* no need to check the size, the only possible value under 1 + * is 0 and in that case the decoder is not called + */ + if (acr->port < 1) + return -EINVAL; + + if (at->size == 1) + return 0; + + if (at->size != sizeof(struct attr_cabletest_result)) + return -EMSGSIZE; + + if (encode) { + acr->v1 = htonl(acr->v1); + acr->v2 = htonl(acr->v2); + } else { + acr->v1 = ntohl(acr->v1); + acr->v2 = ntohl(acr->v2); + } + + return 0; +} + + +static int igmp_vlan_endecode (struct attr *at, bool encode) +{ + struct attr_igmp_vlan *aiv = at->data; + + if (at->size != sizeof(struct attr_igmp_vlan)) + return -EMSGSIZE; + + if (!encode) { + aiv->enable = ntohs(aiv->enable); + aiv->vlan = ntohs(aiv->vlan); + } + + aiv->enable = (aiv->enable != 0); + if (aiv->vlan < VLAN_MIN || aiv->vlan > VLAN_DOT_MAX) + return -EINVAL; + + if (encode) { + aiv->enable = htons(aiv->enable); + aiv->vlan = htons(aiv->vlan); + } + + return 0; +} + + +static int mirror_encode (struct attr *at) +{ + struct attr_mirror *am = at->data; + unsigned char p, ports, *r; + unsigned int sz; + + + /* no need to check attribute size, since + * sizeof(struct attr_mirror) == 1 and encoder is not + * called when attribute size is zero (ie empty attribute) + * + * am->outport encodes the outgoing mirror port and the array + * the ports from which the data is copied, it must not be empty + * + * am->outport == 0 is allowed and means mirroring is disabled + * but in that case the ports array must be empty + */ + ports = at->size - sizeof(struct attr_mirror); + if ((am->outport == 0) ^ (ports == 0)) + return -EINVAL; + + sz = 3 + ((ports - 1) >> 3); + r = malloc(sz); + if (r == NULL) + return -ENOMEM; + memset(r, 0, sz); + + r[0] = am->outport; + + /* FIXME: if ports > 8 */ + for (p = 1; p <= ports; p++) { + if (am->outport != p) + r[2] |= (am->ports[p] & 1) << (8 - p); + } + + free(at->data); + at->data = r; + at->size = sz; + + + return 0; +} + + +static int mirror_decode (struct attr *at) +{ + struct attr_mirror *am; + unsigned char p, ports, *r = at->data; + unsigned int sz; + + + if (at->size < 3) + return -EMSGSIZE; + + /* note: we cannot compute the exact amount of ports from here, + * instead we have the immediate superior multiple of 8 + * it will be the user's job to ignore extra entries + */ + ports = ((at->size - 2) << 3); + + /* r[0] == 0 is allowed and means mirroring is disabled */ + if (r[0] == 0) + ports = 0; + sz = sizeof(struct attr_mirror) + ports; + + am = malloc(sz); + if (am == NULL) + return -ENOMEM; + memset(am, 0, sz); + + am->outport = r[0]; + + /* FIXME: if ports > 8 */ + for (p = 1; p <= ports; p++) + am->ports[p] = (r[2] >> (8 - p)) & 1; + + free(at->data); + at->data = am; + at->size = sz; + + + return 0; +} + + +static int vlan_port_encode (struct attr *at) +{ + struct attr_vlan_conf *avc = at->data; + unsigned char p, ports, *r; + unsigned int sz; + + + /* just a header is valid */ + if (at->size < sizeof(struct attr_vlan_conf)) + return -EMSGSIZE; + ports = at->size - sizeof(struct attr_vlan_conf); + + if (avc->vlan < VLAN_MIN || avc->vlan > VLAN_PORT_MAX) + return -EINVAL; + + if (ports == 0) + sz = 2; + else + sz = (2 + 1 + ((ports - 1) >> 3)); + + r = malloc(sz); + if (r == NULL) + return -ENOMEM; + + memset(r, 0, sz); + *(unsigned short*)r = htons(avc->vlan); + + /* FIXME: if ports > 8 */ + for (p = 0; p < ports; p++) { + if (avc->ports[p] == VLAN_UNTAGGED) + r[2] |= (1 << (7 - p)); + } + + free(at->data); + at->data = r; + at->size = sz; + + + return 0; +} + + +static int vlan_port_decode (struct attr *at) +{ + unsigned char p, ports, *r = at->data; + struct attr_vlan_conf *avc; + unsigned int sz; + + + if (at->size < 2) + return -EMSGSIZE; + + /* note: we cannot compute the exact amount of ports from here, + * instead we have the immediate superior multiple of 8 + * it will be the user's job to ignore extra entries + */ + ports = ((at->size - 2) << 3); + + sz = sizeof(struct attr_vlan_conf) + ports; + avc = malloc(sz); + if (avc == NULL) + return -ENOMEM; + + avc->vlan = ntohs(*(unsigned short*)r); + + /* FIXME: if ports > 8 */ + for (p = 0; p < ports; p++) { + if ((r[2] >> (7 - p)) & 1) + avc->ports[p] = VLAN_UNTAGGED; + else + avc->ports[p] = VLAN_NO; + } + + free(at->data); + at->data = avc; + at->size = sz; + + + return 0; +} + + +static int vlan_dot_encode (struct attr *at) +{ + struct attr_vlan_conf *avc = at->data; + unsigned char p, ports, *r, fl; + unsigned int sz; + + + /* just a header is valid */ + if (at->size < sizeof(struct attr_vlan_conf)) + return -EMSGSIZE; + ports = at->size - sizeof(struct attr_vlan_conf); + + if (avc->vlan < VLAN_MIN || avc->vlan > VLAN_DOT_MAX) + return -EINVAL; + + if (ports == 0) + sz = 2; + else + sz = 2 + 2 * (1 + ((ports - 1) >> 3)); + + r = malloc(sz); + if (r == NULL) + return -EMSGSIZE; + + memset(r, 0, sz); + *(unsigned short*)r = htons(avc->vlan); + + /* FIXME: if ports > 8 */ + for (p = 0; p < ports; p++) { + fl = (1 << (7 - p)); + switch (avc->ports[p]) { + case VLAN_TAGGED: + r[3] |= fl; + /* a tagged VLAN is also marked as untagged + * so do not put a "break" here + */ + case VLAN_UNTAGGED: + r[2] |= fl; + } + } + + + free(at->data); + at->data = r; + at->size = sz; + + + return 0; +} + + +static int vlan_dot_decode (struct attr *at) +{ + unsigned char p, ports, *r = at->data; + struct attr_vlan_conf *avc; + unsigned int sz; + + + /* attribute size must be a multiple of 2 because there are + * 2 bytes (1 for tagged and 1 for untagged) per block of + * 8 ports, plus the 2 first bytes for the VLAN id + */ + if (at->size < 2 || (at->size & 1) != 0) + return -EMSGSIZE; + + /* note: we cannot compute the exact amount of ports from here, + * instead we have the immediate superior multiple of 8 + * it will be the user's job to ignore extra entries + */ + ports = ((at->size - 2) / 2) << 3; + + sz = sizeof(struct attr_vlan_conf) + ports; + avc = malloc(sz); + if (avc == NULL) + return -ENOMEM; + + avc->vlan = ntohs(*(unsigned short*)r); + + /* FIXME: if ports > 8 */ + for (p = 0; p < ports; p++) { + if ((r[3] >> (7 - p)) & 1) + avc->ports[p] = VLAN_TAGGED; + else if ((r[2] >> (7 - p)) & 1) + avc->ports[p] = VLAN_UNTAGGED; + else + avc->ports[p] = VLAN_NO; + } + + free(at->data); + at->data = avc; + at->size = sz; + + return 0; +} + + +static int processAttr (struct attr *at, bool encode) +{ + unsigned char *byte = at->data; + unsigned short *word = at->data; + unsigned int *dword = at->data; + + + /* empty attributes are not processed */ + if (at->size == 0) + return 0; + + if (at->data == NULL) + return -EFAULT; + + switch (at->attr) { + + case ATTR_MAC: + if (at->size != ETH_ALEN) + return -EMSGSIZE; + return 0; + + case ATTR_IP: + case ATTR_NETMASK: + case ATTR_GATEWAY: + /* IP addresses are kept in network byte order even on the host */ + if (at->size != sizeof(struct in_addr)) + return -EMSGSIZE; + + return 0; + + case ATTR_PORTS_COUNT: + if (at->size != 1) + return -EMSGSIZE; + + return 0; + + case ATTR_RESTART: + case ATTR_DEFAULTS: + case ATTR_STATS_RESET: + case ATTR_STORM_ENABLE: + case ATTR_IGMP_BLOCK_UNK: + case ATTR_IGMP_VALID_V3: + if (at->size != 1) + return -EMSGSIZE; + + *byte = (*byte != 0); + + return 0; + + case ATTR_DHCP: + if (at->size != 2) + return -EMSGSIZE; + + if (!encode) + *word = ntohs(*word); + + *word = (*word != 0); + + if (encode) + *word = htons(*word); + + return 0; + + case ATTR_ENCPASS: + if (at->size != 4) + return -EMSGSIZE; + + if (!encode) + *dword = ntohl(*dword); + + *dword = (*dword != 0); + + if (encode) + *dword = htonl(*dword); + + return 0; + + case ATTR_VLAN_TYPE: + if (at->size != 1) + return -EMSGSIZE; + + /* no need to check if *byte < VLAN_DISABLED because + * byte is unsigned and VLAN_DISABLED is 0 */ + if (*byte > VLAN_DOT_ADV) + return -EINVAL; + + return 0; + + case ATTR_QOS_TYPE: + if (at->size != 1) + return -EMSGSIZE; + + if (*byte < QOS_PORT || *byte > QOS_DOT) + return -EINVAL; + + return 0; + + case ATTR_QOS_CONFIG: + return qos_endecode(at); + + case ATTR_VLAN_DESTROY: + if (at->size != 2) + return -EMSGSIZE; + + if (!encode) + *word = ntohs(*word); + + if (*word < VLAN_MIN || *word > VLAN_DOT_MAX) + return -EINVAL; + + if (encode) + *word = htons(*word); + + return 0; + + case ATTR_PORT_STATUS: + return ports_status_endecode(at); + + case ATTR_PORT_STATISTICS: + return port_stat_endecode(at, encode); + + case ATTR_BITRATE_INPUT: + case ATTR_BITRATE_OUTPUT: + case ATTR_STORM_BITRATE: + return bitrate_endecode(at, encode); + + case ATTR_VLAN_PVID: + return pvid_endecode(at, encode); + + case ATTR_CABLETEST_DO: + return cabletest_do_endecode(at); + + case ATTR_CABLETEST_RESULT: + return cabletest_result_endecode(at, encode); + + case ATTR_IGMP_ENABLE_VLAN: + return igmp_vlan_endecode(at, encode); + + case ATTR_MIRROR: + if (encode) + return mirror_encode(at); + else + return mirror_decode(at); + + case ATTR_VLAN_PORT_CONF: + if (encode) + return vlan_port_encode(at); + else + return vlan_port_decode(at); + + case ATTR_VLAN_DOT_CONF: + if (encode) + return vlan_dot_encode(at); + else + return vlan_dot_decode(at); + + /* undefined attributes are not modified */ + default: + return 0; + } +} + + +int encodeAttr (struct attr *at) +{ + return processAttr(at, true); +} + + +int decodeAttr (struct attr *at) +{ + return processAttr(at, false); } diff --git a/raw/src/encoding.c b/raw/src/encoding.c deleted file mode 100644 index 0d8e889..0000000 --- a/raw/src/encoding.c +++ /dev/null @@ -1,192 +0,0 @@ - -#include -#include - -#include -#include -#include "encoding_attr.h" - - - -void initNsdpHeader (struct nsdp_header *nh, const struct nsdp_cmd *nc) -{ - memset(nh, 0, sizeof(struct nsdp_header)); - nh->version = NSDP_VERSION; - nh->code = nc->code; - nh->error = nc->error; - nh->attr = htons(nc->attr_error); - - memcpy(nh->client_mac, &nc->client_mac, ETH_ALEN); - memcpy(nh->switch_mac, &nc->switch_mac, ETH_ALEN); - - nh->seqnum = htonl(nc->seqnum); - memcpy(nh->proto_id, NSDP_PROTOID, 4); -} - - -bool extractNsdpHeader (const struct nsdp_header *nh, struct nsdp_cmd *nc) -{ - unsigned int i; - - - if (nh->version != NSDP_VERSION) - return false; - - if (nc->code > 0 && nh->code != nc->code) - return false; - nc->code = nh->code; - - nc->error = nh->error; - nc->attr_error = ntohs(nh->attr); - - if (nh->unk1 != 0) - return false; - - if (*(unsigned short*)nh->unk2 != 0) - return false; - - for (i = 0; i < ETH_ALEN && nc->client_mac.ether_addr_octet[i] == 0; i++); - if (i < ETH_ALEN && memcmp(nh->client_mac, &nc->client_mac, ETH_ALEN) != 0) - return false; - memcpy(&nc->client_mac, nh->client_mac, ETH_ALEN); - - for (i = 0; i < ETH_ALEN && nc->switch_mac.ether_addr_octet[i] == 0; i++); - if (i < ETH_ALEN && memcmp(nh->switch_mac, &nc->switch_mac, ETH_ALEN) != 0) - return false; - memcpy(&nc->switch_mac, nh->switch_mac, ETH_ALEN); - - if (nc->seqnum > 0 && ntohl(nh->seqnum) != nc->seqnum) - return false; - nc->seqnum = ntohl(nh->seqnum); - - if (memcmp(nh->proto_id, NSDP_PROTOID, 4) != 0) - return false; - - if (*(unsigned int*)nh->unk3 != 0) - return false; - - return true; -} - - -static void addPacketAttr (struct nsdp_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); -} - - -int addPacketAttributes (struct nsdp_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 nsdp_packet *np, List *attr, unsigned char ports) -{ - struct attr *at; - const struct attr_handler *ah; - int ret = 0; - unsigned short size; - bool valid; - - - 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(unsigned char)); - memcpy(at->data, np->ah->data, size); - } - - /* decode attribute data */ - valid = true; - - 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/raw/src/encoding_attr.c b/raw/src/encoding_attr.c deleted file mode 100644 index acb706f..0000000 --- a/raw/src/encoding_attr.c +++ /dev/null @@ -1,548 +0,0 @@ - -#include /* FIXME */ -#include -#include "encoding_attr.h" - - -#define UNUSED __attribute__((unused)) -#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_DOT_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_DOT_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_DOT_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_DOT_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_DOT_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_port_decode (struct attr *at, unsigned char ports) -{ - char *r = at->data; - struct attr_vlan_conf *avc; - int port; - - - if (at->size != (2 + 1 + ((ports - 1) >> 3))) - return false; - - avc = malloc(sizeof(struct attr_vlan_conf) + ports); - if (avc == NULL) - return false; - - avc->vlan = ntohs(*(unsigned short*)r); - r += 2; - - for (port = 0; port < ports; port++) { - /* FIXME: if ports > 8 */ - if ((r[0] >> (7 - port)) & 1) - avc->ports[port] = VLAN_UNTAGGED; - else - avc->ports[port] = VLAN_NO; - } - - free(at->data); - at->data = avc; - at->size = sizeof(struct attr_vlan_conf) + ports; - - - return true; -} - - -static bool vlan_port_encode (struct attr *at, unsigned char ports) -{ - struct attr_vlan_conf *avc = at->data; - char *r; - unsigned int size, port; - - - if (avc->vlan < VLAN_MIN || avc->vlan > VLAN_PORT_MAX) - return false; - - /* just a header is valid */ - if (at->size == sizeof(struct attr_vlan_conf)) - size = 2; - else if (at->size == sizeof(struct attr_vlan_conf) + ports) - size = (2 + 1 + ((ports - 1) >> 3)); - else - return false; - - r = malloc(size); - if (r == NULL) - return false; - - memset(r, 0, size); - *(unsigned short*)r = htons(avc->vlan); - - if (size == 2) - goto end; - - r += 2; - - for (port = 0; port < ports; port++) { - /* FIXME: if ports > 8 */ - if (avc->ports[port] == VLAN_UNTAGGED) - r[0] |= (1 << (7 - port)); - } - - r -= 2; - -end: - free(at->data); - at->data = r; - at->size = size; - - - return true; -} - - -static bool vlan_dot_decode (struct attr *at, unsigned char ports) -{ - char *r = at->data; - struct attr_vlan_conf *avc; - int port; - - - if (at->size != (2 + 2 * (1 + ((ports - 1) >> 3)))) - return false; - - avc = malloc(sizeof(struct attr_vlan_conf) + ports); - if (avc == NULL) - return false; - - avc->vlan = ntohs(*(unsigned short*)r); - r += 2; - - for (port = 0; port < ports; port++) { - /* FIXME: if ports > 8 */ - if ((r[1] >> (7 - port)) & 1) - avc->ports[port] = VLAN_TAGGED; - else if ((r[0] >> (7 - port)) & 1) - avc->ports[port] = VLAN_UNTAGGED; - else - avc->ports[port] = VLAN_NO; - } - - free(at->data); - at->data = avc; - at->size = sizeof(struct attr_vlan_conf) + ports; - - - return true; -} - - -static bool vlan_dot_encode (struct attr *at, unsigned char ports) -{ - struct attr_vlan_conf *avc = at->data; - char *r, fl; - unsigned int size, port; - - - if (avc->vlan < VLAN_MIN || avc->vlan > VLAN_DOT_MAX) - return false; - - /* just a header is valid */ - if (at->size == sizeof(struct attr_vlan_conf)) - size = 2; - else if (at->size == sizeof(struct attr_vlan_conf) + 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(avc->vlan); - - if (size == 2) - goto end; - - r += 2; - - for (port = 0; port < ports; port++) { - /* FIXME: if ports > 8 */ - fl = (1 << (7 - port)); - switch (avc->ports[port]) { - case VLAN_TAGGED: - r[1] |= fl; - /* a tagged VLAN is also marked as untagged - * so do not put a "break" here */ - 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_ENCPASS, 4, 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_PORT_CONF, 0, vlan_port_encode, vlan_port_decode), - 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/raw/src/encoding_attr.h b/raw/src/encoding_attr.h deleted file mode 100644 index ba6146c..0000000 --- a/raw/src/encoding_attr.h +++ /dev/null @@ -1,24 +0,0 @@ - -#ifndef DEF_ENCODING_ATTR -#define DEF_ENCODING_ATTR - - -#include - -#include - - - -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); - - -#endif - diff --git a/raw/src/net.c b/raw/src/net.c index e5af939..83a69f3 100644 --- a/raw/src/net.c +++ b/raw/src/net.c @@ -8,7 +8,7 @@ #include #include -#include +#include static inline void timespec_add (struct timespec *tsa, const struct timespec *tsb) @@ -57,7 +57,7 @@ int sendNsdpPacket (int sock, const struct nsdp_cmd *nc, const List *attr) initNsdpPacket(&np); initNsdpHeader(np.nh, nc); - ret = addPacketAttributes(&np, attr, nc->ports); + ret = addPacketAttributes(&np, attr); if (ret < 0) return ret; @@ -139,7 +139,7 @@ int recvNsdpPacket (int sock, struct nsdp_cmd *nc, List *attr, const struct time (nc->remote_addr.sin_port != 0 && remote.sin_port != nc->remote_addr.sin_port) || len < (int)sizeof(struct nsdp_header) || !extractNsdpHeader(np.nh, nc) || - extractPacketAttributes(&np, attr, nc->ports) < 0) + extractPacketAttributes(&np, attr) < 0) continue; nc->remote_addr = remote; diff --git a/raw/src/packet.c b/raw/src/packet.c new file mode 100644 index 0000000..c9ac718 --- /dev/null +++ b/raw/src/packet.c @@ -0,0 +1,159 @@ + +#include +#include + +#include +#include + + +void initNsdpHeader (struct nsdp_header *nh, const struct nsdp_cmd *nc) +{ + memset(nh, 0, sizeof(struct nsdp_header)); + nh->version = NSDP_VERSION; + nh->code = nc->code; + nh->error = nc->error; + nh->attr = htons(nc->attr_error); + + memcpy(nh->client_mac, &nc->client_mac, ETH_ALEN); + memcpy(nh->switch_mac, &nc->switch_mac, ETH_ALEN); + + nh->seqnum = htonl(nc->seqnum); + memcpy(nh->proto_id, NSDP_PROTOID, 4); +} + + +bool extractNsdpHeader (const struct nsdp_header *nh, struct nsdp_cmd *nc) +{ + unsigned int i; + + + if (nh->version != NSDP_VERSION) + return false; + + if (nc->code > 0 && nh->code != nc->code) + return false; + nc->code = nh->code; + + nc->error = nh->error; + nc->attr_error = ntohs(nh->attr); + + if (nh->unk1 != 0) + return false; + + if (*(unsigned short*)nh->unk2 != 0) + return false; + + for (i = 0; i < ETH_ALEN && nc->client_mac.ether_addr_octet[i] == 0; i++); + if (i < ETH_ALEN && memcmp(nh->client_mac, &nc->client_mac, ETH_ALEN) != 0) + return false; + memcpy(&nc->client_mac, nh->client_mac, ETH_ALEN); + + for (i = 0; i < ETH_ALEN && nc->switch_mac.ether_addr_octet[i] == 0; i++); + if (i < ETH_ALEN && memcmp(nh->switch_mac, &nc->switch_mac, ETH_ALEN) != 0) + return false; + memcpy(&nc->switch_mac, nh->switch_mac, ETH_ALEN); + + if (nc->seqnum > 0 && ntohl(nh->seqnum) != nc->seqnum) + return false; + nc->seqnum = ntohl(nh->seqnum); + + if (memcmp(nh->proto_id, NSDP_PROTOID, 4) != 0) + return false; + + if (*(unsigned int*)nh->unk3 != 0) + return false; + + return true; +} + + +int addPacketAttributes (struct nsdp_packet *np, const List* attr) +{ + ListNode *ln; + struct attr *at; + + + if (attr == NULL) + return 0; + + for (ln = attr->first; ln != NULL; ln = ln->next) { + at = ln->data; + + /* encode attribute data */ + if (encodeAttr(at) < 0) + return -EINVAL; + + /* attribute data bigger than the remaining size: error */ + if ((int)(getPacketTotalSize(np) + sizeof(struct attr_header) + at->size) > np->maxlen) + return -EMSGSIZE; + + /* set attribute code and size */ + np->ah->attr = htons(at->attr); + np->ah->size = htons(at->size); + + /* copy attribute data */ + if (at->size > 0 && at->data != NULL) + memcpy(np->ah->data, at->data, at->size); + + /* move to next attribute */ + np->ah = (struct attr_header*)(np->ah->data + at->size); + } + + + return 0; +} + + +int extractPacketAttributes (struct nsdp_packet *np, List *attr) +{ + struct attr *at; + unsigned short size; + + + while (getPacketTotalSize(np) < np->maxlen) { + /* no room for an attribute header: error */ + if (getPacketTotalSize(np) + (int)sizeof(struct attr_header) > np->maxlen) + return -EMSGSIZE; + + /* create new attribute */ + size = ntohs(np->ah->size); + at = newAttr(ntohs(np->ah->attr), size, NULL); + if (at == NULL) + return -ENOMEM; + + /* attribute data bigger than the remaining size: error */ + if (getPacketTotalSize(np) + (int)sizeof(struct attr_header) + size > np->maxlen) { + free(at); + return -EMSGSIZE; + } + + /* copy attribute raw data */ + if (size == 0) { + at->data = NULL; + } else { + at->data = malloc(size * sizeof(unsigned char)); + memcpy(at->data, np->ah->data, size); + } + + /* decode attribute data */ + if(decodeAttr(at) == 0) { + /* stop on an END attribute */ + if (at->attr == ATTR_END) { + free(at); + break; + } else { + pushBackList(attr, at); + } + } else { + free(at); + } + + /* move to next attribute */ + np->ah = (struct attr_header*)(np->ah->data + size); + } + + + return 0; +} + +