forked from mirrors/linux
		
	mctp: Add device handling and netlink interface
This change adds the infrastructure for managing MCTP netdevices; we add a pointer to the AF_MCTP-specific data to struct netdevice, and hook up the rtnetlink operations for adding and removing addresses. Includes changes from Matt Johnston <matt@codeconstruct.com.au>. Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									4b2e69305c
								
							
						
					
					
						commit
						583be982d9
					
				
					 10 changed files with 491 additions and 1 deletions
				
			
		|  | @ -11039,6 +11039,7 @@ L:	netdev@vger.kernel.org | |||
| S:	Maintained | ||||
| F:	drivers/net/mctp/ | ||||
| F:	include/net/mctp.h | ||||
| F:	include/net/mctpdevice.h | ||||
| F:	net/mctp/ | ||||
| 
 | ||||
| MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7 | ||||
|  |  | |||
|  | @ -1823,6 +1823,7 @@ enum netdev_ml_priv_type { | |||
|  *	@ieee802154_ptr: IEEE 802.15.4 low-rate Wireless Personal Area Network | ||||
|  *			 device struct | ||||
|  *	@mpls_ptr:	mpls_dev struct pointer | ||||
|  *	@mctp_ptr:	MCTP specific data | ||||
|  * | ||||
|  *	@dev_addr:	Hw address (before bcast, | ||||
|  *			because most packets are unicast) | ||||
|  | @ -2110,6 +2111,9 @@ struct net_device { | |||
| #if IS_ENABLED(CONFIG_MPLS_ROUTING) | ||||
| 	struct mpls_dev __rcu	*mpls_ptr; | ||||
| #endif | ||||
| #if IS_ENABLED(CONFIG_MCTP) | ||||
| 	struct mctp_dev __rcu	*mctp_ptr; | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * Cache lines mostly used on receive path (including eth_type_trans()) | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #define __NET_MCTP_H | ||||
| 
 | ||||
| #include <linux/bits.h> | ||||
| #include <linux/mctp.h> | ||||
| 
 | ||||
| /* MCTP packet definitions */ | ||||
| struct mctp_hdr { | ||||
|  | @ -32,4 +33,17 @@ struct mctp_hdr { | |||
| #define MCTP_HDR_TAG_SHIFT	0 | ||||
| #define MCTP_HDR_TAG_MASK	GENMASK(2, 0) | ||||
| 
 | ||||
| static inline bool mctp_address_ok(mctp_eid_t eid) | ||||
| { | ||||
| 	return eid >= 8 && eid < 255; | ||||
| } | ||||
| 
 | ||||
| static inline struct mctp_hdr *mctp_hdr(struct sk_buff *skb) | ||||
| { | ||||
| 	return (struct mctp_hdr *)skb_network_header(skb); | ||||
| } | ||||
| 
 | ||||
| void mctp_device_init(void); | ||||
| void mctp_device_exit(void); | ||||
| 
 | ||||
| #endif /* __NET_MCTP_H */ | ||||
|  |  | |||
							
								
								
									
										35
									
								
								include/net/mctpdevice.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								include/net/mctpdevice.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | |||
| /* SPDX-License-Identifier: GPL-2.0 */ | ||||
| /*
 | ||||
|  * Management Component Transport Protocol (MCTP) - device | ||||
|  * definitions. | ||||
|  * | ||||
|  * Copyright (c) 2021 Code Construct | ||||
|  * Copyright (c) 2021 Google | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __NET_MCTPDEVICE_H | ||||
| #define __NET_MCTPDEVICE_H | ||||
| 
 | ||||
| #include <linux/list.h> | ||||
| #include <linux/types.h> | ||||
| #include <linux/refcount.h> | ||||
| 
 | ||||
| struct mctp_dev { | ||||
| 	struct net_device	*dev; | ||||
| 
 | ||||
| 	unsigned int		net; | ||||
| 
 | ||||
| 	/* Only modified under RTNL. Reads have addrs_lock held */ | ||||
| 	u8			*addrs; | ||||
| 	size_t			num_addrs; | ||||
| 	spinlock_t		addrs_lock; | ||||
| 
 | ||||
| 	struct rcu_head		rcu; | ||||
| }; | ||||
| 
 | ||||
| #define MCTP_INITIAL_DEFAULT_NET	1 | ||||
| 
 | ||||
| struct mctp_dev *mctp_dev_get_rtnl(const struct net_device *dev); | ||||
| struct mctp_dev *__mctp_dev_get(const struct net_device *dev); | ||||
| 
 | ||||
| #endif /* __NET_MCTPDEVICE_H */ | ||||
|  | @ -151,6 +151,9 @@ | |||
| #define ETH_P_MAP	0x00F9		/* Qualcomm multiplexing and | ||||
| 					 * aggregation protocol | ||||
| 					 */ | ||||
| #define ETH_P_MCTP	0x00FA		/* Management component transport | ||||
| 					 * protocol packets | ||||
| 					 */ | ||||
| 
 | ||||
| /*
 | ||||
|  *	This is an Ethernet frame header. | ||||
|  |  | |||
|  | @ -1260,4 +1260,14 @@ struct ifla_rmnet_flags { | |||
| 	__u32	mask; | ||||
| }; | ||||
| 
 | ||||
| /* MCTP section */ | ||||
| 
 | ||||
| enum { | ||||
| 	IFLA_MCTP_UNSPEC, | ||||
| 	IFLA_MCTP_NET, | ||||
| 	__IFLA_MCTP_MAX, | ||||
| }; | ||||
| 
 | ||||
| #define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1) | ||||
| 
 | ||||
| #endif /* _UAPI_LINUX_IF_LINK_H */ | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ struct sockaddr_mctp { | |||
| }; | ||||
| 
 | ||||
| #define MCTP_NET_ANY		0x0 | ||||
| #define MCTP_NET_DEFAULT	0x0 | ||||
| 
 | ||||
| #define MCTP_ADDR_NULL		0x00 | ||||
| #define MCTP_ADDR_ANY		0xff | ||||
|  |  | |||
|  | @ -1,3 +1,3 @@ | |||
| # SPDX-License-Identifier: GPL-2.0
 | ||||
| obj-$(CONFIG_MCTP) += mctp.o | ||||
| mctp-objs := af_mctp.o | ||||
| mctp-objs := af_mctp.o device.o | ||||
|  |  | |||
|  | @ -6,13 +6,18 @@ | |||
|  * Copyright (c) 2021 Google | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/if_arp.h> | ||||
| #include <linux/net.h> | ||||
| #include <linux/mctp.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/socket.h> | ||||
| 
 | ||||
| #include <net/mctp.h> | ||||
| #include <net/mctpdevice.h> | ||||
| #include <net/sock.h> | ||||
| 
 | ||||
| /* socket implementation */ | ||||
| 
 | ||||
| struct mctp_sock { | ||||
| 	struct sock	sk; | ||||
| }; | ||||
|  | @ -152,6 +157,8 @@ static __init int mctp_init(void) | |||
| 	if (rc) | ||||
| 		goto err_unreg_sock; | ||||
| 
 | ||||
| 	mctp_device_init(); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err_unreg_sock: | ||||
|  | @ -162,6 +169,7 @@ static __init int mctp_init(void) | |||
| 
 | ||||
| static __exit void mctp_exit(void) | ||||
| { | ||||
| 	mctp_device_exit(); | ||||
| 	proto_unregister(&mctp_proto); | ||||
| 	sock_unregister(PF_MCTP); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										414
									
								
								net/mctp/device.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								net/mctp/device.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,414 @@ | |||
| // SPDX-License-Identifier: GPL-2.0
 | ||||
| /*
 | ||||
|  * Management Component Transport Protocol (MCTP) - device implementation. | ||||
|  * | ||||
|  * Copyright (c) 2021 Code Construct | ||||
|  * Copyright (c) 2021 Google | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/if_link.h> | ||||
| #include <linux/mctp.h> | ||||
| #include <linux/netdevice.h> | ||||
| #include <linux/rcupdate.h> | ||||
| #include <linux/rtnetlink.h> | ||||
| 
 | ||||
| #include <net/addrconf.h> | ||||
| #include <net/netlink.h> | ||||
| #include <net/mctp.h> | ||||
| #include <net/mctpdevice.h> | ||||
| #include <net/sock.h> | ||||
| 
 | ||||
| struct mctp_dump_cb { | ||||
| 	int h; | ||||
| 	int idx; | ||||
| 	size_t a_idx; | ||||
| }; | ||||
| 
 | ||||
| /* unlocked: caller must hold rcu_read_lock */ | ||||
| struct mctp_dev *__mctp_dev_get(const struct net_device *dev) | ||||
| { | ||||
| 	return rcu_dereference(dev->mctp_ptr); | ||||
| } | ||||
| 
 | ||||
| struct mctp_dev *mctp_dev_get_rtnl(const struct net_device *dev) | ||||
| { | ||||
| 	return rtnl_dereference(dev->mctp_ptr); | ||||
| } | ||||
| 
 | ||||
| static void mctp_dev_destroy(struct mctp_dev *mdev) | ||||
| { | ||||
| 	struct net_device *dev = mdev->dev; | ||||
| 
 | ||||
| 	dev_put(dev); | ||||
| 	kfree_rcu(mdev, rcu); | ||||
| } | ||||
| 
 | ||||
| static int mctp_fill_addrinfo(struct sk_buff *skb, struct netlink_callback *cb, | ||||
| 			      struct mctp_dev *mdev, mctp_eid_t eid) | ||||
| { | ||||
| 	struct ifaddrmsg *hdr; | ||||
| 	struct nlmsghdr *nlh; | ||||
| 
 | ||||
| 	nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, | ||||
| 			RTM_NEWADDR, sizeof(*hdr), NLM_F_MULTI); | ||||
| 	if (!nlh) | ||||
| 		return -EMSGSIZE; | ||||
| 
 | ||||
| 	hdr = nlmsg_data(nlh); | ||||
| 	hdr->ifa_family = AF_MCTP; | ||||
| 	hdr->ifa_prefixlen = 0; | ||||
| 	hdr->ifa_flags = 0; | ||||
| 	hdr->ifa_scope = 0; | ||||
| 	hdr->ifa_index = mdev->dev->ifindex; | ||||
| 
 | ||||
| 	if (nla_put_u8(skb, IFA_LOCAL, eid)) | ||||
| 		goto cancel; | ||||
| 
 | ||||
| 	if (nla_put_u8(skb, IFA_ADDRESS, eid)) | ||||
| 		goto cancel; | ||||
| 
 | ||||
| 	nlmsg_end(skb, nlh); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| cancel: | ||||
| 	nlmsg_cancel(skb, nlh); | ||||
| 	return -EMSGSIZE; | ||||
| } | ||||
| 
 | ||||
| static int mctp_dump_dev_addrinfo(struct mctp_dev *mdev, struct sk_buff *skb, | ||||
| 				  struct netlink_callback *cb) | ||||
| { | ||||
| 	struct mctp_dump_cb *mcb = (void *)cb->ctx; | ||||
| 	int rc = 0; | ||||
| 
 | ||||
| 	for (; mcb->a_idx < mdev->num_addrs; mcb->a_idx++) { | ||||
| 		rc = mctp_fill_addrinfo(skb, cb, mdev, mdev->addrs[mcb->a_idx]); | ||||
| 		if (rc < 0) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	return rc; | ||||
| } | ||||
| 
 | ||||
| static int mctp_dump_addrinfo(struct sk_buff *skb, struct netlink_callback *cb) | ||||
| { | ||||
| 	struct mctp_dump_cb *mcb = (void *)cb->ctx; | ||||
| 	struct net *net = sock_net(skb->sk); | ||||
| 	struct hlist_head *head; | ||||
| 	struct net_device *dev; | ||||
| 	struct ifaddrmsg *hdr; | ||||
| 	struct mctp_dev *mdev; | ||||
| 	int ifindex; | ||||
| 	int idx, rc; | ||||
| 
 | ||||
| 	hdr = nlmsg_data(cb->nlh); | ||||
| 	// filter by ifindex if requested
 | ||||
| 	ifindex = hdr->ifa_index; | ||||
| 
 | ||||
| 	rcu_read_lock(); | ||||
| 	for (; mcb->h < NETDEV_HASHENTRIES; mcb->h++, mcb->idx = 0) { | ||||
| 		idx = 0; | ||||
| 		head = &net->dev_index_head[mcb->h]; | ||||
| 		hlist_for_each_entry_rcu(dev, head, index_hlist) { | ||||
| 			if (idx >= mcb->idx && | ||||
| 			    (ifindex == 0 || ifindex == dev->ifindex)) { | ||||
| 				mdev = __mctp_dev_get(dev); | ||||
| 				if (mdev) { | ||||
| 					rc = mctp_dump_dev_addrinfo(mdev, | ||||
| 								    skb, cb); | ||||
| 					// Error indicates full buffer, this
 | ||||
| 					// callback will get retried.
 | ||||
| 					if (rc < 0) | ||||
| 						goto out; | ||||
| 				} | ||||
| 			} | ||||
| 			idx++; | ||||
| 			// reset for next iteration
 | ||||
| 			mcb->a_idx = 0; | ||||
| 		} | ||||
| 	} | ||||
| out: | ||||
| 	rcu_read_unlock(); | ||||
| 	mcb->idx = idx; | ||||
| 
 | ||||
| 	return skb->len; | ||||
| } | ||||
| 
 | ||||
| static const struct nla_policy ifa_mctp_policy[IFA_MAX + 1] = { | ||||
| 	[IFA_ADDRESS]		= { .type = NLA_U8 }, | ||||
| 	[IFA_LOCAL]		= { .type = NLA_U8 }, | ||||
| }; | ||||
| 
 | ||||
| static int mctp_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, | ||||
| 			    struct netlink_ext_ack *extack) | ||||
| { | ||||
| 	struct net *net = sock_net(skb->sk); | ||||
| 	struct nlattr *tb[IFA_MAX + 1]; | ||||
| 	struct net_device *dev; | ||||
| 	struct mctp_addr *addr; | ||||
| 	struct mctp_dev *mdev; | ||||
| 	struct ifaddrmsg *ifm; | ||||
| 	unsigned long flags; | ||||
| 	u8 *tmp_addrs; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	rc = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_mctp_policy, | ||||
| 			 extack); | ||||
| 	if (rc < 0) | ||||
| 		return rc; | ||||
| 
 | ||||
| 	ifm = nlmsg_data(nlh); | ||||
| 
 | ||||
| 	if (tb[IFA_LOCAL]) | ||||
| 		addr = nla_data(tb[IFA_LOCAL]); | ||||
| 	else if (tb[IFA_ADDRESS]) | ||||
| 		addr = nla_data(tb[IFA_ADDRESS]); | ||||
| 	else | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* find device */ | ||||
| 	dev = __dev_get_by_index(net, ifm->ifa_index); | ||||
| 	if (!dev) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	mdev = mctp_dev_get_rtnl(dev); | ||||
| 	if (!mdev) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	if (!mctp_address_ok(addr->s_addr)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* Prevent duplicates. Under RTNL so don't need to lock for reading */ | ||||
| 	if (memchr(mdev->addrs, addr->s_addr, mdev->num_addrs)) | ||||
| 		return -EEXIST; | ||||
| 
 | ||||
| 	tmp_addrs = kmalloc(mdev->num_addrs + 1, GFP_KERNEL); | ||||
| 	if (!tmp_addrs) | ||||
| 		return -ENOMEM; | ||||
| 	memcpy(tmp_addrs, mdev->addrs, mdev->num_addrs); | ||||
| 	tmp_addrs[mdev->num_addrs] = addr->s_addr; | ||||
| 
 | ||||
| 	/* Lock to write */ | ||||
| 	spin_lock_irqsave(&mdev->addrs_lock, flags); | ||||
| 	mdev->num_addrs++; | ||||
| 	swap(mdev->addrs, tmp_addrs); | ||||
| 	spin_unlock_irqrestore(&mdev->addrs_lock, flags); | ||||
| 
 | ||||
| 	kfree(tmp_addrs); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int mctp_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, | ||||
| 			    struct netlink_ext_ack *extack) | ||||
| { | ||||
| 	struct net *net = sock_net(skb->sk); | ||||
| 	struct nlattr *tb[IFA_MAX + 1]; | ||||
| 	struct net_device *dev; | ||||
| 	struct mctp_addr *addr; | ||||
| 	struct mctp_dev *mdev; | ||||
| 	struct ifaddrmsg *ifm; | ||||
| 	unsigned long flags; | ||||
| 	u8 *pos; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	rc = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_mctp_policy, | ||||
| 			 extack); | ||||
| 	if (rc < 0) | ||||
| 		return rc; | ||||
| 
 | ||||
| 	ifm = nlmsg_data(nlh); | ||||
| 
 | ||||
| 	if (tb[IFA_LOCAL]) | ||||
| 		addr = nla_data(tb[IFA_LOCAL]); | ||||
| 	else if (tb[IFA_ADDRESS]) | ||||
| 		addr = nla_data(tb[IFA_ADDRESS]); | ||||
| 	else | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* find device */ | ||||
| 	dev = __dev_get_by_index(net, ifm->ifa_index); | ||||
| 	if (!dev) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	mdev = mctp_dev_get_rtnl(dev); | ||||
| 	if (!mdev) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	pos = memchr(mdev->addrs, addr->s_addr, mdev->num_addrs); | ||||
| 	if (!pos) | ||||
| 		return -ENOENT; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&mdev->addrs_lock, flags); | ||||
| 	memmove(pos, pos + 1, mdev->num_addrs - 1 - (pos - mdev->addrs)); | ||||
| 	mdev->num_addrs--; | ||||
| 	spin_unlock_irqrestore(&mdev->addrs_lock, flags); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct mctp_dev *mctp_add_dev(struct net_device *dev) | ||||
| { | ||||
| 	struct mctp_dev *mdev; | ||||
| 
 | ||||
| 	ASSERT_RTNL(); | ||||
| 
 | ||||
| 	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); | ||||
| 	if (!mdev) | ||||
| 		return ERR_PTR(-ENOMEM); | ||||
| 
 | ||||
| 	spin_lock_init(&mdev->addrs_lock); | ||||
| 
 | ||||
| 	mdev->net = MCTP_INITIAL_DEFAULT_NET; | ||||
| 
 | ||||
| 	/* associate to net_device */ | ||||
| 	rcu_assign_pointer(dev->mctp_ptr, mdev); | ||||
| 	dev_hold(dev); | ||||
| 	mdev->dev = dev; | ||||
| 
 | ||||
| 	return mdev; | ||||
| } | ||||
| 
 | ||||
