440a45aef7db76f16a0aa59c6b575dd794415fd4
[openwrt/staging/yousong.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 }