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