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
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;
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;
}
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;
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;
}
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;
}
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;
}
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;
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);
+ }
}
int ngadmin_setMirror (struct ngadmin *nga, const char *ports)
{
List *attr;
- char *p;
struct swi_attr *sa;
+ struct attr_mirror *am;
if (nga == NULL)
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);
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));
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) {
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)
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)
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) {
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));
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:
}
-
int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps)
{
List *attr;
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();
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:
}
-
int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb)
{
List *attr;
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));
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;
}
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,
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);
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;
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;
}
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;
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;
}
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;
}
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;
}
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;
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;
}
-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
void filterAttributes (List *attr, ...);
+int encodeAttr (struct attr *at);
+
+
+int decodeAttr (struct attr *at);
+
+
#endif
+++ /dev/null
-
-#ifndef DEF_ENCODING
-#define DEF_ENCODING
-
-
-#include <stdbool.h>
-
-#include <netinet/ether.h>
-
-#include <nsdp/protocol.h>
-#include <nsdp/net.h>
-#include <nsdp/list.h>
-
-
-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
-
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;
--- /dev/null
+
+#ifndef DEF_ENCODING
+#define DEF_ENCODING
+
+
+#include <stdbool.h>
+
+#include <netinet/ether.h>
+
+#include <nsdp/protocol.h>
+#include <nsdp/net.h>
+#include <nsdp/list.h>
+
+
+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
+
} __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 */
};
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)
#include <stdarg.h>
+#include <errno.h>
+#include <ngadmin.h> /* FIXME */
#include <nsdp/attr.h>
#include <nsdp/protocol.h>
-
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->size = size;
at->data = data;
-
return at;
}
bool keep;
- ln = attr->first;
- while (ln != NULL) {
+ for (ln = attr->first; ln != NULL; ) {
at = ln->data;
va_start(ap, 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);
}
+++ /dev/null
-
-#include <string.h>
-#include <errno.h>
-
-#include <nsdp/attr.h>
-#include <nsdp/encoding.h>
-#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;
-}
-
-
+++ /dev/null
-
-#include <ngadmin.h> /* FIXME */
-#include <nsdp/protocol.h>
-#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;
-}
-
-
+++ /dev/null
-
-#ifndef DEF_ENCODING_ATTR
-#define DEF_ENCODING_ATTR
-
-
-#include <stdbool.h>
-
-#include <nsdp/attr.h>
-
-
-
-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
-
#include <poll.h>
#include <nsdp/net.h>
-#include <nsdp/encoding.h>
+#include <nsdp/packet.h>
static inline void timespec_add (struct timespec *tsa, const struct timespec *tsb)
initNsdpPacket(&np);
initNsdpHeader(np.nh, nc);
- ret = addPacketAttributes(&np, attr, nc->ports);
+ ret = addPacketAttributes(&np, attr);
if (ret < 0)
return ret;
(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;
--- /dev/null
+
+#include <string.h>
+#include <errno.h>
+
+#include <nsdp/attr.h>
+#include <nsdp/packet.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;
+}
+
+
+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;
+}
+
+