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