swconfig: Replace SPIN_LOCK_UNLOCKED with DEFINE_SPINLOCK
[openwrt.git] / target / linux / generic / files / drivers / net / phy / swconfig.c
1 /*
2 * swconfig.c: Switch configuration API
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 General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17 #include <linux/types.h>
18 #include <linux/module.h>
19 #include <linux/init.h>
20 #include <linux/list.h>
21 #include <linux/if.h>
22 #include <linux/if_ether.h>
23 #include <linux/capability.h>
24 #include <linux/skbuff.h>
25 #include <linux/switch.h>
26
27 //#define DEBUG 1
28 #ifdef DEBUG
29 #define DPRINTF(format, ...) printk("%s: " format, __func__, ##__VA_ARGS__)
30 #else
31 #define DPRINTF(...) do {} while(0)
32 #endif
33
34 MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
35 MODULE_LICENSE("GPL");
36
37 static int swdev_id = 0;
38 static struct list_head swdevs;
39 static DEFINE_SPINLOCK(swdevs_lock);
40 struct swconfig_callback;
41
42 struct swconfig_callback
43 {
44 struct sk_buff *msg;
45 struct genlmsghdr *hdr;
46 struct genl_info *info;
47 int cmd;
48
49 /* callback for filling in the message data */
50 int (*fill)(struct swconfig_callback *cb, void *arg);
51
52 /* callback for closing the message before sending it */
53 int (*close)(struct swconfig_callback *cb, void *arg);
54
55 struct nlattr *nest[4];
56 int args[4];
57 };
58
59 /* defaults */
60
61 static int
62 swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
63 {
64 int ret;
65 if (val->port_vlan >= dev->vlans)
66 return -EINVAL;
67
68 if (!dev->ops->get_vlan_ports)
69 return -EOPNOTSUPP;
70
71 ret = dev->ops->get_vlan_ports(dev, val);
72 return ret;
73 }
74
75 static int
76 swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
77 {
78 struct switch_port *ports = val->value.ports;
79 const struct switch_dev_ops *ops = dev->ops;
80 int i;
81
82 if (val->port_vlan >= dev->vlans)
83 return -EINVAL;
84
85 /* validate ports */
86 if (val->len > dev->ports)
87 return -EINVAL;
88
89 if (!ops->set_vlan_ports)
90 return -EOPNOTSUPP;
91
92 for (i = 0; i < val->len; i++) {
93 if (ports[i].id >= dev->ports)
94 return -EINVAL;
95
96 if (ops->set_port_pvid &&
97 !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED)))
98 ops->set_port_pvid(dev, ports[i].id, val->port_vlan);
99 }
100
101 return ops->set_vlan_ports(dev, val);
102 }
103
104 static int
105 swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
106 {
107 if (val->port_vlan >= dev->ports)
108 return -EINVAL;
109
110 if (!dev->ops->set_port_pvid)
111 return -EOPNOTSUPP;
112
113 return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i);
114 }
115
116 static int
117 swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
118 {
119 if (val->port_vlan >= dev->ports)
120 return -EINVAL;
121
122 if (!dev->ops->get_port_pvid)
123 return -EOPNOTSUPP;
124
125 return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i);
126 }
127
128 static int
129 swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
130 {
131 /* don't complain if not supported by the switch driver */
132 if (!dev->ops->apply_config)
133 return 0;
134
135 return dev->ops->apply_config(dev);
136 }
137
138 static int
139 swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
140 {
141 /* don't complain if not supported by the switch driver */
142 if (!dev->ops->reset_switch)
143 return 0;
144
145 return dev->ops->reset_switch(dev);
146 }
147
148 enum global_defaults {
149 GLOBAL_APPLY,
150 GLOBAL_RESET,
151 };
152
153 enum vlan_defaults {
154 VLAN_PORTS,
155 };
156
157 enum port_defaults {
158 PORT_PVID,
159 };
160
161 static struct switch_attr default_global[] = {
162 [GLOBAL_APPLY] = {
163 .type = SWITCH_TYPE_NOVAL,
164 .name = "apply",
165 .description = "Activate changes in the hardware",
166 .set = swconfig_apply_config,
167 },
168 [GLOBAL_RESET] = {
169 .type = SWITCH_TYPE_NOVAL,
170 .name = "reset",
171 .description = "Reset the switch",
172 .set = swconfig_reset_switch,
173 }
174 };
175
176 static struct switch_attr default_port[] = {
177 [PORT_PVID] = {
178 .type = SWITCH_TYPE_INT,
179 .name = "pvid",
180 .description = "Primary VLAN ID",
181 .set = swconfig_set_pvid,
182 .get = swconfig_get_pvid,
183 }
184 };
185
186 static struct switch_attr default_vlan[] = {
187 [VLAN_PORTS] = {
188 .type = SWITCH_TYPE_PORTS,
189 .name = "ports",
190 .description = "VLAN port mapping",
191 .set = swconfig_set_vlan_ports,
192 .get = swconfig_get_vlan_ports,
193 },
194 };
195
196
197 static void swconfig_defaults_init(struct switch_dev *dev)
198 {
199 const struct switch_dev_ops *ops = dev->ops;
200
201 dev->def_global = 0;
202 dev->def_vlan = 0;
203 dev->def_port = 0;
204
205 if (ops->get_vlan_ports || ops->set_vlan_ports)
206 set_bit(VLAN_PORTS, &dev->def_vlan);
207
208 if (ops->get_port_pvid || ops->set_port_pvid)
209 set_bit(PORT_PVID, &dev->def_port);
210
211 /* always present, can be no-op */
212 set_bit(GLOBAL_APPLY, &dev->def_global);
213 set_bit(GLOBAL_RESET, &dev->def_global);
214 }
215
216
217 static struct genl_family switch_fam = {
218 .id = GENL_ID_GENERATE,
219 .name = "switch",
220 .hdrsize = 0,
221 .version = 1,
222 .maxattr = SWITCH_ATTR_MAX,
223 };
224
225 static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = {
226 [SWITCH_ATTR_ID] = { .type = NLA_U32 },
227 [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 },
228 [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 },
229 [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 },
230 [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 },
231 [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING },
232 [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED },
233 [SWITCH_ATTR_TYPE] = { .type = NLA_U32 },
234 };
235
236 static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = {
237 [SWITCH_PORT_ID] = { .type = NLA_U32 },
238 [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
239 };
240
241 static inline void
242 swconfig_lock(void)
243 {
244 spin_lock(&swdevs_lock);
245 }
246
247 static inline void
248 swconfig_unlock(void)
249 {
250 spin_unlock(&swdevs_lock);
251 }
252
253 static struct switch_dev *
254 swconfig_get_dev(struct genl_info *info)
255 {
256 struct switch_dev *dev = NULL;
257 struct switch_dev *p;
258 int id;
259
260 if (!info->attrs[SWITCH_ATTR_ID])
261 goto done;
262
263 id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]);
264 swconfig_lock();
265 list_for_each_entry(p, &swdevs, dev_list) {
266 if (id != p->id)
267 continue;
268
269 dev = p;
270 break;
271 }
272 if (dev)
273 spin_lock(&dev->lock);
274 else
275 DPRINTF("device %d not found\n", id);
276 swconfig_unlock();
277 done:
278 return dev;
279 }
280
281 static inline void
282 swconfig_put_dev(struct switch_dev *dev)
283 {
284 spin_unlock(&dev->lock);
285 }
286
287 static int
288 swconfig_dump_attr(struct swconfig_callback *cb, void *arg)
289 {
290 struct switch_attr *op = arg;
291 struct genl_info *info = cb->info;
292 struct sk_buff *msg = cb->msg;
293 int id = cb->args[0];
294 void *hdr;
295
296 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam,
297 NLM_F_MULTI, SWITCH_CMD_NEW_ATTR);
298 if (IS_ERR(hdr))
299 return -1;
300
301 NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, id);
302 NLA_PUT_U32(msg, SWITCH_ATTR_OP_TYPE, op->type);
303 NLA_PUT_STRING(msg, SWITCH_ATTR_OP_NAME, op->name);
304 if (op->description)
305 NLA_PUT_STRING(msg, SWITCH_ATTR_OP_DESCRIPTION,
306 op->description);
307
308 return genlmsg_end(msg, hdr);
309 nla_put_failure:
310 genlmsg_cancel(msg, hdr);
311 return -EMSGSIZE;
312 }
313
314 /* spread multipart messages across multiple message buffers */
315 static int
316 swconfig_send_multipart(struct swconfig_callback *cb, void *arg)
317 {
318 struct genl_info *info = cb->info;
319 int restart = 0;
320 int err;
321
322 do {
323 if (!cb->msg) {
324 cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
325 if (cb->msg == NULL)
326 goto error;
327 }
328
329 if (!(cb->fill(cb, arg) < 0))
330 break;
331
332 /* fill failed, check if this was already the second attempt */
333 if (restart)
334 goto error;
335
336 /* try again in a new message, send the current one */
337 restart = 1;
338 if (cb->close) {
339 if (cb->close(cb, arg) < 0)
340 goto error;
341 }
342 err = genlmsg_reply(cb->msg, info);
343 cb->msg = NULL;
344 if (err < 0)
345 goto error;
346
347 } while (restart);
348
349 return 0;
350
351 error:
352 if (cb->msg)
353 nlmsg_free(cb->msg);
354 return -1;
355 }
356
357 static int
358 swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info)
359 {
360 struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
361 const struct switch_attrlist *alist;
362 struct switch_dev *dev;
363 struct swconfig_callback cb;
364 int err = -EINVAL;
365 int i;
366
367 /* defaults */
368 struct switch_attr *def_list;
369 unsigned long *def_active;
370 int n_def;
371
372 dev = swconfig_get_dev(info);
373 if (!dev)
374 return -EINVAL;
375
376 switch(hdr->cmd) {
377 case SWITCH_CMD_LIST_GLOBAL:
378 alist = &dev->ops->attr_global;
379 def_list = default_global;
380 def_active = &dev->def_global;
381 n_def = ARRAY_SIZE(default_global);
382 break;
383 case SWITCH_CMD_LIST_VLAN:
384 alist = &dev->ops->attr_vlan;
385 def_list = default_vlan;
386 def_active = &dev->def_vlan;
387 n_def = ARRAY_SIZE(default_vlan);
388 break;
389 case SWITCH_CMD_LIST_PORT:
390 alist = &dev->ops->attr_port;
391 def_list = default_port;
392 def_active = &dev->def_port;
393 n_def = ARRAY_SIZE(default_port);
394 break;
395 default:
396 WARN_ON(1);
397 goto out;
398 }
399
400 memset(&cb, 0, sizeof(cb));
401 cb.info = info;
402 cb.fill = swconfig_dump_attr;
403 for (i = 0; i < alist->n_attr; i++) {
404 if (alist->attr[i].disabled)
405 continue;
406 cb.args[0] = i;
407 err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]);
408 if (err < 0)
409 goto error;
410 }
411
412 /* defaults */
413 for (i = 0; i < n_def; i++) {
414 if (!test_bit(i, def_active))
415 continue;
416 cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i;
417 err = swconfig_send_multipart(&cb, (void *) &def_list[i]);
418 if (err < 0)
419 goto error;
420 }
421 swconfig_put_dev(dev);
422
423 if (!cb.msg)
424 return 0;
425
426 return genlmsg_reply(cb.msg, info);
427
428 error:
429 if (cb.msg)
430 nlmsg_free(cb.msg);
431 out:
432 swconfig_put_dev(dev);
433 return err;
434 }
435
436 static const struct switch_attr *
437 swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info,
438 struct switch_val *val)
439 {
440 struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
441 const struct switch_attrlist *alist;
442 const struct switch_attr *attr = NULL;
443 int attr_id;
444
445 /* defaults */
446 struct switch_attr *def_list;
447 unsigned long *def_active;
448 int n_def;
449
450 if (!info->attrs[SWITCH_ATTR_OP_ID])
451 goto done;
452
453 switch(hdr->cmd) {
454 case SWITCH_CMD_SET_GLOBAL:
455 case SWITCH_CMD_GET_GLOBAL:
456 alist = &dev->ops->attr_global;
457 def_list = default_global;
458 def_active = &dev->def_global;
459 n_def = ARRAY_SIZE(default_global);
460 break;
461 case SWITCH_CMD_SET_VLAN:
462 case SWITCH_CMD_GET_VLAN:
463 alist = &dev->ops->attr_vlan;
464 def_list = default_vlan;
465 def_active = &dev->def_vlan;
466 n_def = ARRAY_SIZE(default_vlan);
467 if (!info->attrs[SWITCH_ATTR_OP_VLAN])
468 goto done;
469 val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]);
470 if (val->port_vlan >= dev->vlans)
471 goto done;
472 break;
473 case SWITCH_CMD_SET_PORT:
474 case SWITCH_CMD_GET_PORT:
475 alist = &dev->ops->attr_port;
476 def_list = default_port;
477 def_active = &dev->def_port;
478 n_def = ARRAY_SIZE(default_port);
479 if (!info->attrs[SWITCH_ATTR_OP_PORT])
480 goto done;
481 val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]);
482 if (val->port_vlan >= dev->ports)
483 goto done;
484 break;
485 default:
486 WARN_ON(1);
487 goto done;
488 }
489
490 if (!alist)
491 goto done;
492
493 attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]);
494 if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) {
495 attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET;
496 if (attr_id >= n_def)
497 goto done;
498 if (!test_bit(attr_id, def_active))
499 goto done;
500 attr = &def_list[attr_id];
501 } else {
502 if (attr_id >= alist->n_attr)
503 goto done;
504 attr = &alist->attr[attr_id];
505 }
506
507 if (attr->disabled)
508 attr = NULL;
509
510 done:
511 if (!attr)
512 DPRINTF("attribute lookup failed\n");
513 val->attr = attr;
514 return attr;
515 }
516
517 static int
518 swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head,
519 struct switch_val *val, int max)
520 {
521 struct nlattr *nla;
522 int rem;
523
524 val->len = 0;
525 nla_for_each_nested(nla, head, rem) {
526 struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
527 struct switch_port *port = &val->value.ports[val->len];
528
529 if (val->len >= max)
530 return -EINVAL;
531
532 if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla,
533 port_policy))
534 return -EINVAL;
535
536 if (!tb[SWITCH_PORT_ID])
537 return -EINVAL;
538
539 port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
540 if (tb[SWITCH_PORT_FLAG_TAGGED])
541 port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED);
542 val->len++;
543 }
544
545 return 0;
546 }
547
548 static int
549 swconfig_set_attr(struct sk_buff *skb, struct genl_info *info)
550 {
551 const struct switch_attr *attr;
552 struct switch_dev *dev;
553 struct switch_val val;
554 int err = -EINVAL;
555
556 dev = swconfig_get_dev(info);
557 if (!dev)
558 return -EINVAL;
559
560 memset(&val, 0, sizeof(val));
561 attr = swconfig_lookup_attr(dev, info, &val);
562 if (!attr || !attr->set)
563 goto error;
564
565 val.attr = attr;
566 switch(attr->type) {
567 case SWITCH_TYPE_NOVAL:
568 break;
569 case SWITCH_TYPE_INT:
570 if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT])
571 goto error;
572 val.value.i =
573 nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]);
574 break;
575 case SWITCH_TYPE_STRING:
576 if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR])
577 goto error;
578 val.value.s =
579 nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]);
580 break;
581 case SWITCH_TYPE_PORTS:
582 val.value.ports = dev->portbuf;
583 memset(dev->portbuf, 0,
584 sizeof(struct switch_port) * dev->ports);
585
586 /* TODO: implement multipart? */
587 if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) {
588 err = swconfig_parse_ports(skb,
589 info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], &val, dev->ports);
590 if (err < 0)
591 goto error;
592 } else {
593 val.len = 0;
594 err = 0;
595 }
596 break;
597 default:
598 goto error;
599 }
600
601 err = attr->set(dev, attr, &val);
602 error:
603 swconfig_put_dev(dev);
604 return err;
605 }
606
607 static int
608 swconfig_close_portlist(struct swconfig_callback *cb, void *arg)
609 {
610 if (cb->nest[0])
611 nla_nest_end(cb->msg, cb->nest[0]);
612 return 0;
613 }
614
615 static int
616 swconfig_send_port(struct swconfig_callback *cb, void *arg)
617 {
618 const struct switch_port *port = arg;
619 struct nlattr *p = NULL;
620
621 if (!cb->nest[0]) {
622 cb->nest[0] = nla_nest_start(cb->msg, cb->cmd);
623 if (!cb->nest[0])
624 return -1;
625 }
626
627 p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT);
628 if (!p)
629 goto error;
630
631 NLA_PUT_U32(cb->msg, SWITCH_PORT_ID, port->id);
632 if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
633 NLA_PUT_FLAG(cb->msg, SWITCH_PORT_FLAG_TAGGED);
634
635 nla_nest_end(cb->msg, p);
636 return 0;
637
638 nla_put_failure:
639 nla_nest_cancel(cb->msg, p);
640 error:
641 nla_nest_cancel(cb->msg, cb->nest[0]);
642 return -1;
643 }
644
645 static int
646 swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr,
647 const struct switch_val *val)
648 {
649 struct swconfig_callback cb;
650 int err = 0;
651 int i;
652
653 if (!val->value.ports)
654 return -EINVAL;
655
656 memset(&cb, 0, sizeof(cb));
657 cb.cmd = attr;
658 cb.msg = *msg;
659 cb.info = info;
660 cb.fill = swconfig_send_port;
661 cb.close = swconfig_close_portlist;
662
663 cb.nest[0] = nla_nest_start(cb.msg, cb.cmd);
664 for (i = 0; i < val->len; i++) {
665 err = swconfig_send_multipart(&cb, &val->value.ports[i]);
666 if (err)
667 goto done;
668 }
669 err = val->len;
670 swconfig_close_portlist(&cb, NULL);
671 *msg = cb.msg;
672
673 done:
674 return err;
675 }
676
677 static int
678 swconfig_get_attr(struct sk_buff *skb, struct genl_info *info)
679 {
680 struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
681 const struct switch_attr *attr;
682 struct switch_dev *dev;
683 struct sk_buff *msg = NULL;
684 struct switch_val val;
685 int err = -EINVAL;
686 int cmd = hdr->cmd;
687
688 dev = swconfig_get_dev(info);
689 if (!dev)
690 return -EINVAL;
691
692 memset(&val, 0, sizeof(val));
693 attr = swconfig_lookup_attr(dev, info, &val);
694 if (!attr || !attr->get)
695 goto error;
696
697 if (attr->type == SWITCH_TYPE_PORTS) {
698 val.value.ports = dev->portbuf;
699 memset(dev->portbuf, 0,
700 sizeof(struct switch_port) * dev->ports);
701 }
702
703 err = attr->get(dev, attr, &val);
704 if (err)
705 goto error;
706
707 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
708 if (!msg)
709 goto error;
710
711 hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam,
712 0, cmd);
713 if (IS_ERR(hdr))
714 goto nla_put_failure;
715
716 switch(attr->type) {
717 case SWITCH_TYPE_INT:
718 NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i);
719 break;
720 case SWITCH_TYPE_STRING:
721 NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s);
722 break;
723 case SWITCH_TYPE_PORTS:
724 err = swconfig_send_ports(&msg, info,
725 SWITCH_ATTR_OP_VALUE_PORTS, &val);
726 if (err < 0)
727 goto nla_put_failure;
728 break;
729 default:
730 DPRINTF("invalid type in attribute\n");
731 err = -EINVAL;
732 goto error;
733 }
734 err = genlmsg_end(msg, hdr);
735 if (err < 0)
736 goto nla_put_failure;
737
738 swconfig_put_dev(dev);
739 return genlmsg_reply(msg, info);
740
741 nla_put_failure:
742 if (msg)
743 nlmsg_free(msg);
744 error:
745 swconfig_put_dev(dev);
746 if (!err)
747 err = -ENOMEM;
748 return err;
749 }
750
751 static int
752 swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags,
753 const struct switch_dev *dev)
754 {
755 void *hdr;
756
757 hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags,
758 SWITCH_CMD_NEW_ATTR);
759 if (IS_ERR(hdr))
760 return -1;
761
762 NLA_PUT_U32(msg, SWITCH_ATTR_ID, dev->id);
763 NLA_PUT_STRING(msg, SWITCH_ATTR_NAME, dev->name);
764 NLA_PUT_STRING(msg, SWITCH_ATTR_DEV_NAME, dev->devname);
765 NLA_PUT_U32(msg, SWITCH_ATTR_VLANS, dev->vlans);
766 NLA_PUT_U32(msg, SWITCH_ATTR_PORTS, dev->ports);
767 NLA_PUT_U32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port);
768
769 return genlmsg_end(msg, hdr);
770 nla_put_failure:
771 genlmsg_cancel(msg, hdr);
772 return -EMSGSIZE;
773 }
774
775 static int swconfig_dump_switches(struct sk_buff *skb,
776 struct netlink_callback *cb)
777 {
778 struct switch_dev *dev;
779 int start = cb->args[0];
780 int idx = 0;
781
782 swconfig_lock();
783 list_for_each_entry(dev, &swdevs, dev_list) {
784 if (++idx <= start)
785 continue;
786 if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).pid,
787 cb->nlh->nlmsg_seq, NLM_F_MULTI,
788 dev) < 0)
789 break;
790 }
791 swconfig_unlock();
792 cb->args[0] = idx;
793
794 return skb->len;
795 }
796
797 static int
798 swconfig_done(struct netlink_callback *cb)
799 {
800 return 0;
801 }
802
803 static struct genl_ops swconfig_ops[] = {
804 {
805 .cmd = SWITCH_CMD_LIST_GLOBAL,
806 .doit = swconfig_list_attrs,
807 .policy = switch_policy,
808 },
809 {
810 .cmd = SWITCH_CMD_LIST_VLAN,
811 .doit = swconfig_list_attrs,
812 .policy = switch_policy,
813 },
814 {
815 .cmd = SWITCH_CMD_LIST_PORT,
816 .doit = swconfig_list_attrs,
817 .policy = switch_policy,
818 },
819 {
820 .cmd = SWITCH_CMD_GET_GLOBAL,
821 .doit = swconfig_get_attr,
822 .policy = switch_policy,
823 },
824 {
825 .cmd = SWITCH_CMD_GET_VLAN,
826 .doit = swconfig_get_attr,
827 .policy = switch_policy,
828 },
829 {
830 .cmd = SWITCH_CMD_GET_PORT,
831 .doit = swconfig_get_attr,
832 .policy = switch_policy,
833 },
834 {
835 .cmd = SWITCH_CMD_SET_GLOBAL,
836 .doit = swconfig_set_attr,
837 .policy = switch_policy,
838 },
839 {
840 .cmd = SWITCH_CMD_SET_VLAN,
841 .doit = swconfig_set_attr,
842 .policy = switch_policy,
843 },
844 {
845 .cmd = SWITCH_CMD_SET_PORT,
846 .doit = swconfig_set_attr,
847 .policy = switch_policy,
848 },
849 {
850 .cmd = SWITCH_CMD_GET_SWITCH,
851 .dumpit = swconfig_dump_switches,
852 .policy = switch_policy,
853 .done = swconfig_done,
854 }
855 };
856
857 int
858 register_switch(struct switch_dev *dev, struct net_device *netdev)
859 {
860 INIT_LIST_HEAD(&dev->dev_list);
861 if (netdev) {
862 dev->netdev = netdev;
863 if (!dev->devname)
864 dev->devname = netdev->name;
865 }
866 BUG_ON(!dev->devname);
867
868 if (dev->ports > 0) {
869 dev->portbuf = kzalloc(sizeof(struct switch_port) * dev->ports,
870 GFP_KERNEL);
871 if (!dev->portbuf)
872 return -ENOMEM;
873 }
874 dev->id = ++swdev_id;
875 swconfig_defaults_init(dev);
876 spin_lock_init(&dev->lock);
877 swconfig_lock();
878 list_add(&dev->dev_list, &swdevs);
879 swconfig_unlock();
880
881 return 0;
882 }
883 EXPORT_SYMBOL_GPL(register_switch);
884
885 void
886 unregister_switch(struct switch_dev *dev)
887 {
888 kfree(dev->portbuf);
889 spin_lock(&dev->lock);
890 swconfig_lock();
891 list_del(&dev->dev_list);
892 swconfig_unlock();
893 spin_unlock(&dev->lock);
894 }
895 EXPORT_SYMBOL_GPL(unregister_switch);
896
897
898 static int __init
899 swconfig_init(void)
900 {
901 int i, err;
902
903 INIT_LIST_HEAD(&swdevs);
904 err = genl_register_family(&switch_fam);
905 if (err)
906 return err;
907
908 for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) {
909 err = genl_register_ops(&switch_fam, &swconfig_ops[i]);
910 if (err)
911 goto unregister;
912 }
913
914 return 0;
915
916 unregister:
917 genl_unregister_family(&switch_fam);
918 return err;
919 }
920
921 static void __exit
922 swconfig_exit(void)
923 {
924 genl_unregister_family(&switch_fam);
925 }
926
927 module_init(swconfig_init);
928 module_exit(swconfig_exit);
929
This page took 0.076499 seconds and 5 git commands to generate.