]> git.sur5r.net Git - ngadmin/blob - raw/src/attr.c
Raw: fix few bugs on port mirroring
[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          */
263         ports = at->size - sizeof(struct attr_mirror);
264         if (am->outport > 0 && ports == 0)
265                 return -EINVAL;
266         
267         sz = 3 + ((ports - 1) >> 3);
268         r = malloc(sz);
269         if (r == NULL)
270                 return -ENOMEM;
271         memset(r, 0, sz);
272         
273         r[0] = am->outport;
274         
275         /* FIXME: if ports > 8 */
276         for (p = 1; p <= ports; p++) {
277                 if (am->outport != p)
278                         r[2] |= (am->ports[p - 1] & 1) << (8 - p);
279         }
280         
281         free(at->data);
282         at->data = r;
283         at->size = sz;
284         
285         
286         return 0;
287 }
288
289
290 static int mirror_decode (struct attr *at)
291 {
292         struct attr_mirror *am;
293         unsigned char p, ports, *r = at->data;
294         unsigned int sz;
295         
296         
297         if (at->size < 3)
298                 return -EMSGSIZE;
299         
300         /* note: we cannot compute the exact amount of ports from here,
301          * instead we have the immediate superior multiple of 8
302          * it will be the user's job to ignore extra entries
303          */
304         ports = ((at->size - 2) << 3);
305         
306         /* r[0] == 0 is allowed and means mirroring is disabled */
307         if (r[0] == 0)
308                 ports = 0;
309         sz = sizeof(struct attr_mirror) + ports;
310         
311         am = malloc(sz);
312         if (am == NULL)
313                 return -ENOMEM;
314         memset(am, 0, sz);
315         
316         am->outport = r[0];
317         
318         /* FIXME: if ports > 8 */
319         for (p = 1; p <= ports; p++)
320                 am->ports[p - 1] = (r[2] >> (8 - p)) & 1;
321         
322         free(at->data);
323         at->data = am;
324         at->size = sz;
325         
326         
327         return 0;
328 }
329
330
331 static int vlan_port_encode (struct attr *at)
332 {
333         struct attr_vlan_conf *avc = at->data;
334         unsigned char p, ports, *r;
335         unsigned int sz;
336         
337         
338         /* just a header is valid */
339         if (at->size < sizeof(struct attr_vlan_conf))
340                 return -EMSGSIZE;
341         ports = at->size - sizeof(struct attr_vlan_conf);
342         
343         if (avc->vlan < VLAN_MIN || avc->vlan > VLAN_PORT_MAX)
344                 return -EINVAL;
345         
346         if (ports == 0)
347                 sz = 2;
348         else
349                 sz = (2 + 1 + ((ports - 1) >> 3));
350         
351         r = malloc(sz);
352         if (r == NULL)
353                 return -ENOMEM;
354         
355         memset(r, 0, sz);
356         *(unsigned short*)r = htons(avc->vlan);
357         
358         /* FIXME: if ports > 8 */
359         for (p = 0; p < ports; p++) {
360                 if (avc->ports[p] == VLAN_UNTAGGED)
361                         r[2] |= (1 << (7 - p));
362         }
363         
364         free(at->data);
365         at->data = r;
366         at->size = sz;
367         
368         
369         return 0;
370 }
371
372
373 static int vlan_port_decode (struct attr *at)
374 {
375         unsigned char p, ports, *r = at->data;
376         struct attr_vlan_conf *avc;
377         unsigned int sz;
378         
379         
380         if (at->size < 2)
381                 return -EMSGSIZE;
382         
383         /* note: we cannot compute the exact amount of ports from here,
384          * instead we have the immediate superior multiple of 8
385          * it will be the user's job to ignore extra entries
386          */
387         ports = ((at->size - 2) << 3);
388         
389         sz = sizeof(struct attr_vlan_conf) + ports;
390         avc = malloc(sz);
391         if (avc == NULL)
392                 return -ENOMEM;
393         
394         avc->vlan = ntohs(*(unsigned short*)r);
395         
396         /* FIXME: if ports > 8 */
397         for (p = 0; p < ports; p++) {
398                 if ((r[2] >> (7 - p)) & 1)
399                         avc->ports[p] = VLAN_UNTAGGED;
400                 else
401                         avc->ports[p] = VLAN_NO;
402         }
403         
404         free(at->data);
405         at->data = avc;
406         at->size = sz;
407         
408         
409         return 0;
410 }
411
412
413 static int vlan_dot_encode (struct attr *at)
414 {
415         struct attr_vlan_conf *avc = at->data;
416         unsigned char p, ports, *r, fl;
417         unsigned int sz;
418         
419         
420         /* just a header is valid */
421         if (at->size < sizeof(struct attr_vlan_conf))
422                 return -EMSGSIZE;
423         ports = at->size - sizeof(struct attr_vlan_conf);
424         
425         if (avc->vlan < VLAN_MIN || avc->vlan > VLAN_DOT_MAX)
426                 return -EINVAL;
427         
428         if (ports == 0)
429                 sz = 2;
430         else
431                 sz = 2 + 2 * (1 + ((ports - 1) >> 3));
432         
433         r = malloc(sz);
434         if (r == NULL)
435                 return -EMSGSIZE;
436         
437         memset(r, 0, sz);
438         *(unsigned short*)r = htons(avc->vlan);
439         
440         /* FIXME: if ports > 8 */
441         for (p = 0; p < ports; p++) {
442                 fl = (1 << (7 - p));
443                 switch (avc->ports[p]) {
444                 case VLAN_TAGGED:
445                         r[3] |= fl;
446                         /* a tagged VLAN is also marked as untagged
447                          * so do not put a "break" here
448                          */
449                 case VLAN_UNTAGGED:
450                         r[2] |= fl;
451                 }
452         }
453         
454         
455         free(at->data);
456         at->data = r;
457         at->size = sz;
458         
459         
460         return 0;
461 }
462
463
464 static int vlan_dot_decode (struct attr *at)
465 {
466         unsigned char p, ports, *r = at->data;
467         struct attr_vlan_conf *avc;
468         unsigned int sz;
469         
470         
471         /* attribute size must be a multiple of 2 because there are
472          * 2 bytes (1 for tagged and 1 for untagged) per block of
473          * 8 ports, plus the 2 first bytes for the VLAN id
474          */
475         if (at->size < 2 || (at->size & 1) != 0)
476                 return -EMSGSIZE;
477         
478         /* note: we cannot compute the exact amount of ports from here,
479          * instead we have the immediate superior multiple of 8
480          * it will be the user's job to ignore extra entries
481          */
482         ports = ((at->size - 2) / 2) << 3;
483         
484         sz = sizeof(struct attr_vlan_conf) + ports;
485         avc = malloc(sz);
486         if (avc == NULL)
487                 return -ENOMEM;
488         
489         avc->vlan = ntohs(*(unsigned short*)r);
490         
491         /* FIXME: if ports > 8 */
492         for (p = 0; p < ports; p++) {
493                 if ((r[3] >> (7 - p)) & 1)
494                         avc->ports[p] = VLAN_TAGGED;
495                 else if ((r[2] >> (7 - p)) & 1)
496                         avc->ports[p] = VLAN_UNTAGGED;
497                 else
498                         avc->ports[p] = VLAN_NO;
499         }
500         
501         free(at->data);
502         at->data = avc;
503         at->size = sz;
504         
505         
506         return 0;
507 }
508
509
510 static int processAttr (struct attr *at, bool encode)
511 {
512         unsigned char *byte = at->data;
513         unsigned short *word = at->data;
514         unsigned int *dword = at->data;
515         
516         
517         /* empty attributes are not processed */
518         if (at->size == 0)
519                 return 0;
520         
521         if (at->data == NULL)
522                 return -EFAULT;
523         
524         switch (at->attr) {
525         
526         case ATTR_MAC:
527                 if (at->size != ETH_ALEN)
528                         return -EMSGSIZE;
529                 return 0;
530         
531         case ATTR_IP:
532         case ATTR_NETMASK:
533         case ATTR_GATEWAY:
534                 /* IP addresses are kept in network byte order even on the host */
535                 if (at->size != sizeof(struct in_addr))
536                         return -EMSGSIZE;
537                 
538                 return 0;
539         
540         case ATTR_PORTS_COUNT:
541                 if (at->size != 1)
542                         return -EMSGSIZE;
543                 
544                 return 0;
545         
546         case ATTR_RESTART:
547         case ATTR_DEFAULTS:
548         case ATTR_STATS_RESET:
549         case ATTR_STORM_ENABLE:
550         case ATTR_IGMP_BLOCK_UNK:
551         case ATTR_IGMP_VALID_V3:
552                 if (at->size != 1)
553                         return -EMSGSIZE;
554                 
555                 *byte = (*byte != 0);
556                 
557                 return 0;
558         
559         case ATTR_DHCP:
560                 /* Note: DHCP attribute is special, it is 2 two bytes long
561                  * when sent by the switch but only 1 byte long when sent
562                  * by the client
563                  */
564                 if (at->size == 1) {
565                         *byte = (*byte != 0);
566                         return 0;
567                 } else if (at->size > 2) {
568                         return -EMSGSIZE;
569                 }
570                 
571                 if (!encode)
572                         *word = ntohs(*word);
573                 
574                 *word = (*word != 0);
575                 
576                 if (encode)
577                         *word = htons(*word);
578                 
579                 return 0;
580         
581         case ATTR_ENCPASS:
582                 if (at->size != 4)
583                         return -EMSGSIZE;
584                 
585                 if (!encode)
586                         *dword = ntohl(*dword);
587                 
588                 *dword = (*dword != 0);
589                 
590                 if (encode)
591                         *dword = htonl(*dword);
592                 
593                 return 0;
594         
595         case ATTR_VLAN_TYPE:
596                 if (at->size != 1)
597                         return -EMSGSIZE;
598                 
599                 /* no need to check if *byte < VLAN_DISABLED because
600                  * byte is unsigned and VLAN_DISABLED is 0 */
601                 if (*byte > VLAN_DOT_ADV)
602                         return -EINVAL;
603                 
604                 return 0;
605         
606         case ATTR_QOS_TYPE:
607                 if (at->size != 1)
608                         return -EMSGSIZE;
609                 
610                 if (*byte < QOS_PORT || *byte > QOS_DOT)
611                         return -EINVAL;
612                 
613                 return 0;
614         
615         case ATTR_QOS_CONFIG:
616                 return qos_endecode(at);
617         
618         case ATTR_VLAN_DESTROY:
619                 if (at->size != 2)
620                         return -EMSGSIZE;
621                 
622                 if (!encode)
623                         *word = ntohs(*word);
624                 
625                 if (*word < VLAN_MIN || *word > VLAN_DOT_MAX)
626                         return -EINVAL;
627                 
628                 if (encode)
629                         *word = htons(*word);
630                 
631                 return 0;
632         
633         case ATTR_PORT_STATUS:
634                 return ports_status_endecode(at);
635         
636         case ATTR_PORT_STATISTICS:
637                 return port_stat_endecode(at, encode);
638         
639         case ATTR_BITRATE_INPUT:
640         case ATTR_BITRATE_OUTPUT:
641         case ATTR_STORM_BITRATE:
642                 return bitrate_endecode(at, encode);
643         
644         case ATTR_VLAN_PVID:
645                 return pvid_endecode(at, encode);
646         
647         case ATTR_CABLETEST_DO:
648                 return cabletest_do_endecode(at);
649         
650         case ATTR_CABLETEST_RESULT:
651                 return cabletest_result_endecode(at, encode);
652         
653         case ATTR_IGMP_ENABLE_VLAN:
654                 return igmp_vlan_endecode(at, encode);
655         
656         case ATTR_MIRROR:
657                 if (encode)
658                         return mirror_encode(at);
659                 else
660                         return mirror_decode(at);
661         
662         case ATTR_VLAN_PORT_CONF:
663                 if (encode)
664                         return vlan_port_encode(at);
665                 else
666                         return vlan_port_decode(at);
667         
668         case ATTR_VLAN_DOT_CONF:
669                 if (encode)
670                         return vlan_dot_encode(at);
671                 else
672                         return vlan_dot_decode(at);
673         
674         /* undefined attributes are not modified */
675         default:
676                 return 0;
677         }
678 }
679
680
681 int encodeAttr (struct attr *at)
682 {
683         return processAttr(at, true);
684 }
685
686
687 int decodeAttr (struct attr *at)
688 {
689         return processAttr(at, false);
690 }
691
692