]> git.sur5r.net Git - ngadmin/blob - raw/src/attr.c
ec8a0daad9574c334fe3558e2c5d8241a971f91a
[ngadmin] / raw / src / attr.c
1
2 #include <stdarg.h>
3 #include <errno.h>
4
5 #include <ngadmin.h> /* FIXME */
6 #include <nsdp/attr.h>
7 #include <nsdp/protocol.h>
8
9
10 struct attr* newAttr (unsigned short attr, unsigned short size, void *data)
11 {
12         struct attr *at;
13         
14         at = malloc(sizeof(struct attr));
15         if (at == NULL)
16                 return NULL;
17         
18         at->attr = attr;
19         at->size = size;
20         at->data = data;
21         
22         return at;
23 }
24
25
26 void freeAttr (struct attr *at)
27 {
28         if (at != NULL) {
29                 free(at->data);
30                 free(at);
31         }
32 }
33
34
35 void filterAttributes (List *attr, ...)
36 {
37         va_list ap;
38         ListNode *ln, *pr;
39         struct attr *at;
40         unsigned short attrcode;
41         bool keep;
42         
43         
44         for (ln = attr->first; ln != NULL; ) {
45                 at = ln->data;
46                 
47                 va_start(ap, attr);
48                 keep = false;
49                 attrcode = 0;
50                 while (!keep && attrcode != ATTR_END) {
51                         attrcode = (unsigned short)va_arg(ap, unsigned int);
52                         keep = keep || (at->attr == attrcode);
53                 }
54                 va_end(ap);
55                 
56                 if (keep) {
57                         ln = ln->next;
58                 } else {
59                         pr = ln;
60                         ln = ln->next;
61                         destroyElement(attr, pr, (void(*)(void*))freeAttr);
62                 }
63         }
64 }
65
66
67 static int ports_status_endecode (struct attr *at)
68 {
69         struct attr_port_status *ps = at->data;
70         
71         if (at->size != sizeof(struct attr_port_status))
72                 return -EMSGSIZE;
73         
74         if (ps->port < 1)
75                 return -EINVAL;
76         
77         switch (ps->status) {
78         
79         case SPEED_DOWN:
80         case SPEED_10_HD:
81         case SPEED_10_FD:
82         case SPEED_100_HD:
83         case SPEED_100_FD:
84         case SPEED_1000_FD:
85                 return 0;
86         
87         default:
88                 return -EINVAL;
89         }
90 }
91
92
93 static int port_stat_endecode (struct attr *at, bool encode)
94 {
95         struct attr_port_stat *ps = at->data;
96         unsigned long long *v;
97         
98         if (at->size != sizeof(struct attr_port_stat))
99                 return -EMSGSIZE;
100         
101         if (ps->port < 1)
102                 return -EINVAL;
103         
104         for (v = &ps->recv; ((void*)v) - ((void*)ps) < (int)sizeof(struct attr_port_stat); v++)
105                 *v = encode ? htobe64(*v) : be64toh(*v);
106         
107         return 0;
108 }
109
110
111 static int qos_endecode (struct attr *at)
112 {
113         struct attr_qos *aq = at->data;
114         
115         if (at->size != sizeof(struct attr_qos))
116                 return -EMSGSIZE;
117         
118         if (aq->port < 1)
119                 return -EINVAL;
120         
121         if (aq->prio < PRIO_HIGH || aq->prio > PRIO_LOW)
122                 return -EINVAL;
123         
124         return 0;
125 }
126
127
128 static int bitrate_endecode (struct attr *at, bool encode)
129 {
130         struct attr_bitrate *sb = at->data;
131         
132         if (at->size != sizeof(struct attr_bitrate))
133                 return -EMSGSIZE;
134         
135         if (sb->port < 1)
136                 return -EINVAL;
137         
138         if (!encode)
139                 sb->bitrate = ntohl(sb->bitrate);
140         
141         if (sb->bitrate < BITRATE_UNSPEC || sb->bitrate > BITRATE_512M)
142                 return -EINVAL;
143         
144         if (encode)
145                 sb->bitrate = htonl(sb->bitrate);
146         
147         return 0;
148 }
149
150
151 static int pvid_endecode (struct attr *at, bool encode)
152 {
153         struct attr_pvid *ap = at->data;
154         
155         if (at->size != sizeof(struct attr_pvid))
156                 return -EMSGSIZE;
157         
158         if (ap->port < 1)
159                 return -EINVAL;
160         
161         if (!encode)
162                 ap->vlan = ntohs(ap->vlan);
163         
164         if (ap->vlan < VLAN_MIN || ap->vlan > VLAN_DOT_MAX)
165                 return -EINVAL;
166         
167         if (encode)
168                 ap->vlan = htons(ap->vlan);
169         
170         return 0;
171 }
172
173
174 static int cabletest_do_endecode (struct attr *at)
175 {
176         struct attr_cabletest_do *acd = at->data;
177         
178         if (at->size != sizeof(struct attr_cabletest_do))
179                 return -EMSGSIZE;
180         
181         if (acd->port < 1 || acd->action != 1)
182                 return -EINVAL;
183         
184         return 0;
185 }
186
187
188 static int cabletest_result_endecode (struct attr *at, bool encode)
189 {
190         struct attr_cabletest_result *acr = at->data;
191         
192         /* Note: this attribute is special
193          * - when sent by the client, it contains the port number whe want to
194          *   get cabletest results from
195          * - when the switch replies, it contains the actual test results data
196          */
197         
198         /* no need to check the size, the only possible value under 1
199          * is 0 and in that case the decoder is not called
200          */
201         if (acr->port < 1)
202                 return -EINVAL;
203         
204         if (at->size == 1)
205                 return 0;
206         
207         if (at->size != sizeof(struct attr_cabletest_result))
208                 return -EMSGSIZE;
209         
210         if (encode) {
211                 acr->v1 = htonl(acr->v1);
212                 acr->v2 = htonl(acr->v2);
213         } else {
214                 acr->v1 = ntohl(acr->v1);
215                 acr->v2 = ntohl(acr->v2);
216         }
217         
218         return 0;
219 }
220
221
222 static int igmp_vlan_endecode (struct attr *at, bool encode)
223 {
224         struct attr_igmp_vlan *aiv = at->data;
225         
226         if (at->size != sizeof(struct attr_igmp_vlan))
227                 return -EMSGSIZE;
228         
229         if (!encode) {
230                 aiv->enable = ntohs(aiv->enable);
231                 aiv->vlan = ntohs(aiv->vlan);
232         }
233         
234         aiv->enable = (aiv->enable != 0);
235         if (aiv->vlan < VLAN_MIN || aiv->vlan > VLAN_DOT_MAX)
236                 return -EINVAL;
237         
238         if (encode) {
239                 aiv->enable = htons(aiv->enable);
240                 aiv->vlan = htons(aiv->vlan);
241         }
242         
243         return 0;
244 }
245
246
247 static int mirror_encode (struct attr *at)
248 {
249         struct attr_mirror *am = at->data;
250         unsigned char p, ports, *r;
251         unsigned int sz;
252         
253         
254         /* no need to check attribute size, since
255          * sizeof(struct attr_mirror) == 1 and encoder is not
256          * called when attribute size is zero (ie empty attribute)
257          *
258          * am->outport encodes the outgoing mirror port and the array
259          * the ports from which the data is copied, it must not be empty
260          *
261          * am->outport == 0 is allowed and means mirroring is disabled
262          * but in that case the ports array must be empty
263          */
264         ports = at->size - sizeof(struct attr_mirror);
265         if ((am->outport == 0) ^ (ports == 0))
266                 return -EINVAL;
267         
268         sz = 3 + ((ports - 1) >> 3);
269         r = malloc(sz);
270         if (r == NULL)
271                 return -ENOMEM;
272         memset(r, 0, sz);
273         
274         r[0] = am->outport;
275         
276         /* FIXME: if ports > 8 */
277         for (p = 1; p <= ports; p++) {
278                 if (am->outport != p)
279                         r[2] |= (am->ports[p] & 1) << (8 - p);
280         }
281         
282         free(at->data);
283         at->data = r;
284         at->size = sz;
285         
286         
287         return 0;
288 }
289
290
291 static int mirror_decode (struct attr *at)
292 {
293         struct attr_mirror *am;
294         unsigned char p, ports, *r = at->data;
295         unsigned int sz;
296         
297         
298         if (at->size < 3)
299                 return -EMSGSIZE;
300         
301         /* note: we cannot compute the exact amount of ports from here,
302          * instead we have the immediate superior multiple of 8
303          * it will be the user's job to ignore extra entries
304          */
305         ports = ((at->size - 2) << 3);
306         
307         /* r[0] == 0 is allowed and means mirroring is disabled */
308         if (r[0] == 0)
309                 ports = 0;
310         sz = sizeof(struct attr_mirror) + ports;
311         
312         am = malloc(sz);
313         if (am == NULL)
314                 return -ENOMEM;
315         memset(am, 0, sz);
316         
317         am->outport = r[0];
318         
319         /* FIXME: if ports > 8 */
320         for (p = 1; p <= ports; p++)
321                 am->ports[p] = (r[2] >> (8 - p)) & 1;
322         
323         free(at->data);
324         at->data = am;
325         at->size = sz;
326         
327         
328         return 0;
329 }
330
331
332 static int vlan_port_encode (struct attr *at)
333 {
334         struct attr_vlan_conf *avc = at->data;
335         unsigned char p, ports, *r;
336         unsigned int sz;
337         
338         
339         /* just a header is valid */
340         if (at->size < sizeof(struct attr_vlan_conf))
341                 return -EMSGSIZE;
342         ports = at->size - sizeof(struct attr_vlan_conf);
343         
344         if (avc->vlan < VLAN_MIN || avc->vlan > VLAN_PORT_MAX)
345                 return -EINVAL;
346         
347         if (ports == 0)
348                 sz = 2;
349         else
350                 sz = (2 + 1 + ((ports - 1) >> 3));
351         
352         r = malloc(sz);
353         if (r == NULL)
354                 return -ENOMEM;
355         
356         memset(r, 0, sz);
357         *(unsigned short*)r = htons(avc->vlan);
358         
359         /* FIXME: if ports > 8 */
360         for (p = 0; p < ports; p++) {
361                 if (avc->ports[p] == VLAN_UNTAGGED)
362                         r[2] |= (1 << (7 - p));
363         }
364         
365         free(at->data);
366         at->data = r;
367         at->size = sz;
368         
369         
370         return 0;
371 }
372
373
374 static int vlan_port_decode (struct attr *at)
375 {
376         unsigned char p, ports, *r = at->data;
377         struct attr_vlan_conf *avc;
378         unsigned int sz;
379         
380         
381         if (at->size < 2)
382                 return -EMSGSIZE;
383         
384         /* note: we cannot compute the exact amount of ports from here,
385          * instead we have the immediate superior multiple of 8
386          * it will be the user's job to ignore extra entries
387          */
388         ports = ((at->size - 2) << 3);
389         
390         sz = sizeof(struct attr_vlan_conf) + ports;
391         avc = malloc(sz);
392         if (avc == NULL)
393                 return -ENOMEM;
394         
395         avc->vlan = ntohs(*(unsigned short*)r);
396         
397         /* FIXME: if ports > 8 */
398         for (p = 0; p < ports; p++) {
399                 if ((r[2] >> (7 - p)) & 1)
400                         avc->ports[p] = VLAN_UNTAGGED;
401                 else
402                         avc->ports[p] = VLAN_NO;
403         }
404         
405         free(at->data);
406         at->data = avc;
407         at->size = sz;
408         
409         
410         return 0;
411 }
412
413
414 static int vlan_dot_encode (struct attr *at)
415 {
416         struct attr_vlan_conf *avc = at->data;
417         unsigned char p, ports, *r, fl;
418         unsigned int sz;
419         
420         
421         /* just a header is valid */
422         if (at->size < sizeof(struct attr_vlan_conf))
423                 return -EMSGSIZE;
424         ports = at->size - sizeof(struct attr_vlan_conf);
425         
426         if (avc->vlan < VLAN_MIN || avc->vlan > VLAN_DOT_MAX)
427                 return -EINVAL;
428         
429         if (ports == 0)
430                 sz = 2;
431         else
432                 sz = 2 + 2 * (1 + ((ports - 1) >> 3));
433         
434         r = malloc(sz);
435         if (r == NULL)
436                 return -EMSGSIZE;
437         
438         memset(r, 0, sz);
439         *(unsigned short*)r = htons(avc->vlan);
440         
441         /* FIXME: if ports > 8 */
442         for (p = 0; p < ports; p++) {
443                 fl = (1 << (7 - p));
444                 switch (avc->ports[p]) {
445                 case VLAN_TAGGED:
446                         r[3] |= fl;
447                         /* a tagged VLAN is also marked as untagged
448                          * so do not put a "break" here
449                          */
450                 case VLAN_UNTAGGED:
451                         r[2] |= fl;
452                 }
453         }
454         
455         
456         free(at->data);
457         at->data = r;
458         at->size = sz;
459         
460         
461         return 0;
462 }
463
464
465 static int vlan_dot_decode (struct attr *at)
466 {
467         unsigned char p, ports, *r = at->data;
468         struct attr_vlan_conf *avc;
469         unsigned int sz;
470         
471         
472         /* attribute size must be a multiple of 2 because there are
473          * 2 bytes (1 for tagged and 1 for untagged) per block of
474          * 8 ports, plus the 2 first bytes for the VLAN id
475          */
476         if (at->size < 2 || (at->size & 1) != 0)
477                 return -EMSGSIZE;
478         
479         /* note: we cannot compute the exact amount of ports from here,
480          * instead we have the immediate superior multiple of 8
481          * it will be the user's job to ignore extra entries
482          */
483         ports = ((at->size - 2) / 2) << 3;
484         
485         sz = sizeof(struct attr_vlan_conf) + ports;
486         avc = malloc(sz);
487         if (avc == NULL)
488                 return -ENOMEM;
489         
490         avc->vlan = ntohs(*(unsigned short*)r);
491         
492         /* FIXME: if ports > 8 */
493         for (p = 0; p < ports; p++) {
494                 if ((r[3] >> (7 - p)) & 1)
495                         avc->ports[p] = VLAN_TAGGED;
496                 else if ((r[2] >> (7 - p)) & 1)
497                         avc->ports[p] = VLAN_UNTAGGED;
498                 else
499                         avc->ports[p] = VLAN_NO;
500         }
501         
502         free(at->data);
503         at->data = avc;
504         at->size = sz;
505         
506         
507         return 0;
508 }
509
510
511 static int processAttr (struct attr *at, bool encode)
512 {
513         unsigned char *byte = at->data;
514         unsigned short *word = at->data;
515         unsigned int *dword = at->data;
516         
517         
518         /* empty attributes are not processed */
519         if (at->size == 0)
520                 return 0;
521         
522         if (at->data == NULL)
523                 return -EFAULT;
524         
525         switch (at->attr) {
526         
527         case ATTR_MAC:
528                 if (at->size != ETH_ALEN)
529                         return -EMSGSIZE;
530                 return 0;
531         
532         case ATTR_IP:
533         case ATTR_NETMASK:
534         case ATTR_GATEWAY:
535                 /* IP addresses are kept in network byte order even on the host */
536                 if (at->size != sizeof(struct in_addr))
537                         return -EMSGSIZE;
538                 
539                 return 0;
540         
541         case ATTR_PORTS_COUNT:
542                 if (at->size != 1)
543                         return -EMSGSIZE;
544                 
545                 return 0;
546         
547         case ATTR_RESTART:
548         case ATTR_DEFAULTS:
549         case ATTR_STATS_RESET:
550         case ATTR_STORM_ENABLE:
551         case ATTR_IGMP_BLOCK_UNK:
552         case ATTR_IGMP_VALID_V3:
553                 if (at->size != 1)
554                         return -EMSGSIZE;
555                 
556                 *byte = (*byte != 0);
557                 
558                 return 0;
559         
560         case ATTR_DHCP:
561                 /* Note: DHCP attribute is special, it is 2 two bytes long
562                  * when sent by the switch but only 1 byte long when sent
563                  * by the client
564                  */
565                 if (at->size == 1) {
566                         *byte = (*byte != 0);
567                         return 0;
568                 } else if (at->size > 2) {
569                         return -EMSGSIZE;
570                 }
571                 
572                 if (!encode)
573                         *word = ntohs(*word);
574                 
575                 *word = (*word != 0);
576                 
577                 if (encode)
578                         *word = htons(*word);
579                 
580                 return 0;
581         
582         case ATTR_ENCPASS:
583                 if (at->size != 4)
584                         return -EMSGSIZE;
585                 
586                 if (!encode)
587                         *dword = ntohl(*dword);
588                 
589                 *dword = (*dword != 0);
590                 
591                 if (encode)
592                         *dword = htonl(*dword);
593                 
594                 return 0;
595         
596         case ATTR_VLAN_TYPE:
597                 if (at->size != 1)
598                         return -EMSGSIZE;
599                 
600                 /* no need to check if *byte < VLAN_DISABLED because
601                  * byte is unsigned and VLAN_DISABLED is 0 */
602                 if (*byte > VLAN_DOT_ADV)
603                         return -EINVAL;
604                 
605                 return 0;
606         
607         case ATTR_QOS_TYPE:
608                 if (at->size != 1)
609                         return -EMSGSIZE;
610                 
611                 if (*byte < QOS_PORT || *byte > QOS_DOT)
612                         return -EINVAL;
613                 
614                 return 0;
615         
616         case ATTR_QOS_CONFIG:
617                 return qos_endecode(at);
618         
619         case ATTR_VLAN_DESTROY:
620                 if (at->size != 2)
621                         return -EMSGSIZE;
622                 
623                 if (!encode)
624                         *word = ntohs(*word);
625                 
626                 if (*word < VLAN_MIN || *word > VLAN_DOT_MAX)
627                         return -EINVAL;
628                 
629                 if (encode)
630                         *word = htons(*word);
631                 
632                 return 0;
633         
634         case ATTR_PORT_STATUS:
635                 return ports_status_endecode(at);
636         
637         case ATTR_PORT_STATISTICS:
638                 return port_stat_endecode(at, encode);
639         
640         case ATTR_BITRATE_INPUT:
641         case ATTR_BITRATE_OUTPUT:
642         case ATTR_STORM_BITRATE:
643                 return bitrate_endecode(at, encode);
644         
645         case ATTR_VLAN_PVID:
646                 return pvid_endecode(at, encode);
647         
648         case ATTR_CABLETEST_DO:
649                 return cabletest_do_endecode(at);
650         
651         case ATTR_CABLETEST_RESULT:
652                 return cabletest_result_endecode(at, encode);
653         
654         case ATTR_IGMP_ENABLE_VLAN:
655                 return igmp_vlan_endecode(at, encode);
656         
657         case ATTR_MIRROR:
658                 if (encode)
659                         return mirror_encode(at);
660                 else
661                         return mirror_decode(at);
662         
663         case ATTR_VLAN_PORT_CONF:
664                 if (encode)
665                         return vlan_port_encode(at);
666                 else
667                         return vlan_port_decode(at);
668         
669         case ATTR_VLAN_DOT_CONF:
670                 if (encode)
671                         return vlan_dot_encode(at);
672                 else
673                         return vlan_dot_decode(at);
674         
675         /* undefined attributes are not modified */
676         default:
677                 return 0;
678         }
679 }
680
681
682 int encodeAttr (struct attr *at)
683 {
684         return processAttr(at, true);
685 }
686
687
688 int decodeAttr (struct attr *at)
689 {
690         return processAttr(at, false);
691 }
692
693