]> git.sur5r.net Git - ngadmin/blob - lib/src/ngadmin.c
Raw: separate attribute filtering in a separate function.
[ngadmin] / lib / src / ngadmin.c
1
2 #include <errno.h>
3
4 #include <ngadmin.h>
5
6 #include <attr.h>
7 #include <protocol.h>
8
9 #include "lib.h"
10 #include "network.h"
11
12
13 static const struct timeval default_timeout = {.tv_sec = 4, .tv_usec = 0};
14
15
16
17 struct ngadmin* ngadmin_init (const char *iface)
18 {
19         struct ngadmin *nga;
20         
21         
22         /* allocate main structure */
23         nga = malloc(sizeof(struct ngadmin));
24         memset(nga, 0, sizeof(struct ngadmin));
25         
26         strncpy(nga->iface, iface, IFNAMSIZ - 1);
27         
28         if (startNetwork(nga) < 0) {
29                 free(nga);
30                 return NULL;
31         }
32         
33         nga->timeout = default_timeout;
34         if (updateTimeout(nga) < 0) {
35                 free(nga);
36                 return NULL;
37         }
38         
39         
40         return nga;
41 }
42
43
44 int ngadmin_close (struct ngadmin *nga)
45 {
46         if (nga == NULL)
47                 return ERR_INVARG;
48                 
49         stopNetwork(nga);
50         free(nga->swi_tab);
51         free(nga);
52         
53         return ERR_OK;
54 }
55
56
57 int ngadmin_forceInterface (struct ngadmin *nga)
58 {
59         if (nga == NULL)
60                 return ERR_INVARG;
61         
62         return forceInterface(nga) == 0 ? ERR_OK : ERR_NET;
63 }
64
65
66 int ngadmin_setKeepBroadcasting (struct ngadmin *nga, bool value)
67 {
68         if (nga == NULL)
69                 return ERR_INVARG;
70         
71         nga->keepbroad = value;
72         
73         return ERR_OK;
74 }
75
76
77 int ngadmin_useGlobalBroadcast (struct ngadmin *nga, bool value)
78 {
79         if (nga == NULL)
80                 return ERR_INVARG;
81         
82         nga->globalbroad = value;
83         
84         return ERR_OK;
85 }
86
87
88 int ngadmin_setPassword (struct ngadmin *nga, const char *pass)
89 {
90         if (nga == NULL)
91                 return ERR_INVARG;
92         
93         strncpy(nga->password, pass, PASSWORD_MAX);
94         
95         return ERR_OK;
96 }
97
98
99 int ngadmin_setTimeout (struct ngadmin *nga, const struct timeval *tv)
100 {
101         int ret = ERR_OK;
102         
103         
104         if (nga == NULL || tv == NULL)
105                 return ERR_INVARG;
106         
107         nga->timeout = *tv;
108         if (updateTimeout(nga) < 0)
109                 ret = ERR_NET;
110         
111         
112         return ret;
113 }
114
115
116 int ngadmin_scan (struct ngadmin *nga)
117 {
118         int i;
119         List *attr, *swiList;
120         struct swi_attr *sa;
121         /*
122         sent by official win client:
123         ATTR_PRODUCT,
124         ATTR_UNK2,
125         ATTR_NAME,
126         ATTR_MAC,
127         ATTR_UNK5,
128         ATTR_IP,
129         ATTR_NETMASK,
130         ATTR_GATEWAY,
131         ATTR_DHCP,
132         ATTR_UNK12,
133         ATTR_FIRM_VER,
134         ATTR_UNK14,
135         ATTR_UNK15,
136         ATTR_END
137         */
138         static const unsigned short hello[] = {
139                 ATTR_PRODUCT,
140                 ATTR_NAME,
141                 ATTR_MAC,
142                 ATTR_IP,
143                 ATTR_NETMASK,
144                 ATTR_GATEWAY,
145                 ATTR_DHCP,
146                 ATTR_FIRM_VER,
147                 ATTR_PORTS_COUNT,
148                 ATTR_END
149         };
150         
151         
152         if (nga == NULL)
153                 return ERR_INVARG;
154         
155         free(nga->swi_tab);
156         nga->swi_tab = NULL;
157         nga->swi_count = 0;
158         nga->current = NULL;
159         
160         
161         /* create attributes for an "hello" request */
162         attr = createEmptyList();
163         for (i = 0; ; i++) {
164                 pushBackList(attr, newEmptyAttr(hello[i]));
165                 if (hello[i] == ATTR_END)
166                         break;
167         }
168         
169         /* send request to all potential switches */
170         i = sendNgPacket(nga, CODE_READ_REQ, attr);
171         clearList(attr, (void(*)(void*))freeAttr);
172         if (i == -EINVAL)
173                 return ERR_INVARG;
174         else if (i < 0)
175                 return ERR_NET;
176         
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) >= 0) {
181                 sa = malloc(sizeof(struct swi_attr));
182                 if (sa == NULL)
183                         return ERR_MEM;
184                 extractSwitchAttributes(sa, attr);
185                 clearList(attr, (void(*)(void*))freeAttr);
186                 pushBackList(swiList, sa);
187         }
188         
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);
193         
194         
195         return ERR_OK;
196 }
197
198
199 const struct swi_attr* ngadmin_getSwitchTab (struct ngadmin *nga, int *nb)
200 {
201         if (nga == NULL || nb == NULL)
202                 return NULL;
203         
204         *nb = nga->swi_count;
205         
206         return nga->swi_tab;
207 }
208
209
210 const struct swi_attr* ngadmin_getCurrentSwitch (struct ngadmin *nga)
211 {
212         if (nga == NULL)
213                 return NULL;
214         
215         return nga->current;
216 }
217
218
219 int ngadmin_login (struct ngadmin *nga, int id)
220 {
221         List *attr;
222         int ret = ERR_OK;
223         struct swi_attr *sa;
224         
225         
226         if (nga == NULL)
227                 return ERR_INVARG;
228         else if (id < 0 || id >= nga->swi_count)
229                 return ERR_BADID;
230         
231         sa = &nga->swi_tab[id];
232         nga->current = sa;
233         
234         attr = createEmptyList();
235         pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
236         ret = readRequest(nga, attr);
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 */
242         } else {
243                 /* login failed */
244                 nga->current = NULL;
245         }
246         
247         destroyList(attr, (void(*)(void*))freeAttr);
248         
249         
250         return ret;
251 }
252
253
254 int ngadmin_upgradeFirmware (struct ngadmin *nga, const char *filename)
255 {
256         if (nga == NULL || filename == NULL || *filename == 0)
257                 return ERR_INVARG;
258         else if (nga->current == NULL)
259                 return ERR_NOTLOG;
260         
261         /*
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 
265         content sent to it. 
266         */
267         
268         return ERR_NOTIMPL;
269 }
270
271
272 int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports)
273 {
274         List *attr;
275         ListNode *ln;
276         struct attr *at;
277         int ret = ERR_OK;
278         struct attr_port_status *ps;
279         
280         
281         if (nga == NULL || ports == NULL)
282                 return ERR_INVARG;
283         else if (nga->current == NULL)
284                 return ERR_NOTLOG;
285         
286         
287         attr = createEmptyList();
288         pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
289         ret = readRequest(nga, attr);
290         if (ret != ERR_OK)
291                 goto end;
292         
293         filterAttributes(attr, ATTR_PORT_STATUS, ATTR_END);
294         
295         memset(ports, SPEED_UNK, nga->current->ports);
296         
297         for (ln = attr->first; ln != NULL; ln = ln->next) {
298                 at = ln->data;
299                 ps = at->data;
300                 ports[ps->port - 1] = ps->status;
301         }
302         
303 end:
304         destroyList(attr, (void(*)(void*))freeAttr);
305         
306         
307         return ret;
308 }
309
310
311 int ngadmin_setName (struct ngadmin *nga, const char *name)
312 {
313         List *attr;
314         int ret = ERR_OK;
315         
316         
317         if (nga == NULL)
318                 return ERR_INVARG;
319         else if (nga->current == NULL)
320                 return ERR_NOTLOG;
321         
322         
323         attr = createEmptyList();
324         pushBackList(attr, name == NULL ? newEmptyAttr(ATTR_NAME) : newAttr(ATTR_NAME, strlen(name), strdup(name)) );
325         ret = writeRequest(nga, attr);
326         if (ret != ERR_OK)
327                 goto end;
328          
329         /* successful, also update local name */
330         if (name == NULL)
331                 memset(nga->current->name, '\0', NAME_SIZE);
332         else
333                 strncpy(nga->current->name, name, NAME_SIZE);
334         
335 end:
336         return ret;
337 }
338
339
340 int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps)
341 {
342         List *attr;
343         ListNode *ln;
344         struct attr *at;
345         int ret = ERR_OK;
346         struct attr_port_stat *aps;
347         
348         
349         if (nga == NULL || ps == NULL)
350                 return ERR_INVARG;
351         else if (nga->current == NULL)
352                 return ERR_NOTLOG;
353         
354         attr = createEmptyList();
355         pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
356         ret = readRequest(nga, attr);
357         if (ret != ERR_OK)
358                 goto end;
359         
360         filterAttributes(attr, ATTR_PORT_STATISTICS, ATTR_END);
361         
362         memset(ps, 0, nga->current->ports * sizeof(struct port_stats));
363         
364         for (ln = attr->first; ln != NULL; ln = ln->next) {
365                 at = ln->data;
366                 aps = at->data;
367                 ps[aps->port -1].recv = aps->recv;
368                 ps[aps->port -1].sent = aps->sent;
369                 ps[aps->port -1].crc = aps->crc;
370         }
371         
372 end:
373         destroyList(attr, (void(*)(void*))freeAttr);
374         
375         
376         return ret;
377 }
378
379
380 int ngadmin_resetPortsStatistics (struct ngadmin *nga)
381 {
382         List *attr;
383         
384         
385         attr = createEmptyList();
386         pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
387         
388         
389         return writeRequest(nga, attr);
390 }
391
392
393 int ngadmin_changePassword (struct ngadmin *nga, const char* pass)
394 {
395         List *attr;
396         int ret = ERR_OK;
397         
398         
399         if (nga == NULL || pass == NULL)
400                 return ERR_INVARG;
401         else if (nga->current == NULL)
402                 return ERR_NOTLOG;
403         
404         
405         attr = createEmptyList();
406         pushBackList(attr, newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass)));
407         ret = writeRequest(nga, attr);
408         if (ret != ERR_OK)
409                 goto end;
410         
411         
412         /* successful, also update local password */
413         strncpy(nga->password, pass, PASSWORD_MAX);
414         
415 end:
416         
417         return ret;
418 }
419
420
421 int ngadmin_getStormFilterState (struct ngadmin *nga, int *s)
422 {
423         List *attr;
424         struct attr *at;
425         int ret = ERR_OK;
426         
427         
428         if (nga == NULL || s == NULL)
429                 return ERR_INVARG;
430         else if (nga->current == NULL)
431                 return ERR_NOTLOG;
432         
433         
434         attr = createEmptyList();
435         pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
436         ret = readRequest(nga, attr);
437         if (ret != ERR_OK)
438                 goto end;
439         
440         filterAttributes(attr, ATTR_STORM_ENABLE, ATTR_END);
441         
442         *s = 0;
443         
444         if (attr->first != NULL) {
445                 at = attr->first->data;
446                 *s = *(char*)at->data;
447         }
448         
449         
450 end:
451         destroyList(attr, (void(*)(void*))freeAttr);
452         
453         
454         return ret;
455 }
456
457
458 int ngadmin_setStormFilterState (struct ngadmin *nga, int s)
459 {
460         List *attr;
461         
462         
463         attr = createEmptyList();
464         pushBackList(attr, newByteAttr(ATTR_STORM_ENABLE, s != 0));
465         
466         
467         return writeRequest(nga, attr);
468 }
469
470
471 int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports)
472 {
473         List *attr;
474         ListNode *ln;
475         struct attr *at;
476         int ret = ERR_OK, port;
477         struct attr_bitrate *sb;
478         
479         
480         if (nga == NULL || ports == NULL)
481                 return ERR_INVARG;
482         else if (nga->current == NULL)
483                 return ERR_NOTLOG;
484         
485         
486         attr = createEmptyList();
487         pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
488         ret = readRequest(nga, attr);
489         if (ret != ERR_OK)
490                 goto end;
491         
492         filterAttributes(attr, ATTR_STORM_BITRATE, ATTR_END);
493         
494         for (port = 0; port < nga->current->ports; port++)
495                 ports[port] = BITRATE_UNSPEC;
496         
497         for (ln = attr->first; ln != NULL; ln = ln->next) {
498                 at = ln->data;
499                 sb = at->data;
500                 ports[sb->port - 1] = sb->bitrate;
501         }
502         
503         
504 end:
505         destroyList(attr, (void(*)(void*))freeAttr);
506         
507         
508         return ret;
509 }
510
511
512 int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports)
513 {
514         List *attr;
515         int port;
516         struct attr_bitrate *sb;
517         
518         
519         if (nga == NULL || ports == NULL)
520                 return ERR_INVARG;
521         else if (nga->current == NULL)
522                 return ERR_NOTLOG;
523         
524         
525         attr = createEmptyList();
526         
527         for (port = 0; port < nga->current->ports; port++) {
528                 if (ports[port] != BITRATE_UNSPEC) {
529                         sb = malloc(sizeof(struct attr_bitrate));
530                         if (sb == NULL)
531                                 return ERR_MEM;
532                         sb->port = port + 1;
533                         sb->bitrate = ports[port];
534                         pushBackList(attr, newAttr(ATTR_STORM_BITRATE, sizeof(struct attr_bitrate), sb));
535                 }
536         }
537         
538         return writeRequest(nga, attr);
539 }
540
541
542 int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports)
543 {
544         List *attr;
545         ListNode *ln;
546         struct attr *at;
547         int ret = ERR_OK, port;
548         struct attr_bitrate *pb;
549         
550         
551         if (nga == NULL || ports == NULL)
552                 return ERR_INVARG;
553         else if (nga->current == NULL)
554                 return ERR_NOTLOG;
555         
556         
557         attr = createEmptyList();
558         pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
559         pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
560         ret = readRequest(nga, attr);
561         if (ret != ERR_OK)
562                 goto end;
563         
564         
565         for (port = 0; port < nga->current->ports; port++) {
566                 ports[2 * port + 0] = BITRATE_UNSPEC;
567                 ports[2 * port + 1] = BITRATE_UNSPEC;
568         }
569         
570         for (ln = attr->first; ln != NULL; ln = ln->next) {
571                 at = ln->data;
572                 pb = at->data;
573                 if (at->attr == ATTR_BITRATE_INPUT)
574                         ports[(pb->port - 1) * 2 + 0] = pb->bitrate;
575                 else if (at->attr == ATTR_BITRATE_OUTPUT)
576                         ports[(pb->port - 1) * 2 + 1] = pb->bitrate;
577         }
578         
579         
580 end:
581         destroyList(attr, (void(*)(void*))freeAttr);
582         
583         return ret;
584 }
585
586
587 int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports)
588 {
589         List *attr;
590         int port;
591         struct attr_bitrate *pb;
592         
593         
594         if (nga == NULL || ports == NULL)
595                 return ERR_INVARG;
596         else if (nga->current == NULL)
597                 return ERR_NOTLOG;
598         
599         
600         attr = createEmptyList();
601         
602         for (port = 0; port < nga->current->ports; port++) {
603                 if (ports[2 * port + 0] >= BITRATE_NOLIMIT && ports[2 * port + 0] <= BITRATE_512M) {
604                         pb = malloc(sizeof(struct attr_bitrate));
605                         if (pb == NULL)
606                                 return ERR_MEM;
607                         pb->port = port + 1;
608                         pb->bitrate = ports[2 * port + 0];
609                         pushBackList(attr, newAttr(ATTR_BITRATE_INPUT, sizeof(struct attr_bitrate), pb));
610                 }
611                 if (ports[2 * port + 1] >= BITRATE_NOLIMIT && ports[2 * port + 1] <= BITRATE_512M) {
612                         pb = malloc(sizeof(struct attr_bitrate));
613                         if (pb == NULL)
614                                 return ERR_MEM;
615                         pb->port = port + 1;
616                         pb->bitrate = ports[2 * port + 1];
617                         pushBackList(attr, newAttr(ATTR_BITRATE_OUTPUT, sizeof(struct attr_bitrate), pb));
618                 }
619         }
620         
621         
622         return writeRequest(nga, attr);
623 }
624
625
626 int ngadmin_getQOSMode (struct ngadmin *nga, int *s)
627 {
628         List *attr;
629         struct attr *at;
630         int ret = ERR_OK;
631         
632         
633         if (nga == NULL || s == NULL)
634                 return ERR_INVARG;
635         else if (nga->current == NULL)
636                 return ERR_NOTLOG;
637         
638         
639         attr = createEmptyList();
640         pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
641         ret = readRequest(nga, attr);
642         if (ret != ERR_OK)
643                 goto end;
644         
645         filterAttributes(attr, ATTR_QOS_TYPE, ATTR_END);
646         
647         *s = 0;
648         
649         if (attr->first != NULL) {
650                 at = attr->first->data;
651                 *s = *(char*)at->data;
652         }
653         
654         
655 end:
656         destroyList(attr, (void(*)(void*))freeAttr);
657         
658         
659         return ret;
660 }
661
662
663 int ngadmin_setQOSMode (struct ngadmin *nga, int s)
664 {
665         List *attr;
666         
667         
668         attr = createEmptyList();
669         pushBackList(attr, newByteAttr(ATTR_QOS_TYPE, s));
670         
671         
672         return writeRequest(nga, attr);
673 }
674
675
676 int ngadmin_getQOSValues (struct ngadmin *nga, char *ports)
677 {
678         List *attr;
679         ListNode *ln;
680         struct attr *at;
681         int ret = ERR_OK, port;
682         struct attr_qos *aq;
683         
684         
685         if (nga == NULL || ports == NULL)
686                 return ERR_INVARG;
687         else if (nga->current == NULL)
688                 return ERR_NOTLOG;
689         
690         
691         attr = createEmptyList();
692         pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
693         ret = readRequest(nga, attr);
694         if (ret < 0)
695                 goto end;
696         
697         filterAttributes(attr, ATTR_QOS_CONFIG, ATTR_END);
698         
699         for (port = 0; port < nga->current->ports; port++)
700                 ports[port] = PRIO_UNSPEC;
701         
702         for (ln = attr->first; ln != NULL; ln = ln->next) {
703                 at = ln->data;
704                 aq = at->data;
705                 ports[aq->port - 1] = aq->prio;
706         }
707         
708         
709 end:
710         destroyList(attr, (void(*)(void*))freeAttr);
711         
712         
713         return ret;
714 }
715
716
717 int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports)
718 {
719         List *attr;
720         int port;
721         struct attr_qos *aq;
722         
723         
724         if (nga == NULL || ports == NULL)
725                 return ERR_INVARG;
726         else if (nga->current == NULL)
727                 return ERR_NOTLOG;
728         
729         
730         attr = createEmptyList();
731         
732         for (port = 0; port < nga->current->ports; port++) {
733                 if (ports[port] >= PRIO_HIGH && ports[port] <= PRIO_LOW) {
734                         aq = malloc(sizeof(struct attr_qos));
735                         if (aq == NULL)
736                                 return ERR_MEM;
737                         aq->port = port + 1;
738                         aq->prio = ports[port];
739                         pushBackList(attr, newAttr(ATTR_QOS_CONFIG, sizeof(struct attr_qos), aq));
740                 }
741         }
742         
743         
744         return writeRequest(nga, attr);
745 }
746
747
748 int ngadmin_restart (struct ngadmin *nga)
749 {
750         List *attr;
751         
752         
753         attr = createEmptyList();
754         pushBackList(attr, newByteAttr(ATTR_RESTART, 1));
755         
756         
757         return writeRequest(nga, attr);
758 }
759
760
761 int ngadmin_defaults (struct ngadmin *nga)
762 {
763         List *attr;
764         int ret = ERR_OK;
765         
766         
767         attr = createEmptyList();
768         pushBackList(attr, newByteAttr(ATTR_DEFAULTS, 1));
769         ret = writeRequest(nga, attr);
770         if (ret != ERR_OK)
771                 goto end;
772         
773         
774         /* successful: delog and clean list */
775         free(nga->swi_tab);
776         nga->swi_tab = NULL;
777         nga->swi_count = 0;
778         nga->current = NULL;
779         
780 end:
781         return ret;
782 }
783
784
785 int ngadmin_getMirror (struct ngadmin *nga, char *ports)
786 {
787         List *attr;
788         struct attr *at;
789         int ret = ERR_OK;
790         
791         
792         if (nga == NULL || ports == NULL)
793                 return ERR_INVARG;
794         else if (nga->current == NULL)
795                 return ERR_NOTLOG;
796         
797         
798         attr = createEmptyList();
799         pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
800         ret = readRequest(nga, attr);
801         if (ret < 0)
802                 goto end;
803         
804         filterAttributes(attr, ATTR_MIRROR, ATTR_END);
805         
806         memset(ports, 0, 1 + nga->current->ports);
807         
808         if (attr->first != NULL) {
809                 at = attr->first->data;
810                 memcpy(ports, at->data, 1 + nga->current->ports);
811         }
812         
813         
814 end:
815         destroyList(attr, (void(*)(void*))freeAttr);
816         
817         
818         return ret;
819 }
820
821
822 int ngadmin_setMirror (struct ngadmin *nga, const char *ports)
823 {
824         List *attr;
825         char *p;
826         
827         
828         if (nga == NULL)
829                 return ERR_INVARG;
830         else if (nga->current == NULL)
831                 return ERR_NOTLOG;
832         
833         
834         p = malloc(1 + nga->current->ports);
835         if (p == NULL)
836                 return ERR_MEM;
837         
838         if (ports == NULL)
839                 memset(p, 0, 1 + nga->current->ports);
840         else
841                 memcpy(p, ports, 1 + nga->current->ports);
842         
843         attr = createEmptyList();
844         pushBackList(attr, newAttr(ATTR_MIRROR, 1 + nga->current->ports, p));
845         
846         
847         return writeRequest(nga, attr);
848 }
849
850
851 int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic)
852 {
853         List *attr;
854         struct attr *at;
855         int ret = ERR_OK;
856         struct attr_igmp_vlan *aiv;
857         
858         
859         if (nga == NULL || ic == NULL)
860                 return ERR_INVARG;
861         else if (nga->current == NULL)
862                 return ERR_NOTLOG;
863         
864         /*
865         ATTR_IGMP_ENABLE_VLAN
866         ATTR_IGMP_BLOCK_UNK
867         ATTR_IGMP_VALID_V3
868         
869         Apparently, read-querying these attributes at the same time causes the switch to reply garbage. 
870         Here we are forced to do like the official win app and send a separate request for each attribute. 
871         */
872         
873         
874         attr = createEmptyList();
875         memset(ic, 0, sizeof(struct igmp_conf));
876         
877         
878         pushBackList(attr, newEmptyAttr(ATTR_IGMP_ENABLE_VLAN));
879         ret = readRequest(nga, attr);
880         if (ret < 0)
881                 goto end;
882         
883         filterAttributes(attr, ATTR_IGMP_ENABLE_VLAN, ATTR_END);
884         
885         if (attr->first != NULL) {
886                 at = attr->first->data;
887                 aiv = at->data;
888                 ic->enable = aiv->enable;
889                 ic->vlan = aiv->vlan;
890         }
891         
892         clearList(attr, (void(*)(void*))freeAttr);
893         
894         
895         pushBackList(attr, newEmptyAttr(ATTR_IGMP_BLOCK_UNK));
896         ret = readRequest(nga, attr);
897         if (ret < 0)
898                 goto end;
899         
900         filterAttributes(attr, ATTR_IGMP_BLOCK_UNK, ATTR_END);
901         
902         if (attr->first != NULL) {
903                 at = attr->first->data;
904                 ic->block = *(char*)at->data;
905         }
906         
907         clearList(attr, (void(*)(void*))freeAttr);
908         
909         
910         pushBackList(attr, newEmptyAttr(ATTR_IGMP_VALID_V3));
911         ret = readRequest(nga, attr);
912         if (ret < 0)
913                 goto end;
914         
915         filterAttributes(attr, ATTR_IGMP_VALID_V3, ATTR_END);
916         
917         if (attr->first != NULL) {
918                 at = attr->first->data;
919                 ic->validate = *(char*)at->data;
920         }
921         
922         
923 end:
924         destroyList(attr, (void(*)(void*))freeAttr);
925         
926         
927         return ret;
928 }
929
930
931 int ngadmin_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic)
932 {
933         List *attr;
934         struct attr_igmp_vlan *aiv;
935         
936         
937         if (nga == NULL || ic == NULL)
938                 return ERR_INVARG;
939         else if (nga->current == NULL)
940                 return ERR_NOTLOG;
941         
942         
943         aiv = malloc(sizeof(struct attr_igmp_vlan));
944         if (aiv == NULL)
945                 return ERR_MEM;
946         aiv->enable = ic->enable;
947         aiv->vlan = ic->vlan;
948         
949         
950         attr = createEmptyList();
951         pushBackList(attr, newAttr(ATTR_IGMP_ENABLE_VLAN, sizeof(struct attr_igmp_vlan), aiv));
952         pushBackList(attr, newByteAttr(ATTR_IGMP_BLOCK_UNK, ic->block != false));
953         pushBackList(attr, newByteAttr(ATTR_IGMP_VALID_V3, ic->validate != false));
954         
955         
956         return writeRequest(nga, attr);
957 }
958
959
960 int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb)
961 {
962         List *attr;
963         ListNode *ln;
964         struct attr *at;
965         int ret = ERR_OK, i;
966         struct attr_cabletest_do *acd;
967         struct attr_cabletest_result *acr;
968         
969         
970         if (nga == NULL || ct == NULL)
971                 return ERR_INVARG;
972         else if (nga->current == NULL)
973                 return ERR_NOTLOG;
974         
975         
976         attr = createEmptyList();
977         
978         for (i = 0; i < nb; i++) {
979                 
980                 acd = malloc(sizeof(struct attr_cabletest_do));
981                 if (acd == NULL)
982                         return ERR_MEM;
983                 acd->port = ct[i].port;
984                 acd->action = 1;
985                 pushBackList(attr, newAttr(ATTR_CABLETEST_DO, sizeof(struct attr_cabletest_do), acd));
986                 
987                 ret = writeRequest(nga, attr);
988                 attr = NULL;
989                 if (ret < 0)
990                         goto end;
991                 
992                 /* the list is destroyed by writeRequest, so we need to recreate it */
993                 attr = createEmptyList();
994                 pushBackList(attr, newByteAttr(ATTR_CABLETEST_RESULT, ct[i].port));
995                 ret = readRequest(nga, attr);
996                 if (ret < 0)
997                         goto end;
998                 
999                 filterAttributes(attr, ATTR_CABLETEST_RESULT, ATTR_END);
1000                 
1001                 for (ln = attr->first; ln != NULL; ln = ln->next) {
1002                         at = ln->data;
1003                         acr = at->data;
1004                         if (at->size == sizeof(struct attr_cabletest_result) && acr->port == ct[i].port) {
1005                                 ct[i].v1 = acr->v1;
1006                                 ct[i].v2 = acr->v2;
1007                                 break;
1008                         }
1009                 }
1010                 
1011                 /* just empty the list, it will be used at next iteration */
1012                 clearList(attr, (void(*)(void*))freeAttr);
1013         }
1014         
1015         
1016 end:
1017         destroyList(attr, (void(*)(void*))freeAttr);
1018         
1019         
1020         return ret;
1021 }
1022
1023
1024 int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc)
1025 {
1026         List *attr;
1027         int ret = ERR_OK;
1028         struct swi_attr *sa;
1029         
1030         
1031         if (nga == NULL || nc == NULL)
1032                 return ERR_INVARG;
1033         
1034         sa = nga->current;
1035         if (sa == NULL)
1036                 return ERR_NOTLOG;
1037         
1038         
1039         attr = createEmptyList();
1040         
1041         if (nc->dhcp) {
1042                 pushBackList(attr, newShortAttr(ATTR_DHCP, 1));
1043         } else {
1044                 pushBackList(attr, newShortAttr(ATTR_DHCP, 0));
1045                 /* only add non-null values */
1046                 if (nc->ip.s_addr != 0)
1047                         pushBackList(attr, newAddrAttr(ATTR_IP, nc->ip));
1048                 if (nc->netmask.s_addr != 0)
1049                         pushBackList(attr, newAddrAttr(ATTR_NETMASK, nc->netmask));
1050                 if (nc->gw.s_addr != 0)
1051                         pushBackList(attr, newAddrAttr(ATTR_GATEWAY, nc->gw));
1052         }
1053         
1054         ret = writeRequest(nga, attr);
1055         if (ret != ERR_OK)
1056                 goto end;
1057         
1058         
1059         /* update local values */
1060         sa->nc.dhcp = nc->dhcp;
1061         if (!nc->dhcp) {
1062                 if (nc->ip.s_addr !=0)
1063                         sa->nc.ip = nc->ip;
1064                 if (nc->netmask.s_addr != 0)
1065                         sa->nc.netmask = nc->netmask;
1066                 if (nc->gw.s_addr != 0)
1067                         sa->nc.gw = nc->gw;
1068         }
1069         
1070         
1071 end:
1072         
1073         return ret;
1074 }
1075
1076
1077 int ngadmin_getVLANType (struct ngadmin *nga, int *t)
1078 {
1079         List *attr;
1080         struct attr *at;
1081         int ret = ERR_OK;
1082         
1083         
1084         if (nga == NULL || t == NULL)
1085                 return ERR_INVARG;
1086         else if (nga->current == NULL)
1087                 return ERR_NOTLOG;
1088         
1089         
1090         attr = createEmptyList();
1091         pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
1092         ret=readRequest(nga, attr);
1093         if (ret != ERR_OK)
1094                 goto end;
1095         
1096         filterAttributes(attr, ATTR_VLAN_TYPE, ATTR_END);
1097         
1098         *t = VLAN_DISABLED;
1099         
1100         if (attr->first != NULL) {
1101                 at = attr->first->data;
1102                 *t =(int)*(char*)at->data;
1103         }
1104         
1105         
1106 end:
1107         destroyList(attr, (void(*)(void*))freeAttr);
1108         
1109         
1110         return ret;
1111 }
1112
1113
1114 int ngadmin_setVLANType (struct ngadmin *nga, int t)
1115 {
1116         List *attr;
1117         
1118         
1119         if (nga == NULL || t < 1 || t > 4)
1120                 return ERR_INVARG;
1121         else if (nga->current == NULL)
1122                 return ERR_NOTLOG;
1123         
1124         
1125         attr = createEmptyList();
1126         pushBackList(attr, newByteAttr(ATTR_VLAN_TYPE, t));
1127         
1128         
1129         return writeRequest(nga, attr);
1130 }
1131
1132
1133 int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb)
1134 {
1135         List *attr;
1136         ListNode *ln;
1137         struct attr *at;
1138         int ret = ERR_OK, total;
1139         struct attr_vlan_dot *avd;
1140         
1141         
1142         if (nga == NULL || vlans == NULL || ports== NULL || nb == NULL || *nb <= 0)
1143                 return ERR_INVARG;
1144         else if (nga->current == NULL)
1145                 return ERR_NOTLOG;
1146         
1147         
1148         total = *nb;
1149         *nb = 0;
1150         
1151         attr = createEmptyList();
1152         pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
1153         ret = readRequest(nga, attr);
1154         if (ret != ERR_OK)
1155                 goto end;
1156         
1157         filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
1158         
1159         memset(vlans, 0, total * sizeof(unsigned short));
1160         memset(ports, 0, total * nga->current->ports);
1161         
1162         for (ln = attr->first; ln != NULL; ln = ln->next) {
1163                 at = ln->data;
1164                 avd = at->data;
1165                 
1166                 *vlans = avd->vlan;
1167                 memcpy(ports, avd->ports, nga->current->ports);
1168                 
1169                 vlans++;
1170                 ports += nga->current->ports;
1171                 (*nb)++;
1172                 
1173                 if (*nb > total)
1174                         break; /* no more room */
1175         }
1176         
1177         
1178 end:
1179         destroyList(attr, (void(*)(void*))freeAttr);
1180         
1181         
1182         return ret;
1183 }
1184
1185
1186 int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned char *ports)
1187 {
1188         List *attr;
1189         ListNode *ln;
1190         struct attr *at;
1191         int ret = ERR_OK;
1192         struct attr_vlan_dot *avd;
1193         
1194         
1195         if (nga == NULL || vlan < 1 || vlan > VLAN_MAX || ports == NULL)
1196                 return ERR_INVARG;
1197         else if (nga->current == NULL)
1198                 return ERR_NOTLOG;
1199         
1200         
1201         attr = createEmptyList();
1202         pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
1203         ret = readRequest(nga, attr);
1204         if (ret != ERR_OK)
1205                 goto end;
1206         
1207         filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
1208         
1209         memset(ports, 0, nga->current->ports);
1210         
1211         for (ln = attr->first; ln != NULL; ln = ln->next) {
1212                 at = ln->data;
1213                 avd = at->data;
1214                 if (avd->vlan == vlan) {
1215                         memcpy(ports, avd->ports, nga->current->ports);
1216                         break;
1217                 }
1218         }
1219         
1220         
1221 end:
1222         destroyList(attr, (void(*)(void*))freeAttr);
1223         
1224         
1225         return ret;
1226 }
1227
1228
1229 int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsigned char *ports)
1230 {
1231         List *attr = NULL;
1232         struct attr *at;
1233         struct swi_attr *sa;
1234         struct attr_vlan_dot *avd;
1235         int ret = ERR_OK, port;
1236         
1237         
1238         if (nga == NULL || vlan < 1 || vlan > VLAN_MAX || ports == NULL)
1239                 return ERR_INVARG;
1240         
1241         sa = nga->current;
1242         if (sa == NULL)
1243                 return ERR_NOTLOG;
1244         
1245         
1246         /* if nothing is to be changed, do nothing */
1247         for (port = 0; port < sa->ports && ports[port] == VLAN_UNSPEC; port++);
1248         if (port == sa->ports )
1249                 goto end;
1250         
1251         
1252         attr = createEmptyList();
1253         avd = malloc(sizeof(struct attr_vlan_dot) + sa->ports);
1254         if (avd == NULL)
1255                 return ERR_MEM;
1256         
1257         avd->vlan = vlan;
1258         
1259         /* if all is to be changed, we do not need to read old config */
1260         if (memchr(ports, VLAN_UNSPEC, sa->ports) != NULL) {
1261                 
1262                 pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
1263                 ret = readRequest(nga, attr);
1264                 if (ret != ERR_OK)
1265                         goto end;
1266                 
1267                 filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
1268                 
1269                 if (attr->first != NULL) {
1270                         at = attr->first->data;
1271                         memcpy(avd, at->data, sizeof(struct attr_vlan_dot) + sa->ports);
1272                 }
1273                 
1274                 clearList(attr, (void(*)(void*))freeAttr);
1275         }
1276         
1277         
1278         /* apply changes */
1279         for (port = 0; port < sa->ports; port++) {
1280                 if (ports[port] != VLAN_UNSPEC)
1281                         avd->ports[port] = ports[port];
1282         }
1283         
1284         
1285         pushBackList(attr, newAttr(ATTR_VLAN_DOT_CONF, sizeof(struct attr_vlan_dot) + sa->ports, avd));
1286         ret = writeRequest(nga, attr);
1287         attr = NULL;
1288         
1289         
1290 end:
1291         destroyList(attr, (void(*)(void*))freeAttr);
1292         
1293         
1294         return ret;
1295 }
1296
1297
1298 int ngadmin_VLANDestroy (struct ngadmin *nga, unsigned short vlan)
1299 {
1300         List *attr;
1301         
1302         
1303         if (nga == NULL || vlan < 1 || vlan > VLAN_MAX)
1304                 return ERR_INVARG;
1305         else if (nga->current == NULL)
1306                 return ERR_NOTLOG;
1307         
1308         
1309         attr = createEmptyList();
1310         pushBackList(attr, newShortAttr(ATTR_VLAN_DESTROY, vlan));
1311         
1312         
1313         return writeRequest(nga, attr);
1314 }
1315
1316
1317 int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports)
1318 {
1319         List *attr;
1320         ListNode *ln;
1321         struct attr *at;
1322         int ret = ERR_OK;
1323         struct attr_pvid *ap;
1324         
1325         
1326         if (nga == NULL || ports == NULL)
1327                 return ERR_INVARG;
1328         else if (nga->current == NULL)
1329                 return ERR_NOTLOG;
1330         
1331         
1332         attr = createEmptyList();
1333         pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID));
1334         ret = readRequest(nga, attr);
1335         if (ret != ERR_OK)
1336                 goto end;
1337         
1338         filterAttributes(attr, ATTR_VLAN_PVID, ATTR_END);
1339         
1340         memset(ports, 0, nga->current->ports * sizeof(unsigned short));
1341         
1342         for (ln = attr->first; ln != NULL; ln = ln->next) {
1343                 at = ln->data;
1344                 ap = at->data;
1345                 ports[ap->port - 1] = ap->vlan;
1346         }
1347         
1348         
1349 end:
1350         destroyList(attr, (void(*)(void*))freeAttr);
1351         
1352         
1353         return ret;
1354 }
1355
1356
1357 int ngadmin_setPVID (struct ngadmin *nga, unsigned char port, unsigned short vlan)
1358 {
1359         List *attr;
1360         struct attr_pvid *ap;
1361         
1362         
1363         if (nga == NULL || port < 1 || vlan < 1 || vlan > VLAN_MAX)
1364                 return ERR_INVARG;
1365         else if (nga->current == NULL)
1366                 return ERR_NOTLOG;
1367         else if (port > nga->current->ports)
1368                 return ERR_INVARG;
1369         
1370         
1371         attr = createEmptyList();
1372         ap = malloc(sizeof(struct attr_pvid));
1373         if (ap == NULL)
1374                 return ERR_MEM;
1375         ap->port = port;
1376         ap->vlan = vlan;
1377         
1378         pushBackList(attr, newAttr(ATTR_VLAN_PVID, sizeof(struct attr_pvid), ap));
1379         
1380         
1381         return writeRequest(nga, attr);
1382 }
1383
1384
1385