summaryrefslogtreecommitdiffstats
path: root/net/netrom/nr_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netrom/nr_dev.c')
-rw-r--r--net/netrom/nr_dev.c89
1 files changed, 89 insertions, 0 deletions
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,
+};