2021-07-29 05:20:45 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Management Component Transport Protocol ( MCTP ) - routing
* implementation .
*
* This is currently based on a simple routing table , with no dst cache . The
* number of routes should stay fairly small , so the lookup cost is small .
*
* Copyright ( c ) 2021 Code Construct
* Copyright ( c ) 2021 Google
*/
# include <linux/idr.h>
2021-10-03 06:17:04 +03:00
# include <linux/kconfig.h>
2021-07-29 05:20:45 +03:00
# include <linux/mctp.h>
# include <linux/netdevice.h>
# include <linux/rtnetlink.h>
# include <linux/skbuff.h>
# include <uapi/linux/if_arp.h>
# include <net/mctp.h>
# include <net/mctpdevice.h>
2021-07-29 05:20:46 +03:00
# include <net/netlink.h>
# include <net/sock.h>
2021-07-29 05:20:45 +03:00
2021-09-29 10:26:10 +03:00
# include <trace/events/mctp.h>
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
static const unsigned int mctp_message_maxlen = 64 * 1024 ;
2021-09-29 10:26:09 +03:00
static const unsigned long mctp_key_lifetime = 6 * CONFIG_HZ ;
2021-10-29 06:01:45 +03:00
static void mctp_flow_prepare_output ( struct sk_buff * skb , struct mctp_dev * dev ) ;
2021-07-29 05:20:45 +03:00
/* route output callbacks */
static int mctp_route_discard ( struct mctp_route * route , struct sk_buff * skb )
{
kfree_skb ( skb ) ;
return 0 ;
}
2021-07-29 05:20:49 +03:00
static struct mctp_sock * mctp_lookup_bind ( struct net * net , struct sk_buff * skb )
{
struct mctp_skb_cb * cb = mctp_cb ( skb ) ;
struct mctp_hdr * mh ;
struct sock * sk ;
u8 type ;
WARN_ON ( ! rcu_read_lock_held ( ) ) ;
/* TODO: look up in skb->cb? */
mh = mctp_hdr ( skb ) ;
if ( ! skb_headlen ( skb ) )
return NULL ;
type = ( * ( u8 * ) skb - > data ) & 0x7f ;
sk_for_each_rcu ( sk , & net - > mctp . binds ) {
struct mctp_sock * msk = container_of ( sk , struct mctp_sock , sk ) ;
if ( msk - > bind_net ! = MCTP_NET_ANY & & msk - > bind_net ! = cb - > net )
continue ;
if ( msk - > bind_type ! = type )
continue ;
2022-02-09 07:05:55 +03:00
if ( ! mctp_address_matches ( msk - > bind_addr , mh - > dest ) )
2021-07-29 05:20:49 +03:00
continue ;
return msk ;
}
return NULL ;
}
static bool mctp_key_match ( struct mctp_sk_key * key , mctp_eid_t local ,
mctp_eid_t peer , u8 tag )
{
2022-02-09 07:05:56 +03:00
if ( ! mctp_address_matches ( key - > local_addr , local ) )
2021-07-29 05:20:49 +03:00
return false ;
if ( key - > peer_addr ! = peer )
return false ;
if ( key - > tag ! = tag )
return false ;
return true ;
}
2021-09-29 10:26:07 +03:00
/* returns a key (with key->lock held, and refcounted), or NULL if no such
* key exists .
*/
2021-07-29 05:20:49 +03:00
static struct mctp_sk_key * mctp_lookup_key ( struct net * net , struct sk_buff * skb ,
2021-09-29 10:26:07 +03:00
mctp_eid_t peer ,
unsigned long * irqflags )
__acquires ( & key - > lock )
2021-07-29 05:20:49 +03:00
{
struct mctp_sk_key * key , * ret ;
2021-09-29 10:26:07 +03:00
unsigned long flags ;
2021-07-29 05:20:49 +03:00
struct mctp_hdr * mh ;
u8 tag ;
mh = mctp_hdr ( skb ) ;
tag = mh - > flags_seq_tag & ( MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO ) ;
ret = NULL ;
2021-09-29 10:26:07 +03:00
spin_lock_irqsave ( & net - > mctp . keys_lock , flags ) ;
2021-07-29 05:20:49 +03:00
2021-09-29 10:26:07 +03:00
hlist_for_each_entry ( key , & net - > mctp . keys , hlist ) {
if ( ! mctp_key_match ( key , mh - > dest , peer , tag ) )
continue ;
spin_lock ( & key - > lock ) ;
if ( key - > valid ) {
refcount_inc ( & key - > refs ) ;
2021-07-29 05:20:49 +03:00
ret = key ;
break ;
}
2021-09-29 10:26:07 +03:00
spin_unlock ( & key - > lock ) ;
}
if ( ret ) {
spin_unlock ( & net - > mctp . keys_lock ) ;
* irqflags = flags ;
} else {
spin_unlock_irqrestore ( & net - > mctp . keys_lock , flags ) ;
2021-07-29 05:20:49 +03:00
}
return ret ;
}
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
static struct mctp_sk_key * mctp_key_alloc ( struct mctp_sock * msk ,
mctp_eid_t local , mctp_eid_t peer ,
u8 tag , gfp_t gfp )
{
struct mctp_sk_key * key ;
key = kzalloc ( sizeof ( * key ) , gfp ) ;
if ( ! key )
return NULL ;
key - > peer_addr = peer ;
key - > local_addr = local ;
key - > tag = tag ;
key - > sk = & msk - > sk ;
2021-09-29 10:26:07 +03:00
key - > valid = true ;
spin_lock_init ( & key - > lock ) ;
refcount_set ( & key - > refs , 1 ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
return key ;
}
2021-09-29 10:26:07 +03:00
void mctp_key_unref ( struct mctp_sk_key * key )
{
2021-10-29 06:01:45 +03:00
unsigned long flags ;
if ( ! refcount_dec_and_test ( & key - > refs ) )
return ;
/* even though no refs exist here, the lock allows us to stay
* consistent with the locking requirement of mctp_dev_release_key
*/
spin_lock_irqsave ( & key - > lock , flags ) ;
mctp_dev_release_key ( key - > dev , key ) ;
spin_unlock_irqrestore ( & key - > lock , flags ) ;
kfree ( key ) ;
2021-09-29 10:26:07 +03:00
}
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
static int mctp_key_add ( struct mctp_sk_key * key , struct mctp_sock * msk )
{
struct net * net = sock_net ( & msk - > sk ) ;
struct mctp_sk_key * tmp ;
unsigned long flags ;
int rc = 0 ;
spin_lock_irqsave ( & net - > mctp . keys_lock , flags ) ;
hlist_for_each_entry ( tmp , & net - > mctp . keys , hlist ) {
if ( mctp_key_match ( tmp , key - > local_addr , key - > peer_addr ,
key - > tag ) ) {
2021-09-29 10:26:07 +03:00
spin_lock ( & tmp - > lock ) ;
if ( tmp - > valid )
rc = - EEXIST ;
spin_unlock ( & tmp - > lock ) ;
if ( rc )
break ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
}
}
if ( ! rc ) {
2021-09-29 10:26:07 +03:00
refcount_inc ( & key - > refs ) ;
2021-09-29 10:26:09 +03:00
key - > expiry = jiffies + mctp_key_lifetime ;
timer_reduce ( & msk - > key_expiry , key - > expiry ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
hlist_add_head ( & key - > hlist , & net - > mctp . keys ) ;
hlist_add_head ( & key - > sklist , & msk - > keys ) ;
}
spin_unlock_irqrestore ( & net - > mctp . keys_lock , flags ) ;
return rc ;
}
2022-02-09 07:05:57 +03:00
/* Helper for mctp_route_input().
* We ' re done with the key ; unlock and unref the key .
* For the usual case of automatic expiry we remove the key from lists .
* In the case that manual allocation is set on a key we release the lock
* and local ref , reset reassembly , but don ' t remove from lists .
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
*/
2022-02-09 07:05:57 +03:00
static void __mctp_key_done_in ( struct mctp_sk_key * key , struct net * net ,
unsigned long flags , unsigned long reason )
__releases ( & key - > lock )
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
{
struct sk_buff * skb ;
2022-02-09 07:05:57 +03:00
trace_mctp_key_release ( key , reason ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
skb = key - > reasm_head ;
key - > reasm_head = NULL ;
2022-02-09 07:05:57 +03:00
if ( ! key - > manual_alloc ) {
key - > reasm_dead = true ;
key - > valid = false ;
mctp_dev_release_key ( key - > dev , key ) ;
}
2021-09-29 10:26:07 +03:00
spin_unlock_irqrestore ( & key - > lock , flags ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
2022-02-09 07:05:57 +03:00
if ( ! key - > manual_alloc ) {
spin_lock_irqsave ( & net - > mctp . keys_lock , flags ) ;
2022-10-12 05:08:51 +03:00
if ( ! hlist_unhashed ( & key - > hlist ) ) {
hlist_del_init ( & key - > hlist ) ;
hlist_del_init ( & key - > sklist ) ;
mctp_key_unref ( key ) ;
}
2022-02-09 07:05:57 +03:00
spin_unlock_irqrestore ( & net - > mctp . keys_lock , flags ) ;
}
2021-09-29 10:26:07 +03:00
/* and one for the local reference */
mctp_key_unref ( key ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
2021-11-30 06:12:43 +03:00
kfree_skb ( skb ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
}
2021-10-29 06:01:45 +03:00
# ifdef CONFIG_MCTP_FLOWS
static void mctp_skb_set_flow ( struct sk_buff * skb , struct mctp_sk_key * key )
{
struct mctp_flow * flow ;
flow = skb_ext_add ( skb , SKB_EXT_MCTP ) ;
if ( ! flow )
return ;
refcount_inc ( & key - > refs ) ;
flow - > key = key ;
}
static void mctp_flow_prepare_output ( struct sk_buff * skb , struct mctp_dev * dev )
{
struct mctp_sk_key * key ;
struct mctp_flow * flow ;
flow = skb_ext_find ( skb , SKB_EXT_MCTP ) ;
if ( ! flow )
return ;
key = flow - > key ;
if ( WARN_ON ( key - > dev & & key - > dev ! = dev ) )
return ;
mctp_dev_set_key ( dev , key ) ;
}
# else
static void mctp_skb_set_flow ( struct sk_buff * skb , struct mctp_sk_key * key ) { }
static void mctp_flow_prepare_output ( struct sk_buff * skb , struct mctp_dev * dev ) { }
# endif
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
static int mctp_frag_queue ( struct mctp_sk_key * key , struct sk_buff * skb )
{
struct mctp_hdr * hdr = mctp_hdr ( skb ) ;
u8 exp_seq , this_seq ;
this_seq = ( hdr - > flags_seq_tag > > MCTP_HDR_SEQ_SHIFT )
& MCTP_HDR_SEQ_MASK ;
if ( ! key - > reasm_head ) {
key - > reasm_head = skb ;
key - > reasm_tailp = & ( skb_shinfo ( skb ) - > frag_list ) ;
key - > last_seq = this_seq ;
return 0 ;
}
exp_seq = ( key - > last_seq + 1 ) & MCTP_HDR_SEQ_MASK ;
if ( this_seq ! = exp_seq )
return - EINVAL ;
if ( key - > reasm_head - > len + skb - > len > mctp_message_maxlen )
return - EINVAL ;
skb - > next = NULL ;
skb - > sk = NULL ;
* key - > reasm_tailp = skb ;
key - > reasm_tailp = & skb - > next ;
key - > last_seq = this_seq ;
key - > reasm_head - > data_len + = skb - > len ;
key - > reasm_head - > len + = skb - > len ;
key - > reasm_head - > truesize + = skb - > truesize ;
return 0 ;
}
2021-07-29 05:20:45 +03:00
static int mctp_route_input ( struct mctp_route * route , struct sk_buff * skb )
{
2021-07-29 05:20:49 +03:00
struct net * net = dev_net ( skb - > dev ) ;
struct mctp_sk_key * key ;
struct mctp_sock * msk ;
struct mctp_hdr * mh ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
unsigned long f ;
u8 tag , flags ;
int rc ;
2021-07-29 05:20:49 +03:00
msk = NULL ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
rc = - EINVAL ;
2021-07-29 05:20:49 +03:00
/* we may be receiving a locally-routed packet; drop source sk
* accounting
*/
skb_orphan ( skb ) ;
/* ensure we have enough data for a header and a type */
if ( skb - > len < sizeof ( struct mctp_hdr ) + 1 )
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
goto out ;
2021-07-29 05:20:49 +03:00
/* grab header, advance data ptr */
mh = mctp_hdr ( skb ) ;
skb_pull ( skb , sizeof ( struct mctp_hdr ) ) ;
if ( mh - > ver ! = 1 )
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
goto out ;
2021-07-29 05:20:49 +03:00
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
flags = mh - > flags_seq_tag & ( MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM ) ;
tag = mh - > flags_seq_tag & ( MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO ) ;
2021-07-29 05:20:49 +03:00
rcu_read_lock ( ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
2021-09-29 10:26:07 +03:00
/* lookup socket / reasm context, exactly matching (src,dest,tag).
* we hold a ref on the key , and key - > lock held .
*/
key = mctp_lookup_key ( net , skb , mh - > src , & f ) ;
2021-07-29 05:20:49 +03:00
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
if ( flags & MCTP_HDR_FLAG_SOM ) {
if ( key ) {
msk = container_of ( key - > sk , struct mctp_sock , sk ) ;
} else {
/* first response to a broadcast? do a more general
* key lookup to find the socket , but don ' t use this
* key for reassembly - we ' ll create a more specific
* one for future packets if required ( ie , ! EOM ) .
*/
2021-09-29 10:26:07 +03:00
key = mctp_lookup_key ( net , skb , MCTP_ADDR_ANY , & f ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
if ( key ) {
msk = container_of ( key - > sk ,
struct mctp_sock , sk ) ;
2021-09-29 10:26:07 +03:00
spin_unlock_irqrestore ( & key - > lock , f ) ;
mctp_key_unref ( key ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
key = NULL ;
}
}
2021-07-29 05:20:49 +03:00
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
if ( ! key & & ! msk & & ( tag & MCTP_HDR_FLAG_TO ) )
msk = mctp_lookup_bind ( net , skb ) ;
2021-07-29 05:20:49 +03:00
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
if ( ! msk ) {
rc = - ENOENT ;
goto out_unlock ;
}
2021-07-29 05:20:49 +03:00
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
/* single-packet message? deliver to socket, clean up any
* pending key .
*/
if ( flags & MCTP_HDR_FLAG_EOM ) {
sock_queue_rcv_skb ( & msk - > sk , skb ) ;
if ( key ) {
/* we've hit a pending reassembly; not much we
* can do but drop it
*/
2022-02-09 07:05:57 +03:00
__mctp_key_done_in ( key , net , f ,
MCTP_TRACE_KEY_REPLIED ) ;
2021-09-29 10:26:07 +03:00
key = NULL ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
}
rc = 0 ;
goto out_unlock ;
}
2021-07-29 05:20:49 +03:00
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
/* broadcast response or a bind() - create a key for further
* packets for this message
*/
if ( ! key ) {
key = mctp_key_alloc ( msk , mh - > dest , mh - > src ,
tag , GFP_ATOMIC ) ;
if ( ! key ) {
rc = - ENOMEM ;
goto out_unlock ;
}
2021-07-29 05:20:49 +03:00
2021-09-29 10:26:07 +03:00
/* we can queue without the key lock here, as the
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
* key isn ' t observable yet
*/
mctp_frag_queue ( key , skb ) ;
/* if the key_add fails, we've raced with another
* SOM packet with the same src , dest and tag . There ' s
* no way to distinguish future packets , so all we
* can do is drop ; we ' ll free the skb on exit from
* this function .
*/
rc = mctp_key_add ( key , msk ) ;
2022-02-15 05:05:41 +03:00
if ( rc ) {
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
kfree ( key ) ;
2022-02-15 05:05:41 +03:00
} else {
trace_mctp_key_acquire ( key ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
2022-02-15 05:05:41 +03:00
/* we don't need to release key->lock on exit */
mctp_key_unref ( key ) ;
}
2021-09-29 10:26:07 +03:00
key = NULL ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
2021-09-29 10:26:07 +03:00
} else {
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
if ( key - > reasm_head | | key - > reasm_dead ) {
/* duplicate start? drop everything */
2022-02-09 07:05:57 +03:00
__mctp_key_done_in ( key , net , f ,
MCTP_TRACE_KEY_INVALIDATED ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
rc = - EEXIST ;
2021-09-29 10:26:07 +03:00
key = NULL ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
} else {
rc = mctp_frag_queue ( key , skb ) ;
}
}
} else if ( key ) {
/* this packet continues a previous message; reassemble
* using the message - specific key
*/
/* we need to be continuing an existing reassembly... */
if ( ! key - > reasm_head )
rc = - EINVAL ;
else
rc = mctp_frag_queue ( key , skb ) ;
/* end of message? deliver to socket, and we're done with
* the reassembly / response key
*/
if ( ! rc & & flags & MCTP_HDR_FLAG_EOM ) {
sock_queue_rcv_skb ( key - > sk , key - > reasm_head ) ;
key - > reasm_head = NULL ;
2022-02-09 07:05:57 +03:00
__mctp_key_done_in ( key , net , f , MCTP_TRACE_KEY_REPLIED ) ;
2021-09-29 10:26:07 +03:00
key = NULL ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
}
} else {
/* not a start, no matching key */
rc = - ENOENT ;
}
2021-07-29 05:20:49 +03:00
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
out_unlock :
2021-07-29 05:20:49 +03:00
rcu_read_unlock ( ) ;
2021-09-29 10:26:07 +03:00
if ( key ) {
spin_unlock_irqrestore ( & key - > lock , f ) ;
mctp_key_unref ( key ) ;
}
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
out :
if ( rc )
kfree_skb ( skb ) ;
return rc ;
}
static unsigned int mctp_route_mtu ( struct mctp_route * rt )
{
return rt - > mtu ? : READ_ONCE ( rt - > dev - > dev - > mtu ) ;
2021-07-29 05:20:45 +03:00
}
2021-07-29 05:20:46 +03:00
static int mctp_route_output ( struct mctp_route * route , struct sk_buff * skb )
2021-07-29 05:20:45 +03:00
{
2021-10-26 04:57:28 +03:00
struct mctp_skb_cb * cb = mctp_cb ( skb ) ;
2021-07-29 05:20:51 +03:00
struct mctp_hdr * hdr = mctp_hdr ( skb ) ;
char daddr_buf [ MAX_ADDR_LEN ] ;
char * daddr = NULL ;
2021-07-29 05:20:45 +03:00
unsigned int mtu ;
int rc ;
skb - > protocol = htons ( ETH_P_MCTP ) ;
mtu = READ_ONCE ( skb - > dev - > mtu ) ;
if ( skb - > len > mtu ) {
kfree_skb ( skb ) ;
return - EMSGSIZE ;
}
2021-10-26 04:57:28 +03:00
if ( cb - > ifindex ) {
/* direct route; use the hwaddr we stashed in sendmsg */
2022-04-01 05:48:44 +03:00
if ( cb - > halen ! = skb - > dev - > addr_len ) {
/* sanity check, sendmsg should have already caught this */
kfree_skb ( skb ) ;
return - EMSGSIZE ;
}
2021-10-26 04:57:28 +03:00
daddr = cb - > haddr ;
} else {
/* If lookup fails let the device handle daddr==NULL */
if ( mctp_neigh_lookup ( route - > dev , hdr - > dest , daddr_buf ) = = 0 )
daddr = daddr_buf ;
}
2021-07-29 05:20:51 +03:00
2021-07-29 05:20:45 +03:00
rc = dev_hard_header ( skb , skb - > dev , ntohs ( skb - > protocol ) ,
2021-07-29 05:20:51 +03:00
daddr , skb - > dev - > dev_addr , skb - > len ) ;
2022-04-01 05:48:42 +03:00
if ( rc < 0 ) {
2021-07-29 05:20:45 +03:00
kfree_skb ( skb ) ;
return - EHOSTUNREACH ;
}
2021-10-29 06:01:45 +03:00
mctp_flow_prepare_output ( skb , route - > dev ) ;
2021-07-29 05:20:45 +03:00
rc = dev_queue_xmit ( skb ) ;
if ( rc )
rc = net_xmit_errno ( rc ) ;
return rc ;
}
/* route alloc/release */
static void mctp_route_release ( struct mctp_route * rt )
{
if ( refcount_dec_and_test ( & rt - > refs ) ) {
2021-09-29 10:26:08 +03:00
mctp_dev_put ( rt - > dev ) ;
2021-07-29 05:20:45 +03:00
kfree_rcu ( rt , rcu ) ;
}
}
/* returns a route with the refcount at 1 */
static struct mctp_route * mctp_route_alloc ( void )
{
struct mctp_route * rt ;
rt = kzalloc ( sizeof ( * rt ) , GFP_KERNEL ) ;
if ( ! rt )
return NULL ;
INIT_LIST_HEAD ( & rt - > list ) ;
refcount_set ( & rt - > refs , 1 ) ;
rt - > output = mctp_route_discard ;
return rt ;
}
2021-07-29 05:20:52 +03:00
unsigned int mctp_default_net ( struct net * net )
{
return READ_ONCE ( net - > mctp . default_net ) ;
}
int mctp_default_net_set ( struct net * net , unsigned int index )
{
if ( index = = 0 )
return - EINVAL ;
WRITE_ONCE ( net - > mctp . default_net , index ) ;
return 0 ;
}
2021-07-29 05:20:49 +03:00
/* tag management */
static void mctp_reserve_tag ( struct net * net , struct mctp_sk_key * key ,
struct mctp_sock * msk )
{
struct netns_mctp * mns = & net - > mctp ;
lockdep_assert_held ( & mns - > keys_lock ) ;
2021-09-29 10:26:09 +03:00
key - > expiry = jiffies + mctp_key_lifetime ;
timer_reduce ( & msk - > key_expiry , key - > expiry ) ;
2021-07-29 05:20:49 +03:00
/* we hold the net->key_lock here, allowing updates to both
* then net and sk
*/
hlist_add_head_rcu ( & key - > hlist , & mns - > keys ) ;
hlist_add_head_rcu ( & key - > sklist , & msk - > keys ) ;
2021-09-29 10:26:07 +03:00
refcount_inc ( & key - > refs ) ;
2021-07-29 05:20:49 +03:00
}
/* Allocate a locally-owned tag value for (saddr, daddr), and reserve
* it for the socket msk
*/
2022-02-09 07:05:57 +03:00
struct mctp_sk_key * mctp_alloc_local_tag ( struct mctp_sock * msk ,
mctp_eid_t daddr , mctp_eid_t saddr ,
bool manual , u8 * tagp )
2021-07-29 05:20:49 +03:00
{
struct net * net = sock_net ( & msk - > sk ) ;
struct netns_mctp * mns = & net - > mctp ;
struct mctp_sk_key * key , * tmp ;
unsigned long flags ;
u8 tagbits ;
2021-09-29 10:26:06 +03:00
/* for NULL destination EIDs, we may get a response from any peer */
if ( daddr = = MCTP_ADDR_NULL )
daddr = MCTP_ADDR_ANY ;
2021-07-29 05:20:49 +03:00
/* be optimistic, alloc now */
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
key = mctp_key_alloc ( msk , saddr , daddr , 0 , GFP_KERNEL ) ;
2021-07-29 05:20:49 +03:00
if ( ! key )
2021-10-29 06:01:43 +03:00
return ERR_PTR ( - ENOMEM ) ;
2021-07-29 05:20:49 +03:00
/* 8 possible tag values */
tagbits = 0xff ;
spin_lock_irqsave ( & mns - > keys_lock , flags ) ;
/* Walk through the existing keys, looking for potential conflicting
* tags . If we find a conflict , clear that bit from tagbits
*/
hlist_for_each_entry ( tmp , & mns - > keys , hlist ) {
2021-09-29 10:26:07 +03:00
/* We can check the lookup fields (*_addr, tag) without the
* lock held , they don ' t change over the lifetime of the key .
*/
2021-07-29 05:20:49 +03:00
/* if we don't own the tag, it can't conflict */
if ( tmp - > tag & MCTP_HDR_FLAG_TO )
continue ;
2022-02-09 07:05:55 +03:00
if ( ! ( mctp_address_matches ( tmp - > peer_addr , daddr ) & &
2022-02-09 07:05:56 +03:00
mctp_address_matches ( tmp - > local_addr , saddr ) ) )
2021-09-29 10:26:07 +03:00
continue ;
spin_lock ( & tmp - > lock ) ;
/* key must still be valid. If we find a match, clear the
* potential tag value
*/
if ( tmp - > valid )
2021-07-29 05:20:49 +03:00
tagbits & = ~ ( 1 < < tmp - > tag ) ;
2021-09-29 10:26:07 +03:00
spin_unlock ( & tmp - > lock ) ;
2021-07-29 05:20:49 +03:00
if ( ! tagbits )
break ;
}
if ( tagbits ) {
key - > tag = __ffs ( tagbits ) ;
mctp_reserve_tag ( net , key , msk ) ;
2021-09-29 10:26:10 +03:00
trace_mctp_key_acquire ( key ) ;
2022-02-09 07:05:57 +03:00
key - > manual_alloc = manual ;
2021-07-29 05:20:49 +03:00
* tagp = key - > tag ;
}
spin_unlock_irqrestore ( & mns - > keys_lock , flags ) ;
2021-10-29 06:01:43 +03:00
if ( ! tagbits ) {
2021-07-29 05:20:49 +03:00
kfree ( key ) ;
2021-10-29 06:01:43 +03:00
return ERR_PTR ( - EBUSY ) ;
}
2021-07-29 05:20:49 +03:00
2021-10-29 06:01:43 +03:00
return key ;
2021-07-29 05:20:49 +03:00
}
2022-02-09 07:05:57 +03:00
static struct mctp_sk_key * mctp_lookup_prealloc_tag ( struct mctp_sock * msk ,
mctp_eid_t daddr ,
u8 req_tag , u8 * tagp )
{
struct net * net = sock_net ( & msk - > sk ) ;
struct netns_mctp * mns = & net - > mctp ;
struct mctp_sk_key * key , * tmp ;
unsigned long flags ;
req_tag & = ~ ( MCTP_TAG_PREALLOC | MCTP_TAG_OWNER ) ;
key = NULL ;
spin_lock_irqsave ( & mns - > keys_lock , flags ) ;
hlist_for_each_entry ( tmp , & mns - > keys , hlist ) {
if ( tmp - > tag ! = req_tag )
continue ;
if ( ! mctp_address_matches ( tmp - > peer_addr , daddr ) )
continue ;
if ( ! tmp - > manual_alloc )
continue ;
spin_lock ( & tmp - > lock ) ;
if ( tmp - > valid ) {
key = tmp ;
refcount_inc ( & key - > refs ) ;
spin_unlock ( & tmp - > lock ) ;
break ;
}
spin_unlock ( & tmp - > lock ) ;
}
spin_unlock_irqrestore ( & mns - > keys_lock , flags ) ;
if ( ! key )
return ERR_PTR ( - ENOENT ) ;
if ( tagp )
* tagp = key - > tag ;
return key ;
}
2021-07-29 05:20:45 +03:00
/* routing lookups */
static bool mctp_rt_match_eid ( struct mctp_route * rt ,
unsigned int net , mctp_eid_t eid )
{
return READ_ONCE ( rt - > dev - > net ) = = net & &
rt - > min < = eid & & rt - > max > = eid ;
}
/* compares match, used for duplicate prevention */
static bool mctp_rt_compare_exact ( struct mctp_route * rt1 ,
struct mctp_route * rt2 )
{
ASSERT_RTNL ( ) ;
return rt1 - > dev - > net = = rt2 - > dev - > net & &
rt1 - > min = = rt2 - > min & &
rt1 - > max = = rt2 - > max ;
}
struct mctp_route * mctp_route_lookup ( struct net * net , unsigned int dnet ,
mctp_eid_t daddr )
{
struct mctp_route * tmp , * rt = NULL ;
list_for_each_entry_rcu ( tmp , & net - > mctp . routes , list ) {
/* TODO: add metrics */
if ( mctp_rt_match_eid ( tmp , dnet , daddr ) ) {
if ( refcount_inc_not_zero ( & tmp - > refs ) ) {
rt = tmp ;
break ;
}
}
}
return rt ;
}
2021-09-29 10:26:06 +03:00
static struct mctp_route * mctp_route_lookup_null ( struct net * net ,
struct net_device * dev )
{
struct mctp_route * rt ;
list_for_each_entry_rcu ( rt , & net - > mctp . routes , list ) {
if ( rt - > dev - > dev = = dev & & rt - > type = = RTN_LOCAL & &
refcount_inc_not_zero ( & rt - > refs ) )
return rt ;
}
return NULL ;
}
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
static int mctp_do_fragment_route ( struct mctp_route * rt , struct sk_buff * skb ,
unsigned int mtu , u8 tag )
{
const unsigned int hlen = sizeof ( struct mctp_hdr ) ;
struct mctp_hdr * hdr , * hdr2 ;
2022-04-01 05:48:44 +03:00
unsigned int pos , size , headroom ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
struct sk_buff * skb2 ;
int rc ;
u8 seq ;
hdr = mctp_hdr ( skb ) ;
seq = 0 ;
rc = 0 ;
if ( mtu < hlen + 1 ) {
kfree_skb ( skb ) ;
return - EMSGSIZE ;
}
2022-04-01 05:48:44 +03:00
/* keep same headroom as the original skb */
headroom = skb_headroom ( skb ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
/* we've got the header */
skb_pull ( skb , hlen ) ;
for ( pos = 0 ; pos < skb - > len ; ) {
/* size of message payload */
size = min ( mtu - hlen , skb - > len - pos ) ;
2022-04-01 05:48:44 +03:00
skb2 = alloc_skb ( headroom + hlen + size , GFP_KERNEL ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
if ( ! skb2 ) {
rc = - ENOMEM ;
break ;
}
/* generic skb copy */
skb2 - > protocol = skb - > protocol ;
skb2 - > priority = skb - > priority ;
skb2 - > dev = skb - > dev ;
memcpy ( skb2 - > cb , skb - > cb , sizeof ( skb2 - > cb ) ) ;
if ( skb - > sk )
skb_set_owner_w ( skb2 , skb - > sk ) ;
/* establish packet */
2022-04-01 05:48:44 +03:00
skb_reserve ( skb2 , headroom ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
skb_reset_network_header ( skb2 ) ;
skb_put ( skb2 , hlen + size ) ;
skb2 - > transport_header = skb2 - > network_header + hlen ;
/* copy header fields, calculate SOM/EOM flags & seq */
hdr2 = mctp_hdr ( skb2 ) ;
hdr2 - > ver = hdr - > ver ;
hdr2 - > dest = hdr - > dest ;
hdr2 - > src = hdr - > src ;
hdr2 - > flags_seq_tag = tag &
( MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO ) ;
if ( pos = = 0 )
hdr2 - > flags_seq_tag | = MCTP_HDR_FLAG_SOM ;
if ( pos + size = = skb - > len )
hdr2 - > flags_seq_tag | = MCTP_HDR_FLAG_EOM ;
hdr2 - > flags_seq_tag | = seq < < MCTP_HDR_SEQ_SHIFT ;
/* copy message payload */
skb_copy_bits ( skb , pos , skb_transport_header ( skb2 ) , size ) ;
2021-10-26 04:57:28 +03:00
/* do route */
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
rc = rt - > output ( rt , skb2 ) ;
if ( rc )
break ;
seq = ( seq + 1 ) & MCTP_HDR_SEQ_MASK ;
pos + = size ;
}
consume_skb ( skb ) ;
return rc ;
}
2021-07-29 05:20:45 +03:00
int mctp_local_output ( struct sock * sk , struct mctp_route * rt ,
struct sk_buff * skb , mctp_eid_t daddr , u8 req_tag )
{
2021-07-29 05:20:49 +03:00
struct mctp_sock * msk = container_of ( sk , struct mctp_sock , sk ) ;
2021-07-29 05:20:45 +03:00
struct mctp_skb_cb * cb = mctp_cb ( skb ) ;
2022-02-22 07:17:38 +03:00
struct mctp_route tmp_rt = { 0 } ;
2021-10-29 06:01:43 +03:00
struct mctp_sk_key * key ;
2021-07-29 05:20:45 +03:00
struct mctp_hdr * hdr ;
unsigned long flags ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
unsigned int mtu ;
2021-07-29 05:20:45 +03:00
mctp_eid_t saddr ;
2021-10-26 04:57:28 +03:00
bool ext_rt ;
2021-07-29 05:20:45 +03:00
int rc ;
2021-07-29 05:20:49 +03:00
u8 tag ;
2021-07-29 05:20:45 +03:00
2021-10-26 04:57:28 +03:00
rc = - ENODEV ;
if ( rt ) {
ext_rt = false ;
if ( WARN_ON ( ! rt - > dev ) )
goto out_release ;
} else if ( cb - > ifindex ) {
2022-02-22 07:17:39 +03:00
struct net_device * dev ;
2021-10-26 04:57:28 +03:00
ext_rt = true ;
rt = & tmp_rt ;
rcu_read_lock ( ) ;
dev = dev_get_by_index_rcu ( sock_net ( sk ) , cb - > ifindex ) ;
if ( ! dev ) {
rcu_read_unlock ( ) ;
return rc ;
}
rt - > dev = __mctp_dev_get ( dev ) ;
rcu_read_unlock ( ) ;
if ( ! rt - > dev )
goto out_release ;
/* establish temporary route - we set up enough to keep
* mctp_route_output happy
*/
rt - > output = mctp_route_output ;
rt - > mtu = 0 ;
} else {
2021-07-29 05:20:45 +03:00
return - EINVAL ;
2021-10-26 04:57:28 +03:00
}
2021-07-29 05:20:45 +03:00
spin_lock_irqsave ( & rt - > dev - > addrs_lock , flags ) ;
if ( rt - > dev - > num_addrs = = 0 ) {
rc = - EHOSTUNREACH ;
} else {
/* use the outbound interface's first address as our source */
saddr = rt - > dev - > addrs [ 0 ] ;
rc = 0 ;
}
spin_unlock_irqrestore ( & rt - > dev - > addrs_lock , flags ) ;
if ( rc )
2021-10-26 04:57:28 +03:00
goto out_release ;
2021-07-29 05:20:45 +03:00
2022-02-09 07:05:57 +03:00
if ( req_tag & MCTP_TAG_OWNER ) {
if ( req_tag & MCTP_TAG_PREALLOC )
key = mctp_lookup_prealloc_tag ( msk , daddr ,
req_tag , & tag ) ;
else
key = mctp_alloc_local_tag ( msk , daddr , saddr ,
false , & tag ) ;
2021-10-29 06:01:43 +03:00
if ( IS_ERR ( key ) ) {
rc = PTR_ERR ( key ) ;
2021-10-26 04:57:28 +03:00
goto out_release ;
2021-10-29 06:01:43 +03:00
}
2021-10-29 06:01:45 +03:00
mctp_skb_set_flow ( skb , key ) ;
2021-10-29 06:01:43 +03:00
/* done with the key in this scope */
mctp_key_unref ( key ) ;
2021-07-29 05:20:49 +03:00
tag | = MCTP_HDR_FLAG_TO ;
} else {
2021-10-29 06:01:43 +03:00
key = NULL ;
2022-02-09 07:05:57 +03:00
tag = req_tag & MCTP_TAG_MASK ;
2021-07-29 05:20:49 +03:00
}
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
skb - > protocol = htons ( ETH_P_MCTP ) ;
skb - > priority = 0 ;
2021-07-29 05:20:45 +03:00
skb_reset_transport_header ( skb ) ;
skb_push ( skb , sizeof ( struct mctp_hdr ) ) ;
skb_reset_network_header ( skb ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
skb - > dev = rt - > dev - > dev ;
/* cb->net will have been set on initial ingress */
cb - > src = saddr ;
/* set up common header fields */
2021-07-29 05:20:45 +03:00
hdr = mctp_hdr ( skb ) ;
hdr - > ver = 1 ;
hdr - > dest = daddr ;
hdr - > src = saddr ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
mtu = mctp_route_mtu ( rt ) ;
2021-07-29 05:20:45 +03:00
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
if ( skb - > len + sizeof ( struct mctp_hdr ) < = mtu ) {
2021-10-26 04:57:28 +03:00
hdr - > flags_seq_tag = MCTP_HDR_FLAG_SOM |
MCTP_HDR_FLAG_EOM | tag ;
rc = rt - > output ( rt , skb ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
} else {
2021-10-26 04:57:28 +03:00
rc = mctp_do_fragment_route ( rt , skb , mtu , tag ) ;
mctp: Implement message fragmentation & reassembly
This change implements MCTP fragmentation (based on route & device MTU),
and corresponding reassembly.
The MCTP specification only allows for fragmentation on the originating
message endpoint, and reassembly on the destination endpoint -
intermediate nodes do not need to reassemble/refragment. Consequently,
we only fragment in the local transmit path, and reassemble
locally-bound packets. Messages are required to be in-order, so we
simply cancel reassembly on out-of-order or missing packets.
In the fragmentation path, we just break up the message into MTU-sized
fragments; the skb structure is a simple copy for now, which we can later
improve with a shared data implementation.
For reassembly, we keep track of incoming message fragments using the
existing tag infrastructure, allocating a key on the (src,dest,tag)
tuple, and reassembles matching fragments into a skb->frag_list.
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-29 05:20:50 +03:00
}
2021-10-26 04:57:28 +03:00
out_release :
if ( ! ext_rt )
mctp_route_release ( rt ) ;
2022-02-22 07:17:38 +03:00
mctp_dev_put ( tmp_rt . dev ) ;
2021-10-26 04:57:28 +03:00
return rc ;
2021-07-29 05:20:45 +03:00
}
/* route management */
2021-07-29 05:20:46 +03:00
static int mctp_route_add ( struct mctp_dev * mdev , mctp_eid_t daddr_start ,
unsigned int daddr_extent , unsigned int mtu ,
2021-08-10 05:38:34 +03:00
unsigned char type )
2021-07-29 05:20:45 +03:00
{
2021-08-10 05:38:34 +03:00
int ( * rtfn ) ( struct mctp_route * rt , struct sk_buff * skb ) ;
2021-07-29 05:20:45 +03:00
struct net * net = dev_net ( mdev - > dev ) ;
struct mctp_route * rt , * ert ;
2022-02-18 07:25:53 +03:00
if ( ! mctp_address_unicast ( daddr_start ) )
2021-07-29 05:20:46 +03:00
return - EINVAL ;
if ( daddr_extent > 0xff | | daddr_start + daddr_extent > = 255 )
return - EINVAL ;
2021-08-10 05:38:34 +03:00
switch ( type ) {
case RTN_LOCAL :
rtfn = mctp_route_input ;
break ;
case RTN_UNICAST :
rtfn = mctp_route_output ;
break ;
default :
return - EINVAL ;
}
2021-07-29 05:20:45 +03:00
rt = mctp_route_alloc ( ) ;
if ( ! rt )
return - ENOMEM ;
2021-07-29 05:20:46 +03:00
rt - > min = daddr_start ;
rt - > max = daddr_start + daddr_extent ;
rt - > mtu = mtu ;
2021-07-29 05:20:45 +03:00
rt - > dev = mdev ;
2021-09-29 10:26:08 +03:00
mctp_dev_hold ( rt - > dev ) ;
2021-08-10 05:38:34 +03:00
rt - > type = type ;
rt - > output = rtfn ;
2021-07-29 05:20:45 +03:00
ASSERT_RTNL ( ) ;
/* Prevent duplicate identical routes. */
list_for_each_entry ( ert , & net - > mctp . routes , list ) {
if ( mctp_rt_compare_exact ( rt , ert ) ) {
mctp_route_release ( rt ) ;
return - EEXIST ;
}
}
list_add_rcu ( & rt - > list , & net - > mctp . routes ) ;
return 0 ;
}
2021-07-29 05:20:46 +03:00
static int mctp_route_remove ( struct mctp_dev * mdev , mctp_eid_t daddr_start ,
2021-12-01 11:07:42 +03:00
unsigned int daddr_extent , unsigned char type )
2021-07-29 05:20:45 +03:00
{
struct net * net = dev_net ( mdev - > dev ) ;
struct mctp_route * rt , * tmp ;
2021-07-29 05:20:46 +03:00
mctp_eid_t daddr_end ;
bool dropped ;
if ( daddr_extent > 0xff | | daddr_start + daddr_extent > = 255 )
return - EINVAL ;
daddr_end = daddr_start + daddr_extent ;
dropped = false ;
2021-07-29 05:20:45 +03:00
ASSERT_RTNL ( ) ;
list_for_each_entry_safe ( rt , tmp , & net - > mctp . routes , list ) {
2021-07-29 05:20:46 +03:00
if ( rt - > dev = = mdev & &
2021-12-01 11:07:42 +03:00
rt - > min = = daddr_start & & rt - > max = = daddr_end & &
rt - > type = = type ) {
2021-07-29 05:20:45 +03:00
list_del_rcu ( & rt - > list ) ;
/* TODO: immediate RTM_DELROUTE */
mctp_route_release ( rt ) ;
2021-07-29 05:20:46 +03:00
dropped = true ;
2021-07-29 05:20:45 +03:00
}
}
2021-07-29 05:20:46 +03:00
return dropped ? 0 : - ENOENT ;
}
int mctp_route_add_local ( struct mctp_dev * mdev , mctp_eid_t addr )
{
2021-08-10 05:38:34 +03:00
return mctp_route_add ( mdev , addr , 0 , 0 , RTN_LOCAL ) ;
2021-07-29 05:20:46 +03:00
}
int mctp_route_remove_local ( struct mctp_dev * mdev , mctp_eid_t addr )
{
2021-12-01 11:07:42 +03:00
return mctp_route_remove ( mdev , addr , 0 , RTN_LOCAL ) ;
2021-07-29 05:20:45 +03:00
}
/* removes all entries for a given device */
void mctp_route_remove_dev ( struct mctp_dev * mdev )
{
struct net * net = dev_net ( mdev - > dev ) ;
struct mctp_route * rt , * tmp ;
ASSERT_RTNL ( ) ;
list_for_each_entry_safe ( rt , tmp , & net - > mctp . routes , list ) {
if ( rt - > dev = = mdev ) {
list_del_rcu ( & rt - > list ) ;
/* TODO: immediate RTM_DELROUTE */
mctp_route_release ( rt ) ;
}
}
}
/* Incoming packet-handling */
static int mctp_pkttype_receive ( struct sk_buff * skb , struct net_device * dev ,
struct packet_type * pt ,
struct net_device * orig_dev )
{
struct net * net = dev_net ( dev ) ;
2021-09-29 10:26:05 +03:00
struct mctp_dev * mdev ;
2021-07-29 05:20:45 +03:00
struct mctp_skb_cb * cb ;
struct mctp_route * rt ;
struct mctp_hdr * mh ;
2021-09-29 10:26:05 +03:00
rcu_read_lock ( ) ;
mdev = __mctp_dev_get ( dev ) ;
rcu_read_unlock ( ) ;
if ( ! mdev ) {
/* basic non-data sanity checks */
2021-07-29 05:20:45 +03:00
goto err_drop ;
2021-09-29 10:26:05 +03:00
}
2021-07-29 05:20:45 +03:00
if ( ! pskb_may_pull ( skb , sizeof ( struct mctp_hdr ) ) )
goto err_drop ;
skb_reset_transport_header ( skb ) ;
skb_reset_network_header ( skb ) ;
/* We have enough for a header; decode and route */
mh = mctp_hdr ( skb ) ;
if ( mh - > ver < MCTP_VER_MIN | | mh - > ver > MCTP_VER_MAX )
goto err_drop ;
2022-02-18 07:25:54 +03:00
/* source must be valid unicast or null; drop reserved ranges and
* broadcast
*/
if ( ! ( mctp_address_unicast ( mh - > src ) | | mctp_address_null ( mh - > src ) ) )
goto err_drop ;
/* dest address: as above, but allow broadcast */
if ( ! ( mctp_address_unicast ( mh - > dest ) | | mctp_address_null ( mh - > dest ) | |
mctp_address_broadcast ( mh - > dest ) ) )
goto err_drop ;
2021-10-26 04:57:28 +03:00
/* MCTP drivers must populate halen/haddr */
if ( dev - > type = = ARPHRD_MCTP ) {
cb = mctp_cb ( skb ) ;
} else {
cb = __mctp_cb ( skb ) ;
cb - > halen = 0 ;
}
2021-09-29 10:26:05 +03:00
cb - > net = READ_ONCE ( mdev - > net ) ;
2021-10-26 04:57:28 +03:00
cb - > ifindex = dev - > ifindex ;
2021-07-29 05:20:45 +03:00
rt = mctp_route_lookup ( net , cb - > net , mh - > dest ) ;
2021-09-29 10:26:06 +03:00
/* NULL EID, but addressed to our physical address */
if ( ! rt & & mh - > dest = = MCTP_ADDR_NULL & & skb - > pkt_type = = PACKET_HOST )
rt = mctp_route_lookup_null ( net , dev ) ;
2021-07-29 05:20:45 +03:00
if ( ! rt )
goto err_drop ;
2021-10-26 04:57:28 +03:00
rt - > output ( rt , skb ) ;
mctp_route_release ( rt ) ;
2022-02-22 07:17:38 +03:00
mctp_dev_put ( mdev ) ;
2021-07-29 05:20:45 +03:00
return NET_RX_SUCCESS ;
err_drop :
kfree_skb ( skb ) ;
2022-02-22 07:17:38 +03:00
mctp_dev_put ( mdev ) ;
2021-07-29 05:20:45 +03:00
return NET_RX_DROP ;
}
static struct packet_type mctp_packet_type = {
. type = cpu_to_be16 ( ETH_P_MCTP ) ,
. func = mctp_pkttype_receive ,
} ;
2021-07-29 05:20:46 +03:00
/* netlink interface */
static const struct nla_policy rta_mctp_policy [ RTA_MAX + 1 ] = {
[ RTA_DST ] = { . type = NLA_U8 } ,
[ RTA_METRICS ] = { . type = NLA_NESTED } ,
[ RTA_OIF ] = { . type = NLA_U32 } ,
} ;
/* Common part for RTM_NEWROUTE and RTM_DELROUTE parsing.
* tb must hold RTA_MAX + 1 elements .
*/
static int mctp_route_nlparse ( struct sk_buff * skb , struct nlmsghdr * nlh ,
struct netlink_ext_ack * extack ,
struct nlattr * * tb , struct rtmsg * * rtm ,
struct mctp_dev * * mdev , mctp_eid_t * daddr_start )
{
struct net * net = sock_net ( skb - > sk ) ;
struct net_device * dev ;
unsigned int ifindex ;
int rc ;
rc = nlmsg_parse ( nlh , sizeof ( struct rtmsg ) , tb , RTA_MAX ,
rta_mctp_policy , extack ) ;
if ( rc < 0 ) {
NL_SET_ERR_MSG ( extack , " incorrect format " ) ;
return rc ;
}
if ( ! tb [ RTA_DST ] ) {
NL_SET_ERR_MSG ( extack , " dst EID missing " ) ;
return - EINVAL ;
}
* daddr_start = nla_get_u8 ( tb [ RTA_DST ] ) ;
if ( ! tb [ RTA_OIF ] ) {
NL_SET_ERR_MSG ( extack , " ifindex missing " ) ;
return - EINVAL ;
}
ifindex = nla_get_u32 ( tb [ RTA_OIF ] ) ;
* rtm = nlmsg_data ( nlh ) ;
if ( ( * rtm ) - > rtm_family ! = AF_MCTP ) {
NL_SET_ERR_MSG ( extack , " route family must be AF_MCTP " ) ;
return - EINVAL ;
}
dev = __dev_get_by_index ( net , ifindex ) ;
if ( ! dev ) {
NL_SET_ERR_MSG ( extack , " bad ifindex " ) ;
return - ENODEV ;
}
* mdev = mctp_dev_get_rtnl ( dev ) ;
if ( ! * mdev )
return - ENODEV ;
if ( dev - > flags & IFF_LOOPBACK ) {
NL_SET_ERR_MSG ( extack , " no routes to loopback " ) ;
return - EINVAL ;
}
return 0 ;
}
2021-09-29 10:26:13 +03:00
static const struct nla_policy rta_metrics_policy [ RTAX_MAX + 1 ] = {
[ RTAX_MTU ] = { . type = NLA_U32 } ,
} ;
2021-07-29 05:20:46 +03:00
static int mctp_newroute ( struct sk_buff * skb , struct nlmsghdr * nlh ,
struct netlink_ext_ack * extack )
{
struct nlattr * tb [ RTA_MAX + 1 ] ;
2021-09-29 10:26:13 +03:00
struct nlattr * tbx [ RTAX_MAX + 1 ] ;
2021-07-29 05:20:46 +03:00
mctp_eid_t daddr_start ;
struct mctp_dev * mdev ;
struct rtmsg * rtm ;
unsigned int mtu ;
int rc ;
rc = mctp_route_nlparse ( skb , nlh , extack , tb ,
& rtm , & mdev , & daddr_start ) ;
if ( rc < 0 )
return rc ;
if ( rtm - > rtm_type ! = RTN_UNICAST ) {
NL_SET_ERR_MSG ( extack , " rtm_type must be RTN_UNICAST " ) ;
return - EINVAL ;
}
mtu = 0 ;
2021-09-29 10:26:13 +03:00
if ( tb [ RTA_METRICS ] ) {
rc = nla_parse_nested ( tbx , RTAX_MAX , tb [ RTA_METRICS ] ,
rta_metrics_policy , NULL ) ;
if ( rc < 0 )
return rc ;
if ( tbx [ RTAX_MTU ] )
mtu = nla_get_u32 ( tbx [ RTAX_MTU ] ) ;
}
2021-07-29 05:20:46 +03:00
2021-08-10 05:38:34 +03:00
if ( rtm - > rtm_type ! = RTN_UNICAST )
return - EINVAL ;
rc = mctp_route_add ( mdev , daddr_start , rtm - > rtm_dst_len , mtu ,
rtm - > rtm_type ) ;
2021-07-29 05:20:46 +03:00
return rc ;
}
static int mctp_delroute ( struct sk_buff * skb , struct nlmsghdr * nlh ,
struct netlink_ext_ack * extack )
{
struct nlattr * tb [ RTA_MAX + 1 ] ;
mctp_eid_t daddr_start ;
struct mctp_dev * mdev ;
struct rtmsg * rtm ;
int rc ;
rc = mctp_route_nlparse ( skb , nlh , extack , tb ,
& rtm , & mdev , & daddr_start ) ;
if ( rc < 0 )
return rc ;
/* we only have unicast routes */
if ( rtm - > rtm_type ! = RTN_UNICAST )
return - EINVAL ;
2021-12-01 11:07:42 +03:00
rc = mctp_route_remove ( mdev , daddr_start , rtm - > rtm_dst_len , RTN_UNICAST ) ;
2021-07-29 05:20:46 +03:00
return rc ;
}
static int mctp_fill_rtinfo ( struct sk_buff * skb , struct mctp_route * rt ,
u32 portid , u32 seq , int event , unsigned int flags )
{
struct nlmsghdr * nlh ;
struct rtmsg * hdr ;
void * metrics ;
nlh = nlmsg_put ( skb , portid , seq , event , sizeof ( * hdr ) , flags ) ;
if ( ! nlh )
return - EMSGSIZE ;
hdr = nlmsg_data ( nlh ) ;
hdr - > rtm_family = AF_MCTP ;
/* we use the _len fields as a number of EIDs, rather than
* a number of bits in the address
*/
hdr - > rtm_dst_len = rt - > max - rt - > min ;
hdr - > rtm_src_len = 0 ;
hdr - > rtm_tos = 0 ;
hdr - > rtm_table = RT_TABLE_DEFAULT ;
hdr - > rtm_protocol = RTPROT_STATIC ; /* everything is user-defined */
hdr - > rtm_scope = RT_SCOPE_LINK ; /* TODO: scope in mctp_route? */
2021-08-10 05:38:34 +03:00
hdr - > rtm_type = rt - > type ;
2021-07-29 05:20:46 +03:00
if ( nla_put_u8 ( skb , RTA_DST , rt - > min ) )
goto cancel ;
metrics = nla_nest_start_noflag ( skb , RTA_METRICS ) ;
if ( ! metrics )
goto cancel ;
if ( rt - > mtu ) {
if ( nla_put_u32 ( skb , RTAX_MTU , rt - > mtu ) )
goto cancel ;
}
nla_nest_end ( skb , metrics ) ;
if ( rt - > dev ) {
if ( nla_put_u32 ( skb , RTA_OIF , rt - > dev - > dev - > ifindex ) )
goto cancel ;
}
/* TODO: conditional neighbour physaddr? */
nlmsg_end ( skb , nlh ) ;
return 0 ;
cancel :
nlmsg_cancel ( skb , nlh ) ;
return - EMSGSIZE ;
}
static int mctp_dump_rtinfo ( struct sk_buff * skb , struct netlink_callback * cb )
{
struct net * net = sock_net ( skb - > sk ) ;
struct mctp_route * rt ;
int s_idx , idx ;
/* TODO: allow filtering on route data, possibly under
* cb - > strict_check
*/
/* TODO: change to struct overlay */
s_idx = cb - > args [ 0 ] ;
idx = 0 ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( rt , & net - > mctp . routes , list ) {
if ( idx + + < s_idx )
continue ;
if ( mctp_fill_rtinfo ( skb , rt ,
NETLINK_CB ( cb - > skb ) . portid ,
cb - > nlh - > nlmsg_seq ,
RTM_NEWROUTE , NLM_F_MULTI ) < 0 )
break ;
}
rcu_read_unlock ( ) ;
cb - > args [ 0 ] = idx ;
return skb - > len ;
}
2021-07-29 05:20:45 +03:00
/* net namespace implementation */
static int __net_init mctp_routes_net_init ( struct net * net )
{
struct netns_mctp * ns = & net - > mctp ;
INIT_LIST_HEAD ( & ns - > routes ) ;
2021-07-29 05:20:49 +03:00
INIT_HLIST_HEAD ( & ns - > binds ) ;
mutex_init ( & ns - > bind_lock ) ;
INIT_HLIST_HEAD ( & ns - > keys ) ;
spin_lock_init ( & ns - > keys_lock ) ;
2021-07-29 05:20:52 +03:00
WARN_ON ( mctp_default_net_set ( net , MCTP_INITIAL_DEFAULT_NET ) ) ;
2021-07-29 05:20:45 +03:00
return 0 ;
}
static void __net_exit mctp_routes_net_exit ( struct net * net )
{
struct mctp_route * rt ;
2021-09-08 07:13:10 +03:00
rcu_read_lock ( ) ;
2021-07-29 05:20:45 +03:00
list_for_each_entry_rcu ( rt , & net - > mctp . routes , list )
mctp_route_release ( rt ) ;
2021-09-08 07:13:10 +03:00
rcu_read_unlock ( ) ;
2021-07-29 05:20:45 +03:00
}
static struct pernet_operations mctp_net_ops = {
. init = mctp_routes_net_init ,
. exit = mctp_routes_net_exit ,
} ;
int __init mctp_routes_init ( void )
{
dev_add_pack ( & mctp_packet_type ) ;
2021-07-29 05:20:46 +03:00
rtnl_register_module ( THIS_MODULE , PF_MCTP , RTM_GETROUTE ,
NULL , mctp_dump_rtinfo , 0 ) ;
rtnl_register_module ( THIS_MODULE , PF_MCTP , RTM_NEWROUTE ,
mctp_newroute , NULL , 0 ) ;
rtnl_register_module ( THIS_MODULE , PF_MCTP , RTM_DELROUTE ,
mctp_delroute , NULL , 0 ) ;
2021-07-29 05:20:45 +03:00
return register_pernet_subsys ( & mctp_net_ops ) ;
}
void __exit mctp_routes_exit ( void )
{
unregister_pernet_subsys ( & mctp_net_ops ) ;
2021-07-29 05:20:46 +03:00
rtnl_unregister ( PF_MCTP , RTM_DELROUTE ) ;
rtnl_unregister ( PF_MCTP , RTM_NEWROUTE ) ;
rtnl_unregister ( PF_MCTP , RTM_GETROUTE ) ;
2021-07-29 05:20:45 +03:00
dev_remove_pack ( & mctp_packet_type ) ;
}
2021-10-03 06:17:04 +03:00
# if IS_ENABLED(CONFIG_MCTP_TEST)
# include "test/route-test.c"
# endif