]> git.sur5r.net Git - ngadmin/blobdiff - lib/src/vlan.c
Add error codes to handle bad replies and unknown errors
[ngadmin] / lib / src / vlan.c
index 9bd14c69a21449b5bba3e5aea1bca139164c6cc9..962f2f2e0c5dbc280aa8396ca708c1f398447443 100644 (file)
@@ -1,8 +1,8 @@
 
 #include <ngadmin.h>
 
-#include <attr.h>
-#include <protocol.h>
+#include <nsdp/attr.h>
+#include <nsdp/protocol.h>
 
 #include "lib.h"
 #include "network.h"
@@ -31,11 +31,12 @@ int ngadmin_getVLANType (struct ngadmin *nga, int *t)
        
        *t = VLAN_DISABLED;
        
-       if (attr->first != NULL) {
-               at = attr->first->data;
-               *t =(int)*(char*)at->data;
+       if (attr->first == NULL) {
+               ret = ERR_BADREPLY;
+               goto end;
        }
-       
+       at = attr->first->data;
+       *t =(int)*(char*)at->data;
        
 end:
        destroyList(attr, (void(*)(void*))freeAttr);
@@ -50,7 +51,7 @@ int ngadmin_setVLANType (struct ngadmin *nga, int t)
        List *attr;
        
        
-       if (nga == NULL || t < 1 || t > 4)
+       if (nga == NULL || t < VLAN_DISABLED || t > VLAN_DOT_ADV)
                return ERR_INVARG;
        else if (nga->current == NULL)
                return ERR_NOTLOG;
@@ -91,14 +92,21 @@ int ngadmin_getVLANPortConf (struct ngadmin *nga, unsigned char *ports)
        
        filterAttributes(attr, ATTR_VLAN_PORT_CONF, ATTR_END);
        
+       if (attr->first == NULL) {
+               ret = ERR_BADREPLY;
+               goto 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;
+               if (at->size < sizeof(struct attr_vlan_conf) + sa->ports) {
+                       ret = ERR_BADREPLY;
+                       goto end;
+               }
                
                for (port = 0; port < sa->ports; port++) {
                        if (avc->ports[port] == VLAN_UNTAGGED)
@@ -117,13 +125,12 @@ end:
 
 int ngadmin_setVLANPortConf (struct ngadmin *nga, const unsigned char *ports)
 {
-       List *attr = NULL;
+       List *conf_old = NULL, *conf_new = NULL;
        ListNode *ln;
        struct attr *at;
        struct swi_attr *sa;
-       struct attr_vlan_conf *avc;
+       struct attr_vlan_conf *avc_old, *avc_new;
        int ret = ERR_OK, port;
-       unsigned char vlan;
        
        
        if (nga == NULL || ports == NULL)
@@ -135,47 +142,69 @@ int ngadmin_setVLANPortConf (struct ngadmin *nga, const unsigned char *ports)
        
        /* if nothing is to be changed, do nothing */
        for (port = 0; port < sa->ports && ports[port] == 0; port++);
-       if (port == sa->ports )
+       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));
-               }
+       /* read old config */
+       conf_old = createEmptyList();
+       pushBackList(conf_old, newEmptyAttr(ATTR_VLAN_PORT_CONF));
+       ret = readRequest(nga, conf_old);
+       if (ret != ERR_OK)
+               goto end;
+       
+       filterAttributes(conf_old, ATTR_VLAN_PORT_CONF, ATTR_END);
+       
+       if (conf_old->first == NULL) {
+               ret = ERR_BADREPLY;
+               goto end;
        }
        
-       for (ln = attr->first; ln != NULL; ln = ln->next) {
+       /* merge old config with requested config */
+       conf_new = createEmptyList();
+       avc_new = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
+       
+       for (ln = conf_old->first; ln != NULL; ln = ln->next) {
                at = ln->data;
-               avc = at->data;
+               avc_old = at->data;
+               
+               if (at->size < sizeof(struct attr_vlan_conf) + sa->ports) {
+                       ret = ERR_BADREPLY;
+                       free(avc_new);
+                       goto end;
+               }
+               
+               /* compute new VLAN configuration */
+               avc_new->vlan = avc_old->vlan;
+               
                for (port = 0; port < sa->ports; port++) {
-                       if (ports[port] == avc->vlan)
-                               avc->ports[port] = VLAN_UNTAGGED;
+                       if (ports[port] == 0)
+                               avc_new->ports[port] = avc_old->ports[port];
+                       else if (ports[port] == avc_new->vlan)
+                               avc_new->ports[port] = VLAN_UNTAGGED;
                        else
-                               avc->ports[port] = VLAN_NO;
+                               avc_new->ports[port] = VLAN_NO;
+               }
+               
+               /* only add it if it is different from old config */
+               if (memcmp(avc_old->ports, avc_new->ports, sa->ports) != 0) {
+                       pushBackList(conf_new, newAttr(ATTR_VLAN_PORT_CONF, sizeof(struct attr_vlan_conf) + sa->ports, avc_new));
+                       avc_new = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
                }
        }
        
-       ret = writeRequest(nga, attr);
-       attr = NULL;
+       free(avc_new);
+       
+       /* if no VLAN is changed, no need to send anything to the switch */
+       if (conf_new->first == NULL)
+               goto end;
        
+       /* send new configuration to the switch */
+       ret = writeRequest(nga, conf_new);
+       conf_new = NULL;
        
 end:
-       destroyList(attr, (void(*)(void*))freeAttr);
+       destroyList(conf_old, (void(*)(void*))freeAttr);
+       destroyList(conf_new, (void(*)(void*))freeAttr);
        
        
        return ret;
@@ -211,6 +240,11 @@ int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsig
        
        filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
        
+       if (attr->first == NULL) {
+               ret = ERR_BADREPLY;
+               goto end;
+       }
+       
        memset(vlans, 0, total * sizeof(unsigned short));
        memset(ports, 0, total * sa->ports);
        
@@ -218,8 +252,10 @@ 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)
-                       return ERR_INVARG;
+               if (at->size < sizeof(struct attr_vlan_conf) + sa->ports) {
+                       ret = ERR_BADREPLY;
+                       goto end;
+               }
                
                *vlans = avc->vlan;
                memcpy(ports, avc->ports, sa->ports);
@@ -247,14 +283,16 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned c
        ListNode *ln;
        struct attr *at;
        int ret = ERR_OK;
+       struct swi_attr *sa;
        struct attr_vlan_conf *avc;
        
        
        if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX || 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, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
@@ -264,13 +302,24 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned c
        
        filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
        
-       memset(ports, 0, nga->current->ports);
+       if (attr->first == NULL) {
+               ret = ERR_BADREPLY;
+               goto 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) {
+                       ret = ERR_BADREPLY;
+                       goto end;
+               }
+               
                if (avc->vlan == vlan) {
-                       memcpy(ports, avc->ports, nga->current->ports);
+                       memcpy(ports, avc->ports, sa->ports);
                        break;
                }
        }
@@ -324,11 +373,19 @@ int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsi
                
                filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
                
-               if (attr->first != NULL) {
+               /* check if the switch is in 802.1Q mode */
+               if (attr->first == NULL) {
+                       ret = ERR_BADREPLY;
+                       goto end;
+               } else {
                        at = attr->first->data;
-                       memcpy(avc, at->data, sizeof(struct attr_vlan_conf) + sa->ports);
+                       if (at->size < sizeof(struct attr_vlan_conf) + sa->ports) {
+                               ret = ERR_BADREPLY;
+                               goto end;
+                       }
                }
                
+               memcpy(avc, at->data, sizeof(struct attr_vlan_conf) + sa->ports);
                clearList(attr, (void(*)(void*))freeAttr);
        }
        
@@ -379,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;
        
        
@@ -395,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;
        }