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

Archive Download this file



interactive