| static int mctp_fill_link_af(struct sk_buff *skb, | ||||
| 			     const struct net_device *dev, u32 ext_filter_mask) | ||||
| { | ||||
| 	struct mctp_dev *mdev; | ||||
| 
 | ||||
| 	mdev = mctp_dev_get_rtnl(dev); | ||||
| 	if (!mdev) | ||||
| 		return -ENODATA; | ||||
| 	if (nla_put_u32(skb, IFLA_MCTP_NET, mdev->net)) | ||||
| 		return -EMSGSIZE; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static size_t mctp_get_link_af_size(const struct net_device *dev, | ||||
| 				    u32 ext_filter_mask) | ||||
| { | ||||
| 	struct mctp_dev *mdev; | ||||
| 	unsigned int ret; | ||||
| 
 | ||||
| 	/* caller holds RCU */ | ||||
| 	mdev = __mctp_dev_get(dev); | ||||
| 	if (!mdev) | ||||
| 		return 0; | ||||
| 	ret = nla_total_size(4); /* IFLA_MCTP_NET */ | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const struct nla_policy ifla_af_mctp_policy[IFLA_MCTP_MAX + 1] = { | ||||
| 	[IFLA_MCTP_NET]		= { .type = NLA_U32 }, | ||||
| }; | ||||
| 
 | ||||
| static int mctp_set_link_af(struct net_device *dev, const struct nlattr *attr, | ||||
| 			    struct netlink_ext_ack *extack) | ||||
| { | ||||
| 	struct nlattr *tb[IFLA_MCTP_MAX + 1]; | ||||
| 	struct mctp_dev *mdev; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	rc = nla_parse_nested(tb, IFLA_MCTP_MAX, attr, ifla_af_mctp_policy, | ||||
| 			      NULL); | ||||
| 	if (rc) | ||||
| 		return rc; | ||||
| 
 | ||||
| 	mdev = mctp_dev_get_rtnl(dev); | ||||
| 	if (!mdev) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (tb[IFLA_MCTP_NET]) | ||||
| 		WRITE_ONCE(mdev->net, nla_get_u32(tb[IFLA_MCTP_NET])); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void mctp_unregister(struct net_device *dev) | ||||
| { | ||||
| 	struct mctp_dev *mdev; | ||||
| 
 | ||||
| 	mdev = mctp_dev_get_rtnl(dev); | ||||
| 
 | ||||
| 	if (!mdev) | ||||
| 		return; | ||||
| 
 | ||||
| 	RCU_INIT_POINTER(mdev->dev->mctp_ptr, NULL); | ||||
| 
 | ||||
| 	kfree(mdev->addrs); | ||||
| 
 | ||||
| 	mctp_dev_destroy(mdev); | ||||
| } | ||||
| 
 | ||||
| static int mctp_register(struct net_device *dev) | ||||
| { | ||||
| 	struct mctp_dev *mdev; | ||||
| 
 | ||||
| 	/* Already registered? */ | ||||
| 	if (rtnl_dereference(dev->mctp_ptr)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* only register specific types; MCTP-specific and loopback for now */ | ||||
| 	if (dev->type != ARPHRD_MCTP && dev->type != ARPHRD_LOOPBACK) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	mdev = mctp_add_dev(dev); | ||||
| 	if (IS_ERR(mdev)) | ||||
| 		return PTR_ERR(mdev); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int mctp_dev_notify(struct notifier_block *this, unsigned long event, | ||||
| 			   void *ptr) | ||||
| { | ||||
| 	struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||||
| 	int rc; | ||||
| 
 | ||||
| 	switch (event) { | ||||
| 	case NETDEV_REGISTER: | ||||
| 		rc = mctp_register(dev); | ||||
| 		if (rc) | ||||
| 			return notifier_from_errno(rc); | ||||
| 		break; | ||||
| 	case NETDEV_UNREGISTER: | ||||
| 		mctp_unregister(dev); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	return NOTIFY_OK; | ||||
| } | ||||
| 
 | ||||
| static struct rtnl_af_ops mctp_af_ops = { | ||||
| 	.family = AF_MCTP, | ||||
| 	.fill_link_af = mctp_fill_link_af, | ||||
| 	.get_link_af_size = mctp_get_link_af_size, | ||||
| 	.set_link_af = mctp_set_link_af, | ||||
| }; | ||||
| 
 | ||||
| static struct notifier_block mctp_dev_nb = { | ||||
| 	.notifier_call = mctp_dev_notify, | ||||
| 	.priority = ADDRCONF_NOTIFY_PRIORITY, | ||||
| }; | ||||
| 
 | ||||
| void __init mctp_device_init(void) | ||||
| { | ||||
| 	register_netdevice_notifier(&mctp_dev_nb); | ||||
| 
 | ||||
| 	rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_GETADDR, | ||||
| 			     NULL, mctp_dump_addrinfo, 0); | ||||
| 	rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_NEWADDR, | ||||
| 			     mctp_rtm_newaddr, NULL, 0); | ||||
| 	rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_DELADDR, | ||||
| 			     mctp_rtm_deladdr, NULL, 0); | ||||
| 	rtnl_af_register(&mctp_af_ops); | ||||
| } | ||||
| 
 | ||||
| void __exit mctp_device_exit(void) | ||||
| { | ||||
| 	rtnl_af_unregister(&mctp_af_ops); | ||||
| 	rtnl_unregister(PF_MCTP, RTM_DELADDR); | ||||
| 	rtnl_unregister(PF_MCTP, RTM_NEWADDR); | ||||
| 	rtnl_unregister(PF_MCTP, RTM_GETADDR); | ||||
| 
 | ||||
| 	unregister_netdevice_notifier(&mctp_dev_nb); | ||||
| } | ||||
		Loading…
	
		Reference in a new issue
	
	 Jeremy Kerr
						Jeremy Kerr