]> git.sur5r.net Git - ngadmin/blobdiff - lib/src/ngadmin.c
Fix crash when reading the wrong type of VLAN
[ngadmin] / lib / src / ngadmin.c
index 4ab33060d1f95f5c02620681d53d69b90cccc88f..fa0982906cd810b93047a77a55bbce168a15a226 100644 (file)
@@ -3,11 +3,11 @@
 
 #include <ngadmin.h>
 
+#include <attr.h>
+#include <protocol.h>
+
 #include "lib.h"
 #include "network.h"
-#include "attr.h"
-#include "protocol.h"
-
 
 
 static const struct timeval default_timeout = {.tv_sec = 4, .tv_usec = 0};
@@ -177,7 +177,7 @@ int ngadmin_scan (struct ngadmin *nga)
        /* try to receive any packets until timeout */
        swiList = createEmptyList();
        /* FIXME: end after timeout whatever received packet is good or not */
-       while (recvNgPacket(nga, CODE_READ_REP, NULL, NULL, attr, ATTR_END) >= 0) {
+       while (recvNgPacket(nga, CODE_READ_REP, NULL, NULL, attr) >= 0) {
                sa = malloc(sizeof(struct swi_attr));
                if (sa == NULL)
                        return ERR_MEM;
@@ -219,6 +219,7 @@ const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga)
 int ngadmin_login (struct ngadmin *nga, int id)
 {
        List *attr;
+       struct attr *at;
        int ret = ERR_OK;
        struct swi_attr *sa;
        
@@ -230,10 +231,25 @@ int ngadmin_login (struct ngadmin *nga, int id)
        
        sa = &nga->swi_tab[id];
        nga->current = sa;
+       nga->encrypt_pass = false;
        
        attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_ENCPASS));
+       ret = readRequest(nga, attr);
+       if (ret != ERR_OK)
+               goto end;
+       
+       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);
+       }
+       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. */
        pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
