Build p54 driver from compat-wireless
[openwrt.git] / package / swconfig / src / swlib.c
1 /*
2  * swlib.c: Switch configuration API (user space part)
3  *
4  * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * version 2.1 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <inttypes.h>
20 #include <errno.h>
21 #include <stdint.h>
22 #include <getopt.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <linux/switch.h>
26 #include "swlib.h"
27
28 //#define DEBUG 1
29 #ifdef DEBUG
30 #define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__)
31 #else
32 #define DPRINTF(fmt, ...) do {} while (0)
33 #endif
34
35 static struct nl_handle *handle;
36 static struct nl_cache *cache;
37 static struct genl_family *family;
38 static struct nlattr *tb[SWITCH_ATTR_MAX];
39 static int refcount = 0;
40
41 static struct nla_policy port_policy[] = {
42         [SWITCH_PORT_ID] = { .type = NLA_U32 },
43         [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
44 };
45
46 static inline void *
47 swlib_alloc(size_t size)
48 {
49         void *ptr;
50
51         ptr = malloc(size);
52         if (!ptr)
53                 goto done;
54         memset(ptr, 0, size);
55
56 done:
57         return ptr;
58 }
59
60 static int
61 wait_handler(struct nl_msg *msg, void *arg)
62 {
63         int *finished = arg;
64
65         *finished = 1;
66         return NL_STOP;
67 }
68
69 /* helper function for performing netlink requests */
70 static int
71 swlib_call(int cmd, int (*call)(struct nl_msg *, void *),
72                 int (*data)(struct nl_msg *, void *), void *arg)
73 {
74         struct nl_msg *msg;
75         struct nl_cb *cb = NULL;
76         int finished;
77         int flags = 0;
78         int err;
79
80         msg = nlmsg_alloc();
81         if (!msg) {
82                 fprintf(stderr, "Out of memory!\n");
83                 exit(1);
84         }
85
86         if (!data)
87                 flags |= NLM_F_DUMP;
88
89         genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family), 0, flags, cmd, 0);
90         if (data) {
91                 if (data(msg, arg) < 0)
92                         goto nla_put_failure;
93         }
94
95         cb = nl_cb_alloc(NL_CB_CUSTOM);
96         if (!cb) {
97                 fprintf(stderr, "nl_cb_alloc failed.\n");
98                 exit(1);
99         }
100
101         err = nl_send_auto_complete(handle, msg);
102         if (err < 0) {
103                 fprintf(stderr, "nl_send_auto_complete failed: %d\n", err);
104                 goto out;
105         }
106
107         finished = 0;
108
109         if (call)
110                 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, call, arg);
111
112         if (data)
113                 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
114         else
115                 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished);
116
117         err = nl_recvmsgs(handle, cb);
118         if (err < 0) {
119                 goto out;
120         }
121
122         if (!finished)
123                 err = nl_wait_for_ack(handle);
124
125 out:
126         if (cb)
127                 nl_cb_put(cb);
128 nla_put_failure:
129         nlmsg_free(msg);
130         return err;
131 }
132
133 static int
134 send_attr(struct nl_msg *msg, void *arg)
135 {
136         struct switch_val *val = arg;
137         struct switch_attr *attr = val->attr;
138
139         NLA_PUT_U32(msg, SWITCH_ATTR_ID, attr->dev->id);
140         NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, attr->id);
141         switch(attr->atype) {
142         case SWLIB_ATTR_GROUP_PORT:
143                 NLA_PUT_U32(msg, SWITCH_ATTR_OP_PORT, val->port_vlan);
144                 break;
145         case SWLIB_ATTR_GROUP_VLAN:
146                 NLA_PUT_U32(msg, SWITCH_ATTR_OP_VLAN, val->port_vlan);
147                 break;
148         default:
149                 break;
150         }
151
152         return 0;
153
154 nla_put_failure:
155         return -1;
156 }
157
158 static int
159 store_port_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val)
160 {
161         struct nlattr *p;
162         int ports = val->attr->dev->ports;
163         int err = 0;
164         int remaining;
165
166         if (!val->value.ports)
167                 val->value.ports = malloc(sizeof(struct switch_port) * ports);
168
169         nla_for_each_nested(p, nla, remaining) {
170                 struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
171                 struct switch_port *port;
172
173                 if (val->len >= ports)
174                         break;
175
176                 err = nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, p, port_policy);
177                 if (err < 0)
178                         goto out;
179
180                 if (!tb[SWITCH_PORT_ID])
181                         continue;
182
183                 port = &val->value.ports[val->len];
184                 port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
185                 port->flags = 0;
186                 if (tb[SWITCH_PORT_FLAG_TAGGED])
187                         port->flags |= SWLIB_PORT_FLAG_TAGGED;
188
189                 val->len++;
190         }
191
192 out:
193         return err;
194 }
195
196 static int
197 store_val(struct nl_msg *msg, void *arg)
198 {
199         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
200         struct switch_val *val = arg;
201         struct switch_attr *attr = val->attr;
202
203         if (!val)
204                 goto error;
205
206         if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
207                         genlmsg_attrlen(gnlh, 0), NULL) < 0) {
208                 goto error;
209         }
210
211         if (tb[SWITCH_ATTR_OP_VALUE_INT])
212                 val->value.i = nla_get_u32(tb[SWITCH_ATTR_OP_VALUE_INT]);
213         else if (tb[SWITCH_ATTR_OP_VALUE_STR])
214                 val->value.s = strdup(nla_get_string(tb[SWITCH_ATTR_OP_VALUE_STR]));
215         else if (tb[SWITCH_ATTR_OP_VALUE_PORTS])
216                 val->err = store_port_val(msg, tb[SWITCH_ATTR_OP_VALUE_PORTS], val);
217
218         val->err = 0;
219         return 0;
220
221 error:
222         return NL_SKIP;
223 }
224
225 int
226 swlib_get_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
227 {
228         int cmd;
229         int err;
230
231         switch(attr->atype) {
232         case SWLIB_ATTR_GROUP_GLOBAL:
233                 cmd = SWITCH_CMD_GET_GLOBAL;
234                 break;
235         case SWLIB_ATTR_GROUP_PORT:
236                 cmd = SWITCH_CMD_GET_PORT;
237                 break;
238         case SWLIB_ATTR_GROUP_VLAN:
239                 cmd = SWITCH_CMD_GET_VLAN;
240                 break;
241         default:
242                 return -EINVAL;
243         }
244
245         memset(&val->value, 0, sizeof(val->value));
246         val->len = 0;
247         val->attr = attr;
248         val->err = -EINVAL;
249         err = swlib_call(cmd, store_val, send_attr, val);
250         if (!err)
251                 err = val->err;
252
253         return err;
254 }
255
256 static int
257 send_attr_ports(struct nl_msg *msg, struct switch_val *val)
258 {
259         struct nlattr *n;
260         int i;
261
262         /* TODO implement multipart? */
263         if (val->len == 0)
264                 goto done;
265         n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_PORTS);
266         if (!n)
267                 goto nla_put_failure;
268         for (i = 0; i < val->len; i++) {
269                 struct switch_port *port = &val->value.ports[i];
270                 struct nlattr *np;
271
272                 np = nla_nest_start(msg, SWITCH_ATTR_PORT);
273                 if (!np)
274                         goto nla_put_failure;
275
276                 NLA_PUT_U32(msg, SWITCH_PORT_ID, port->id);
277                 if (port->flags & SWLIB_PORT_FLAG_TAGGED)
278                         NLA_PUT_FLAG(msg, SWITCH_PORT_FLAG_TAGGED);
279
280                 nla_nest_end(msg, np);
281         }
282         nla_nest_end(msg, n);
283 done:
284         return 0;
285
286 nla_put_failure:
287         return -1;
288 }
289
290 static int
291 send_attr_val(struct nl_msg *msg, void *arg)
292 {
293         struct switch_val *val = arg;
294         struct switch_attr *attr = val->attr;
295
296         if (send_attr(msg, arg))
297                 goto nla_put_failure;
298
299         switch(attr->type) {
300         case SWITCH_TYPE_NOVAL:
301                 break;
302         case SWITCH_TYPE_INT:
303                 NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val->value.i);
304                 break;
305         case SWITCH_TYPE_STRING:
306                 if (!val->value.s)
307                         goto nla_put_failure;
308                 NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val->value.s);
309                 break;
310         case SWITCH_TYPE_PORTS:
311                 if (send_attr_ports(msg, val) < 0)
312                         goto nla_put_failure;
313                 break;
314         default:
315                 goto nla_put_failure;
316         }
317         return 0;
318
319 nla_put_failure:
320         return -1;
321 }
322
323 int
324 swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
325 {
326         int cmd;
327
328         switch(attr->atype) {
329         case SWLIB_ATTR_GROUP_GLOBAL:
330                 cmd = SWITCH_CMD_SET_GLOBAL;
331                 break;
332         case SWLIB_ATTR_GROUP_PORT:
333                 cmd = SWITCH_CMD_SET_PORT;
334                 break;
335         case SWLIB_ATTR_GROUP_VLAN:
336                 cmd = SWITCH_CMD_SET_VLAN;
337                 break;
338         default:
339                 return -EINVAL;
340         }
341
342         val->attr = attr;
343         return swlib_call(cmd, NULL, send_attr_val, val);
344 }
345
346
347 struct attrlist_arg {
348         int id;
349         int atype;
350         struct switch_dev *dev;
351         struct switch_attr *prev;
352         struct switch_attr **head;
353 };
354
355 static int
356 add_id(struct nl_msg *msg, void *arg)
357 {
358         struct attrlist_arg *l = arg;
359
360         NLA_PUT_U32(msg, SWITCH_ATTR_ID, l->id);
361
362         return 0;
363 nla_put_failure:
364         return -1;
365 }
366
367 static int
368 add_attr(struct nl_msg *msg, void *ptr)
369 {
370         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
371         struct attrlist_arg *arg = ptr;
372         struct switch_attr *new;
373
374         if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
375                         genlmsg_attrlen(gnlh, 0), NULL) < 0)
376                 goto done;
377
378         new = swlib_alloc(sizeof(struct switch_attr));
379         if (!new)
380                 goto done;
381
382         new->dev = arg->dev;
383         new->atype = arg->atype;
384         if (arg->prev) {
385                 arg->prev->next = new;
386         } else {
387                 arg->prev = *arg->head;
388         }
389         *arg->head = new;
390         arg->head = &new->next;
391
392         if (tb[SWITCH_ATTR_OP_ID])
393                 new->id = nla_get_u32(tb[SWITCH_ATTR_OP_ID]);
394         if (tb[SWITCH_ATTR_OP_TYPE])
395                 new->type = nla_get_u32(tb[SWITCH_ATTR_OP_TYPE]);
396         if (tb[SWITCH_ATTR_OP_NAME])
397                 new->name = strdup(nla_get_string(tb[SWITCH_ATTR_OP_NAME]));
398         if (tb[SWITCH_ATTR_OP_DESCRIPTION])
399                 new->description = strdup(nla_get_string(tb[SWITCH_ATTR_OP_DESCRIPTION]));
400
401 done:
402         return NL_SKIP;
403 }
404
405 int
406 swlib_scan(struct switch_dev *dev)
407 {
408         struct attrlist_arg arg;
409
410         if (dev->ops || dev->port_ops || dev->vlan_ops)
411                 return 0;
412
413         arg.atype = SWLIB_ATTR_GROUP_GLOBAL;
414         arg.dev = dev;
415         arg.id = dev->id;
416         arg.prev = NULL;
417         arg.head = &dev->ops;
418         swlib_call(SWITCH_CMD_LIST_GLOBAL, add_attr, add_id, &arg);
419
420         arg.atype = SWLIB_ATTR_GROUP_PORT;
421         arg.prev = NULL;
422         arg.head = &dev->port_ops;
423         swlib_call(SWITCH_CMD_LIST_PORT, add_attr, add_id, &arg);
424
425         arg.atype = SWLIB_ATTR_GROUP_VLAN;
426         arg.prev = NULL;
427         arg.head = &dev->vlan_ops;
428         swlib_call(SWITCH_CMD_LIST_VLAN, add_attr, add_id, &arg);
429
430         return 0;
431 }
432
433 struct switch_attr *swlib_lookup_attr(struct switch_dev *dev,
434                 enum swlib_attr_group atype, const char *name)
435 {
436         struct switch_attr *head;
437
438         if (!name || !dev)
439                 return NULL;
440
441         switch(atype) {
442         case SWLIB_ATTR_GROUP_GLOBAL:
443                 head = dev->ops;
444                 break;
445         case SWLIB_ATTR_GROUP_PORT:
446                 head = dev->port_ops;
447                 break;
448         case SWLIB_ATTR_GROUP_VLAN:
449                 head = dev->vlan_ops;
450                 break;
451         }
452         while(head) {
453                 if (!strcmp(name, head->name))
454                         return head;
455                 head = head->next;
456         }
457
458         return NULL;
459 }
460
461 static void
462 swlib_priv_free(void)
463 {
464         if (cache)
465                 nl_cache_free(cache);
466         if (handle)
467                 nl_handle_destroy(handle);
468         handle = NULL;
469         cache = NULL;
470 }
471
472 static int
473 swlib_priv_init(void)
474 {
475         handle = nl_handle_alloc();
476         if (!handle) {
477                 DPRINTF("Failed to create handle\n");
478                 goto err;
479         }
480
481         if (genl_connect(handle)) {
482                 DPRINTF("Failed to connect to generic netlink\n");
483                 goto err;
484         }
485
486         cache = genl_ctrl_alloc_cache(handle);
487         if (!cache) {
488                 DPRINTF("Failed to allocate netlink cache\n");
489                 goto err;
490         }
491
492         family = genl_ctrl_search_by_name(cache, "switch");
493         if (!family) {
494                 DPRINTF("Switch API not present\n");
495                 goto err;
496         }
497         return 0;
498
499 err:
500         swlib_priv_free();
501         return -EINVAL;
502 }
503
504 struct swlib_scan_arg {
505         const char *name;
506         struct switch_dev *head;
507         struct switch_dev *ptr;
508 };
509
510 static int
511 add_switch(struct nl_msg *msg, void *arg)
512 {
513         struct swlib_scan_arg *sa = arg;
514         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
515         struct switch_dev *dev;
516         const char *name;
517
518         if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
519                 goto done;
520
521         if (!tb[SWITCH_ATTR_DEV_NAME])
522                 goto done;
523
524         name = nla_get_string(tb[SWITCH_ATTR_DEV_NAME]);
525         if (sa->name && (strcmp(name, sa->name) != 0))
526                 goto done;
527
528         dev = swlib_alloc(sizeof(struct switch_dev));
529         if (!dev)
530                 goto done;
531
532         dev->dev_name = strdup(name);
533         if (tb[SWITCH_ATTR_ID])
534                 dev->id = nla_get_u32(tb[SWITCH_ATTR_ID]);
535         if (tb[SWITCH_ATTR_NAME])
536                 dev->name = strdup(nla_get_string(tb[SWITCH_ATTR_DEV_NAME]));
537         if (tb[SWITCH_ATTR_PORTS])
538                 dev->ports = nla_get_u32(tb[SWITCH_ATTR_PORTS]);
539         if (tb[SWITCH_ATTR_VLANS])
540                 dev->vlans = nla_get_u32(tb[SWITCH_ATTR_VLANS]);
541
542         if (!sa->head) {
543                 sa->head = dev;
544                 sa->ptr = dev;
545         } else {
546                 sa->ptr->next = dev;
547                 sa->ptr = dev;
548         }
549
550         refcount++;
551 done:
552         return NL_SKIP;
553 }
554
555
556 struct switch_dev *
557 swlib_connect(const char *name)
558 {
559         struct swlib_scan_arg arg;
560         int err;
561
562         if (!refcount) {
563                 if (swlib_priv_init() < 0)
564                         return NULL;
565         };
566
567         arg.head = NULL;
568         arg.ptr = NULL;
569         arg.name = name;
570         swlib_call(SWITCH_CMD_GET_SWITCH, add_switch, NULL, &arg);
571
572         if (!refcount)
573                 swlib_priv_free();
574
575         return arg.head;
576 }
577
578 static void
579 swlib_free_attributes(struct switch_attr **head)
580 {
581         struct switch_attr *a = *head;
582         struct switch_attr *next;
583
584         while (a) {
585                 next = a->next;
586                 free(a);
587                 a = next;
588         }
589         *head = NULL;
590 }
591
592 void
593 swlib_free(struct switch_dev *dev)
594 {
595         swlib_free_attributes(&dev->ops);
596         swlib_free_attributes(&dev->port_ops);
597         swlib_free_attributes(&dev->vlan_ops);
598         free(dev);
599
600         if (--refcount == 0)
601                 swlib_priv_free();
602 }
603
604 void
605 swlib_free_all(struct switch_dev *dev)
606 {
607         struct switch_dev *p;
608
609         while (dev) {
610                 p = dev->next;
611                 swlib_free(dev);
612                 dev = p;
613         }
614 }