summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/netrom/af_netrom.c103
-rw-r--r--net/netrom/nr_dev.c89
2 files changed, 107 insertions, 85 deletions
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index cd1dca1f0df7..be99fc7679a2 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -44,8 +44,6 @@
#include <net/arp.h>
#include <linux/init.h>
-static int nr_ndevs = 4;
-
int sysctl_netrom_default_path_quality = NR_DEFAULT_QUAL;
int sysctl_netrom_obsolescence_count_initialiser = NR_DEFAULT_OBS;
int sysctl_netrom_network_ttl_initialiser = NR_DEFAULT_TTL;
@@ -67,28 +65,6 @@ static DEFINE_SPINLOCK(nr_list_lock);
static const struct proto_ops nr_proto_ops;
/*
- * NETROM network devices are virtual network devices encapsulating NETROM
- * 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 nr_netdev_xmit_lock_key;
-static struct lock_class_key nr_netdev_addr_lock_key;
-
-static void nr_set_lockdep_one(struct net_device *dev,
- struct netdev_queue *txq,
- void *_unused)
-{
- lockdep_set_class(&txq->_xmit_lock, &nr_netdev_xmit_lock_key);
-}
-
-static void nr_set_lockdep_key(struct net_device *dev)
-{
- lockdep_set_class(&dev->addr_list_lock, &nr_netdev_addr_lock_key);
- netdev_for_each_tx_queue(dev, nr_set_lockdep_one, NULL);
-}
-
-/*
* Socket removal during an interrupt is now safe.
*/
static void nr_remove_socket(struct sock *sk)
@@ -1376,8 +1352,6 @@ static struct notifier_block nr_dev_notifier = {
.notifier_call = nr_device_event,
};
-static struct net_device **dev_nr;
-
static struct ax25_protocol nr_pid = {
.pid = AX25_P_NETROM,
.func = nr_route_frame
@@ -1389,47 +1363,19 @@ static struct ax25_linkfail nr_linkfail_notifier = {
static int __init nr_proto_init(void)
{
- int i;
- int rc = proto_register(&nr_proto, 0);
+ int err;
- if (rc != 0)
+ err = proto_register(&nr_proto, 0);
+ if (err)
goto out;
- if (nr_ndevs > 0x7fffffff/sizeof(struct net_device *)) {
- printk(KERN_ERR "NET/ROM: nr_proto_init - nr_ndevs parameter to large\n");
- return -1;
- }
-
- dev_nr = kcalloc(nr_ndevs, sizeof(struct net_device *), GFP_KERNEL);
- if (dev_nr == NULL) {
- printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device array\n");
- return -1;
- }
-
- for (i = 0; i < nr_ndevs; i++) {
- char name[IFNAMSIZ];
- struct net_device *dev;
-
- sprintf(name, "nr%d", i);
- dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, nr_setup);
- if (!dev) {
- printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n");
- goto fail;
- }
-
- dev->base_addr = i;
- if (register_netdev(dev)) {
- printk(KERN_ERR "NET/ROM: nr_proto_init - unable to register network device\n");
- free_netdev(dev);
- goto fail;
- }
- nr_set_lockdep_key(dev);
- dev_nr[i] = dev;
- }
+ err = rtnl_link_register(&nr_link_ops);
+ if (err)
+ goto out_unregister_proto;
if (sock_register(&nr_family_ops)) {
printk(KERN_ERR "NET/ROM: nr_proto_init - unable to register socket family\n");
- goto fail;
+ goto out_rtnl_link_unregister;
}
register_netdevice_notifier(&nr_dev_notifier);
@@ -1446,23 +1392,21 @@ static int __init nr_proto_init(void)
proc_create_seq("nr", 0444, init_net.proc_net, &nr_info_seqops);
proc_create_seq("nr_neigh", 0444, init_net.proc_net, &nr_neigh_seqops);
proc_create_seq("nr_nodes", 0444, init_net.proc_net, &nr_node_seqops);
-out:
- return rc;
-fail:
- while (--i >= 0) {
- unregister_netdev(dev_nr[i]);
- free_netdev(dev_nr[i]);
- }
- kfree(dev_nr);
+
+ return 0;
+
+out_rtnl_link_unregister:
+ rtnl_link_unregister(&nr_link_ops);
+
+out_unregister_proto:
proto_unregister(&nr_proto);
- rc = -1;
- goto out;
+
+out:
+ return err;
}
static void __exit nr_exit(void)
{
- int i;
-
remove_proc_entry("nr", init_net.proc_net);
remove_proc_entry("nr_neigh", init_net.proc_net);
remove_proc_entry("nr_nodes", init_net.proc_net);
@@ -1481,24 +1425,13 @@ static void __exit nr_exit(void)
sock_unregister(PF_NETROM);
- for (i = 0; i < nr_ndevs; i++) {
- struct net_device *dev = dev_nr[i];
- if (dev) {
- unregister_netdev(dev);
- free_netdev(dev);
- }
- }
-
- kfree(dev_nr);
+ rtnl_link_unregister(&nr_link_ops);
proto_unregister(&nr_proto);
}
module_init(nr_proto_init);
module_exit(nr_exit);
-module_param(nr_ndevs, int, 0);
-MODULE_PARM_DESC(nr_ndevs, "number of NET/ROM devices");
-
MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The amateur radio NET/ROM network and transport layer protocol");
MODULE_LICENSE("GPL");
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 988f542481a8..3dc192317005 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -37,6 +37,28 @@
#include <net/netrom.h>
/*
+ * NETROM network devices are virtual network devices encapsulating NETROM
+ * 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 nr_netdev_xmit_lock_key;
+static struct lock_class_key nr_netdev_addr_lock_key;
+
+static void nr_set_lockdep_one(struct net_device *dev,
+ struct netdev_queue *txq,
+ void *_unused)
+{
+ lockdep_set_class(&txq->_xmit_lock, &nr_netdev_xmit_lock_key);
+}
+
+static void nr_set_lockdep_key(struct net_device *dev)
+{
+ lockdep_set_class(&dev->addr_list_lock, &nr_netdev_addr_lock_key);
+ netdev_for_each_tx_queue(dev, nr_set_lockdep_one, NULL);
+}
+
+/*
* Only allow IP over NET/ROM frames through if the netrom device is up.
*/
@@ -171,6 +193,8 @@ void nr_setup(struct net_device *dev)
{
dev->mtu = NR_MAX_PACKET_SIZE;
dev->netdev_ops = &nr_netdev_ops;
+ //dev->destructor = free_netdev;
+
dev->header_ops = &nr_header_ops;
dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
dev->addr_len = AX25_ADDR_LEN;
@@ -179,3 +203,68 @@ void nr_setup(struct net_device *dev)
/* New-style flags. */
dev->flags = IFF_NOARP;
}
+
+static struct device_type nr_type = {
+ .name = "netrom",
+};
+
+static int nr_validate(struct nlattr *tb[], struct nlattr *data[],
+ struct netlink_ext_ack *extack)
+{
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != AX25_ADDR_LEN) {
+ NL_SET_ERR_MSG_MOD(extack, "Invalid link address");
+ return -EINVAL;
+ }
+
+ if (!ax25_address_is_valid((void *)nla_data(tb[IFLA_ADDRESS]))) {
+ NL_SET_ERR_MSG_MOD(extack, "Invalid link address");
+ return -EADDRNOTAVAIL;
+ }
+ }
+
+ return 0;
+}
+
+static int nr_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, &nr_type);
+
+ err = register_netdevice(dev);
+ if (err)
+ return err;
+
+ nr_set_lockdep_key(dev);
+
+ return 0;
+}
+
+static void nr_dellink(struct net_device *dev, struct list_head *head)
+{
+ unregister_netdevice(dev);
+}
+
+static size_t nr_get_size(const struct net_device *dev)
+{
+ return nla_total_size(AX25_ADDR_LEN) + /* IFLA_ADDRESS */
+ 0;
+}
+
+struct rtnl_link_ops nr_link_ops __read_mostly = {
+ .kind = "netrom",
+ .priv_size = sizeof(struct net_device),
+ .setup = nr_setup,
+ .maxtype = 0,
+ .policy = NULL,
+ .validate = nr_validate,
+ .newlink = nr_newlink,
+ .changelink = NULL,
+ .dellink = nr_dellink,
+ .get_size = nr_get_size,
+ .fill_info = NULL,
+ .get_link_net = NULL,
+};