diff options
-rw-r--r-- | include/net/rose.h | 1 | ||||
-rw-r--r-- | net/rose/af_rose.c | 102 | ||||
-rw-r--r-- | net/rose/rose_dev.c | 88 |
3 files changed, 101 insertions, 90 deletions
diff --git a/include/net/rose.h b/include/net/rose.h index 4c3033a9484b..d030acf851c6 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -176,6 +176,7 @@ void rose_destroy_socket(struct sock *); /* rose_dev.c */ void rose_setup(struct net_device *); +extern struct rtnl_link_ops rose_link_ops; /* rose_in.c */ int rose_process_rx_frame(struct sock *, struct sk_buff *); diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 576846eaee1d..794bab4ab818 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -48,8 +48,6 @@ #include <net/ip.h> #include <net/arp.h> -static int rose_ndevs = 10; - int sysctl_rose_restart_request_timeout = ROSE_DEFAULT_T0; int sysctl_rose_call_request_timeout = ROSE_DEFAULT_T1; int sysctl_rose_reset_request_timeout = ROSE_DEFAULT_T2; @@ -69,28 +67,6 @@ static const struct proto_ops rose_proto_ops; ax25_address rose_callsign; /* - * ROSE network devices are virtual network devices encapsulating ROSE - * frames into AX.25 which will be sent through an AX.25 device, so form a - * special "super class" of normal net devices; split their locks off into a - * separate class since they always nest. - */ -static struct lock_class_key rose_netdev_xmit_lock_key; -static struct lock_class_key rose_netdev_addr_lock_key; - -static void rose_set_lockdep_one(struct net_device *dev, - struct netdev_queue *txq, - void *_unused) -{ - lockdep_set_class(&txq->_xmit_lock, &rose_netdev_xmit_lock_key); -} - -static void rose_set_lockdep_key(struct net_device *dev) -{ - lockdep_set_class(&dev->addr_list_lock, &rose_netdev_addr_lock_key); - netdev_for_each_tx_queue(dev, rose_set_lockdep_one, NULL); -} - -/* * Convert a ROSE address into text. */ char *rose2asc(char *buf, const rose_address *addr) @@ -1526,8 +1502,6 @@ static struct notifier_block rose_dev_notifier = { .notifier_call = rose_device_event, }; -static struct net_device **dev_rose; - static struct ax25_protocol rose_pid = { .pid = AX25_P_ROSE, .func = rose_route_frame @@ -1539,50 +1513,18 @@ static struct ax25_linkfail rose_linkfail_notifier = { static int __init rose_proto_init(void) { - int i; - int rc; + int err; - if (rose_ndevs > 0x7FFFFFFF/sizeof(struct net_device *)) { - pr_err("ROSE: rose_proto_init - rose_ndevs parameter to large\n"); - rc = -EINVAL; - goto out; - } + err = proto_register(&rose_proto, 0); + if (err) + return err; - rc = proto_register(&rose_proto, 0); - if (rc != 0) - goto out; + err = rtnl_link_register(&rose_link_ops); + if (err) + goto rtnl_link_failed; rose_callsign = null_ax25_address; - dev_rose = kcalloc(rose_ndevs, sizeof(struct net_device *), - GFP_KERNEL); - if (dev_rose == NULL) { - pr_err("ROSE: rose_proto_init - unable to allocate device structure\n"); - rc = -ENOMEM; - goto out_proto_unregister; - } - - for (i = 0; i < rose_ndevs; i++) { - struct net_device *dev; - char name[IFNAMSIZ]; - - sprintf(name, "rose%d", i); - dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, rose_setup); - if (!dev) { - pr_err("ROSE: rose_proto_init - unable to allocate memory\n"); - rc = -ENOMEM; - goto fail; - } - rc = register_netdev(dev); - if (rc) { - pr_err("ROSE: netdevice registration failed\n"); - free_netdev(dev); - goto fail; - } - rose_set_lockdep_key(dev); - dev_rose[i] = dev; - } - sock_register(&rose_family_ops); register_netdevice_notifier(&rose_dev_notifier); @@ -1603,23 +1545,15 @@ static int __init rose_proto_init(void) &rose_node_seqops); proc_create_seq("rose_routes", 0444, init_net.proc_net, &rose_route_seqops); -out: - return rc; -fail: - while (--i >= 0) { - unregister_netdev(dev_rose[i]); - free_netdev(dev_rose[i]); - } - kfree(dev_rose); -out_proto_unregister: + +rtnl_link_failed: proto_unregister(&rose_proto); - goto out; + + return err; } static void __exit rose_exit(void) { - int i; - remove_proc_entry("rose", init_net.proc_net); remove_proc_entry("rose_neigh", init_net.proc_net); remove_proc_entry("rose_nodes", init_net.proc_net); @@ -1641,25 +1575,13 @@ static void __exit rose_exit(void) sock_unregister(PF_ROSE); - for (i = 0; i < rose_ndevs; i++) { - struct net_device *dev = dev_rose[i]; - - if (dev) { - unregister_netdev(dev); - free_netdev(dev); - } - } - - kfree(dev_rose); + rtnl_link_unregister(&rose_link_ops); proto_unregister(&rose_proto); } module_init(rose_proto_init); module_exit(rose_exit); -module_param(rose_ndevs, int, 0); -MODULE_PARM_DESC(rose_ndevs, "number of ROSE devices"); - MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>"); MODULE_DESCRIPTION("The amateur radio ROSE network layer protocol"); MODULE_LICENSE("GPL"); diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c index ef22440d07eb..92ff400d2449 100644 --- a/net/rose/rose_dev.c +++ b/net/rose/rose_dev.c @@ -33,6 +33,28 @@ #include <net/ax25.h> #include <net/rose.h> +/* + * ROSE network devices are virtual network devices encapsulating ROSE + * frames into AX.25 which will be sent through an AX.25 device, so form a + * special "super class" of normal net devices; split their locks off into a + * separate class since they always nest. + */ +static struct lock_class_key rose_netdev_xmit_lock_key; +static struct lock_class_key rose_netdev_addr_lock_key; + +static void rose_set_lockdep_one(struct net_device *dev, + struct netdev_queue *txq, + void *_unused) +{ + lockdep_set_class(&txq->_xmit_lock, &rose_netdev_xmit_lock_key); +} + +static void rose_set_lockdep_key(struct net_device *dev) +{ + lockdep_set_class(&dev->addr_list_lock, &rose_netdev_addr_lock_key); + netdev_for_each_tx_queue(dev, rose_set_lockdep_one, NULL); +} + static int rose_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, const void *saddr, unsigned int len) @@ -131,6 +153,7 @@ void rose_setup(struct net_device *dev) { dev->mtu = ROSE_MAX_PACKET_SIZE - 2; dev->netdev_ops = &rose_netdev_ops; + //dev->destructor = free_netdev; dev->header_ops = &rose_header_ops; dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; @@ -140,3 +163,68 @@ void rose_setup(struct net_device *dev) /* New-style flags. */ dev->flags = IFF_NOARP; } + +static struct device_type rose_type = { + .name = "rose", +}; + +static int rose_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ROSE_ADDR_LEN) { + NL_SET_ERR_MSG_MOD(extack, "Invalid link address"); + return -EINVAL; + } + + if (!rose_address_is_valid((void *)nla_data(tb[IFLA_ADDRESS]))) { + NL_SET_ERR_MSG_MOD(extack, "Invalid link address"); + return -EADDRNOTAVAIL; + } + } + + return 0; +} + +static int rose_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +{ + int err; + + SET_NETDEV_DEVTYPE(dev, &rose_type); + + err = register_netdevice(dev); + if (err) + return err; + + rose_set_lockdep_key(dev); + + return 0; +} + +static void rose_dellink(struct net_device *dev, struct list_head *head) +{ + unregister_netdevice(dev); +} + +static size_t rose_get_size(const struct net_device *dev) +{ + return nla_total_size(ROSE_ADDR_LEN) + /* IFLA_ADDRESS */ + 0; +} + +struct rtnl_link_ops rose_link_ops __read_mostly = { + .kind = "rose", + .priv_size = sizeof(struct net_device), + .setup = rose_setup, + .maxtype = 0, + .policy = NULL, + .validate = rose_validate, + .newlink = rose_newlink, + .changelink = NULL, + .dellink = rose_dellink, + .get_size = rose_get_size, + .fill_info = NULL, + .get_link_net = NULL, +}; |