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