]> git.sur5r.net Git - ngadmin/commitdiff
Add support for port based VLANs
authordarkcoven <admin@darkcoven.tk>
Sat, 21 Sep 2013 23:52:59 +0000 (01:52 +0200)
committerdarkcoven <admin@darkcoven.tk>
Sat, 21 Sep 2013 23:52:59 +0000 (01:52 +0200)
cli/com_vlan.c
cli/commands.c
lib/include/ngadmin.h
lib/src/ngadmin.c
raw/include/attr.h
raw/src/attr.c

index 1e2b573dd60e368fa5fa1c0ee03a8dfdc9a49ab0..7c911bccbe1ca5c0f84c5f4c8fdac1aa77b14aca 100644 (file)
@@ -41,7 +41,7 @@ int do_vlan_8021q_del (int argc, const char **argv, struct ngadmin *nga)
        }
        
        vlan=strtoul(argv[0], NULL, 0);
-       if (vlan < 1 || vlan > VLAN_MAX) {
+       if (vlan < VLAN_MIN || vlan > VLAN_DOT_MAX) {
                printf("vlan out of range\n");
                return 1;
        }
@@ -54,6 +54,125 @@ int do_vlan_8021q_del (int argc, const char **argv, struct ngadmin *nga)
 }
 
 
+int do_vlan_port_set (int argc, const char **argv, struct ngadmin *nga)
+{
+       unsigned char vlan, port, *ports = NULL;
+       const struct swi_attr *sa;
+       int i, k = 0, ret = 0;
+       
+       
+       if (argc < 2) {
+               printf("usage: vlan port set [all <vlan>] [<port1> <vlan>] [<port2> <vlan>] [...]\n");
+               ret = 1;
+               goto end;
+       }
+       
+       sa = ngadmin_getCurrentSwitch(nga);
+       if (sa == NULL) {
+               printf("must be logged\n");
+               ret = 1;
+               goto end;
+       }
+       
+       ports = malloc(sa->ports * sizeof(unsigned char));
+
+       /* read defaults */
+       port = 0;
+       if (strcmp(argv[k], "all") == 0) {
+               k++;
+               port = strtoul(argv[k++], NULL, 0);
+               if (port < 1 || port > sa->ports) {
+                       printf("port out of range");
+                       ret = 1;
+                       goto end;
+               }
+       }
+       
+       /* apply defaults */
+       memset(ports, port, sa->ports);
+       
+       /* read and apply port specifics */
+       while (k < argc - 1) {
+               /* read port */
+               port = strtoul(argv[k++], NULL, 0);
+               if (port < 1 || port > sa->ports) {
+                       printf("port out of range");
+                       ret = 1;
+                       goto end;
+               }
+               
+               /* read vlan */
+               vlan = strtoul(argv[k++], NULL, 0);
+               if (vlan < VLAN_MIN || vlan > VLAN_PORT_MAX) {
+                       printf("vlan out of range\n");
+                       ret = 1;
+                       goto end;
+               }
+               
+               ports[port - 1] = vlan;
+       }
+       
+       /* set conf */
+       i = ngadmin_setVLANPortConf(nga, ports);
+       printErrCode(i);
+       
+end:
+       free(ports);
+       
+       return ret;
+}
+
+
+int do_vlan_port_show (int argc, const char **argv UNUSED, struct ngadmin *nga)
+{
+       unsigned char *ports = NULL;
+       const struct swi_attr *sa;
+       int i, ret = 0;
+       
+       
+       if (argc > 0) {
+               printf("this command takes no argument\n");
+               ret = 1;
+               goto end;
+       }
+       
+       sa = ngadmin_getCurrentSwitch(nga);
+       if (sa == NULL) {
+               printf("must be logged\n");
+               ret = 1;
+               goto end;
+       }
+       
+       ports = malloc(sa->ports * sizeof(unsigned char));
+       
+       /* request all VLANs config */
+       i = ngadmin_getVLANPortConf(nga, ports);
+       
+       if (i != ERR_OK) {
+               printErrCode(i);
+               ret = 1;
+               goto end;
+       }
+       
+       printf("Ports configuration: \n");
+       printf("Port\t");
+       for (i = 1; i <= sa->ports; i++)
+               printf("%i\t", i);
+       putchar('\n');
+       
+       /* show all VLANs */
+       printf("VLAN\t");
+       for (i = 0; i < sa->ports; i++)
+               printf("%u\t", ports[i]);
+       putchar('\n');
+       
+end:
+       free(ports);
+       
+       return ret;
+}
+
+
 int do_vlan_8021q_set (int argc, const char **argv, struct ngadmin *nga)
 {
        unsigned char *ports = NULL, p, def = VLAN_UNSPEC;
@@ -78,7 +197,7 @@ int do_vlan_8021q_set (int argc, const char **argv, struct ngadmin *nga)
        /* read vlan */
        vlan = strtoul(argv[k++], NULL, 0);
        
-       if (vlan < 1 || vlan > VLAN_MAX) {
+       if (vlan < VLAN_MIN || vlan > VLAN_DOT_MAX) {
                printf("vlan out of range\n");
                ret = 1;
                goto end;
@@ -108,7 +227,7 @@ int do_vlan_8021q_set (int argc, const char **argv, struct ngadmin *nga)
        /* apply defaults */
        memset(ports, def, sa->ports);
        
-       /* apply port specifics */
+       /* read and apply port specifics */
        while (k < argc - 1) {
                p = strtoul(argv[k++], NULL, 0) - 1;
                if (p >= sa->ports) {
@@ -329,7 +448,7 @@ int do_vlan_pvid_set (int argc, const char **argv, struct ngadmin *nga)
                return 1;
        }
        
-       if (vlan < 1 || vlan > VLAN_MAX) {
+       if (vlan < VLAN_MIN || vlan > VLAN_DOT_MAX) {
                printf("vlan out of range\n");
                return 1;
        }
index 6d6bc2ac88dc17b11bd705566be21481cd50b686..2d37ea82040dee4d5babbe30db11a0f68fe2797a 100644 (file)
@@ -95,6 +95,8 @@ int do_tree (int argc, const char **argv, struct ngadmin *nga);
 
 /* vlan */
 int do_vlan_8021q_del (int argc, const char **argv, struct ngadmin *nga);
+int do_vlan_port_set (int argc, const char **argv, struct ngadmin *nga);
+int do_vlan_port_show (int argc, const char **argv, struct ngadmin *nga);
 int do_vlan_8021q_set (int argc, const char **argv, struct ngadmin *nga);
 int do_vlan_8021q_show (int argc, const char **argv, struct ngadmin *nga);
 int do_vlan_mode_set (int argc, const char **argv, struct ngadmin *nga);
@@ -191,8 +193,8 @@ COM_ROOT_START(commands)
                        COM_TERM(show, do_vlan_mode_show)
                COM_END
                COM_START(port)
-                       COM_TERM(set, NULL)
-                       COM_TERM(show, NULL)
+                       COM_TERM(set, do_vlan_port_set)
+                       COM_TERM(show, do_vlan_port_show)
                COM_END
                COM_START(pvid)
                        COM_TERM(set, do_vlan_pvid_set)
index d4c7685c309ffd6f6106e1a2358ee48cccf4c1b5..43bcf12ea9c3e0cfa42055f2ccfa32563aed3071 100644 (file)
@@ -106,10 +106,14 @@ enum {
 #define VLAN_MIN               1
 
 /**
- * Maximum VLAN id. 
+ * Maximum 802.1q VLAN id. 
  **/
-#define VLAN_MAX               4093
+#define VLAN_DOT_MAX           4093
 
+/**
+ * Maximum port VLAN id.
+ **/
+#define VLAN_PORT_MAX          9
 
 
 /**
@@ -685,6 +689,32 @@ int ngadmin_getVLANType (struct ngadmin *nga, int *t) EXPORT;
 int ngadmin_setVLANType (struct ngadmin *nga, int t) EXPORT;
 
 
+/**
+ * Get the ports VLANs in port mode. 
+ * Retrieves the associated VLAN of ports in port mode. 
+ * @note The switch should be in port mode. 
+ * @note You must be logged on a switch. 
+ * @param nga A pointer to the ngadmin structure. 
+ * @param ports A pointer to an array of integers which will receive the 
+                number of associated VLAN. Must not be NULL. 
+ * @return ERR_OK when everything is well or an error code otherwise. 
+ **/
+int ngadmin_getVLANPortConf (struct ngadmin *nga, unsigned char *ports) EXPORT;
+
+
+/**
+ * Set the ports VLAN in port mode. 
+ * Changes the associated VLAN of ports in port mode. 
+ * @note The switch should be in port mode. 
+ * @note You must be logged on a switch. 
+ * @param nga A pointer to the ngadmin structure. 
+ * @param ports A pointer to an array of integers which contain the 
+                number of associated VLAN. Must not be NULL. 
+ * @return ERR_OK when everything is well or an error code otherwise. 
+ **/
+int ngadmin_setVLANPortConf (struct ngadmin *nga, const unsigned char *ports) EXPORT;
+
+
 /**
  * Get all the 802.1q VLAN configuration. 
  * Retrieves all the VLAN configuration in 802.1q mode. 
index 3156d02df1ee0e29e5bb900c12d6d83dd36b1dbb..165d0e444668d9570f0144282f52732014410be4 100644 (file)
@@ -1151,13 +1151,128 @@ 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;
+
+               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;
        
        
        if (nga == NULL || vlans == NULL || ports== NULL || nb == NULL || *nb <= 0)
@@ -1182,10 +1297,10 @@ int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsig
        
        for (ln = attr->first; ln != NULL; ln = ln->next) {
                at = ln->data;
-               avd = at->data;
+               avc = at->data;
                
-               *vlans = avd->vlan;
-               memcpy(ports, avd->ports, nga->current->ports);
+               *vlans = avc->vlan;
+               memcpy(ports, avc->ports, nga->current->ports);
                
                vlans++;
                ports += nga->current->ports;
@@ -1210,10 +1325,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;
@@ -1231,9 +1346,9 @@ int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned c
        
        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;
                }
        }
@@ -1252,11 +1367,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;
@@ -1271,11 +1386,11 @@ 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) {
@@ -1289,7 +1404,7 @@ int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsi
                
                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);
@@ -1299,11 +1414,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;
        
@@ -1321,7 +1436,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;
@@ -1381,7 +1496,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;
index 7f0c6e94790bfa3373c8b9d73f5fa0012326068b..dfbdce0e58d17279fa6b8b02b6e0cc0bd4ecc9a7 100644 (file)
@@ -123,7 +123,7 @@ struct attr_cabletest_result {
 } __attribute__((packed));
 
 
-struct attr_vlan_dot {
+struct attr_vlan_conf {
        unsigned short vlan;
        unsigned char ports[0];
 };
index e6ce0ca679dc3320c57762a5b4d9c89e33c60f98..45477139d38a3cbef6b69d411e8e1d7edb18052c 100644 (file)
@@ -112,7 +112,7 @@ static bool pvid_decode (struct attr *at, unsigned char ports)
        
        ap->vlan = ntohs(ap->vlan);
        
-       return (ap->vlan >= VLAN_MIN && ap->vlan <= VLAN_MAX);
+       return (ap->vlan >= VLAN_MIN && ap->vlan <= VLAN_DOT_MAX);
 }
 
 
@@ -123,7 +123,7 @@ static bool pvid_encode (struct attr *at, unsigned char ports)
        if (ap->port < 1 || ap->port > ports)
                return false;
        
-       if (ap->vlan < VLAN_MIN || ap->vlan > VLAN_MAX)
+       if (ap->vlan < VLAN_MIN || ap->vlan > VLAN_DOT_MAX)
                return false;
        
        ap->vlan = htons(ap->vlan);
@@ -136,7 +136,7 @@ static bool vlan_destroy_encode (struct attr *at, unsigned char ports UNUSED)
 {
        unsigned short v = *(unsigned short*)at->data;
        
-       if (v < VLAN_MIN || v > VLAN_MAX)
+       if (v < VLAN_MIN || v > VLAN_DOT_MAX)
                return false;
        
        *(unsigned short*)at->data = htons(v);
@@ -230,7 +230,7 @@ static bool igmp_vlan_decode (struct attr *at, unsigned char ports UNUSED)
                return false;
        
        aiv->vlan = ntohs(aiv->vlan);
-       if (aiv->vlan < VLAN_MIN || aiv->vlan > VLAN_MAX)
+       if (aiv->vlan < VLAN_MIN || aiv->vlan > VLAN_DOT_MAX)
                return false;
        
        return true;
@@ -245,7 +245,7 @@ static bool igmp_vlan_encode (struct attr *at, unsigned char ports UNUSED)
                return false;
        aiv->enable = htons(aiv->enable);
        
-       if (aiv->vlan < VLAN_MIN || aiv->vlan > VLAN_MAX)
+       if (aiv->vlan < VLAN_MIN || aiv->vlan > VLAN_DOT_MAX)
                return false;
        aiv->vlan = htons(aiv->vlan);
        
@@ -310,36 +310,118 @@ static bool vlan_type_endecode (struct attr *at, unsigned char ports UNUSED)
 }
 
 
+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_dot *avd;
+       struct attr_vlan_conf *avc;
        int port;
        
        
        if (at->size != (2 + 2 * (1 + ((ports - 1) >> 3))))
                return false;
        
-       avd = malloc(sizeof(struct attr_vlan_dot) + ports);
-       if (avd == NULL)
+       avc = malloc(sizeof(struct attr_vlan_conf) + ports);
+       if (avc == NULL)
                return false;
        
-       avd->vlan = ntohs(*(unsigned short*)r);
+       avc->vlan = ntohs(*(unsigned short*)r);
        r += 2;
        
        for (port = 0; port < ports; port++) {
                /* FIXME: if ports > 8 */
                if ((r[1] >> (7 - port)) & 1)
-                       avd->ports[port] = VLAN_TAGGED;
+                       avc->ports[port] = VLAN_TAGGED;
                else if ((r[0] >> (7 - port)) & 1)
-                       avd->ports[port] = VLAN_UNTAGGED;
+                       avc->ports[port] = VLAN_UNTAGGED;
                else
-                       avd->ports[port] = VLAN_NO;
+                       avc->ports[port] = VLAN_NO;
        }
        
        free(at->data);
-       at->data = avd;
-       at->size = sizeof(struct attr_vlan_dot) + ports;
+       at->data = avc;
+       at->size = sizeof(struct attr_vlan_conf) + ports;
        
        
        return true;
@@ -348,18 +430,18 @@ static bool vlan_dot_decode (struct attr *at, unsigned char ports)
 
 static bool vlan_dot_encode (struct attr *at, unsigned char ports)
 {
-       struct attr_vlan_dot *avd = at->data;
+       struct attr_vlan_conf *avc = at->data;
        char *r, fl;
        unsigned int size, port;
        
        
-       if (avd->vlan < VLAN_MIN || avd->vlan > VLAN_MAX)
+       if (avc->vlan < VLAN_MIN || avc->vlan > VLAN_DOT_MAX)
                return false;
        
        /* just a header is valid */
-       if (at->size == sizeof(struct attr_vlan_dot))
+       if (at->size == sizeof(struct attr_vlan_conf))
                size = 2;
-       else if (at->size == sizeof(struct attr_vlan_dot) + ports)
+       else if (at->size == sizeof(struct attr_vlan_conf) + ports)
                size = (2 + 2 * (1 + ((ports - 1) >> 3)));
        else
                return false;
@@ -369,7 +451,7 @@ static bool vlan_dot_encode (struct attr *at, unsigned char ports)
                return false;
        
        memset(r, 0, size);
-       *(unsigned short*)r = htons(avd->vlan);
+       *(unsigned short*)r = htons(avc->vlan);
        
        if (size == 2)
                goto end;
@@ -379,9 +461,11 @@ static bool vlan_dot_encode (struct attr *at, unsigned char ports)
        for (port = 0; port < ports; port++) {
                /* FIXME: if ports > 8 */
                fl = (1 << (7 - port));
-               switch (avd->ports[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;
                }
@@ -416,6 +500,7 @@ static const struct attr_handler attrtab[] = {
        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),