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

Archive Download this file



interactive