diff options
Diffstat (limited to 'net/netrom/nr_dev.c')
-rw-r--r-- | net/netrom/nr_dev.c | 89 |
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, +}; |