]> git.sur5r.net Git - ngadmin/blob - raw/src/attr.c
Fix network configuration modification
[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                 /* Note: DHCP attribute is special, it is 2 two bytes long
560                  * when sent by the switch but only 1 byte long when sent
561                  * by the client
562                  */
563                 if (at->size == 1) {
564                         *byte = (*byte != 0);
565                         return 0;
566                 } else if (at->size > 2) {
567                         return -EMSGSIZE;
568                 }
569                 
570                 if (!encode)
571                         *word = ntohs(*word);
572                 
573                 *word = (*word != 0);
574                 
575                 if (encode)
576                         *word = htons(*word);
577                 
578                 return 0;
579         
580         case ATTR_ENCPASS:
581                 if (at->size != 4)
582                         return -EMSGSIZE;
583                 
584                 if (!encode)
585                         *dword = ntohl(*dword);
586                 
587                 *dword = (*dword != 0);
588                 
589                 if (encode)
590                         *dword = htonl(*dword);
591                 
592                 return 0;
593         
594         case ATTR_VLAN_TYPE:
595                 if (at->size != 1)
596                         return -EMSGSIZE;
597                 
598                 /* no need to check if *byte < VLAN_DISABLED because
599                  * byte is unsigned and VLAN_DISABLED is 0 */
600                 if (*byte > VLAN_DOT_ADV)
601                         return -EINVAL;
602                 
603                 return 0;
604         
605         case ATTR_QOS_TYPE:
606                 if (at->size != 1)
607                         return -EMSGSIZE;
608                 
609                 if (*byte < QOS_PORT || *byte > QOS_DOT)
610                         return -EINVAL;
611                 
612                 return 0;
613         
614         case ATTR_QOS_CONFIG:
615                 return qos_endecode(at);
616         
617         case ATTR_VLAN_DESTROY:
618                 if (at->size != 2)
619                         return -EMSGSIZE;
620                 
621                 if (!encode)
622                         *word = ntohs(*word);
623                 
624                 if (*word < VLAN_MIN || *word > VLAN_DOT_MAX)
625                         return -EINVAL;
626                 
627                 if (encode)
628                         *word = htons(*word);
629                 
630                 return 0;
631         
632         case ATTR_PORT_STATUS:
633                 return ports_status_endecode(at);
634         
635         case ATTR_PORT_STATISTICS:
636                 return port_stat_endecode(at, encode);
637         
638         case ATTR_BITRATE_INPUT:
639         case ATTR_BITRATE_OUTPUT:
640         case ATTR_STORM_BITRATE:
641                 return bitrate_endecode(at, encode);
642         
643         case ATTR_VLAN_PVID:
644                 return pvid_endecode(at, encode);
645         
646         case ATTR_CABLETEST_DO:
647                 return cabletest_do_endecode(at);
648         
649         case ATTR_CABLETEST_RESULT:
650                 return cabletest_result_endecode(at, encode);
651         
652         case ATTR_IGMP_ENABLE_VLAN:
653                 return igmp_vlan_endecode(at, encode);
654         
655         case ATTR_MIRROR:
656                 if (encode)
657                         return mirror_encode(at);
658                 else
659                         return mirror_decode(at);
660         
661         case ATTR_VLAN_PORT_CONF:
662                 if (encode)
663                         return vlan_port_encode(at);
664                 else
665                         return vlan_port_decode(at);
666         
667         case ATTR_VLAN_DOT_CONF:
668                 if (encode)
669                         return vlan_dot_encode(at);
670                 else
671                         return vlan_dot_decode(at);
672         
673         /* undefined attributes are not modified */
674         default:
675                 return 0;
676         }
677 }
678
679
680 int encodeAttr (struct attr *at)
681 {
682         return processAttr(at, true);
683 }
684
685
686 int decodeAttr (struct attr *at)
687 {
688         return processAttr(at, false);
689 }
690
691