cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

af_mctp.c (15585B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Management Component Transport Protocol (MCTP)
      4 *
      5 * Copyright (c) 2021 Code Construct
      6 * Copyright (c) 2021 Google
      7 */
      8
      9#include <linux/compat.h>
     10#include <linux/if_arp.h>
     11#include <linux/net.h>
     12#include <linux/mctp.h>
     13#include <linux/module.h>
     14#include <linux/socket.h>
     15
     16#include <net/mctp.h>
     17#include <net/mctpdevice.h>
     18#include <net/sock.h>
     19
     20#define CREATE_TRACE_POINTS
     21#include <trace/events/mctp.h>
     22
     23/* socket implementation */
     24
     25static void mctp_sk_expire_keys(struct timer_list *timer);
     26
     27static int mctp_release(struct socket *sock)
     28{
     29	struct sock *sk = sock->sk;
     30
     31	if (sk) {
     32		sock->sk = NULL;
     33		sk->sk_prot->close(sk, 0);
     34	}
     35
     36	return 0;
     37}
     38
     39/* Generic sockaddr checks, padding checks only so far */
     40static bool mctp_sockaddr_is_ok(const struct sockaddr_mctp *addr)
     41{
     42	return !addr->__smctp_pad0 && !addr->__smctp_pad1;
     43}
     44
     45static bool mctp_sockaddr_ext_is_ok(const struct sockaddr_mctp_ext *addr)
     46{
     47	return !addr->__smctp_pad0[0] &&
     48	       !addr->__smctp_pad0[1] &&
     49	       !addr->__smctp_pad0[2];
     50}
     51
     52static int mctp_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
     53{
     54	struct sock *sk = sock->sk;
     55	struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
     56	struct sockaddr_mctp *smctp;
     57	int rc;
     58
     59	if (addrlen < sizeof(*smctp))
     60		return -EINVAL;
     61
     62	if (addr->sa_family != AF_MCTP)
     63		return -EAFNOSUPPORT;
     64
     65	if (!capable(CAP_NET_BIND_SERVICE))
     66		return -EACCES;
     67
     68	/* it's a valid sockaddr for MCTP, cast and do protocol checks */
     69	smctp = (struct sockaddr_mctp *)addr;
     70
     71	if (!mctp_sockaddr_is_ok(smctp))
     72		return -EINVAL;
     73
     74	lock_sock(sk);
     75
     76	/* TODO: allow rebind */
     77	if (sk_hashed(sk)) {
     78		rc = -EADDRINUSE;
     79		goto out_release;
     80	}
     81	msk->bind_net = smctp->smctp_network;
     82	msk->bind_addr = smctp->smctp_addr.s_addr;
     83	msk->bind_type = smctp->smctp_type & 0x7f; /* ignore the IC bit */
     84
     85	rc = sk->sk_prot->hash(sk);
     86
     87out_release:
     88	release_sock(sk);
     89
     90	return rc;
     91}
     92
     93static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
     94{
     95	DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name);
     96	int rc, addrlen = msg->msg_namelen;
     97	struct sock *sk = sock->sk;
     98	struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
     99	struct mctp_skb_cb *cb;
    100	struct mctp_route *rt;
    101	struct sk_buff *skb = NULL;
    102	int hlen;
    103
    104	if (addr) {
    105		const u8 tagbits = MCTP_TAG_MASK | MCTP_TAG_OWNER |
    106			MCTP_TAG_PREALLOC;
    107
    108		if (addrlen < sizeof(struct sockaddr_mctp))
    109			return -EINVAL;
    110		if (addr->smctp_family != AF_MCTP)
    111			return -EINVAL;
    112		if (!mctp_sockaddr_is_ok(addr))
    113			return -EINVAL;
    114		if (addr->smctp_tag & ~tagbits)
    115			return -EINVAL;
    116		/* can't preallocate a non-owned tag */
    117		if (addr->smctp_tag & MCTP_TAG_PREALLOC &&
    118		    !(addr->smctp_tag & MCTP_TAG_OWNER))
    119			return -EINVAL;
    120
    121	} else {
    122		/* TODO: connect()ed sockets */
    123		return -EDESTADDRREQ;
    124	}
    125
    126	if (!capable(CAP_NET_RAW))
    127		return -EACCES;
    128
    129	if (addr->smctp_network == MCTP_NET_ANY)
    130		addr->smctp_network = mctp_default_net(sock_net(sk));
    131
    132	/* direct addressing */
    133	if (msk->addr_ext && addrlen >= sizeof(struct sockaddr_mctp_ext)) {
    134		DECLARE_SOCKADDR(struct sockaddr_mctp_ext *,
    135				 extaddr, msg->msg_name);
    136		struct net_device *dev;
    137
    138		rc = -EINVAL;
    139		rcu_read_lock();
    140		dev = dev_get_by_index_rcu(sock_net(sk), extaddr->smctp_ifindex);
    141		/* check for correct halen */
    142		if (dev && extaddr->smctp_halen == dev->addr_len) {
    143			hlen = LL_RESERVED_SPACE(dev) + sizeof(struct mctp_hdr);
    144			rc = 0;
    145		}
    146		rcu_read_unlock();
    147		if (rc)
    148			goto err_free;
    149		rt = NULL;
    150	} else {
    151		rt = mctp_route_lookup(sock_net(sk), addr->smctp_network,
    152				       addr->smctp_addr.s_addr);
    153		if (!rt) {
    154			rc = -EHOSTUNREACH;
    155			goto err_free;
    156		}
    157		hlen = LL_RESERVED_SPACE(rt->dev->dev) + sizeof(struct mctp_hdr);
    158	}
    159
    160	skb = sock_alloc_send_skb(sk, hlen + 1 + len,
    161				  msg->msg_flags & MSG_DONTWAIT, &rc);
    162	if (!skb)
    163		return rc;
    164
    165	skb_reserve(skb, hlen);
    166
    167	/* set type as fist byte in payload */
    168	*(u8 *)skb_put(skb, 1) = addr->smctp_type;
    169
    170	rc = memcpy_from_msg((void *)skb_put(skb, len), msg, len);
    171	if (rc < 0)
    172		goto err_free;
    173
    174	/* set up cb */
    175	cb = __mctp_cb(skb);
    176	cb->net = addr->smctp_network;
    177
    178	if (!rt) {
    179		/* fill extended address in cb */
    180		DECLARE_SOCKADDR(struct sockaddr_mctp_ext *,
    181				 extaddr, msg->msg_name);
    182
    183		if (!mctp_sockaddr_ext_is_ok(extaddr) ||
    184		    extaddr->smctp_halen > sizeof(cb->haddr)) {
    185			rc = -EINVAL;
    186			goto err_free;
    187		}
    188
    189		cb->ifindex = extaddr->smctp_ifindex;
    190		/* smctp_halen is checked above */
    191		cb->halen = extaddr->smctp_halen;
    192		memcpy(cb->haddr, extaddr->smctp_haddr, cb->halen);
    193	}
    194
    195	rc = mctp_local_output(sk, rt, skb, addr->smctp_addr.s_addr,
    196			       addr->smctp_tag);
    197
    198	return rc ? : len;
    199
    200err_free:
    201	kfree_skb(skb);
    202	return rc;
    203}
    204
    205static int mctp_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
    206			int flags)
    207{
    208	DECLARE_SOCKADDR(struct sockaddr_mctp *, addr, msg->msg_name);
    209	struct sock *sk = sock->sk;
    210	struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
    211	struct sk_buff *skb;
    212	size_t msglen;
    213	u8 type;
    214	int rc;
    215
    216	if (flags & ~(MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK))
    217		return -EOPNOTSUPP;
    218
    219	skb = skb_recv_datagram(sk, flags, &rc);
    220	if (!skb)
    221		return rc;
    222
    223	if (!skb->len) {
    224		rc = 0;
    225		goto out_free;
    226	}
    227
    228	/* extract message type, remove from data */
    229	type = *((u8 *)skb->data);
    230	msglen = skb->len - 1;
    231
    232	if (len < msglen)
    233		msg->msg_flags |= MSG_TRUNC;
    234	else
    235		len = msglen;
    236
    237	rc = skb_copy_datagram_msg(skb, 1, msg, len);
    238	if (rc < 0)
    239		goto out_free;
    240
    241	sock_recv_cmsgs(msg, sk, skb);
    242
    243	if (addr) {
    244		struct mctp_skb_cb *cb = mctp_cb(skb);
    245		/* TODO: expand mctp_skb_cb for header fields? */
    246		struct mctp_hdr *hdr = mctp_hdr(skb);
    247
    248		addr = msg->msg_name;
    249		addr->smctp_family = AF_MCTP;
    250		addr->__smctp_pad0 = 0;
    251		addr->smctp_network = cb->net;
    252		addr->smctp_addr.s_addr = hdr->src;
    253		addr->smctp_type = type;
    254		addr->smctp_tag = hdr->flags_seq_tag &
    255					(MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO);
    256		addr->__smctp_pad1 = 0;
    257		msg->msg_namelen = sizeof(*addr);
    258
    259		if (msk->addr_ext) {
    260			DECLARE_SOCKADDR(struct sockaddr_mctp_ext *, ae,
    261					 msg->msg_name);
    262			msg->msg_namelen = sizeof(*ae);
    263			ae->smctp_ifindex = cb->ifindex;
    264			ae->smctp_halen = cb->halen;
    265			memset(ae->__smctp_pad0, 0x0, sizeof(ae->__smctp_pad0));
    266			memset(ae->smctp_haddr, 0x0, sizeof(ae->smctp_haddr));
    267			memcpy(ae->smctp_haddr, cb->haddr, cb->halen);
    268		}
    269	}
    270
    271	rc = len;
    272
    273	if (flags & MSG_TRUNC)
    274		rc = msglen;
    275
    276out_free:
    277	skb_free_datagram(sk, skb);
    278	return rc;
    279}
    280
    281/* We're done with the key; invalidate, stop reassembly, and remove from lists.
    282 */
    283static void __mctp_key_remove(struct mctp_sk_key *key, struct net *net,
    284			      unsigned long flags, unsigned long reason)
    285__releases(&key->lock)
    286__must_hold(&net->mctp.keys_lock)
    287{
    288	struct sk_buff *skb;
    289
    290	trace_mctp_key_release(key, reason);
    291	skb = key->reasm_head;
    292	key->reasm_head = NULL;
    293	key->reasm_dead = true;
    294	key->valid = false;
    295	mctp_dev_release_key(key->dev, key);
    296	spin_unlock_irqrestore(&key->lock, flags);
    297
    298	hlist_del(&key->hlist);
    299	hlist_del(&key->sklist);
    300
    301	/* unref for the lists */
    302	mctp_key_unref(key);
    303
    304	kfree_skb(skb);
    305}
    306
    307static int mctp_setsockopt(struct socket *sock, int level, int optname,
    308			   sockptr_t optval, unsigned int optlen)
    309{
    310	struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk);
    311	int val;
    312
    313	if (level != SOL_MCTP)
    314		return -EINVAL;
    315
    316	if (optname == MCTP_OPT_ADDR_EXT) {
    317		if (optlen != sizeof(int))
    318			return -EINVAL;
    319		if (copy_from_sockptr(&val, optval, sizeof(int)))
    320			return -EFAULT;
    321		msk->addr_ext = val;
    322		return 0;
    323	}
    324
    325	return -ENOPROTOOPT;
    326}
    327
    328static int mctp_getsockopt(struct socket *sock, int level, int optname,
    329			   char __user *optval, int __user *optlen)
    330{
    331	struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk);
    332	int len, val;
    333
    334	if (level != SOL_MCTP)
    335		return -EINVAL;
    336
    337	if (get_user(len, optlen))
    338		return -EFAULT;
    339
    340	if (optname == MCTP_OPT_ADDR_EXT) {
    341		if (len != sizeof(int))
    342			return -EINVAL;
    343		val = !!msk->addr_ext;
    344		if (copy_to_user(optval, &val, len))
    345			return -EFAULT;
    346		return 0;
    347	}
    348
    349	return -EINVAL;
    350}
    351
    352static int mctp_ioctl_alloctag(struct mctp_sock *msk, unsigned long arg)
    353{
    354	struct net *net = sock_net(&msk->sk);
    355	struct mctp_sk_key *key = NULL;
    356	struct mctp_ioc_tag_ctl ctl;
    357	unsigned long flags;
    358	u8 tag;
    359
    360	if (copy_from_user(&ctl, (void __user *)arg, sizeof(ctl)))
    361		return -EFAULT;
    362
    363	if (ctl.tag)
    364		return -EINVAL;
    365
    366	if (ctl.flags)
    367		return -EINVAL;
    368
    369	key = mctp_alloc_local_tag(msk, ctl.peer_addr, MCTP_ADDR_ANY,
    370				   true, &tag);
    371	if (IS_ERR(key))
    372		return PTR_ERR(key);
    373
    374	ctl.tag = tag | MCTP_TAG_OWNER | MCTP_TAG_PREALLOC;
    375	if (copy_to_user((void __user *)arg, &ctl, sizeof(ctl))) {
    376		spin_lock_irqsave(&key->lock, flags);
    377		__mctp_key_remove(key, net, flags, MCTP_TRACE_KEY_DROPPED);
    378		mctp_key_unref(key);
    379		return -EFAULT;
    380	}
    381
    382	mctp_key_unref(key);
    383	return 0;
    384}
    385
    386static int mctp_ioctl_droptag(struct mctp_sock *msk, unsigned long arg)
    387{
    388	struct net *net = sock_net(&msk->sk);
    389	struct mctp_ioc_tag_ctl ctl;
    390	unsigned long flags, fl2;
    391	struct mctp_sk_key *key;
    392	struct hlist_node *tmp;
    393	int rc;
    394	u8 tag;
    395
    396	if (copy_from_user(&ctl, (void __user *)arg, sizeof(ctl)))
    397		return -EFAULT;
    398
    399	if (ctl.flags)
    400		return -EINVAL;
    401
    402	/* Must be a local tag, TO set, preallocated */
    403	if ((ctl.tag & ~MCTP_TAG_MASK) != (MCTP_TAG_OWNER | MCTP_TAG_PREALLOC))
    404		return -EINVAL;
    405
    406	tag = ctl.tag & MCTP_TAG_MASK;
    407	rc = -EINVAL;
    408
    409	spin_lock_irqsave(&net->mctp.keys_lock, flags);
    410	hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) {
    411		/* we do an irqsave here, even though we know the irq state,
    412		 * so we have the flags to pass to __mctp_key_remove
    413		 */
    414		spin_lock_irqsave(&key->lock, fl2);
    415		if (key->manual_alloc &&
    416		    ctl.peer_addr == key->peer_addr &&
    417		    tag == key->tag) {
    418			__mctp_key_remove(key, net, fl2,
    419					  MCTP_TRACE_KEY_DROPPED);
    420			rc = 0;
    421		} else {
    422			spin_unlock_irqrestore(&key->lock, fl2);
    423		}
    424	}
    425	spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
    426
    427	return rc;
    428}
    429
    430static int mctp_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
    431{
    432	struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk);
    433
    434	switch (cmd) {
    435	case SIOCMCTPALLOCTAG:
    436		return mctp_ioctl_alloctag(msk, arg);
    437	case SIOCMCTPDROPTAG:
    438		return mctp_ioctl_droptag(msk, arg);
    439	}
    440
    441	return -EINVAL;
    442}
    443
    444#ifdef CONFIG_COMPAT
    445static int mctp_compat_ioctl(struct socket *sock, unsigned int cmd,
    446			     unsigned long arg)
    447{
    448	void __user *argp = compat_ptr(arg);
    449
    450	switch (cmd) {
    451	/* These have compatible ptr layouts */
    452	case SIOCMCTPALLOCTAG:
    453	case SIOCMCTPDROPTAG:
    454		return mctp_ioctl(sock, cmd, (unsigned long)argp);
    455	}
    456
    457	return -ENOIOCTLCMD;
    458}
    459#endif
    460
    461static const struct proto_ops mctp_dgram_ops = {
    462	.family		= PF_MCTP,
    463	.release	= mctp_release,
    464	.bind		= mctp_bind,
    465	.connect	= sock_no_connect,
    466	.socketpair	= sock_no_socketpair,
    467	.accept		= sock_no_accept,
    468	.getname	= sock_no_getname,
    469	.poll		= datagram_poll,
    470	.ioctl		= mctp_ioctl,
    471	.gettstamp	= sock_gettstamp,
    472	.listen		= sock_no_listen,
    473	.shutdown	= sock_no_shutdown,
    474	.setsockopt	= mctp_setsockopt,
    475	.getsockopt	= mctp_getsockopt,
    476	.sendmsg	= mctp_sendmsg,
    477	.recvmsg	= mctp_recvmsg,
    478	.mmap		= sock_no_mmap,
    479	.sendpage	= sock_no_sendpage,
    480#ifdef CONFIG_COMPAT
    481	.compat_ioctl	= mctp_compat_ioctl,
    482#endif
    483};
    484
    485static void mctp_sk_expire_keys(struct timer_list *timer)
    486{
    487	struct mctp_sock *msk = container_of(timer, struct mctp_sock,
    488					     key_expiry);
    489	struct net *net = sock_net(&msk->sk);
    490	unsigned long next_expiry, flags, fl2;
    491	struct mctp_sk_key *key;
    492	struct hlist_node *tmp;
    493	bool next_expiry_valid = false;
    494
    495	spin_lock_irqsave(&net->mctp.keys_lock, flags);
    496
    497	hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) {
    498		/* don't expire. manual_alloc is immutable, no locking
    499		 * required.
    500		 */
    501		if (key->manual_alloc)
    502			continue;
    503
    504		spin_lock_irqsave(&key->lock, fl2);
    505		if (!time_after_eq(key->expiry, jiffies)) {
    506			__mctp_key_remove(key, net, fl2,
    507					  MCTP_TRACE_KEY_TIMEOUT);
    508			continue;
    509		}
    510
    511		if (next_expiry_valid) {
    512			if (time_before(key->expiry, next_expiry))
    513				next_expiry = key->expiry;
    514		} else {
    515			next_expiry = key->expiry;
    516			next_expiry_valid = true;
    517		}
    518		spin_unlock_irqrestore(&key->lock, fl2);
    519	}
    520
    521	spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
    522
    523	if (next_expiry_valid)
    524		mod_timer(timer, next_expiry);
    525}
    526
    527static int mctp_sk_init(struct sock *sk)
    528{
    529	struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
    530
    531	INIT_HLIST_HEAD(&msk->keys);
    532	timer_setup(&msk->key_expiry, mctp_sk_expire_keys, 0);
    533	return 0;
    534}
    535
    536static void mctp_sk_close(struct sock *sk, long timeout)
    537{
    538	struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
    539
    540	del_timer_sync(&msk->key_expiry);
    541	sk_common_release(sk);
    542}
    543
    544static int mctp_sk_hash(struct sock *sk)
    545{
    546	struct net *net = sock_net(sk);
    547
    548	mutex_lock(&net->mctp.bind_lock);
    549	sk_add_node_rcu(sk, &net->mctp.binds);
    550	mutex_unlock(&net->mctp.bind_lock);
    551
    552	return 0;
    553}
    554
    555static void mctp_sk_unhash(struct sock *sk)
    556{
    557	struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
    558	struct net *net = sock_net(sk);
    559	unsigned long flags, fl2;
    560	struct mctp_sk_key *key;
    561	struct hlist_node *tmp;
    562
    563	/* remove from any type-based binds */
    564	mutex_lock(&net->mctp.bind_lock);
    565	sk_del_node_init_rcu(sk);
    566	mutex_unlock(&net->mctp.bind_lock);
    567
    568	/* remove tag allocations */
    569	spin_lock_irqsave(&net->mctp.keys_lock, flags);
    570	hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) {
    571		spin_lock_irqsave(&key->lock, fl2);
    572		__mctp_key_remove(key, net, fl2, MCTP_TRACE_KEY_CLOSED);
    573	}
    574	spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
    575}
    576
    577static struct proto mctp_proto = {
    578	.name		= "MCTP",
    579	.owner		= THIS_MODULE,
    580	.obj_size	= sizeof(struct mctp_sock),
    581	.init		= mctp_sk_init,
    582	.close		= mctp_sk_close,
    583	.hash		= mctp_sk_hash,
    584	.unhash		= mctp_sk_unhash,
    585};
    586
    587static int mctp_pf_create(struct net *net, struct socket *sock,
    588			  int protocol, int kern)
    589{
    590	const struct proto_ops *ops;
    591	struct proto *proto;
    592	struct sock *sk;
    593	int rc;
    594
    595	if (protocol)
    596		return -EPROTONOSUPPORT;
    597
    598	/* only datagram sockets are supported */
    599	if (sock->type != SOCK_DGRAM)
    600		return -ESOCKTNOSUPPORT;
    601
    602	proto = &mctp_proto;
    603	ops = &mctp_dgram_ops;
    604
    605	sock->state = SS_UNCONNECTED;
    606	sock->ops = ops;
    607
    608	sk = sk_alloc(net, PF_MCTP, GFP_KERNEL, proto, kern);
    609	if (!sk)
    610		return -ENOMEM;
    611
    612	sock_init_data(sock, sk);
    613
    614	rc = 0;
    615	if (sk->sk_prot->init)
    616		rc = sk->sk_prot->init(sk);
    617
    618	if (rc)
    619		goto err_sk_put;
    620
    621	return 0;
    622
    623err_sk_put:
    624	sock_orphan(sk);
    625	sock_put(sk);
    626	return rc;
    627}
    628
    629static struct net_proto_family mctp_pf = {
    630	.family = PF_MCTP,
    631	.create = mctp_pf_create,
    632	.owner = THIS_MODULE,
    633};
    634
    635static __init int mctp_init(void)
    636{
    637	int rc;
    638
    639	/* ensure our uapi tag definitions match the header format */
    640	BUILD_BUG_ON(MCTP_TAG_OWNER != MCTP_HDR_FLAG_TO);
    641	BUILD_BUG_ON(MCTP_TAG_MASK != MCTP_HDR_TAG_MASK);
    642
    643	pr_info("mctp: management component transport protocol core\n");
    644
    645	rc = sock_register(&mctp_pf);
    646	if (rc)
    647		return rc;
    648
    649	rc = proto_register(&mctp_proto, 0);
    650	if (rc)
    651		goto err_unreg_sock;
    652
    653	rc = mctp_routes_init();
    654	if (rc)
    655		goto err_unreg_proto;
    656
    657	rc = mctp_neigh_init();
    658	if (rc)
    659		goto err_unreg_proto;
    660
    661	mctp_device_init();
    662
    663	return 0;
    664
    665err_unreg_proto:
    666	proto_unregister(&mctp_proto);
    667err_unreg_sock:
    668	sock_unregister(PF_MCTP);
    669
    670	return rc;
    671}
    672
    673static __exit void mctp_exit(void)
    674{
    675	mctp_device_exit();
    676	mctp_neigh_exit();
    677	mctp_routes_exit();
    678	proto_unregister(&mctp_proto);
    679	sock_unregister(PF_MCTP);
    680}
    681
    682subsys_initcall(mctp_init);
    683module_exit(mctp_exit);
    684
    685MODULE_DESCRIPTION("MCTP core");
    686MODULE_LICENSE("GPL v2");
    687MODULE_AUTHOR("Jeremy Kerr <jk@codeconstruct.com.au>");
    688
    689MODULE_ALIAS_NETPROTO(PF_MCTP);