13 static const struct timeval default_timeout = {.tv_sec = 4, .tv_usec = 0};
17 struct ngadmin* ngadmin_init (const char *iface)
22 /* allocate main structure */
23 nga = malloc(sizeof(struct ngadmin));
24 memset(nga, 0, sizeof(struct ngadmin));
26 strncpy(nga->iface, iface, IFNAMSIZ - 1);
28 if (startNetwork(nga) < 0) {
33 nga->timeout = default_timeout;
34 if (updateTimeout(nga) < 0) {
44 int ngadmin_close (struct ngadmin *nga)
57 int ngadmin_forceInterface (struct ngadmin *nga)
62 return forceInterface(nga) == 0 ? ERR_OK : ERR_NET;
66 int ngadmin_setKeepBroadcasting (struct ngadmin *nga, bool value)
71 nga->keepbroad = value;
77 int ngadmin_useGlobalBroadcast (struct ngadmin *nga, bool value)
82 nga->globalbroad = value;
88 int ngadmin_setPassword (struct ngadmin *nga, const char *pass)
93 strncpy(nga->password, pass, PASSWORD_MAX);
99 int ngadmin_setTimeout (struct ngadmin *nga, const struct timeval *tv)
104 if (nga == NULL || tv == NULL)
108 if (updateTimeout(nga) < 0)
116 int ngadmin_scan (struct ngadmin *nga)
119 List *attr, *swiList;
122 sent by official win client:
138 static const unsigned short hello[] = {
161 /* create attributes for an "hello" request */
162 attr = createEmptyList();
164 pushBackList(attr, newEmptyAttr(hello[i]));
165 if (hello[i] == ATTR_END)
169 /* send request to all potential switches */
170 i = sendNgPacket(nga, CODE_READ_REQ, attr);
171 clearList(attr, (void(*)(void*))freeAttr);
177 /* try to receive any packets until timeout */
178 swiList = createEmptyList();
179 /* FIXME: end after timeout whatever received packet is good or not */
180 while (recvNgPacket(nga, CODE_READ_REP, NULL, NULL, attr, ATTR_END) >= 0) {
181 sa = malloc(sizeof(struct swi_attr));
184 extractSwitchAttributes(sa, attr);
185 clearList(attr, (void(*)(void*))freeAttr);
186 pushBackList(swiList, sa);
189 nga->swi_count = swiList->count;
190 nga->swi_tab = convertToArray(swiList, sizeof(struct swi_attr));
191 destroyList(swiList, free);
192 destroyList(attr, (void(*)(void*))freeAttr);
199 const struct swi_attr* ngadmin_getSwitchTab (struct ngadmin *nga, int *nb)
201 if (nga == NULL || nb == NULL)
204 *nb = nga->swi_count;
210 const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga)
219 int ngadmin_login (struct ngadmin *nga, int id)
228 else if (id < 0 || id >= nga->swi_count)
231 sa = &nga->swi_tab[id];
234 attr = createEmptyList();
235 pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
236 ret = readRequest(nga, attr, ATTR_END);
237 if (ret == ERR_OK ) {
238 /* login succeeded */
239 /* TODO: if keep broadcasting is disabled, connect() the UDP
240 socket so icmp errors messages (port unreachable, TTL exceeded
241 in transit, ...) can be received */
247 destroyList(attr, (void(*)(void*))freeAttr);
254 int ngadmin_upgradeFirmware (struct ngadmin *nga, const char *filename)
256 if (nga == NULL || filename == NULL || *filename == 0)
258 else if (nga->current == NULL)
262 Firmware upgrade is not yet implemented.
263 This would require much more work and the use of a TFTP client.
264 Overall, it could be quite dangerous, as the switch may not check the binary
272 int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports)
278 struct attr_port_status *ps;
281 if (nga == NULL || ports == NULL)
283 else if (nga->current == NULL)
287 attr = createEmptyList();
288 pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
289 ret = readRequest(nga, attr, ATTR_PORT_STATUS);
293 memset(ports, SPEED_UNK, nga->current->ports);
295 for (ln = attr->first; ln != NULL; ln = ln->next) {
298 ports[ps->port - 1] = ps->status;
302 destroyList(attr, (void(*)(void*))freeAttr);
309 int ngadmin_setName (struct ngadmin *nga, const char *name)
317 else if (nga->current == NULL)
321 attr = createEmptyList();
322 pushBackList(attr, name == NULL ? newEmptyAttr(ATTR_NAME) : newAttr(ATTR_NAME, strlen(name), strdup(name)) );
323 ret = writeRequest(nga, attr);
327 /* successful, also update local name */
329 memset(nga->current->name, '\0', NAME_SIZE);
331 strncpy(nga->current->name, name, NAME_SIZE);
338 int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps)
344 struct attr_port_stat *aps;
347 if (nga == NULL || ps == NULL)
349 else if (nga->current == NULL)
352 attr = createEmptyList();
353 pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
354 ret = readRequest(nga, attr, ATTR_PORT_STATISTICS);
358 memset(ps, 0, nga->current->ports * sizeof(struct port_stats));
360 for (ln = attr->first; ln != NULL; ln = ln->next) {
363 ps[aps->port -1].recv = aps->recv;
364 ps[aps->port -1].sent = aps->sent;
365 ps[aps->port -1].crc = aps->crc;
369 destroyList(attr, (void(*)(void*))freeAttr);
376 int ngadmin_resetPortsStatistics (struct ngadmin *nga)
381 attr = createEmptyList();
382 pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
385 return writeRequest(nga, attr);
389 int ngadmin_changePassword (struct ngadmin *nga, const char* pass)
395 if (nga == NULL || pass == NULL)
397 else if (nga->current == NULL)
401 attr = createEmptyList();
402 pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
403 ret = writeRequest(nga, attr);
408 /* successful, also update local password */
409 strncpy(nga->password, pass, PASSWORD_MAX);
417 int ngadmin_getStormFilterState (struct ngadmin *nga, int *s)
424 if (nga == NULL || s == NULL)
426 else if (nga->current == NULL)
430 attr = createEmptyList();
431 pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
432 ret = readRequest(nga, attr, ATTR_STORM_ENABLE);
438 if (attr->first != NULL) {
439 at = attr->first->data;
440 *s = *(char*)at->data;
445 destroyList(attr, (void(*)(void*))freeAttr);
452 int ngadmin_setStormFilterState (struct ngadmin *nga, int s)
457 attr = createEmptyList();
458 pushBackList(attr, newByteAttr(ATTR_STORM_ENABLE, s != 0));
461 return writeRequest(nga, attr);
465 int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports)
470 int ret = ERR_OK, port;
471 struct attr_bitrate *sb;
474 if (nga == NULL || ports == NULL)
476 else if (nga->current == NULL)
480 attr = createEmptyList();
481 pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
482 ret = readRequest(nga, attr, ATTR_STORM_BITRATE);
486 for (port = 0; port < nga->current->ports; port++)
487 ports[port] = BITRATE_UNSPEC;
489 for (ln = attr->first; ln != NULL; ln = ln->next) {
492 ports[sb->port - 1] = sb->bitrate;
497 destroyList(attr, (void(*)(void*))freeAttr);
504 int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports)
508 struct attr_bitrate *sb;
511 if (nga == NULL || ports == NULL)
513 else if (nga->current == NULL)
517 attr = createEmptyList();
519 for (port = 0; port < nga->current->ports; port++) {
520 if (ports[port] != BITRATE_UNSPEC) {
521 sb = malloc(sizeof(struct attr_bitrate));
525 sb->bitrate = ports[port];
526 pushBackList(attr, newAttr(ATTR_STORM_BITRATE, sizeof(struct attr_bitrate), sb));
530 return writeRequest(nga, attr);
534 int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports)
539 int ret = ERR_OK, port;
540 struct attr_bitrate *pb;
543 if (nga == NULL || ports == NULL)
545 else if (nga->current == NULL)
549 attr = createEmptyList();
550 pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
551 pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
552 ret = readRequest(nga, attr, ATTR_END);
557 for (port = 0; port < nga->current->ports; port++) {
558 ports[2 * port + 0] = BITRATE_UNSPEC;
559 ports[2 * port + 1] = BITRATE_UNSPEC;
562 for (ln = attr->first; ln != NULL; ln = ln->next) {
565 if (at->attr == ATTR_BITRATE_INPUT)
566 ports[(pb->port - 1) * 2 + 0] = pb->bitrate;
567 else if (at->attr == ATTR_BITRATE_OUTPUT)
568 ports[(pb->port - 1) * 2 + 1] = pb->bitrate;
573 destroyList(attr, (void(*)(void*))freeAttr);
579 int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports)
583 struct attr_bitrate *pb;
586 if (nga == NULL || ports == NULL)
588 else if (nga->current == NULL)
592 attr = createEmptyList();
594 for (port = 0; port < nga->current->ports; port++) {
595 if (ports[2 * port + 0] >= BITRATE_NOLIMIT && ports[2 * port + 0] <= BITRATE_512M) {
596 pb = malloc(sizeof(struct attr_bitrate));
600 pb->bitrate = ports[2 * port + 0];
601 pushBackList(attr, newAttr(ATTR_BITRATE_INPUT, sizeof(struct attr_bitrate), pb));
603 if (ports[2 * port + 1] >= BITRATE_NOLIMIT && ports[2 * port + 1] <= BITRATE_512M) {
604 pb = malloc(sizeof(struct attr_bitrate));
608 pb->bitrate = ports[2 * port + 1];
609 pushBackList(attr, newAttr(ATTR_BITRATE_OUTPUT, sizeof(struct attr_bitrate), pb));
614 return writeRequest(nga, attr);
618 int ngadmin_getQOSMode (struct ngadmin *nga, int *s)
625 if (nga == NULL || s == NULL)
627 else if (nga->current == NULL)
631 attr = createEmptyList();
632 pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
633 ret = readRequest(nga, attr, ATTR_QOS_TYPE);
639 if (attr->first != NULL) {
640 at = attr->first->data;
641 *s = *(char*)at->data;
646 destroyList(attr, (void(*)(void*))freeAttr);
653 int ngadmin_setQOSMode (struct ngadmin *nga, int s)
658 attr = createEmptyList();
659 pushBackList(attr, newByteAttr(ATTR_QOS_TYPE, s));
662 return writeRequest(nga, attr);
666 int ngadmin_getQOSValues (struct ngadmin *nga, char *ports)
671 int ret = ERR_OK, port;
675 if (nga == NULL || ports == NULL)
677 else if (nga->current == NULL)
681 attr = createEmptyList();
682 pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
683 ret = readRequest(nga, attr, ATTR_QOS_CONFIG);
687 for (port = 0; port < nga->current->ports; port++)
688 ports[port] = PRIO_UNSPEC;
690 for (ln = attr->first; ln != NULL; ln = ln->next) {
693 ports[aq->port - 1] = aq->prio;
698 destroyList(attr, (void(*)(void*))freeAttr);
705 int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports)
712 if (nga == NULL || ports == NULL)
714 else if (nga->current == NULL)
718 attr = createEmptyList();
720 for (port = 0; port < nga->current->ports; port++) {
721 if (ports[port] >= PRIO_HIGH && ports[port] <= PRIO_LOW) {
722 aq = malloc(sizeof(struct attr_qos));
726 aq->prio = ports[port];
727 pushBackList(attr, newAttr(ATTR_QOS_CONFIG, sizeof(struct attr_qos), aq));
732 return writeRequest(nga, attr);
736 int ngadmin_restart (struct ngadmin *nga)
741 attr = createEmptyList();
742 pushBackList(attr, newByteAttr(ATTR_RESTART, 1));
745 return writeRequest(nga, attr);
749 int ngadmin_defaults (struct ngadmin *nga)
755 attr = createEmptyList();
756 pushBackList(attr, newByteAttr(ATTR_DEFAULTS, 1));
757 ret = writeRequest(nga, attr);
762 /* successful: delog and clean list */
773 int ngadmin_getMirror (struct ngadmin *nga, char *ports)
780 if (nga == NULL || ports == NULL)
782 else if (nga->current == NULL)
786 attr = createEmptyList();
787 pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
788 ret = readRequest(nga, attr, ATTR_MIRROR);
792 memset(ports, 0, 1 + nga->current->ports);
794 if (attr->first != NULL) {
795 at = attr->first->data;
796 memcpy(ports, at->data, 1 + nga->current->ports);
801 destroyList(attr, (void(*)(void*))freeAttr);
808 int ngadmin_setMirror (struct ngadmin *nga, const char *ports)
816 else if (nga->current == NULL)
820 p = malloc(1 + nga->current->ports);
825 memset(p, 0, 1 + nga->current->ports);
827 memcpy(p, ports, 1 + nga->current->ports);
829 attr = createEmptyList();
830 pushBackList(attr, newAttr(ATTR_MIRROR, 1 + nga->current->ports, p));
833 return writeRequest(nga, attr);
837 int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic)
842 struct attr_igmp_vlan *aiv;
845 if (nga == NULL || ic == NULL)
847 else if (nga->current == NULL)
851 ATTR_IGMP_ENABLE_VLAN
855 Apparently, read-querying these attributes at the same time causes the switch to reply garbage.
856 Here we are forced to do like the official win app and send a separate request for each attribute.
860 attr = createEmptyList();
861 memset(ic, 0, sizeof(struct igmp_conf));
864 pushBackList(attr, newEmptyAttr(ATTR_IGMP_ENABLE_VLAN));
865 ret = readRequest(nga, attr, ATTR_IGMP_ENABLE_VLAN);
869 if (attr->first != NULL) {
870 at = attr->first->data;
872 ic->enable = aiv->enable;
873 ic->vlan = aiv->vlan;
876 clearList(attr, (void(*)(void*))freeAttr);
879 pushBackList(attr, newEmptyAttr(ATTR_IGMP_BLOCK_UNK));
880 ret = readRequest(nga, attr, ATTR_IGMP_BLOCK_UNK);
884 if (attr->first != NULL) {
885 at = attr->first->data;
886 ic->block = *(char*)at->data;
889 clearList(attr, (void(*)(void*))freeAttr);
892 pushBackList(attr, newEmptyAttr(ATTR_IGMP_VALID_V3));
893 ret = readRequest(nga, attr, ATTR_IGMP_VALID_V3);
897 if (attr->first != NULL) {
898 at = attr->first->data;
899 ic->validate = *(char*)at->data;
904 destroyList(attr, (void(*)(void*))freeAttr);
911 int ngadmin_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic)
914 struct attr_igmp_vlan *aiv;
917 if (nga == NULL || ic == NULL)
919 else if (nga->current == NULL)
923 aiv = malloc(sizeof(struct attr_igmp_vlan));
926 aiv->enable = ic->enable;
927 aiv->vlan = ic->vlan;
930 attr = createEmptyList();
931 pushBackList(attr, newAttr(ATTR_IGMP_ENABLE_VLAN, sizeof(struct attr_igmp_vlan), aiv));
932 pushBackList(attr, newByteAttr(ATTR_IGMP_BLOCK_UNK, ic->block != false));
933 pushBackList(attr, newByteAttr(ATTR_IGMP_VALID_V3, ic->validate != false));
936 return writeRequest(nga, attr);
940 int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb)
946 struct attr_cabletest_do *acd;
947 struct attr_cabletest_result *acr;
950 if (nga == NULL || ct == NULL)
952 else if (nga->current == NULL)
956 attr = createEmptyList();
958 for (i = 0; i < nb; i++) {
960 acd = malloc(sizeof(struct attr_cabletest_do));
963 acd->port = ct[i].port;
965 pushBackList(attr, newAttr(ATTR_CABLETEST_DO, sizeof(struct attr_cabletest_do), acd));
967 ret = writeRequest(nga, attr);
972 /* the list is destroyed by writeRequest, so we need to recreate it */
973 attr = createEmptyList();
974 pushBackList(attr, newByteAttr(ATTR_CABLETEST_RESULT, ct[i].port));
975 ret = readRequest(nga, attr, ATTR_CABLETEST_RESULT);
979 for (ln = attr->first; ln != NULL; ln = ln->next) {
982 if (at->size == sizeof(struct attr_cabletest_result) && acr->port == ct[i].port) {
989 /* just empty the list, it will be used at next iteration */
990 clearList(attr, (void(*)(void*))freeAttr);
995 destroyList(attr, (void(*)(void*))freeAttr);
1002 int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc)
1006 struct swi_attr *sa;
1009 if (nga == NULL || nc == NULL)
1017 attr = createEmptyList();
1020 pushBackList(attr, newShortAttr(ATTR_DHCP, 1));
1022 pushBackList(attr, newShortAttr(ATTR_DHCP, 0));
1023 /* only add non-null values */
1024 if (nc->ip.s_addr != 0)
1025 pushBackList(attr, newAddrAttr(ATTR_IP, nc->ip));
1026 if (nc->netmask.s_addr != 0)
1027 pushBackList(attr, newAddrAttr(ATTR_NETMASK, nc->netmask));
1028 if (nc->gw.s_addr != 0)
1029 pushBackList(attr, newAddrAttr(ATTR_GATEWAY, nc->gw));
1032 ret = writeRequest(nga, attr);
1037 /* update local values */
1038 sa->nc.dhcp = nc->dhcp;
1040 if (nc->ip.s_addr !=0)
1042 if (nc->netmask.s_addr != 0)
1043 sa->nc.netmask = nc->netmask;
1044 if (nc->gw.s_addr != 0)
1055 int ngadmin_getVLANType (struct ngadmin *nga, int *t)
1062 if (nga == NULL || t == NULL)
1064 else if (nga->current == NULL)
1068 attr = createEmptyList();
1069 pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
1070 ret=readRequest(nga, attr, ATTR_VLAN_TYPE);
1076 if (attr->first != NULL) {
1077 at = attr->first->data;
1078 *t =(int)*(char*)at->data;
1083 destroyList(attr, (void(*)(void*))freeAttr);
1090 int ngadmin_setVLANType (struct ngadmin *nga, int t)
1095 if (nga == NULL || t < 1 || t > 4)
1097 else if (nga->current == NULL)
1101 attr = createEmptyList();
1102 pushBackList(attr, newByteAttr(ATTR_VLAN_TYPE, t));
1105 return writeRequest(nga, attr);
1109 int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb)
1114 int ret = ERR_OK, total;
1115 struct attr_vlan_dot *avd;
1118 if (nga == NULL || vlans == NULL || ports== NULL || nb == NULL || *nb <= 0)
1120 else if (nga->current == NULL)
1127 attr = createEmptyList();
1128 pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
1129 ret = readRequest(nga, attr, ATTR_VLAN_DOT_CONF);
1133 memset(vlans, 0, total * sizeof(unsigned short));
1134 memset(ports, 0, total * nga->current->ports);
1136 for (ln = attr->first; ln != NULL; ln = ln->next) {
1141 memcpy(ports, avd->ports, nga->current->ports);
1144 ports += nga->current->ports;
1148 break; /* no more room */
1153 destroyList(attr, (void(*)(void*))freeAttr);
1160 int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned char *ports)
1166 struct attr_vlan_dot *avd;
1169 if (nga == NULL || vlan < 1 || vlan > VLAN_MAX || ports == NULL)
1171 else if (nga->current == NULL)
1175 attr = createEmptyList();
1176 pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
1177 ret = readRequest(nga, attr, ATTR_END);
1181 memset(ports, 0, nga->current->ports);
1183 for (ln = attr->first; ln != NULL; ln = ln->next) {
1186 if (avd->vlan == vlan) {
1187 memcpy(ports, avd->ports, nga->current->ports);
1194 destroyList(attr, (void(*)(void*))freeAttr);
1201 int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsigned char *ports)
1205 struct swi_attr *sa;
1206 struct attr_vlan_dot *avd;
1207 int ret = ERR_OK, port;
1210 if (nga == NULL || vlan < 1 || vlan > VLAN_MAX || ports == NULL)
1218 /* if nothing is to be changed, do nothing */
1219 for (port = 0; port < sa->ports && ports[port] == VLAN_UNSPEC; port++);
1220 if (port == sa->ports )
1224 attr = createEmptyList();
1225 avd = malloc(sizeof(struct attr_vlan_dot) + sa->ports);
1231 /* if all is to be changed, we do not need to read old config */
1232 if (memchr(ports, VLAN_UNSPEC, sa->ports) != NULL) {
1234 pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
1235 ret = readRequest(nga, attr, ATTR_VLAN_DOT_CONF);
1239 if (attr->first != NULL) {
1240 at = attr->first->data;
1241 memcpy(avd, at->data, sizeof(struct attr_vlan_dot) + sa->ports);
1244 clearList(attr, (void(*)(void*))freeAttr);
1249 for (port = 0; port < sa->ports; port++) {
1250 if (ports[port] != VLAN_UNSPEC)
1251 avd->ports[port] = ports[port];
1255 pushBackList(attr, newAttr(ATTR_VLAN_DOT_CONF, sizeof(struct attr_vlan_dot) + sa->ports, avd));
1256 ret = writeRequest(nga, attr);
1261 destroyList(attr, (void(*)(void*))freeAttr);
1268 int ngadmin_VLANDestroy (struct ngadmin *nga, unsigned short vlan)
1273 if (nga == NULL || vlan < 1 || vlan > VLAN_MAX)
1275 else if (nga->current == NULL)
1279 attr = createEmptyList();
1280 pushBackList(attr, newShortAttr(ATTR_VLAN_DESTROY, vlan));
1283 return writeRequest(nga, attr);
1287 int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports)
1293 struct attr_pvid *ap;
1296 if (nga == NULL || ports == NULL)
1298 else if (nga->current == NULL)
1302 attr = createEmptyList();
1303 pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID));
1304 ret = readRequest(nga, attr, ATTR_VLAN_PVID);
1308 memset(ports, 0, nga->current->ports * sizeof(unsigned short));
1310 for (ln = attr->first; ln != NULL; ln = ln->next) {
1313 ports[ap->port - 1] = ap->vlan;
1318 destroyList(attr, (void(*)(void*))freeAttr);
1325 int ngadmin_setPVID (struct ngadmin *nga, unsigned char port, unsigned short vlan)
1328 struct attr_pvid *ap;
1331 if (nga == NULL || port < 1 || vlan < 1 || vlan > VLAN_MAX)
1333 else if (nga->current == NULL)
1335 else if (port > nga->current->ports)
1339 attr = createEmptyList();
1340 ap = malloc(sizeof(struct attr_pvid));
1346 pushBackList(attr, newAttr(ATTR_VLAN_PVID, sizeof(struct attr_pvid), ap));
1349 return writeRequest(nga, attr);