swconfig: remove obsolete portmapping feature
[librecmc/librecmc.git] / package / network / config / swconfig / src / swlib.c
1 /*
2  * swlib.c: Switch configuration API (user space part)
3  *
4  * Copyright (C) 2008 Felix Fietkau <nbd@nbd.name>
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 #include <netlink/netlink.h>
28 #include <netlink/genl/genl.h>
29 #include <netlink/genl/family.h>
30
31 //#define DEBUG 1
32 #ifdef DEBUG
33 #define DPRINTF(fmt, ...) fprintf(stderr, "%s(%d): " fmt, __func__, __LINE__, ##__VA_ARGS__)
34 #else
35 #define DPRINTF(fmt, ...) do {} while (0)
36 #endif
37
38 static struct nl_sock *handle;
39 static struct nl_cache *cache;
40 static struct genl_family *family;
41 static struct nlattr *tb[SWITCH_ATTR_MAX + 1];
42 static int refcount = 0;
43
44 static struct nla_policy port_policy[SWITCH_ATTR_MAX] = {
45         [SWITCH_PORT_ID] = { .type = NLA_U32 },
46         [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
47 };
48
49 static struct nla_policy link_policy[SWITCH_LINK_ATTR_MAX] = {
50         [SWITCH_LINK_FLAG_LINK] = { .type = NLA_FLAG },
51         [SWITCH_LINK_FLAG_DUPLEX] = { .type = NLA_FLAG },
52         [SWITCH_LINK_FLAG_ANEG] = { .type = NLA_FLAG },
53         [SWITCH_LINK_SPEED] = { .type = NLA_U32 },
54         [SWITCH_LINK_FLAG_EEE_100BASET] = { .type = NLA_FLAG },
55         [SWITCH_LINK_FLAG_EEE_1000BASET] = { .type = NLA_FLAG },
56 };
57
58 static inline void *
59 swlib_alloc(size_t size)
60 {
61         void *ptr;
62
63         ptr = malloc(size);
64         if (!ptr)
65                 goto done;
66         memset(ptr, 0, size);
67
68 done:
69         return ptr;
70 }
71
72 static int
73 wait_handler(struct nl_msg *msg, void *arg)
74 {
75         int *finished = arg;
76
77         *finished = 1;
78         return NL_STOP;
79 }
80
81 /* helper function for performing netlink requests */
82 static int
83 swlib_call(int cmd, int (*call)(struct nl_msg *, void *),
84                 int (*data)(struct nl_msg *, void *), void *arg)
85 {
86         struct nl_msg *msg;
87         struct nl_cb *cb = NULL;
88         int finished;
89         int flags = 0;
90         int err;
91
92         msg = nlmsg_alloc();
93         if (!msg) {
94                 fprintf(stderr, "Out of memory!\n");
95                 exit(1);
96         }
97
98         if (!data)
99                 flags |= NLM_F_DUMP;
100
101         genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, genl_family_get_id(family), 0, flags, cmd, 0);
102         if (data) {
103                 if (data(msg, arg) < 0)
104                         goto nla_put_failure;
105         }
106
107         cb = nl_cb_alloc(NL_CB_CUSTOM);
108         if (!cb) {
109                 fprintf(stderr, "nl_cb_alloc failed.\n");
110                 exit(1);
111         }
112
113         err = nl_send_auto_complete(handle, msg);
114         if (err < 0) {
115                 fprintf(stderr, "nl_send_auto_complete failed: %d\n", err);
116                 goto out;
117         }
118
119         finished = 0;
120
121         if (call)
122                 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, call, arg);
123
124         if (data)
125                 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, wait_handler, &finished);
126         else
127                 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, wait_handler, &finished);
128
129         err = nl_recvmsgs(handle, cb);
130         if (err < 0) {
131                 goto out;
132         }
133
134         if (!finished)
135                 err = nl_wait_for_ack(handle);
136
137 out:
138         if (cb)
139                 nl_cb_put(cb);
140 nla_put_failure:
141         nlmsg_free(msg);
142         return err;
143 }
144
145 static int
146 send_attr(struct nl_msg *msg, void *arg)
147 {
148         struct switch_val *val = arg;
149         struct switch_attr *attr = val->attr;
150
151         NLA_PUT_U32(msg, SWITCH_ATTR_ID, attr->dev->id);
152         NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, attr->id);
153         switch(attr->atype) {
154         case SWLIB_ATTR_GROUP_PORT:
155                 NLA_PUT_U32(msg, SWITCH_ATTR_OP_PORT, val->port_vlan);
156                 break;
157         case SWLIB_ATTR_GROUP_VLAN:
158                 NLA_PUT_U32(msg, SWITCH_ATTR_OP_VLAN, val->port_vlan);
159                 break;
160         default:
161                 break;
162         }
163
164         return 0;
165
166 nla_put_failure:
167         return -1;
168 }
169
170 static int
171 store_port_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val)
172 {
173         struct nlattr *p;
174         int ports = val->attr->dev->ports;
175         int err = 0;
176         int remaining;
177
178         if (!val->value.ports)
179                 val->value.ports = malloc(sizeof(struct switch_port) * ports);
180
181         nla_for_each_nested(p, nla, remaining) {
182                 struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
183                 struct switch_port *port;
184
185                 if (val->len >= ports)
186                         break;
187
188                 err = nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, p, port_policy);
189                 if (err < 0)
190                         goto out;
191
192                 if (!tb[SWITCH_PORT_ID])
193                         continue;
194
195                 port = &val->value.ports[val->len];
196                 port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
197                 port->flags = 0;
198                 if (tb[SWITCH_PORT_FLAG_TAGGED])
199                         port->flags |= SWLIB_PORT_FLAG_TAGGED;
200
201                 val->len++;
202         }
203
204 out:
205         return err;
206 }
207
208 static int
209 store_link_val(struct nl_msg *msg, struct nlattr *nla, struct switch_val *val)
210 {
211         struct nlattr *tb[SWITCH_LINK_ATTR_MAX + 1];
212         struct switch_port_link *link;
213         int err = 0;
214
215         if (!val->value.link)
216                 val->value.link = malloc(sizeof(struct switch_port_link));
217
218         err = nla_parse_nested(tb, SWITCH_LINK_ATTR_MAX, nla, link_policy);
219         if (err < 0)
220                 goto out;
221
222         link = val->value.link;
223         link->link = !!tb[SWITCH_LINK_FLAG_LINK];
224         link->duplex = !!tb[SWITCH_LINK_FLAG_DUPLEX];
225         link->aneg = !!tb[SWITCH_LINK_FLAG_ANEG];
226         link->tx_flow = !!tb[SWITCH_LINK_FLAG_TX_FLOW];
227         link->rx_flow = !!tb[SWITCH_LINK_FLAG_RX_FLOW];
228         link->speed = nla_get_u32(tb[SWITCH_LINK_SPEED]);
229         link->eee = 0;
230         if (tb[SWITCH_LINK_FLAG_EEE_100BASET])
231                 link->eee |= SWLIB_LINK_FLAG_EEE_100BASET;
232         if (tb[SWITCH_LINK_FLAG_EEE_1000BASET])
233                 link->eee |= SWLIB_LINK_FLAG_EEE_1000BASET;
234
235 out:
236         return err;
237 }
238
239 static int
240 store_val(struct nl_msg *msg, void *arg)
241 {
242         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
243         struct switch_val *val = arg;
244
245         if (!val)
246                 goto error;
247
248         if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
249                         genlmsg_attrlen(gnlh, 0), NULL) < 0) {
250                 goto error;
251         }
252
253         if (tb[SWITCH_ATTR_OP_VALUE_INT])
254                 val->value.i = nla_get_u32(tb[SWITCH_ATTR_OP_VALUE_INT]);
255         else if (tb[SWITCH_ATTR_OP_VALUE_STR])
256                 val->value.s = strdup(nla_get_string(tb[SWITCH_ATTR_OP_VALUE_STR]));
257         else if (tb[SWITCH_ATTR_OP_VALUE_PORTS])
258                 val->err = store_port_val(msg, tb[SWITCH_ATTR_OP_VALUE_PORTS], val);
259         else if (tb[SWITCH_ATTR_OP_VALUE_LINK])
260                 val->err = store_link_val(msg, tb[SWITCH_ATTR_OP_VALUE_LINK], val);
261
262         val->err = 0;
263         return 0;
264
265 error:
266         return NL_SKIP;
267 }
268
269 int
270 swlib_get_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
271 {
272         int cmd;
273         int err;
274
275         switch(attr->atype) {
276         case SWLIB_ATTR_GROUP_GLOBAL:
277                 cmd = SWITCH_CMD_GET_GLOBAL;
278                 break;
279         case SWLIB_ATTR_GROUP_PORT:
280                 cmd = SWITCH_CMD_GET_PORT;
281                 break;
282         case SWLIB_ATTR_GROUP_VLAN:
283                 cmd = SWITCH_CMD_GET_VLAN;
284                 break;
285         default:
286                 return -EINVAL;
287         }
288
289         memset(&val->value, 0, sizeof(val->value));
290         val->len = 0;
291         val->attr = attr;
292         val->err = -EINVAL;
293         err = swlib_call(cmd, store_val, send_attr, val);
294         if (!err)
295                 err = val->err;
296
297         return err;
298 }
299
300 static int
301 send_attr_ports(struct nl_msg *msg, struct switch_val *val)
302 {
303         struct nlattr *n;
304         int i;
305
306         /* TODO implement multipart? */
307         if (val->len == 0)
308                 goto done;
309         n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_PORTS);
310         if (!n)
311                 goto nla_put_failure;
312         for (i = 0; i < val->len; i++) {
313                 struct switch_port *port = &val->value.ports[i];
314                 struct nlattr *np;
315
316                 np = nla_nest_start(msg, SWITCH_ATTR_PORT);
317                 if (!np)
318                         goto nla_put_failure;
319
320                 NLA_PUT_U32(msg, SWITCH_PORT_ID, port->id);
321                 if (port->flags & SWLIB_PORT_FLAG_TAGGED)
322                         NLA_PUT_FLAG(msg, SWITCH_PORT_FLAG_TAGGED);
323
324                 nla_nest_end(msg, np);
325         }
326         nla_nest_end(msg, n);
327 done:
328         return 0;
329
330 nla_put_failure:
331         return -1;
332 }
333
334 static int
335 send_attr_link(struct nl_msg *msg, struct switch_val *val)
336 {
337         struct switch_port_link *link = val->value.link;
338         struct nlattr *n;
339
340         n = nla_nest_start(msg, SWITCH_ATTR_OP_VALUE_LINK);
341         if (!n)
342                 goto nla_put_failure;
343
344         if (link->duplex)
345                 NLA_PUT_FLAG(msg, SWITCH_LINK_FLAG_DUPLEX);
346         if (link->aneg)
347                 NLA_PUT_FLAG(msg, SWITCH_LINK_FLAG_ANEG);
348         NLA_PUT_U32(msg, SWITCH_LINK_SPEED, link->speed);
349
350         nla_nest_end(msg, n);
351
352         return 0;
353
354 nla_put_failure:
355         return -1;
356 }
357
358 static int
359 send_attr_val(struct nl_msg *msg, void *arg)
360 {
361         struct switch_val *val = arg;
362         struct switch_attr *attr = val->attr;
363
364         if (send_attr(msg, arg))
365                 goto nla_put_failure;
366
367         switch(attr->type) {
368         case SWITCH_TYPE_NOVAL:
369                 break;
370         case SWITCH_TYPE_INT:
371                 NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val->value.i);
372                 break;
373         case SWITCH_TYPE_STRING:
374                 if (!val->value.s)
375                         goto nla_put_failure;
376                 NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val->value.s);
377                 break;
378         case SWITCH_TYPE_PORTS:
379                 if (send_attr_ports(msg, val) < 0)
380                         goto nla_put_failure;
381                 break;
382         case SWITCH_TYPE_LINK:
383                 if (send_attr_link(msg, val))
384                         goto nla_put_failure;
385                 break;
386         default:
387                 goto nla_put_failure;
388         }
389         return 0;
390
391 nla_put_failure:
392         return -1;
393 }
394
395 int
396 swlib_set_attr(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val)
397 {
398         int cmd;
399
400         switch(attr->atype) {
401         case SWLIB_ATTR_GROUP_GLOBAL:
402                 cmd = SWITCH_CMD_SET_GLOBAL;
403                 break;
404         case SWLIB_ATTR_GROUP_PORT:
405                 cmd = SWITCH_CMD_SET_PORT;
406                 break;
407         case SWLIB_ATTR_GROUP_VLAN:
408                 cmd = SWITCH_CMD_SET_VLAN;
409                 break;
410         default:
411                 return -EINVAL;
412         }
413
414         val->attr = attr;
415         return swlib_call(cmd, NULL, send_attr_val, val);
416 }
417
418 enum {
419         CMD_NONE,
420         CMD_DUPLEX,
421         CMD_ANEG,
422         CMD_SPEED,
423 };
424
425 int swlib_set_attr_string(struct switch_dev *dev, struct switch_attr *a, int port_vlan, const char *str)
426 {
427         struct switch_port *ports;
428         struct switch_port_link *link;
429         struct switch_val val;
430         char *ptr;
431         int cmd = CMD_NONE;
432
433         memset(&val, 0, sizeof(val));
434         val.port_vlan = port_vlan;
435         switch(a->type) {
436         case SWITCH_TYPE_INT:
437                 val.value.i = atoi(str);
438                 break;
439         case SWITCH_TYPE_STRING:
440                 val.value.s = (char *)str;
441                 break;
442         case SWITCH_TYPE_PORTS:
443                 ports = alloca(sizeof(struct switch_port) * dev->ports);
444                 memset(ports, 0, sizeof(struct switch_port) * dev->ports);
445                 val.len = 0;
446                 ptr = (char *)str;
447                 while(ptr && *ptr)
448                 {
449                         while(*ptr && isspace(*ptr))
450                                 ptr++;
451
452                         if (!*ptr)
453                                 break;
454
455                         if (!isdigit(*ptr))
456                                 return -1;
457
458                         if (val.len >= dev->ports)
459                                 return -1;
460
461                         ports[val.len].flags = 0;
462                         ports[val.len].id = strtoul(ptr, &ptr, 10);
463                         while(*ptr && !isspace(*ptr)) {
464                                 if (*ptr == 't')
465                                         ports[val.len].flags |= SWLIB_PORT_FLAG_TAGGED;
466                                 else
467                                         return -1;
468
469                                 ptr++;
470                         }
471                         if (*ptr)
472                                 ptr++;
473                         val.len++;
474                 }
475                 val.value.ports = ports;
476                 break;
477         case SWITCH_TYPE_LINK:
478                 link = malloc(sizeof(struct switch_port_link));
479                 memset(link, 0, sizeof(struct switch_port_link));
480                 ptr = (char *)str;
481                 for (ptr = strtok(ptr," "); ptr; ptr = strtok(NULL, " ")) {
482                         switch (cmd) {
483                         case CMD_NONE:
484                                 if (!strcmp(ptr, "duplex"))
485                                         cmd = CMD_DUPLEX;
486                                 else if (!strcmp(ptr, "autoneg"))
487                                         cmd = CMD_ANEG;
488                                 else if (!strcmp(ptr, "speed"))
489                                         cmd = CMD_SPEED;
490                                 else
491                                         fprintf(stderr, "Unsupported option %s\n", ptr);
492                                 break;
493                         case CMD_DUPLEX:
494                                 if (!strcmp(ptr, "half"))
495                                         link->duplex = 0;
496                                 else if (!strcmp(ptr, "full"))
497                                         link->duplex = 1;
498                                 else
499                                         fprintf(stderr, "Unsupported value %s\n", ptr);
500                                 cmd = CMD_NONE;
501                                 break;
502                         case CMD_ANEG:
503                                 if (!strcmp(ptr, "on"))
504                                         link->aneg = 1;
505                                 else if (!strcmp(ptr, "off"))
506                                         link->aneg = 0;
507                                 else
508                                         fprintf(stderr, "Unsupported value %s\n", ptr);
509                                 cmd = CMD_NONE;
510                                 break;
511                         case CMD_SPEED:
512                                 link->speed = atoi(ptr);
513                                 cmd = CMD_NONE;
514                                 break;
515                         }
516                 }
517                 val.value.link = link;
518                 break;
519         case SWITCH_TYPE_NOVAL:
520                 if (str && !strcmp(str, "0"))
521                         return 0;
522
523                 break;
524         default:
525                 return -1;
526         }
527         return swlib_set_attr(dev, a, &val);
528 }
529
530
531 struct attrlist_arg {
532         int id;
533         int atype;
534         struct switch_dev *dev;
535         struct switch_attr *prev;
536         struct switch_attr **head;
537 };
538
539 static int
540 add_id(struct nl_msg *msg, void *arg)
541 {
542         struct attrlist_arg *l = arg;
543
544         NLA_PUT_U32(msg, SWITCH_ATTR_ID, l->id);
545
546         return 0;
547 nla_put_failure:
548         return -1;
549 }
550
551 static int
552 add_attr(struct nl_msg *msg, void *ptr)
553 {
554         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
555         struct attrlist_arg *arg = ptr;
556         struct switch_attr *new;
557
558         if (nla_parse(tb, SWITCH_ATTR_MAX - 1, genlmsg_attrdata(gnlh, 0),
559                         genlmsg_attrlen(gnlh, 0), NULL) < 0)
560                 goto done;
561
562         new = swlib_alloc(sizeof(struct switch_attr));
563         if (!new)
564                 goto done;
565
566         new->dev = arg->dev;
567         new->atype = arg->atype;
568         if (arg->prev) {
569                 arg->prev->next = new;
570         } else {
571                 arg->prev = *arg->head;
572         }
573         *arg->head = new;
574         arg->head = &new->next;
575
576         if (tb[SWITCH_ATTR_OP_ID])
577                 new->id = nla_get_u32(tb[SWITCH_ATTR_OP_ID]);
578         if (tb[SWITCH_ATTR_OP_TYPE])
579                 new->type = nla_get_u32(tb[SWITCH_ATTR_OP_TYPE]);
580         if (tb[SWITCH_ATTR_OP_NAME])
581                 new->name = strdup(nla_get_string(tb[SWITCH_ATTR_OP_NAME]));
582         if (tb[SWITCH_ATTR_OP_DESCRIPTION])
583                 new->description = strdup(nla_get_string(tb[SWITCH_ATTR_OP_DESCRIPTION]));
584
585 done:
586         return NL_SKIP;
587 }
588
589 int
590 swlib_scan(struct switch_dev *dev)
591 {
592         struct attrlist_arg arg;
593
594         if (dev->ops || dev->port_ops || dev->vlan_ops)
595                 return 0;
596
597         arg.atype = SWLIB_ATTR_GROUP_GLOBAL;
598         arg.dev = dev;
599         arg.id = dev->id;
600         arg.prev = NULL;
601         arg.head = &dev->ops;
602         swlib_call(SWITCH_CMD_LIST_GLOBAL, add_attr, add_id, &arg);
603
604         arg.atype = SWLIB_ATTR_GROUP_PORT;
605         arg.prev = NULL;
606         arg.head = &dev->port_ops;
607         swlib_call(SWITCH_CMD_LIST_PORT, add_attr, add_id, &arg);
608
609         arg.atype = SWLIB_ATTR_GROUP_VLAN;
610         arg.prev = NULL;
611         arg.head = &dev->vlan_ops;
612         swlib_call(SWITCH_CMD_LIST_VLAN, add_attr, add_id, &arg);
613
614         return 0;
615 }
616
617 struct switch_attr *swlib_lookup_attr(struct switch_dev *dev,
618                 enum swlib_attr_group atype, const char *name)
619 {
620         struct switch_attr *head;
621
622         if (!name || !dev)
623                 return NULL;
624
625         switch(atype) {
626         case SWLIB_ATTR_GROUP_GLOBAL:
627                 head = dev->ops;
628                 break;
629         case SWLIB_ATTR_GROUP_PORT:
630                 head = dev->port_ops;
631                 break;
632         case SWLIB_ATTR_GROUP_VLAN:
633                 head = dev->vlan_ops;
634                 break;
635         }
636         while(head) {
637                 if (!strcmp(name, head->name))
638                         return head;
639                 head = head->next;
640         }
641
642         return NULL;
643 }
644
645 static void
646 swlib_priv_free(void)
647 {
648         if (family)
649                 nl_object_put((struct nl_object*)family);
650         if (cache)
651                 nl_cache_free(cache);
652         if (handle)
653                 nl_socket_free(handle);
654         family = NULL;
655         handle = NULL;
656         cache = NULL;
657 }
658
659 static int
660 swlib_priv_init(void)
661 {
662         int ret;
663
664         handle = nl_socket_alloc();
665         if (!handle) {
666                 DPRINTF("Failed to create handle\n");
667                 goto err;
668         }
669
670         if (genl_connect(handle)) {
671                 DPRINTF("Failed to connect to generic netlink\n");
672                 goto err;
673         }
674
675         ret = genl_ctrl_alloc_cache(handle, &cache);
676         if (ret < 0) {
677                 DPRINTF("Failed to allocate netlink cache\n");
678                 goto err;
679         }
680
681         family = genl_ctrl_search_by_name(cache, "switch");
682         if (!family) {
683                 DPRINTF("Switch API not present\n");
684                 goto err;
685         }
686         return 0;
687
688 err:
689         swlib_priv_free();
690         return -EINVAL;
691 }
692
693 struct swlib_scan_arg {
694         const char *name;
695         struct switch_dev *head;
696         struct switch_dev *ptr;
697 };
698
699 static int
700 add_switch(struct nl_msg *msg, void *arg)
701 {
702         struct swlib_scan_arg *sa = arg;
703         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
704         struct switch_dev *dev;
705         const char *name;
706         const char *alias;
707
708         if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
709                 goto done;
710
711         if (!tb[SWITCH_ATTR_DEV_NAME])
712                 goto done;
713
714         name = nla_get_string(tb[SWITCH_ATTR_DEV_NAME]);
715         alias = nla_get_string(tb[SWITCH_ATTR_ALIAS]);
716
717         if (sa->name && (strcmp(name, sa->name) != 0) && (strcmp(alias, sa->name) != 0))
718                 goto done;
719
720         dev = swlib_alloc(sizeof(struct switch_dev));
721         if (!dev)
722                 goto done;
723
724         strncpy(dev->dev_name, name, IFNAMSIZ - 1);
725         dev->alias = strdup(alias);
726         if (tb[SWITCH_ATTR_ID])
727                 dev->id = nla_get_u32(tb[SWITCH_ATTR_ID]);
728         if (tb[SWITCH_ATTR_NAME])
729                 dev->name = strdup(nla_get_string(tb[SWITCH_ATTR_NAME]));
730         if (tb[SWITCH_ATTR_PORTS])
731                 dev->ports = nla_get_u32(tb[SWITCH_ATTR_PORTS]);
732         if (tb[SWITCH_ATTR_VLANS])
733                 dev->vlans = nla_get_u32(tb[SWITCH_ATTR_VLANS]);
734         if (tb[SWITCH_ATTR_CPU_PORT])
735                 dev->cpu_port = nla_get_u32(tb[SWITCH_ATTR_CPU_PORT]);
736
737         if (!sa->head) {
738                 sa->head = dev;
739                 sa->ptr = dev;
740         } else {
741                 sa->ptr->next = dev;
742                 sa->ptr = dev;
743         }
744
745         refcount++;
746 done:
747         return NL_SKIP;
748 }
749
750 static int
751 list_switch(struct nl_msg *msg, void *arg)
752 {
753         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
754
755         if (nla_parse(tb, SWITCH_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
756                 goto done;
757
758         if (!tb[SWITCH_ATTR_DEV_NAME] || !tb[SWITCH_ATTR_NAME])
759                 goto done;
760
761         printf("Found: %s - %s\n", nla_get_string(tb[SWITCH_ATTR_DEV_NAME]),
762                 nla_get_string(tb[SWITCH_ATTR_ALIAS]));
763
764 done:
765         return NL_SKIP;
766 }
767
768 void
769 swlib_list(void)
770 {
771         if (swlib_priv_init() < 0)
772                 return;
773         swlib_call(SWITCH_CMD_GET_SWITCH, list_switch, NULL, NULL);
774         swlib_priv_free();
775 }
776
777 struct switch_dev *
778 swlib_connect(const char *name)
779 {
780         struct swlib_scan_arg arg;
781
782         if (!refcount) {
783                 if (swlib_priv_init() < 0)
784                         return NULL;
785         };
786
787         arg.head = NULL;
788         arg.ptr = NULL;
789         arg.name = name;
790         swlib_call(SWITCH_CMD_GET_SWITCH, add_switch, NULL, &arg);
791
792         if (!refcount)
793                 swlib_priv_free();
794
795         return arg.head;
796 }
797
798 static void
799 swlib_free_attributes(struct switch_attr **head)
800 {
801         struct switch_attr *a = *head;
802         struct switch_attr *next;
803
804         while (a) {
805                 next = a->next;
806                 free(a->name);
807                 free(a->description);
808                 free(a);
809                 a = next;
810         }
811         *head = NULL;
812 }
813
814 void
815 swlib_free(struct switch_dev *dev)
816 {
817         swlib_free_attributes(&dev->ops);
818         swlib_free_attributes(&dev->port_ops);
819         swlib_free_attributes(&dev->vlan_ops);
820         free(dev->name);
821         free(dev->alias);
822         free(dev);
823
824         if (--refcount == 0)
825                 swlib_priv_free();
826 }
827
828 void
829 swlib_free_all(struct switch_dev *dev)
830 {
831         struct switch_dev *p;
832
833         while (dev) {
834                 p = dev->next;
835                 swlib_free(dev);
836                 dev = p;
837         }
838 }