-       ret = readRequest(nga, attr, ATTR_END);
+       ret = readRequest(nga, attr);
        if (ret == ERR_OK ) {
                /* login succeeded */
                /* TODO: if keep broadcasting is disabled, connect() the UDP 
@@ -244,6 +260,7 @@ int ngadmin_login (struct ngadmin *nga, int id)
                nga->current = NULL;
        }
        
+end:
        destroyList(attr, (void(*)(void*))freeAttr);
        
        
@@ -286,10 +303,12 @@ int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports)
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
-       ret = readRequest(nga, attr, ATTR_PORT_STATUS);
+       ret = readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
+       filterAttributes(attr, ATTR_PORT_STATUS, ATTR_END);
+       
        memset(ports, SPEED_UNK, nga->current->ports);
        
        for (ln = attr->first; ln != NULL; ln = ln->next) {
@@ -351,10 +370,12 @@ int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps)
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
-       ret = readRequest(nga, attr, ATTR_PORT_STATISTICS);
+       ret = readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
+       filterAttributes(attr, ATTR_PORT_STATISTICS, ATTR_END);
+       
        memset(ps, 0, nga->current->ports * sizeof(struct port_stats));
        
        for (ln = attr->first; ln != NULL; ln = ln->next) {
@@ -389,6 +410,7 @@ int ngadmin_resetPortsStatistics (struct ngadmin *nga)
 int ngadmin_changePassword (struct ngadmin *nga, const char* pass)
 {
        List *attr;
+       struct attr *at;
        int ret = ERR_OK;
        
        
@@ -399,7 +421,10 @@ int ngadmin_changePassword (struct ngadmin *nga, const char* pass)
        
        
        attr = createEmptyList();
-       pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
+       at = newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass));
+       if (nga->encrypt_pass)
+               passwordEndecode(at->data, at->size);
+       pushBackList(attr, at);
        ret = writeRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
@@ -429,10 +454,12 @@ int ngadmin_getStormFilterState (struct ngadmin *nga, int *s)
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
-       ret = readRequest(nga, attr, ATTR_STORM_ENABLE);
+       ret = readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
+       filterAttributes(attr, ATTR_STORM_ENABLE, ATTR_END);
+       
        *s = 0;
        
        if (attr->first != NULL) {
@@ -479,10 +506,12 @@ int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports)
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
-       ret = readRequest(nga, attr, ATTR_STORM_BITRATE);
+       ret = readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
+       filterAttributes(attr, ATTR_STORM_BITRATE, ATTR_END);
+       
        for (port = 0; port < nga->current->ports; port++)
                ports[port] = BITRATE_UNSPEC;
        
@@ -549,7 +578,7 @@ int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports)
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
        pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
-       ret = readRequest(nga, attr, ATTR_END);
+       ret = readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
@@ -630,10 +659,12 @@ int ngadmin_getQOSMode (struct ngadmin *nga, int *s)
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
-       ret = readRequest(nga, attr, ATTR_QOS_TYPE);
+       ret = readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
+       filterAttributes(attr, ATTR_QOS_TYPE, ATTR_END);
+       
        *s = 0;
        
        if (attr->first != NULL) {
@@ -680,10 +711,12 @@ int ngadmin_getQOSValues (struct ngadmin *nga, char *ports)
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
-       ret = readRequest(nga, attr, ATTR_QOS_CONFIG);
+       ret = readRequest(nga, attr);
        if (ret < 0)
                goto end;
        
+       filterAttributes(attr, ATTR_QOS_CONFIG, ATTR_END);
+       
        for (port = 0; port < nga->current->ports; port++)
                ports[port] = PRIO_UNSPEC;
        
@@ -785,10 +818,12 @@ int ngadmin_getMirror (struct ngadmin *nga, char *ports)
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
-       ret = readRequest(nga, attr, ATTR_MIRROR);
+       ret = readRequest(nga, attr);
        if (ret < 0)
                goto end;
        
+       filterAttributes(attr, ATTR_MIRROR, ATTR_END);
+       
        memset(ports, 0, 1 + nga->current->ports);
        
        if (attr->first != NULL) {
@@ -862,10 +897,12 @@ int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic)
        
        
        pushBackList(attr, newEmptyAttr(ATTR_IGMP_ENABLE_VLAN));
-       ret = readRequest(nga, attr, ATTR_IGMP_ENABLE_VLAN);
+       ret = readRequest(nga, attr);
        if (ret < 0)
                goto end;
        
+       filterAttributes(attr, ATTR_IGMP_ENABLE_VLAN, ATTR_END);
+       
        if (attr->first != NULL) {
                at = attr->first->data;
                aiv = at->data;
@@ -877,10 +914,12 @@ int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic)
        
        
        pushBackList(attr, newEmptyAttr(ATTR_IGMP_BLOCK_UNK));
-       ret = readRequest(nga, attr, ATTR_IGMP_BLOCK_UNK);
+       ret = readRequest(nga, attr);
        if (ret < 0)
                goto end;
        
+       filterAttributes(attr, ATTR_IGMP_BLOCK_UNK, ATTR_END);
+       
        if (attr->first != NULL) {
                at = attr->first->data;
                ic->block = *(char*)at->data;
@@ -890,10 +929,12 @@ int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic)
        
        
        pushBackList(attr, newEmptyAttr(ATTR_IGMP_VALID_V3));
-       ret = readRequest(nga, attr, ATTR_IGMP_VALID_V3);
+       ret = readRequest(nga, attr);
        if (ret < 0)
                goto end;
        
+       filterAttributes(attr, ATTR_IGMP_VALID_V3, ATTR_END);
+       
        if (attr->first != NULL) {
                at = attr->first->data;
                ic->validate = *(char*)at->data;
@@ -972,10 +1013,12 @@ int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb)
                /* the list is destroyed by writeRequest, so we need to recreate it */
                attr = createEmptyList();
                pushBackList(attr, newByteAttr(ATTR_CABLETEST_RESULT, ct[i].port));
-               ret = readRequest(nga, attr, ATTR_CABLETEST_RESULT);
+               ret = readRequest(nga, attr);
                if (ret < 0)
                        goto end;
                
+               filterAttributes(attr, ATTR_CABLETEST_RESULT, ATTR_END);
+               
                for (ln = attr->first; ln != NULL; ln = ln->next) {
                        at = ln->data;
                        acr = at->data;
@@ -1067,10 +1110,12 @@ int ngadmin_getVLANType (struct ngadmin *nga, int *t)
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
-       ret=readRequest(nga, attr, ATTR_VLAN_TYPE);
+       ret=readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
+       filterAttributes(attr, ATTR_VLAN_TYPE, ATTR_END);
+       
        *t = VLAN_DISABLED;
        
        if (attr->first != NULL) {
@@ -1106,18 +1151,139 @@ int ngadmin_setVLANType (struct ngadmin *nga, int t)
 }
 
 
+int ngadmin_getVLANPortConf (struct ngadmin *nga, unsigned char *ports)
+{
+       List *attr;
+       ListNode *ln;
+       struct attr *at;
+       int ret = ERR_OK;
+       struct attr_vlan_conf *avc;
+       struct swi_attr *sa;
+       int port;
+       
+       
+       if (nga == NULL || ports== NULL)
+               return ERR_INVARG;
+       
+       sa = nga->current;
+       if (sa == NULL)
+               return ERR_NOTLOG;
+       
+       
+       attr = createEmptyList();
+       pushBackList(attr, newEmptyAttr(ATTR_VLAN_PORT_CONF));
+       ret = readRequest(nga, attr);
+       if (ret != ERR_OK)
+               goto end;
+       
+       filterAttributes(attr, ATTR_VLAN_PORT_CONF, ATTR_END);
+       
+       memset(ports, 0, sa->ports);
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               avc = at->data;
+
+               if (at->size != sizeof(struct attr_vlan_conf) + sa->ports)
+                       return ERR_INVARG;
+               
+               for (port = 0; port < sa->ports; port++) {
+                       if (avc->ports[port] == VLAN_UNTAGGED)
+                               ports[port] = avc->vlan;
+               }
+       }
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
+}
+
+
+int ngadmin_setVLANPortConf (struct ngadmin *nga, const unsigned char *ports)
+{
+       List *attr = NULL;
+       ListNode *ln;
+       struct attr *at;
+       struct swi_attr *sa;
+       struct attr_vlan_conf *avc;
+       int ret = ERR_OK, port;
+       unsigned char vlan;
+       
+       
+       if (nga == NULL || ports == NULL)
+               return ERR_INVARG;
+       
+       sa = nga->current;
+       if (sa == NULL)
+               return ERR_NOTLOG;
+       
+       /* if nothing is to be changed, do nothing */
+       for (port = 0; port < sa->ports && ports[port] == 0; port++);
+       if (port == sa->ports )
+               goto end;
+       
+       attr = createEmptyList();
+
+       if (memchr(ports, 0, sa->ports) != NULL) {
+               /* if at least one port is unchanged, we need to read old config */
+               pushBackList(attr, newEmptyAttr(ATTR_VLAN_PORT_CONF));
+               ret = readRequest(nga, attr);
+               if (ret != ERR_OK)
+                       goto end;
+               
+               filterAttributes(attr, ATTR_VLAN_PORT_CONF, ATTR_END);
+               /* FIXME: check if the returned array effectively contains correct data */
+       } else {
+               /* create an empty VLAN config */
+               for (vlan = VLAN_MIN; vlan <= VLAN_PORT_MAX; vlan++) {
+                       avc = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
+                       avc->vlan = vlan;
+                       memset(avc->ports, 0, sa->ports);
+                       pushBackList(attr, newAttr(ATTR_VLAN_PORT_CONF, sizeof(struct attr_vlan_conf) + sa->ports, avc));
+               }
+       }
+       
+       for (ln = attr->first; ln != NULL; ln = ln->next) {
+               at = ln->data;
+               avc = at->data;
+               for (port = 0; port < sa->ports; port++) {
+                       if (ports[port] == avc->vlan)
+                               avc->ports[port] = VLAN_UNTAGGED;
+                       else
+                               avc->ports[port] = VLAN_NO;
+               }
+       }
+       
+       ret = writeRequest(nga, attr);
+       attr = NULL;
+       
+       
+end:
+       destroyList(attr, (void(*)(void*))freeAttr);
+       
+       
+       return ret;
+}
+
+
 int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb)
 {
        List *attr;
        ListNode *ln;
        struct attr *at;
        int ret = ERR_OK, total;
-       struct attr_vlan_dot *avd;
+       struct attr_vlan_conf *avc;
+       struct swi_attr *sa;
        
        
        if (nga == NULL || vlans == NULL || ports== NULL || nb == NULL || *nb <= 0)
                return ERR_INVARG;
-       else if (nga->current == NULL)
+       
+       sa = nga->current;
+       if (sa == NULL)
                return ERR_NOTLOG;
        
        
@@ -1126,22 +1292,27 @@ int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsig
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
-       ret = readRequest(nga, attr, ATTR_VLAN_DOT_CONF);
+       ret = readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
+       filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
+       
        memset(vlans, 0, total * sizeof(unsigned short));
-       memset(ports, 0, total * nga->current->ports);
+       memset(ports, 0, total * sa->ports);
        
        for (ln = attr->first; ln != NULL; ln = ln->next) {
                at = ln->data;
-               avd = at->data;
+               avc = at->data;
+               
+               if (at->size != sizeof(struct attr_vlan_conf) + sa->ports)
+                       return ERR_INVARG;
                
-               *vlans = avd->vlan;
-               memcpy(ports, avd->ports, nga->current->ports);
+               *vlans = avc->vlan;
+               memcpy(ports, avc->ports, sa->ports);
                
                vlans++;
-               ports += nga->current->ports;
+               ports += sa->ports;
                (*nb)++;
                
                if (*nb > total)
@@ -1163,10 +1334,10 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned c
        ListNode *ln;
        struct attr *at;
        int ret = ERR_OK;
-       struct attr_vlan_dot *avd;
+       struct attr_vlan_conf *avc;
        
        
-       if (nga == NULL || vlan < 1 || vlan > VLAN_MAX || ports == NULL)
+       if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX || ports == NULL)
                return ERR_INVARG;
        else if (nga->current == NULL)
                return ERR_NOTLOG;
@@ -1174,17 +1345,19 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned c
        
        attr = createEmptyList();
        pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
-       ret = readRequest(nga, attr, ATTR_END);
+       ret = readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
+       filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
+       
        memset(ports, 0, nga->current->ports);
        
        for (ln = attr->first; ln != NULL; ln = ln->next) {
                at = ln->data;
-               avd = at->data;
-               if (avd->vlan == vlan) {
-                       memcpy(ports, avd->ports, nga->current->ports);
+               avc = at->data;
+               if (avc->vlan == vlan) {
+                       memcpy(ports, avc->ports, nga->current->ports);
                        break;
                }
        }
@@ -1203,11 +1376,11 @@ int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsi
        List *attr = NULL;
        struct attr *at;
        struct swi_attr *sa;
-       struct attr_vlan_dot *avd;
+       struct attr_vlan_conf *avc;
        int ret = ERR_OK, port;
        
        
-       if (nga == NULL || vlan < 1 || vlan > VLAN_MAX || ports == NULL)
+       if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX || ports == NULL)
                return ERR_INVARG;
        
        sa = nga->current;
@@ -1222,23 +1395,25 @@ int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsi
        
        
        attr = createEmptyList();
-       avd = malloc(sizeof(struct attr_vlan_dot) + sa->ports);
-       if (avd == NULL)
+       avc = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
+       if (avc == NULL)
                return ERR_MEM;
        
-       avd->vlan = vlan;
+       avc->vlan = vlan;
        
        /* if all is to be changed, we do not need to read old config */
        if (memchr(ports, VLAN_UNSPEC, sa->ports) != NULL) {
                
                pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
-               ret = readRequest(nga, attr, ATTR_VLAN_DOT_CONF);
+               ret = readRequest(nga, attr);
                if (ret != ERR_OK)
                        goto end;
                
+               filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
+               
                if (attr->first != NULL) {
                        at = attr->first->data;
-                       memcpy(avd, at->data, sizeof(struct attr_vlan_dot) + sa->ports);
+                       memcpy(avc, at->data, sizeof(struct attr_vlan_conf) + sa->ports);
                }
                
                clearList(attr, (void(*)(void*))freeAttr);
@@ -1248,11 +1423,11 @@ int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsi
        /* apply changes */
        for (port = 0; port < sa->ports; port++) {
                if (ports[port] != VLAN_UNSPEC)
-                       avd->ports[port] = ports[port];
+                       avc->ports[port] = ports[port];
        }
        
        
-       pushBackList(attr, newAttr(ATTR_VLAN_DOT_CONF, sizeof(struct attr_vlan_dot) + sa->ports, avd));
+       pushBackList(attr, newAttr(ATTR_VLAN_DOT_CONF, sizeof(struct attr_vlan_conf) + sa->ports, avc));
        ret = writeRequest(nga, attr);
        attr = NULL;
        
@@ -1270,7 +1445,7 @@ int ngadmin_VLANDestroy (struct ngadmin *nga, unsigned short vlan)
        List *attr;
        
        
-       if (nga == NULL || vlan < 1 || vlan > VLAN_MAX)
+       if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX)
                return ERR_INVARG;
        else if (nga->current == NULL)
                return ERR_NOTLOG;
@@ -1301,10 +1476,12 @@ int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports)
        
        attr = createEmptyList();
        pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID));
-       ret = readRequest(nga, attr, ATTR_VLAN_PVID);
+       ret = readRequest(nga, attr);
        if (ret != ERR_OK)
                goto end;
        
+       filterAttributes(attr, ATTR_VLAN_PVID, ATTR_END);
+       
        memset(ports, 0, nga->current->ports * sizeof(unsigned short));
        
        for (ln = attr->first; ln != NULL; ln = ln->next) {
@@ -1328,7 +1505,7 @@ int ngadmin_setPVID (struct ngadmin *nga, unsigned char port, unsigned short vla
        struct attr_pvid *ap;
        
        
-       if (nga == NULL || port < 1 || vlan < 1 || vlan > VLAN_MAX)
+       if (nga == NULL || port < 1 || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX)
                return ERR_INVARG;
        else if (nga->current == NULL)
                return ERR_NOTLOG;