}
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;
}
}
+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;
/* 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;
/* 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) {
return 1;
}
- if (vlan < 1 || vlan > VLAN_MAX) {
+ if (vlan < VLAN_MIN || vlan > VLAN_DOT_MAX) {
printf("vlan out of range\n");
return 1;
}
/* 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);
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)
#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
/**
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.
}
+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)
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;
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;
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;
}
}
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;
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) {
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);
/* 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;
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;
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;
} __attribute__((packed));
-struct attr_vlan_dot {
+struct attr_vlan_conf {
unsigned short vlan;
unsigned char ports[0];
};
ap->vlan = ntohs(ap->vlan);
- return (ap->vlan >= VLAN_MIN && ap->vlan <= VLAN_MAX);
+ return (ap->vlan >= VLAN_MIN && ap->vlan <= VLAN_DOT_MAX);
}
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);
{
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);
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;
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);
}
+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;
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;
return false;
memset(r, 0, size);
- *(unsigned short*)r = htons(avd->vlan);
+ *(unsigned short*)r = htons(avc->vlan);
if (size == 2)
goto end;
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;
}
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),