2021-07-29 05:20:39 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Management Component Transport Protocol ( MCTP )
*
* Copyright ( c ) 2021 Code Construct
* Copyright ( c ) 2021 Google
*/
2022-02-09 07:05:57 +03:00
# include <linux/compat.h>
2021-07-29 05:20:44 +03:00
# include <linux/if_arp.h>
2021-07-29 05:20:40 +03:00
# include <linux/net.h>
# include <linux/mctp.h>
2021-07-29 05:20:39 +03:00
# include <linux/module.h>
2021-07-29 05:20:40 +03:00
# include <linux/socket.h>
2021-07-29 05:20:44 +03:00
# include <net/mctp.h>
# include <net/mctpdevice.h>
2021-07-29 05:20:40 +03:00
# include <net/sock.h>
2021-09-29 10:26:10 +03:00
# define CREATE_TRACE_POINTS
# include <trace/events/mctp.h>
2021-07-29 05:20:44 +03:00
/* socket implementation */
2022-02-09 07:05:57 +03:00
static void mctp_sk_expire_keys ( struct timer_list * timer ) ;
2021-07-29 05:20:40 +03:00
static int mctp_release ( struct socket * sock )
{
struct sock * sk = sock - > sk ;
if ( sk ) {
sock - > sk = NULL ;
sk - > sk_prot - > close ( sk , 0 ) ;
}
return 0 ;
}
2021-11-03 22:09:42 +03:00
/* Generic sockaddr checks, padding checks only so far */
static bool mctp_sockaddr_is_ok ( const struct sockaddr_mctp * addr )
{
return ! addr - > __smctp_pad0 & & ! addr - > __smctp_pad1 ;
}
2021-11-03 22:09:46 +03:00
static bool mctp_sockaddr_ext_is_ok ( const struct sockaddr_mctp_ext * addr )
{
return ! addr - > __smctp_pad0 [ 0 ] & &
! addr - > __smctp_pad0 [ 1 ] & &
! addr - > __smctp_pad0 [ 2 ] ;
}
2021-07-29 05:20:40 +03:00
static int mctp_bind ( struct socket * sock , struct sockaddr * addr , int addrlen )
{
2021-07-29 05:20:49 +03:00
struct sock * sk = sock - > sk ;
struct mctp_sock * msk = container_of ( sk , struct mctp_sock , sk ) ;
struct sockaddr_mctp * smctp ;
int rc ;
if ( addrlen < sizeof ( * smctp ) )
return - EINVAL ;
if ( addr - > sa_family ! = AF_MCTP )
return - EAFNOSUPPORT ;
if ( ! capable ( CAP_NET_BIND_SERVICE ) )
return - EACCES ;
/* it's a valid sockaddr for MCTP, cast and do protocol checks */
smctp = ( struct sockaddr_mctp * ) addr ;
2021-11-03 22:09:42 +03:00
if ( ! mctp_sockaddr_is_ok ( smctp ) )
return - EINVAL ;
2021-07-29 05:20:49 +03:00
lock_sock ( sk ) ;
/* TODO: allow rebind */
if ( sk_hashed ( sk ) ) {
rc = - EADDRINUSE ;
goto out_release ;
}
msk - > bind_net = smctp - > smctp_network ;
msk - > bind_addr = smctp - > smctp_addr . s_addr ;
msk - > bind_type = smctp - > smctp_type & 0x7f ; /* ignore the IC bit */
rc = sk - > sk_prot - > hash ( sk ) ;
out_release :
release_sock ( sk ) ;
return rc ;
2021-07-29 05:20:40 +03:00
}
static int mctp_sendmsg ( struct socket * sock , struct msghdr * msg , size_t len )
{
2021-07-29 05:20:49 +03:00
DECLARE_SOCKADDR ( struct sockaddr_mctp * , addr , msg - > msg_name ) ;
int rc , addrlen = msg - > msg_namelen ;
struct sock * sk = sock - > sk ;
2021-10-26 04:57:28 +03:00
struct mctp_sock * msk = container_of ( sk , struct mctp_sock , sk ) ;
2021-07-29 05:20:49 +03:00
struct mctp_skb_cb * cb ;
struct mctp_route * rt ;
2022-04-01 05:48:44 +03:00
struct sk_buff * skb = NULL ;
int hlen ;
2021-07-29 05:20:49 +03:00
if ( addr ) {
2022-02-09 07:05:57 +03:00
const u8 tagbits = MCTP_TAG_MASK | MCTP_TAG_OWNER |
MCTP_TAG_PREALLOC ;
2021-07-29 05:20:49 +03:00
if ( addrlen < sizeof ( struct sockaddr_mctp ) )
return - EINVAL ;
if ( addr - > smctp_family ! = AF_MCTP )
return - EINVAL ;
2021-11-03 22:09:42 +03:00
if ( ! mctp_sockaddr_is_ok ( addr ) )
return - EINVAL ;
2022-02-09 07:05:57 +03:00
if ( addr - > smctp_tag & ~ tagbits )
return - EINVAL ;
/* can't preallocate a non-owned tag */
if ( addr - > smctp_tag & MCTP_TAG_PREALLOC & &
! ( addr - > smctp_tag & MCTP_TAG_OWNER ) )
2021-07-29 05:20:49 +03:00
return - EINVAL ;
} else {
/* TODO: connect()ed sockets */
return - EDESTADDRREQ ;
}
if ( ! capable ( CAP_NET_RAW ) )
return - EACCES ;
2021-07-29 05:20:52 +03:00
if ( addr - > smctp_network = = MCTP_NET_ANY )
addr - > smctp_network = mctp_default_net ( sock_net ( sk ) ) ;
2022-04-01 05:48:44 +03:00
/* direct addressing */
if ( msk - > addr_ext & & addrlen > = sizeof ( struct sockaddr_mctp_ext ) ) {
DECLARE_SOCKADDR ( struct sockaddr_mctp_ext * ,
extaddr , msg - > msg_name ) ;
struct net_device * dev ;
rc = - EINVAL ;
rcu_read_lock ( ) ;
dev = dev_get_by_index_rcu ( sock_net ( sk ) , extaddr - > smctp_ifindex ) ;
/* check for correct halen */
if ( dev & & extaddr - > smctp_halen = = dev - > addr_len ) {
hlen = LL_RESERVED_SPACE ( dev ) + sizeof ( struct mctp_hdr ) ;
rc = 0 ;
}
rcu_read_unlock ( ) ;
if ( rc )
goto err_free ;
rt = NULL ;
} else {
rt = mctp_route_lookup ( sock_net ( sk ) , addr - > smctp_network ,
addr - > smctp_addr . s_addr ) ;
if ( ! rt ) {
rc = - EHOSTUNREACH ;
goto err_free ;
}
hlen = LL_RESERVED_SPACE ( rt - > dev - > dev ) + sizeof ( struct mctp_hdr ) ;
}
2021-07-29 05:20:49 +03:00
skb = sock_alloc_send_skb ( sk , hlen + 1 + len ,
msg - > msg_flags & MSG_DONTWAIT , & rc ) ;
if ( ! skb )
return rc ;
skb_reserve ( skb , hlen ) ;
/* set type as fist byte in payload */
* ( u8 * ) skb_put ( skb , 1 ) = addr - > smctp_type ;
rc = memcpy_from_msg ( ( void * ) skb_put ( skb , len ) , msg , len ) ;
2021-10-26 04:57:28 +03:00
if ( rc < 0 )
goto err_free ;
2021-07-29 05:20:49 +03:00
/* set up cb */
cb = __mctp_cb ( skb ) ;
cb - > net = addr - > smctp_network ;
2022-04-01 05:48:44 +03:00
if ( ! rt ) {
/* fill extended address in cb */
2021-10-26 04:57:28 +03:00
DECLARE_SOCKADDR ( struct sockaddr_mctp_ext * ,
extaddr , msg - > msg_name ) ;
2021-11-03 22:09:46 +03:00
if ( ! mctp_sockaddr_ext_is_ok ( extaddr ) | |
extaddr - > smctp_halen > sizeof ( cb - > haddr ) ) {
2021-10-26 04:57:28 +03:00
rc = - EINVAL ;
goto err_free ;
}
cb - > ifindex = extaddr - > smctp_ifindex ;
2022-04-01 05:48:44 +03:00
/* smctp_halen is checked above */
2021-10-26 04:57:28 +03:00
cb - > halen = extaddr - > smctp_halen ;
memcpy ( cb - > haddr , extaddr - > smctp_haddr , cb - > halen ) ;
}
2021-07-29 05:20:49 +03:00
rc = mctp_local_output ( sk , rt , skb , addr - > smctp_addr . s_addr ,
addr - > smctp_tag ) ;
return rc ? : len ;
2021-10-26 04:57:28 +03:00
err_free :
kfree_skb ( skb ) ;
return rc ;
2021-07-29 05:20:40 +03:00
}
static int mctp_recvmsg ( struct socket * sock , struct msghdr * msg , size_t len ,
int flags )
{
2021-07-29 05:20:49 +03:00
DECLARE_SOCKADDR ( struct sockaddr_mctp * , addr , msg - > msg_name ) ;
struct sock * sk = sock - > sk ;
2021-10-26 04:57:28 +03:00
struct mctp_sock * msk = container_of ( sk , struct mctp_sock , sk ) ;
2021-07-29 05:20:49 +03:00
struct sk_buff * skb ;
size_t msglen ;
u8 type ;
int rc ;
if ( flags & ~ ( MSG_DONTWAIT | MSG_TRUNC | MSG_PEEK ) )
return - EOPNOTSUPP ;
2022-04-04 19:30:22 +03:00
skb = skb_recv_datagram ( sk , flags , & rc ) ;
2021-07-29 05:20:49 +03:00
if ( ! skb )
return rc ;
if ( ! skb - > len ) {
rc = 0 ;
goto out_free ;
}
/* extract message type, remove from data */
type = * ( ( u8 * ) skb - > data ) ;
msglen = skb - > len - 1 ;
if ( len < msglen )
msg - > msg_flags | = MSG_TRUNC ;
else
len = msglen ;
rc = skb_copy_datagram_msg ( skb , 1 , msg , len ) ;
if ( rc < 0 )
goto out_free ;
2022-04-27 23:02:37 +03:00
sock_recv_cmsgs ( msg , sk , skb ) ;
2021-07-29 05:20:49 +03:00
if ( addr ) {
struct mctp_skb_cb * cb = mctp_cb ( skb ) ;
/* TODO: expand mctp_skb_cb for header fields? */
struct mctp_hdr * hdr = mctp_hdr ( skb ) ;
addr = msg - > msg_name ;
addr - > smctp_family = AF_MCTP ;
2021-11-03 22:09:42 +03:00
addr - > __smctp_pad0 = 0 ;
2021-07-29 05:20:49 +03:00
addr - > smctp_network = cb - > net ;
addr - > smctp_addr . s_addr = hdr - > src ;
addr - > smctp_type = type ;
addr - > smctp_tag = hdr - > flags_seq_tag &
( MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO ) ;
2021-11-03 22:09:42 +03:00
addr - > __smctp_pad1 = 0 ;
2021-07-29 05:20:49 +03:00
msg - > msg_namelen = sizeof ( * addr ) ;
2021-10-26 04:57:28 +03:00
if ( msk - > addr_ext ) {
DECLARE_SOCKADDR ( struct sockaddr_mctp_ext * , ae ,
msg - > msg_name ) ;
msg - > msg_namelen = sizeof ( * ae ) ;
ae - > smctp_ifindex = cb - > ifindex ;
ae - > smctp_halen = cb - > halen ;
2021-11-03 22:09:46 +03:00
memset ( ae - > __smctp_pad0 , 0x0 , sizeof ( ae - > __smctp_pad0 ) ) ;
2021-10-26 04:57:28 +03:00
memset ( ae - > smctp_haddr , 0x0 , sizeof ( ae - > smctp_haddr ) ) ;
memcpy ( ae - > smctp_haddr , cb - > haddr , cb - > halen ) ;
}
2021-07-29 05:20:49 +03:00
}
rc = len ;
if ( flags & MSG_TRUNC )
rc = msglen ;
out_free :
skb_free_datagram ( sk , skb ) ;
return rc ;
2021-07-29 05:20:40 +03:00
}
2022-02-09 07:05:57 +03:00
/* We're done with the key; invalidate, stop reassembly, and remove from lists.
*/
static void __mctp_key_remove ( struct mctp_sk_key * key , struct net * net ,
unsigned long flags , unsigned long reason )
__releases ( & key - > lock )
__must_hold ( & net - > mctp . keys_lock )
{
struct sk_buff * skb ;
trace_mctp_key_release ( key , reason ) ;
skb = key - > reasm_head ;
key - > reasm_head = NULL ;
key - > reasm_dead = true ;
key - > valid = false ;
mctp_dev_release_key ( key - > dev , key ) ;
spin_unlock_irqrestore ( & key - > lock , flags ) ;
hlist_del ( & key - > hlist ) ;
hlist_del ( & key - > sklist ) ;
/* unref for the lists */
mctp_key_unref ( key ) ;
kfree_skb ( skb ) ;
}
2021-07-29 05:20:40 +03:00
static int mctp_setsockopt ( struct socket * sock , int level , int optname ,
sockptr_t optval , unsigned int optlen )
{
2021-10-26 04:57:28 +03:00
struct mctp_sock * msk = container_of ( sock - > sk , struct mctp_sock , sk ) ;
int val ;
if ( level ! = SOL_MCTP )
return - EINVAL ;
if ( optname = = MCTP_OPT_ADDR_EXT ) {
if ( optlen ! = sizeof ( int ) )
return - EINVAL ;
if ( copy_from_sockptr ( & val , optval , sizeof ( int ) ) )
return - EFAULT ;
msk - > addr_ext = val ;
return 0 ;
}
return - ENOPROTOOPT ;
2021-07-29 05:20:40 +03:00
}
static int mctp_getsockopt ( struct socket * sock , int level , int optname ,
char __user * optval , int __user * optlen )
{
2021-10-26 04:57:28 +03:00
struct mctp_sock * msk = container_of ( sock - > sk , struct mctp_sock , sk ) ;
int len , val ;
if ( level ! = SOL_MCTP )
return - EINVAL ;
if ( get_user ( len , optlen ) )
return - EFAULT ;
if ( optname = = MCTP_OPT_ADDR_EXT ) {
if ( len ! = sizeof ( int ) )
return - EINVAL ;
val = ! ! msk - > addr_ext ;
if ( copy_to_user ( optval , & val , len ) )
return - EFAULT ;
return 0 ;
}
2021-07-29 05:20:40 +03:00
return - EINVAL ;
}
2022-02-09 07:05:57 +03:00
static int mctp_ioctl_alloctag ( struct mctp_sock * msk , unsigned long arg )
{
struct net * net = sock_net ( & msk - > sk ) ;
struct mctp_sk_key * key = NULL ;
struct mctp_ioc_tag_ctl ctl ;
unsigned long flags ;
u8 tag ;
if ( copy_from_user ( & ctl , ( void __user * ) arg , sizeof ( ctl ) ) )
return - EFAULT ;
if ( ctl . tag )
return - EINVAL ;
if ( ctl . flags )
return - EINVAL ;
key = mctp_alloc_local_tag ( msk , ctl . peer_addr , MCTP_ADDR_ANY ,
true , & tag ) ;
if ( IS_ERR ( key ) )
return PTR_ERR ( key ) ;
ctl . tag = tag | MCTP_TAG_OWNER | MCTP_TAG_PREALLOC ;
if ( copy_to_user ( ( void __user * ) arg , & ctl , sizeof ( ctl ) ) ) {
spin_lock_irqsave ( & key - > lock , flags ) ;
__mctp_key_remove ( key , net , flags , MCTP_TRACE_KEY_DROPPED ) ;
mctp_key_unref ( key ) ;
return - EFAULT ;
}
mctp_key_unref ( key ) ;
return 0 ;
}
static int mctp_ioctl_droptag ( struct mctp_sock * msk , unsigned long arg )
{
struct net * net = sock_net ( & msk - > sk ) ;
struct mctp_ioc_tag_ctl ctl ;
unsigned long flags , fl2 ;
struct mctp_sk_key * key ;
struct hlist_node * tmp ;
int rc ;
u8 tag ;
if ( copy_from_user ( & ctl , ( void __user * ) arg , sizeof ( ctl ) ) )
return - EFAULT ;
if ( ctl . flags )
return - EINVAL ;
/* Must be a local tag, TO set, preallocated */
if ( ( ctl . tag & ~ MCTP_TAG_MASK ) ! = ( MCTP_TAG_OWNER | MCTP_TAG_PREALLOC ) )
return - EINVAL ;
tag = ctl . tag & MCTP_TAG_MASK ;
rc = - EINVAL ;
spin_lock_irqsave ( & net - > mctp . keys_lock , flags ) ;
hlist_for_each_entry_safe ( key , tmp , & msk - > keys , sklist ) {
/* we do an irqsave here, even though we know the irq state,
* so we have the flags to pass to __mctp_key_remove
*/
spin_lock_irqsave ( & key - > lock , fl2 ) ;
if ( key - > manual_alloc & &
ctl . peer_addr = = key - > peer_addr & &
tag = = key - > tag ) {
__mctp_key_remove ( key , net , fl2 ,
MCTP_TRACE_KEY_DROPPED ) ;
rc = 0 ;
} else {
spin_unlock_irqrestore ( & key - > lock , fl2 ) ;
}
}
spin_unlock_irqrestore ( & net - > mctp . keys_lock , flags ) ;
return rc ;
}
static int mctp_ioctl ( struct socket * sock , unsigned int cmd , unsigned long arg )
{
struct mctp_sock * msk = container_of ( sock - > sk , struct mctp_sock , sk ) ;
switch ( cmd ) {
case SIOCMCTPALLOCTAG :
return mctp_ioctl_alloctag ( msk , arg ) ;
case SIOCMCTPDROPTAG :
return mctp_ioctl_droptag ( msk , arg ) ;
}
return - EINVAL ;
}
# ifdef CONFIG_COMPAT
static int mctp_compat_ioctl ( struct socket * sock , unsigned int cmd ,
unsigned long arg )
{
void __user * argp = compat_ptr ( arg ) ;
switch ( cmd ) {
/* These have compatible ptr layouts */
case SIOCMCTPALLOCTAG :
case SIOCMCTPDROPTAG :
return mctp_ioctl ( sock , cmd , ( unsigned long ) argp ) ;
}
return - ENOIOCTLCMD ;
}
# endif
2021-07-29 05:20:40 +03:00
static const struct proto_ops mctp_dgram_ops = {
. family = PF_MCTP ,
. release = mctp_release ,
. bind = mctp_bind ,
. connect = sock_no_connect ,
. socketpair = sock_no_socketpair ,
. accept = sock_no_accept ,
. getname = sock_no_getname ,
. poll = datagram_poll ,
2022-02-09 07:05:57 +03:00
. ioctl = mctp_ioctl ,
2021-07-29 05:20:40 +03:00
. gettstamp = sock_gettstamp ,
. listen = sock_no_listen ,
. shutdown = sock_no_shutdown ,
. setsockopt = mctp_setsockopt ,
. getsockopt = mctp_getsockopt ,
. sendmsg = mctp_sendmsg ,
. recvmsg = mctp_recvmsg ,
. mmap = sock_no_mmap ,
. sendpage = sock_no_sendpage ,
2022-02-09 07:05:57 +03:00
# ifdef CONFIG_COMPAT
. compat_ioctl = mctp_compat_ioctl ,
# endif
2021-07-29 05:20:40 +03:00
} ;
2021-09-29 10:26:09 +03:00
static void mctp_sk_expire_keys ( struct timer_list * timer )
{
struct mctp_sock * msk = container_of ( timer , struct mctp_sock ,
key_expiry ) ;
struct net * net = sock_net ( & msk - > sk ) ;
2022-02-09 07:05:57 +03:00
unsigned long next_expiry , flags , fl2 ;
2021-09-29 10:26:09 +03:00
struct mctp_sk_key * key ;
struct hlist_node * tmp ;
bool next_expiry_valid = false ;
spin_lock_irqsave ( & net - > mctp . keys_lock , flags ) ;
hlist_for_each_entry_safe ( key , tmp , & msk - > keys , sklist ) {
2022-02-09 07:05:57 +03:00
/* don't expire. manual_alloc is immutable, no locking
* required .
*/
if ( key - > manual_alloc )
continue ;
2021-09-29 10:26:09 +03:00
2022-02-09 07:05:57 +03:00
spin_lock_irqsave ( & key - > lock , fl2 ) ;
2021-09-29 10:26:09 +03:00
if ( ! time_after_eq ( key - > expiry , jiffies ) ) {
2022-02-09 07:05:57 +03:00
__mctp_key_remove ( key , net , fl2 ,
MCTP_TRACE_KEY_TIMEOUT ) ;
2021-09-29 10:26:09 +03:00
continue ;
}
if ( next_expiry_valid ) {
if ( time_before ( key - > expiry , next_expiry ) )
next_expiry = key - > expiry ;
} else {
next_expiry = key - > expiry ;
next_expiry_valid = true ;
}
2022-02-09 07:05:57 +03:00
spin_unlock_irqrestore ( & key - > lock , fl2 ) ;
2021-09-29 10:26:09 +03:00
}
spin_unlock_irqrestore ( & net - > mctp . keys_lock , flags ) ;
if ( next_expiry_valid )
mod_timer ( timer , next_expiry ) ;
}
2021-07-29 05:20:49 +03:00
static int mctp_sk_init ( struct sock * sk )
{
struct mctp_sock * msk = container_of ( sk , struct mctp_sock , sk ) ;
INIT_HLIST_HEAD ( & msk - > keys ) ;
2021-09-29 10:26:09 +03:00
timer_setup ( & msk - > key_expiry , mctp_sk_expire_keys , 0 ) ;
2021-07-29 05:20:49 +03:00
return 0 ;
}
2021-07-29 05:20:40 +03:00
static void mctp_sk_close ( struct sock * sk , long timeout )
{
2021-09-29 10:26:09 +03:00
struct mctp_sock * msk = container_of ( sk , struct mctp_sock , sk ) ;
del_timer_sync ( & msk - > key_expiry ) ;
2021-07-29 05:20:40 +03:00
sk_common_release ( sk ) ;
}
2021-07-29 05:20:49 +03:00
static int mctp_sk_hash ( struct sock * sk )
{
struct net * net = sock_net ( sk ) ;
mutex_lock ( & net - > mctp . bind_lock ) ;
sk_add_node_rcu ( sk , & net - > mctp . binds ) ;
mutex_unlock ( & net - > mctp . bind_lock ) ;
return 0 ;
}
static void mctp_sk_unhash ( struct sock * sk )
{
struct mctp_sock * msk = container_of ( sk , struct mctp_sock , sk ) ;
struct net * net = sock_net ( sk ) ;
2022-02-09 07:05:57 +03:00
unsigned long flags , fl2 ;
2021-07-29 05:20:49 +03:00
struct mctp_sk_key * key ;
struct hlist_node * tmp ;
/* remove from any type-based binds */
mutex_lock ( & net - > mctp . bind_lock ) ;
sk_del_node_init_rcu ( sk ) ;
mutex_unlock ( & net - > mctp . bind_lock ) ;
/* remove tag allocations */
spin_lock_irqsave ( & net - > mctp . keys_lock , flags ) ;
hlist_for_each_entry_safe ( key , tmp , & msk - > keys , sklist ) {
2022-02-09 07:05:57 +03:00
spin_lock_irqsave ( & key - > lock , fl2 ) ;
__mctp_key_remove ( key , net , fl2 , MCTP_TRACE_KEY_CLOSED ) ;
2021-07-29 05:20:49 +03:00
}
spin_unlock_irqrestore ( & net - > mctp . keys_lock , flags ) ;
}
2021-07-29 05:20:40 +03:00
static struct proto mctp_proto = {
. name = " MCTP " ,
. owner = THIS_MODULE ,
. obj_size = sizeof ( struct mctp_sock ) ,
2021-07-29 05:20:49 +03:00
. init = mctp_sk_init ,
2021-07-29 05:20:40 +03:00
. close = mctp_sk_close ,
2021-07-29 05:20:49 +03:00
. hash = mctp_sk_hash ,
. unhash = mctp_sk_unhash ,
2021-07-29 05:20:40 +03:00
} ;
static int mctp_pf_create ( struct net * net , struct socket * sock ,
int protocol , int kern )
{
const struct proto_ops * ops ;
struct proto * proto ;
struct sock * sk ;
int rc ;
if ( protocol )
return - EPROTONOSUPPORT ;
/* only datagram sockets are supported */
if ( sock - > type ! = SOCK_DGRAM )
return - ESOCKTNOSUPPORT ;
proto = & mctp_proto ;
ops = & mctp_dgram_ops ;
sock - > state = SS_UNCONNECTED ;
sock - > ops = ops ;
sk = sk_alloc ( net , PF_MCTP , GFP_KERNEL , proto , kern ) ;
if ( ! sk )
return - ENOMEM ;
sock_init_data ( sock , sk ) ;
rc = 0 ;
if ( sk - > sk_prot - > init )
rc = sk - > sk_prot - > init ( sk ) ;
if ( rc )
goto err_sk_put ;
return 0 ;
err_sk_put :
sock_orphan ( sk ) ;
sock_put ( sk ) ;
return rc ;
}
static struct net_proto_family mctp_pf = {
. family = PF_MCTP ,
. create = mctp_pf_create ,
. owner = THIS_MODULE ,
} ;
static __init int mctp_init ( void )
{
int rc ;
2021-07-29 05:20:49 +03:00
/* ensure our uapi tag definitions match the header format */
BUILD_BUG_ON ( MCTP_TAG_OWNER ! = MCTP_HDR_FLAG_TO ) ;
BUILD_BUG_ON ( MCTP_TAG_MASK ! = MCTP_HDR_TAG_MASK ) ;
2021-07-29 05:20:40 +03:00
pr_info ( " mctp: management component transport protocol core \n " ) ;
rc = sock_register ( & mctp_pf ) ;
if ( rc )
return rc ;
rc = proto_register ( & mctp_proto , 0 ) ;
if ( rc )
goto err_unreg_sock ;
2021-07-29 05:20:45 +03:00
rc = mctp_routes_init ( ) ;
if ( rc )
goto err_unreg_proto ;
2021-07-29 05:20:47 +03:00
rc = mctp_neigh_init ( ) ;
if ( rc )
goto err_unreg_proto ;
2021-07-29 05:20:44 +03:00
mctp_device_init ( ) ;
2021-07-29 05:20:40 +03:00
return 0 ;
2021-07-29 05:20:45 +03:00
err_unreg_proto :
proto_unregister ( & mctp_proto ) ;
2021-07-29 05:20:40 +03:00
err_unreg_sock :
sock_unregister ( PF_MCTP ) ;
return rc ;
}
static __exit void mctp_exit ( void )
{
2021-07-29 05:20:44 +03:00
mctp_device_exit ( ) ;
2021-07-29 05:20:47 +03:00
mctp_neigh_exit ( ) ;
2021-07-29 05:20:45 +03:00
mctp_routes_exit ( ) ;
2021-07-29 05:20:40 +03:00
proto_unregister ( & mctp_proto ) ;
sock_unregister ( PF_MCTP ) ;
}
2021-09-29 10:26:11 +03:00
subsys_initcall ( mctp_init ) ;
2021-07-29 05:20:40 +03:00
module_exit ( mctp_exit ) ;
2021-07-29 05:20:39 +03:00
MODULE_DESCRIPTION ( " MCTP core " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Jeremy Kerr <jk@codeconstruct.com.au> " ) ;
2021-07-29 05:20:40 +03:00
MODULE_ALIAS_NETPROTO ( PF_MCTP ) ;