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