diff options
-rw-r--r-- | include/net/netrom.h | 1 | ||||
-rw-r--r-- | net/netrom/af_netrom.c | 103 | ||||
-rw-r--r-- | net/netrom/nr_dev.c | 89 |
3 files changed, 108 insertions, 85 deletions
diff --git a/include/net/netrom.h b/include/net/netrom.h index 5a0714ff500f..004bd8c98326 100644 --- a/include/net/netrom.h +++ b/include/net/netrom.h @@ -192,6 +192,7 @@ void nr_destroy_socket(struct sock *); /* nr_dev.c */ int nr_rx_ip(struct sk_buff *, struct net_device *); void nr_setup(struct net_device *); +extern struct rtnl_link_ops nr_link_ops; /* nr_in.c */ int nr_process_rx_frame(struct sock *, struct sk_buff *); 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, +}; |