summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/rose.h1
-rw-r--r--net/rose/af_rose.c102
-rw-r--r--net/rose/rose_dev.c88
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,
+};