]> git.sur5r.net Git - ngadmin/blob - lib/src/ngadmin.c
Fix crash when reading the wrong type of VLAN
[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         struct attr *at;
223         int ret = ERR_OK;
224         struct swi_attr *sa;
225         
226         
227         if (nga == NULL)
228                 return ERR_INVARG;
229         else if (id < 0 || id >= nga->swi_count)
230                 return ERR_BADID;
231         
232         sa = &nga->swi_tab[id];
233         nga->current = sa;
234         nga->encrypt_pass = false;
235         
236         attr = createEmptyList();
237         pushBackList(attr, newEmptyAttr(ATTR_ENCPASS));
238         ret = readRequest(nga, attr);
239         if (ret != ERR_OK)
240                 goto end;
241         
242         filterAttributes(attr, ATTR_ENCPASS, ATTR_END);
243         if (attr->first != NULL) {
244                 at = attr->first->data;
245                 nga->encrypt_pass = (at->size == 4 && ntohl(*(unsigned int*)at->data) == 1);
246         }
247         clearList(attr, (void(*)(void*))freeAttr);
248         
249         /* Strangely, passwords must never be encrypted inside a read request,
250          * or it will be rejected. Seems more to be a firmware bug. */
251         pushBackList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
252         ret = readRequest(nga, attr);
253         if (ret == ERR_OK ) {
254                 /* login succeeded */
255                 /* TODO: if keep broadcasting is disabled, connect() the UDP 
256                 socket so icmp errors messages (port unreachable, TTL exceeded 
257                 in transit, ...) can be received */
258         } else {
259                 /* login failed */
260                 nga->current = NULL;
261         }
262         
263 end:
264         destroyList(attr, (void(*)(void*))freeAttr);
265         
266         
267         return ret;
268 }
269
270
271 int ngadmin_upgradeFirmware (struct ngadmin *nga, const char *filename)
272 {
273         if (nga == NULL || filename == NULL || *filename == 0)
274                 return ERR_INVARG;
275         else if (nga->current == NULL)
276                 return ERR_NOTLOG;
277         
278         /*
279         Firmware upgrade is not yet implemented. 
280         This would require much more work and the use of a TFTP client. 
281         Overall, it could be quite dangerous, as the switch may not check the binary 
282         content sent to it. 
283         */
284         
285         return ERR_NOTIMPL;
286 }
287
288
289 int ngadmin_getPortsStatus (struct ngadmin *nga, unsigned char *ports)
290 {
291         List *attr;
292         ListNode *ln;
293         struct attr *at;
294         int ret = ERR_OK;
295         struct attr_port_status *ps;
296         
297         
298         if (nga == NULL || ports == NULL)
299                 return ERR_INVARG;
300         else if (nga->current == NULL)
301                 return ERR_NOTLOG;
302         
303         
304         attr = createEmptyList();
305         pushBackList(attr, newEmptyAttr(ATTR_PORT_STATUS));
306         ret = readRequest(nga, attr);
307         if (ret != ERR_OK)
308                 goto end;
309         
310         filterAttributes(attr, ATTR_PORT_STATUS, ATTR_END);
311         
312         memset(ports, SPEED_UNK, nga->current->ports);
313         
314         for (ln = attr->first; ln != NULL; ln = ln->next) {
315                 at = ln->data;
316                 ps = at->data;
317                 ports[ps->port - 1] = ps->status;
318         }
319         
320 end:
321         destroyList(attr, (void(*)(void*))freeAttr);
322         
323         
324         return ret;
325 }
326
327
328 int ngadmin_setName (struct ngadmin *nga, const char *name)
329 {
330         List *attr;
331         int ret = ERR_OK;
332         
333         
334         if (nga == NULL)
335                 return ERR_INVARG;
336         else if (nga->current == NULL)
337                 return ERR_NOTLOG;
338         
339         
340         attr = createEmptyList();
341         pushBackList(attr, name == NULL ? newEmptyAttr(ATTR_NAME) : newAttr(ATTR_NAME, strlen(name), strdup(name)) );
342         ret = writeRequest(nga, attr);
343         if (ret != ERR_OK)
344                 goto end;
345          
346         /* successful, also update local name */
347         if (name == NULL)
348                 memset(nga->current->name, '\0', NAME_SIZE);
349         else
350                 strncpy(nga->current->name, name, NAME_SIZE);
351         
352 end:
353         return ret;
354 }
355
356
357 int ngadmin_getPortsStatistics (struct ngadmin *nga, struct port_stats *ps)
358 {
359         List *attr;
360         ListNode *ln;
361         struct attr *at;
362         int ret = ERR_OK;
363         struct attr_port_stat *aps;
364         
365         
366         if (nga == NULL || ps == NULL)
367                 return ERR_INVARG;
368         else if (nga->current == NULL)
369                 return ERR_NOTLOG;
370         
371         attr = createEmptyList();
372         pushBackList(attr, newEmptyAttr(ATTR_PORT_STATISTICS));
373         ret = readRequest(nga, attr);
374         if (ret != ERR_OK)
375                 goto end;
376         
377         filterAttributes(attr, ATTR_PORT_STATISTICS, ATTR_END);
378         
379         memset(ps, 0, nga->current->ports * sizeof(struct port_stats));
380         
381         for (ln = attr->first; ln != NULL; ln = ln->next) {
382                 at = ln->data;
383                 aps = at->data;
384                 ps[aps->port -1].recv = aps->recv;
385                 ps[aps->port -1].sent = aps->sent;
386                 ps[aps->port -1].crc = aps->crc;
387         }
388         
389 end:
390         destroyList(attr, (void(*)(void*))freeAttr);
391         
392         
393         return ret;
394 }
395
396
397 int ngadmin_resetPortsStatistics (struct ngadmin *nga)
398 {
399         List *attr;
400         
401         
402         attr = createEmptyList();
403         pushBackList(attr, newByteAttr(ATTR_STATS_RESET, 1));
404         
405         
406         return writeRequest(nga, attr);
407 }
408
409
410 int ngadmin_changePassword (struct ngadmin *nga, const char* pass)
411 {
412         List *attr;
413         struct attr *at;
414         int ret = ERR_OK;
415         
416         
417         if (nga == NULL || pass == NULL)
418                 return ERR_INVARG;
419         else if (nga->current == NULL)
420                 return ERR_NOTLOG;
421         
422         
423         attr = createEmptyList();
424         at = newAttr(ATTR_NEW_PASSWORD, strlen(pass), strdup(pass));
425         if (nga->encrypt_pass)
426                 passwordEndecode(at->data, at->size);
427         pushBackList(attr, at);
428         ret = writeRequest(nga, attr);
429         if (ret != ERR_OK)
430                 goto end;
431         
432         
433         /* successful, also update local password */
434         strncpy(nga->password, pass, PASSWORD_MAX);
435         
436 end:
437         
438         return ret;
439 }
440
441
442 int ngadmin_getStormFilterState (struct ngadmin *nga, int *s)
443 {
444         List *attr;
445         struct attr *at;
446         int ret = ERR_OK;
447         
448         
449         if (nga == NULL || s == NULL)
450                 return ERR_INVARG;
451         else if (nga->current == NULL)
452                 return ERR_NOTLOG;
453         
454         
455         attr = createEmptyList();
456         pushBackList(attr, newEmptyAttr(ATTR_STORM_ENABLE));
457         ret = readRequest(nga, attr);
458         if (ret != ERR_OK)
459                 goto end;
460         
461         filterAttributes(attr, ATTR_STORM_ENABLE, ATTR_END);
462         
463         *s = 0;
464         
465         if (attr->first != NULL) {
466                 at = attr->first->data;
467                 *s = *(char*)at->data;
468         }
469         
470         
471 end:
472         destroyList(attr, (void(*)(void*))freeAttr);
473         
474         
475         return ret;
476 }
477
478
479 int ngadmin_setStormFilterState (struct ngadmin *nga, int s)
480 {
481         List *attr;
482         
483         
484         attr = createEmptyList();
485         pushBackList(attr, newByteAttr(ATTR_STORM_ENABLE, s != 0));
486         
487         
488         return writeRequest(nga, attr);
489 }
490
491
492 int ngadmin_getStormFilterValues (struct ngadmin *nga, int *ports)
493 {
494         List *attr;
495         ListNode *ln;
496         struct attr *at;
497         int ret = ERR_OK, port;
498         struct attr_bitrate *sb;
499         
500         
501         if (nga == NULL || ports == NULL)
502                 return ERR_INVARG;
503         else if (nga->current == NULL)
504                 return ERR_NOTLOG;
505         
506         
507         attr = createEmptyList();
508         pushBackList(attr, newEmptyAttr(ATTR_STORM_BITRATE));
509         ret = readRequest(nga, attr);
510         if (ret != ERR_OK)
511                 goto end;
512         
513         filterAttributes(attr, ATTR_STORM_BITRATE, ATTR_END);
514         
515         for (port = 0; port < nga->current->ports; port++)
516                 ports[port] = BITRATE_UNSPEC;
517         
518         for (ln = attr->first; ln != NULL; ln = ln->next) {
519                 at = ln->data;
520                 sb = at->data;
521                 ports[sb->port - 1] = sb->bitrate;
522         }
523         
524         
525 end:
526         destroyList(attr, (void(*)(void*))freeAttr);
527         
528         
529         return ret;
530 }
531
532
533 int ngadmin_setStormFilterValues (struct ngadmin *nga, const int *ports)
534 {
535         List *attr;
536         int port;
537         struct attr_bitrate *sb;
538         
539         
540         if (nga == NULL || ports == NULL)
541                 return ERR_INVARG;
542         else if (nga->current == NULL)
543                 return ERR_NOTLOG;
544         
545         
546         attr = createEmptyList();
547         
548         for (port = 0; port < nga->current->ports; port++) {
549                 if (ports[port] != BITRATE_UNSPEC) {
550                         sb = malloc(sizeof(struct attr_bitrate));
551                         if (sb == NULL)
552                                 return ERR_MEM;
553                         sb->port = port + 1;
554                         sb->bitrate = ports[port];
555                         pushBackList(attr, newAttr(ATTR_STORM_BITRATE, sizeof(struct attr_bitrate), sb));
556                 }
557         }
558         
559         return writeRequest(nga, attr);
560 }
561
562
563 int ngadmin_getBitrateLimits (struct ngadmin *nga, int *ports)
564 {
565         List *attr;
566         ListNode *ln;
567         struct attr *at;
568         int ret = ERR_OK, port;
569         struct attr_bitrate *pb;
570         
571         
572         if (nga == NULL || ports == NULL)
573                 return ERR_INVARG;
574         else if (nga->current == NULL)
575                 return ERR_NOTLOG;
576         
577         
578         attr = createEmptyList();
579         pushBackList(attr, newEmptyAttr(ATTR_BITRATE_INPUT));
580         pushBackList(attr, newEmptyAttr(ATTR_BITRATE_OUTPUT));
581         ret = readRequest(nga, attr);
582         if (ret != ERR_OK)
583                 goto end;
584         
585         
586         for (port = 0; port < nga->current->ports; port++) {
587                 ports[2 * port + 0] = BITRATE_UNSPEC;
588                 ports[2 * port + 1] = BITRATE_UNSPEC;
589         }
590         
591         for (ln = attr->first; ln != NULL; ln = ln->next) {
592                 at = ln->data;
593                 pb = at->data;
594                 if (at->attr == ATTR_BITRATE_INPUT)
595                         ports[(pb->port - 1) * 2 + 0] = pb->bitrate;
596                 else if (at->attr == ATTR_BITRATE_OUTPUT)
597                         ports[(pb->port - 1) * 2 + 1] = pb->bitrate;
598         }
599         
600         
601 end:
602         destroyList(attr, (void(*)(void*))freeAttr);
603         
604         return ret;
605 }
606
607
608 int ngadmin_setBitrateLimits (struct ngadmin *nga, const int *ports)
609 {
610         List *attr;
611         int port;
612         struct attr_bitrate *pb;
613         
614         
615         if (nga == NULL || ports == NULL)
616                 return ERR_INVARG;
617         else if (nga->current == NULL)
618                 return ERR_NOTLOG;
619         
620         
621         attr = createEmptyList();
622         
623         for (port = 0; port < nga->current->ports; port++) {
624                 if (ports[2 * port + 0] >= BITRATE_NOLIMIT && ports[2 * port + 0] <= BITRATE_512M) {
625                         pb = malloc(sizeof(struct attr_bitrate));
626                         if (pb == NULL)
627                                 return ERR_MEM;
628                         pb->port = port + 1;
629                         pb->bitrate = ports[2 * port + 0];
630                         pushBackList(attr, newAttr(ATTR_BITRATE_INPUT, sizeof(struct attr_bitrate), pb));
631                 }
632                 if (ports[2 * port + 1] >= BITRATE_NOLIMIT && ports[2 * port + 1] <= BITRATE_512M) {
633                         pb = malloc(sizeof(struct attr_bitrate));
634                         if (pb == NULL)
635                                 return ERR_MEM;
636                         pb->port = port + 1;
637                         pb->bitrate = ports[2 * port + 1];
638                         pushBackList(attr, newAttr(ATTR_BITRATE_OUTPUT, sizeof(struct attr_bitrate), pb));
639                 }
640         }
641         
642         
643         return writeRequest(nga, attr);
644 }
645
646
647 int ngadmin_getQOSMode (struct ngadmin *nga, int *s)
648 {
649         List *attr;
650         struct attr *at;
651         int ret = ERR_OK;
652         
653         
654         if (nga == NULL || s == NULL)
655                 return ERR_INVARG;
656         else if (nga->current == NULL)
657                 return ERR_NOTLOG;
658         
659         
660         attr = createEmptyList();
661         pushBackList(attr, newEmptyAttr(ATTR_QOS_TYPE));
662         ret = readRequest(nga, attr);
663         if (ret != ERR_OK)
664                 goto end;
665         
666         filterAttributes(attr, ATTR_QOS_TYPE, ATTR_END);
667         
668         *s = 0;
669         
670         if (attr->first != NULL) {
671                 at = attr->first->data;
672                 *s = *(char*)at->data;
673         }
674         
675         
676 end:
677         destroyList(attr, (void(*)(void*))freeAttr);
678         
679         
680         return ret;
681 }
682
683
684 int ngadmin_setQOSMode (struct ngadmin *nga, int s)
685 {
686         List *attr;
687         
688         
689         attr = createEmptyList();
690         pushBackList(attr, newByteAttr(ATTR_QOS_TYPE, s));
691         
692         
693         return writeRequest(nga, attr);
694 }
695
696
697 int ngadmin_getQOSValues (struct ngadmin *nga, char *ports)
698 {
699         List *attr;
700         ListNode *ln;
701         struct attr *at;
702         int ret = ERR_OK, port;
703         struct attr_qos *aq;
704         
705         
706         if (nga == NULL || ports == NULL)
707                 return ERR_INVARG;
708         else if (nga->current == NULL)
709                 return ERR_NOTLOG;
710         
711         
712         attr = createEmptyList();
713         pushBackList(attr, newEmptyAttr(ATTR_QOS_CONFIG));
714         ret = readRequest(nga, attr);
715         if (ret < 0)
716                 goto end;
717         
718         filterAttributes(attr, ATTR_QOS_CONFIG, ATTR_END);
719         
720         for (port = 0; port < nga->current->ports; port++)
721                 ports[port] = PRIO_UNSPEC;
722         
723         for (ln = attr->first; ln != NULL; ln = ln->next) {
724                 at = ln->data;
725                 aq = at->data;
726                 ports[aq->port - 1] = aq->prio;
727         }
728         
729         
730 end:
731         destroyList(attr, (void(*)(void*))freeAttr);
732         
733         
734         return ret;
735 }
736
737
738 int ngadmin_setQOSValues (struct ngadmin *nga, const char *ports)
739 {
740         List *attr;
741         int port;
742         struct attr_qos *aq;
743         
744         
745         if (nga == NULL || ports == NULL)
746                 return ERR_INVARG;
747         else if (nga->current == NULL)
748                 return ERR_NOTLOG;
749         
750         
751         attr = createEmptyList();
752         
753         for (port = 0; port < nga->current->ports; port++) {
754                 if (ports[port] >= PRIO_HIGH && ports[port] <= PRIO_LOW) {
755                         aq = malloc(sizeof(struct attr_qos));
756                         if (aq == NULL)
757                                 return ERR_MEM;
758                         aq->port = port + 1;
759                         aq->prio = ports[port];
760                         pushBackList(attr, newAttr(ATTR_QOS_CONFIG, sizeof(struct attr_qos), aq));
761                 }
762         }
763         
764         
765         return writeRequest(nga, attr);
766 }
767
768
769 int ngadmin_restart (struct ngadmin *nga)
770 {
771         List *attr;
772         
773         
774         attr = createEmptyList();
775         pushBackList(attr, newByteAttr(ATTR_RESTART, 1));
776         
777         
778         return writeRequest(nga, attr);
779 }
780
781
782 int ngadmin_defaults (struct ngadmin *nga)
783 {
784         List *attr;
785         int ret = ERR_OK;
786         
787         
788         attr = createEmptyList();
789         pushBackList(attr, newByteAttr(ATTR_DEFAULTS, 1));
790         ret = writeRequest(nga, attr);
791         if (ret != ERR_OK)
792                 goto end;
793         
794         
795         /* successful: delog and clean list */
796         free(nga->swi_tab);
797         nga->swi_tab = NULL;
798         nga->swi_count = 0;
799         nga->current = NULL;
800         
801 end:
802         return ret;
803 }
804
805
806 int ngadmin_getMirror (struct ngadmin *nga, char *ports)
807 {
808         List *attr;
809         struct attr *at;
810         int ret = ERR_OK;
811         
812         
813         if (nga == NULL || ports == NULL)
814                 return ERR_INVARG;
815         else if (nga->current == NULL)
816                 return ERR_NOTLOG;
817         
818         
819         attr = createEmptyList();
820         pushBackList(attr, newEmptyAttr(ATTR_MIRROR));
821         ret = readRequest(nga, attr);
822         if (ret < 0)
823                 goto end;
824         
825         filterAttributes(attr, ATTR_MIRROR, ATTR_END);
826         
827         memset(ports, 0, 1 + nga->current->ports);
828         
829         if (attr->first != NULL) {
830                 at = attr->first->data;
831                 memcpy(ports, at->data, 1 + nga->current->ports);
832         }
833         
834         
835 end:
836         destroyList(attr, (void(*)(void*))freeAttr);
837         
838         
839         return ret;
840 }
841
842
843 int ngadmin_setMirror (struct ngadmin *nga, const char *ports)
844 {
845         List *attr;
846         char *p;
847         
848         
849         if (nga == NULL)
850                 return ERR_INVARG;
851         else if (nga->current == NULL)
852                 return ERR_NOTLOG;
853         
854         
855         p = malloc(1 + nga->current->ports);
856         if (p == NULL)
857                 return ERR_MEM;
858         
859         if (ports == NULL)
860                 memset(p, 0, 1 + nga->current->ports);
861         else
862                 memcpy(p, ports, 1 + nga->current->ports);
863         
864         attr = createEmptyList();
865         pushBackList(attr, newAttr(ATTR_MIRROR, 1 + nga->current->ports, p));
866         
867         
868         return writeRequest(nga, attr);
869 }
870
871
872 int ngadmin_getIGMPConf (struct ngadmin *nga, struct igmp_conf *ic)
873 {
874         List *attr;
875         struct attr *at;
876         int ret = ERR_OK;
877         struct attr_igmp_vlan *aiv;
878         
879         
880         if (nga == NULL || ic == NULL)
881                 return ERR_INVARG;
882         else if (nga->current == NULL)
883                 return ERR_NOTLOG;
884         
885         /*
886         ATTR_IGMP_ENABLE_VLAN
887         ATTR_IGMP_BLOCK_UNK
888         ATTR_IGMP_VALID_V3
889         
890         Apparently, read-querying these attributes at the same time causes the switch to reply garbage. 
891         Here we are forced to do like the official win app and send a separate request for each attribute. 
892         */
893         
894         
895         attr = createEmptyList();
896         memset(ic, 0, sizeof(struct igmp_conf));
897         
898         
899         pushBackList(attr, newEmptyAttr(ATTR_IGMP_ENABLE_VLAN));
900         ret = readRequest(nga, attr);
901         if (ret < 0)
902                 goto end;
903         
904         filterAttributes(attr, ATTR_IGMP_ENABLE_VLAN, ATTR_END);
905         
906         if (attr->first != NULL) {
907                 at = attr->first->data;
908                 aiv = at->data;
909                 ic->enable = aiv->enable;
910                 ic->vlan = aiv->vlan;
911         }
912         
913         clearList(attr, (void(*)(void*))freeAttr);
914         
915         
916         pushBackList(attr, newEmptyAttr(ATTR_IGMP_BLOCK_UNK));
917         ret = readRequest(nga, attr);
918         if (ret < 0)
919                 goto end;
920         
921         filterAttributes(attr, ATTR_IGMP_BLOCK_UNK, ATTR_END);
922         
923         if (attr->first != NULL) {
924                 at = attr->first->data;
925                 ic->block = *(char*)at->data;
926         }
927         
928         clearList(attr, (void(*)(void*))freeAttr);
929         
930         
931         pushBackList(attr, newEmptyAttr(ATTR_IGMP_VALID_V3));
932         ret = readRequest(nga, attr);
933         if (ret < 0)
934                 goto end;
935         
936         filterAttributes(attr, ATTR_IGMP_VALID_V3, ATTR_END);
937         
938         if (attr->first != NULL) {
939                 at = attr->first->data;
940                 ic->validate = *(char*)at->data;
941         }
942         
943         
944 end:
945         destroyList(attr, (void(*)(void*))freeAttr);
946         
947         
948         return ret;
949 }
950
951
952 int ngadmin_setIGMPConf (struct ngadmin *nga, const struct igmp_conf *ic)
953 {
954         List *attr;
955         struct attr_igmp_vlan *aiv;
956         
957         
958         if (nga == NULL || ic == NULL)
959                 return ERR_INVARG;
960         else if (nga->current == NULL)
961                 return ERR_NOTLOG;
962         
963         
964         aiv = malloc(sizeof(struct attr_igmp_vlan));
965         if (aiv == NULL)
966                 return ERR_MEM;
967         aiv->enable = ic->enable;
968         aiv->vlan = ic->vlan;
969         
970         
971         attr = createEmptyList();
972         pushBackList(attr, newAttr(ATTR_IGMP_ENABLE_VLAN, sizeof(struct attr_igmp_vlan), aiv));
973         pushBackList(attr, newByteAttr(ATTR_IGMP_BLOCK_UNK, ic->block != false));
974         pushBackList(attr, newByteAttr(ATTR_IGMP_VALID_V3, ic->validate != false));
975         
976         
977         return writeRequest(nga, attr);
978 }
979
980
981 int ngadmin_cabletest (struct ngadmin *nga, struct cabletest *ct, int nb)
982 {
983         List *attr;
984         ListNode *ln;
985         struct attr *at;
986         int ret = ERR_OK, i;
987         struct attr_cabletest_do *acd;
988         struct attr_cabletest_result *acr;
989         
990         
991         if (nga == NULL || ct == NULL)
992                 return ERR_INVARG;
993         else if (nga->current == NULL)
994                 return ERR_NOTLOG;
995         
996         
997         attr = createEmptyList();
998         
999         for (i = 0; i < nb; i++) {
1000                 
1001                 acd = malloc(sizeof(struct attr_cabletest_do));
1002                 if (acd == NULL)
1003                         return ERR_MEM;
1004                 acd->port = ct[i].port;
1005                 acd->action = 1;
1006                 pushBackList(attr, newAttr(ATTR_CABLETEST_DO, sizeof(struct attr_cabletest_do), acd));
1007                 
1008                 ret = writeRequest(nga, attr);
1009                 attr = NULL;
1010                 if (ret < 0)
1011                         goto end;
1012                 
1013                 /* the list is destroyed by writeRequest, so we need to recreate it */
1014                 attr = createEmptyList();
1015                 pushBackList(attr, newByteAttr(ATTR_CABLETEST_RESULT, ct[i].port));
1016                 ret = readRequest(nga, attr);
1017                 if (ret < 0)
1018                         goto end;
1019                 
1020                 filterAttributes(attr, ATTR_CABLETEST_RESULT, ATTR_END);
1021                 
1022                 for (ln = attr->first; ln != NULL; ln = ln->next) {
1023                         at = ln->data;
1024                         acr = at->data;
1025                         if (at->size == sizeof(struct attr_cabletest_result) && acr->port == ct[i].port) {
1026                                 ct[i].v1 = acr->v1;
1027                                 ct[i].v2 = acr->v2;
1028                                 break;
1029                         }
1030                 }
1031                 
1032                 /* just empty the list, it will be used at next iteration */
1033                 clearList(attr, (void(*)(void*))freeAttr);
1034         }
1035         
1036         
1037 end:
1038         destroyList(attr, (void(*)(void*))freeAttr);
1039         
1040         
1041         return ret;
1042 }
1043
1044
1045 int ngadmin_setNetConf (struct ngadmin *nga, const struct net_conf *nc)
1046 {
1047         List *attr;
1048         int ret = ERR_OK;
1049         struct swi_attr *sa;
1050         
1051         
1052         if (nga == NULL || nc == NULL)
1053                 return ERR_INVARG;
1054         
1055         sa = nga->current;
1056         if (sa == NULL)
1057                 return ERR_NOTLOG;
1058         
1059         
1060         attr = createEmptyList();
1061         
1062         if (nc->dhcp) {
1063                 pushBackList(attr, newShortAttr(ATTR_DHCP, 1));
1064         } else {
1065                 pushBackList(attr, newShortAttr(ATTR_DHCP, 0));
1066                 /* only add non-null values */
1067                 if (nc->ip.s_addr != 0)
1068                         pushBackList(attr, newAddrAttr(ATTR_IP, nc->ip));
1069                 if (nc->netmask.s_addr != 0)
1070                         pushBackList(attr, newAddrAttr(ATTR_NETMASK, nc->netmask));
1071                 if (nc->gw.s_addr != 0)
1072                         pushBackList(attr, newAddrAttr(ATTR_GATEWAY, nc->gw));
1073         }
1074         
1075         ret = writeRequest(nga, attr);
1076         if (ret != ERR_OK)
1077                 goto end;
1078         
1079         
1080         /* update local values */
1081         sa->nc.dhcp = nc->dhcp;
1082         if (!nc->dhcp) {
1083                 if (nc->ip.s_addr !=0)
1084                         sa->nc.ip = nc->ip;
1085                 if (nc->netmask.s_addr != 0)
1086                         sa->nc.netmask = nc->netmask;
1087                 if (nc->gw.s_addr != 0)
1088                         sa->nc.gw = nc->gw;
1089         }
1090         
1091         
1092 end:
1093         
1094         return ret;
1095 }
1096
1097
1098 int ngadmin_getVLANType (struct ngadmin *nga, int *t)
1099 {
1100         List *attr;
1101         struct attr *at;
1102         int ret = ERR_OK;
1103         
1104         
1105         if (nga == NULL || t == NULL)
1106                 return ERR_INVARG;
1107         else if (nga->current == NULL)
1108                 return ERR_NOTLOG;
1109         
1110         
1111         attr = createEmptyList();
1112         pushBackList(attr, newEmptyAttr(ATTR_VLAN_TYPE));
1113         ret=readRequest(nga, attr);
1114         if (ret != ERR_OK)
1115                 goto end;
1116         
1117         filterAttributes(attr, ATTR_VLAN_TYPE, ATTR_END);
1118         
1119         *t = VLAN_DISABLED;
1120         
1121         if (attr->first != NULL) {
1122                 at = attr->first->data;
1123                 *t =(int)*(char*)at->data;
1124         }
1125         
1126         
1127 end:
1128         destroyList(attr, (void(*)(void*))freeAttr);
1129         
1130         
1131         return ret;
1132 }
1133
1134
1135 int ngadmin_setVLANType (struct ngadmin *nga, int t)
1136 {
1137         List *attr;
1138         
1139         
1140         if (nga == NULL || t < 1 || t > 4)
1141                 return ERR_INVARG;
1142         else if (nga->current == NULL)
1143                 return ERR_NOTLOG;
1144         
1145         
1146         attr = createEmptyList();
1147         pushBackList(attr, newByteAttr(ATTR_VLAN_TYPE, t));
1148         
1149         
1150         return writeRequest(nga, attr);
1151 }
1152
1153
1154 int ngadmin_getVLANPortConf (struct ngadmin *nga, unsigned char *ports)
1155 {
1156         List *attr;
1157         ListNode *ln;
1158         struct attr *at;
1159         int ret = ERR_OK;
1160         struct attr_vlan_conf *avc;
1161         struct swi_attr *sa;
1162         int port;
1163         
1164         
1165         if (nga == NULL || ports== NULL)
1166                 return ERR_INVARG;
1167         
1168         sa = nga->current;
1169         if (sa == NULL)
1170                 return ERR_NOTLOG;
1171         
1172         
1173         attr = createEmptyList();
1174         pushBackList(attr, newEmptyAttr(ATTR_VLAN_PORT_CONF));
1175         ret = readRequest(nga, attr);
1176         if (ret != ERR_OK)
1177                 goto end;
1178         
1179         filterAttributes(attr, ATTR_VLAN_PORT_CONF, ATTR_END);
1180         
1181         memset(ports, 0, sa->ports);
1182         
1183         for (ln = attr->first; ln != NULL; ln = ln->next) {
1184                 at = ln->data;
1185                 avc = at->data;
1186
1187                 if (at->size != sizeof(struct attr_vlan_conf) + sa->ports)
1188                         return ERR_INVARG;
1189                 
1190                 for (port = 0; port < sa->ports; port++) {
1191                         if (avc->ports[port] == VLAN_UNTAGGED)
1192                                 ports[port] = avc->vlan;
1193                 }
1194         }
1195         
1196         
1197 end:
1198         destroyList(attr, (void(*)(void*))freeAttr);
1199         
1200         
1201         return ret;
1202 }
1203
1204
1205 int ngadmin_setVLANPortConf (struct ngadmin *nga, const unsigned char *ports)
1206 {
1207         List *attr = NULL;
1208         ListNode *ln;
1209         struct attr *at;
1210         struct swi_attr *sa;
1211         struct attr_vlan_conf *avc;
1212         int ret = ERR_OK, port;
1213         unsigned char vlan;
1214         
1215         
1216         if (nga == NULL || ports == NULL)
1217                 return ERR_INVARG;
1218         
1219         sa = nga->current;
1220         if (sa == NULL)
1221                 return ERR_NOTLOG;
1222         
1223         /* if nothing is to be changed, do nothing */
1224         for (port = 0; port < sa->ports && ports[port] == 0; port++);
1225         if (port == sa->ports )
1226                 goto end;
1227         
1228         attr = createEmptyList();
1229
1230         if (memchr(ports, 0, sa->ports) != NULL) {
1231                 /* if at least one port is unchanged, we need to read old config */
1232                 pushBackList(attr, newEmptyAttr(ATTR_VLAN_PORT_CONF));
1233                 ret = readRequest(nga, attr);
1234                 if (ret != ERR_OK)
1235                         goto end;
1236                 
1237                 filterAttributes(attr, ATTR_VLAN_PORT_CONF, ATTR_END);
1238                 /* FIXME: check if the returned array effectively contains correct data */
1239         } else {
1240                 /* create an empty VLAN config */
1241                 for (vlan = VLAN_MIN; vlan <= VLAN_PORT_MAX; vlan++) {
1242                         avc = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
1243                         avc->vlan = vlan;
1244                         memset(avc->ports, 0, sa->ports);
1245                         pushBackList(attr, newAttr(ATTR_VLAN_PORT_CONF, sizeof(struct attr_vlan_conf) + sa->ports, avc));
1246                 }
1247         }
1248         
1249         for (ln = attr->first; ln != NULL; ln = ln->next) {
1250                 at = ln->data;
1251                 avc = at->data;
1252                 for (port = 0; port < sa->ports; port++) {
1253                         if (ports[port] == avc->vlan)
1254                                 avc->ports[port] = VLAN_UNTAGGED;
1255                         else
1256                                 avc->ports[port] = VLAN_NO;
1257                 }
1258         }
1259         
1260         ret = writeRequest(nga, attr);
1261         attr = NULL;
1262         
1263         
1264 end:
1265         destroyList(attr, (void(*)(void*))freeAttr);
1266         
1267         
1268         return ret;
1269 }
1270
1271
1272 int ngadmin_getVLANDotAllConf (struct ngadmin *nga, unsigned short *vlans, unsigned char *ports, int *nb)
1273 {
1274         List *attr;
1275         ListNode *ln;
1276         struct attr *at;
1277         int ret = ERR_OK, total;
1278         struct attr_vlan_conf *avc;
1279         struct swi_attr *sa;
1280         
1281         
1282         if (nga == NULL || vlans == NULL || ports== NULL || nb == NULL || *nb <= 0)
1283                 return ERR_INVARG;
1284         
1285         sa = nga->current;
1286         if (sa == NULL)
1287                 return ERR_NOTLOG;
1288         
1289         
1290         total = *nb;
1291         *nb = 0;
1292         
1293         attr = createEmptyList();
1294         pushBackList(attr, newEmptyAttr(ATTR_VLAN_DOT_CONF));
1295         ret = readRequest(nga, attr);
1296         if (ret != ERR_OK)
1297                 goto end;
1298         
1299         filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
1300         
1301         memset(vlans, 0, total * sizeof(unsigned short));
1302         memset(ports, 0, total * sa->ports);
1303         
1304         for (ln = attr->first; ln != NULL; ln = ln->next) {
1305                 at = ln->data;
1306                 avc = at->data;
1307                 
1308                 if (at->size != sizeof(struct attr_vlan_conf) + sa->ports)
1309                         return ERR_INVARG;
1310                 
1311                 *vlans = avc->vlan;
1312                 memcpy(ports, avc->ports, sa->ports);
1313                 
1314                 vlans++;
1315                 ports += sa->ports;
1316                 (*nb)++;
1317                 
1318                 if (*nb > total)
1319                         break; /* no more room */
1320         }
1321         
1322         
1323 end:
1324         destroyList(attr, (void(*)(void*))freeAttr);
1325         
1326         
1327         return ret;
1328 }
1329
1330
1331 int ngadmin_getVLANDotConf (struct ngadmin *nga, unsigned short vlan, unsigned char *ports)
1332 {
1333         List *attr;
1334         ListNode *ln;
1335         struct attr *at;
1336         int ret = ERR_OK;
1337         struct attr_vlan_conf *avc;
1338         
1339         
1340         if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX || ports == NULL)
1341                 return ERR_INVARG;
1342         else if (nga->current == NULL)
1343                 return ERR_NOTLOG;
1344         
1345         
1346         attr = createEmptyList();
1347         pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
1348         ret = readRequest(nga, attr);
1349         if (ret != ERR_OK)
1350                 goto end;
1351         
1352         filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
1353         
1354         memset(ports, 0, nga->current->ports);
1355         
1356         for (ln = attr->first; ln != NULL; ln = ln->next) {
1357                 at = ln->data;
1358                 avc = at->data;
1359                 if (avc->vlan == vlan) {
1360                         memcpy(ports, avc->ports, nga->current->ports);
1361                         break;
1362                 }
1363         }
1364         
1365         
1366 end:
1367         destroyList(attr, (void(*)(void*))freeAttr);
1368         
1369         
1370         return ret;
1371 }
1372
1373
1374 int ngadmin_setVLANDotConf (struct ngadmin *nga, unsigned short vlan, const unsigned char *ports)
1375 {
1376         List *attr = NULL;
1377         struct attr *at;
1378         struct swi_attr *sa;
1379         struct attr_vlan_conf *avc;
1380         int ret = ERR_OK, port;
1381         
1382         
1383         if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX || ports == NULL)
1384                 return ERR_INVARG;
1385         
1386         sa = nga->current;
1387         if (sa == NULL)
1388                 return ERR_NOTLOG;
1389         
1390         
1391         /* if nothing is to be changed, do nothing */
1392         for (port = 0; port < sa->ports && ports[port] == VLAN_UNSPEC; port++);
1393         if (port == sa->ports )
1394                 goto end;
1395         
1396         
1397         attr = createEmptyList();
1398         avc = malloc(sizeof(struct attr_vlan_conf) + sa->ports);
1399         if (avc == NULL)
1400                 return ERR_MEM;
1401         
1402         avc->vlan = vlan;
1403         
1404         /* if all is to be changed, we do not need to read old config */
1405         if (memchr(ports, VLAN_UNSPEC, sa->ports) != NULL) {
1406                 
1407                 pushBackList(attr, newShortAttr(ATTR_VLAN_DOT_CONF, vlan));
1408                 ret = readRequest(nga, attr);
1409                 if (ret != ERR_OK)
1410                         goto end;
1411                 
1412                 filterAttributes(attr, ATTR_VLAN_DOT_CONF, ATTR_END);
1413                 
1414                 if (attr->first != NULL) {
1415                         at = attr->first->data;
1416                         memcpy(avc, at->data, sizeof(struct attr_vlan_conf) + sa->ports);
1417                 }
1418                 
1419                 clearList(attr, (void(*)(void*))freeAttr);
1420         }
1421         
1422         
1423         /* apply changes */
1424         for (port = 0; port < sa->ports; port++) {
1425                 if (ports[port] != VLAN_UNSPEC)
1426                         avc->ports[port] = ports[port];
1427         }
1428         
1429         
1430         pushBackList(attr, newAttr(ATTR_VLAN_DOT_CONF, sizeof(struct attr_vlan_conf) + sa->ports, avc));
1431         ret = writeRequest(nga, attr);
1432         attr = NULL;
1433         
1434         
1435 end:
1436         destroyList(attr, (void(*)(void*))freeAttr);
1437         
1438         
1439         return ret;
1440 }
1441
1442
1443 int ngadmin_VLANDestroy (struct ngadmin *nga, unsigned short vlan)
1444 {
1445         List *attr;
1446         
1447         
1448         if (nga == NULL || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX)
1449                 return ERR_INVARG;
1450         else if (nga->current == NULL)
1451                 return ERR_NOTLOG;
1452         
1453         
1454         attr = createEmptyList();
1455         pushBackList(attr, newShortAttr(ATTR_VLAN_DESTROY, vlan));
1456         
1457         
1458         return writeRequest(nga, attr);
1459 }
1460
1461
1462 int ngadmin_getAllPVID (struct ngadmin *nga, unsigned short *ports)
1463 {
1464         List *attr;
1465         ListNode *ln;
1466         struct attr *at;
1467         int ret = ERR_OK;
1468         struct attr_pvid *ap;
1469         
1470         
1471         if (nga == NULL || ports == NULL)
1472                 return ERR_INVARG;
1473         else if (nga->current == NULL)
1474                 return ERR_NOTLOG;
1475         
1476         
1477         attr = createEmptyList();
1478         pushBackList(attr, newEmptyAttr(ATTR_VLAN_PVID));
1479         ret = readRequest(nga, attr);
1480         if (ret != ERR_OK)
1481                 goto end;
1482         
1483         filterAttributes(attr, ATTR_VLAN_PVID, ATTR_END);
1484         
1485         memset(ports, 0, nga->current->ports * sizeof(unsigned short));
1486         
1487         for (ln = attr->first; ln != NULL; ln = ln->next) {
1488                 at = ln->data;
1489                 ap = at->data;
1490                 ports[ap->port - 1] = ap->vlan;
1491         }
1492         
1493         
1494 end:
1495         destroyList(attr, (void(*)(void*))freeAttr);
1496         
1497         
1498         return ret;
1499 }
1500
1501
1502 int ngadmin_setPVID (struct ngadmin *nga, unsigned char port, unsigned short vlan)
1503 {
1504         List *attr;
1505         struct attr_pvid *ap;
1506         
1507         
1508         if (nga == NULL || port < 1 || vlan < VLAN_MIN || vlan > VLAN_DOT_MAX)
1509                 return ERR_INVARG;
1510         else if (nga->current == NULL)
1511                 return ERR_NOTLOG;
1512         else if (port > nga->current->ports)
1513                 return ERR_INVARG;
1514         
1515         
1516         attr = createEmptyList();
1517         ap = malloc(sizeof(struct attr_pvid));
1518         if (ap == NULL)
1519                 return ERR_MEM;
1520         ap->port = port;
1521         ap->vlan = vlan;
1522         
1523         pushBackList(attr, newAttr(ATTR_VLAN_PVID, sizeof(struct attr_pvid), ap));
1524         
1525         
1526         return writeRequest(nga, attr);
1527 }
1528
1529
1530