xref: /openbmc/linux/include/net/mctp.h (revision 63ed1aab)
12c8e2e9aSJeremy Kerr /* SPDX-License-Identifier: GPL-2.0 */
22c8e2e9aSJeremy Kerr /*
32c8e2e9aSJeremy Kerr  * Management Component Transport Protocol (MCTP)
42c8e2e9aSJeremy Kerr  *
52c8e2e9aSJeremy Kerr  * Copyright (c) 2021 Code Construct
62c8e2e9aSJeremy Kerr  * Copyright (c) 2021 Google
72c8e2e9aSJeremy Kerr  */
82c8e2e9aSJeremy Kerr 
92c8e2e9aSJeremy Kerr #ifndef __NET_MCTP_H
102c8e2e9aSJeremy Kerr #define __NET_MCTP_H
112c8e2e9aSJeremy Kerr 
122c8e2e9aSJeremy Kerr #include <linux/bits.h>
13583be982SJeremy Kerr #include <linux/mctp.h>
1499ce45d5SJeremy Kerr #include <linux/netdevice.h>
15889b7da2SJeremy Kerr #include <net/net_namespace.h>
16833ef3b9SJeremy Kerr #include <net/sock.h>
172c8e2e9aSJeremy Kerr 
182c8e2e9aSJeremy Kerr /* MCTP packet definitions */
192c8e2e9aSJeremy Kerr struct mctp_hdr {
202c8e2e9aSJeremy Kerr 	u8	ver;
212c8e2e9aSJeremy Kerr 	u8	dest;
222c8e2e9aSJeremy Kerr 	u8	src;
232c8e2e9aSJeremy Kerr 	u8	flags_seq_tag;
242c8e2e9aSJeremy Kerr };
252c8e2e9aSJeremy Kerr 
262c8e2e9aSJeremy Kerr #define MCTP_VER_MIN	1
272c8e2e9aSJeremy Kerr #define MCTP_VER_MAX	1
282c8e2e9aSJeremy Kerr 
292c8e2e9aSJeremy Kerr /* Definitions for flags_seq_tag field */
302c8e2e9aSJeremy Kerr #define MCTP_HDR_FLAG_SOM	BIT(7)
312c8e2e9aSJeremy Kerr #define MCTP_HDR_FLAG_EOM	BIT(6)
322c8e2e9aSJeremy Kerr #define MCTP_HDR_FLAG_TO	BIT(3)
332c8e2e9aSJeremy Kerr #define MCTP_HDR_FLAGS		GENMASK(5, 3)
342c8e2e9aSJeremy Kerr #define MCTP_HDR_SEQ_SHIFT	4
352c8e2e9aSJeremy Kerr #define MCTP_HDR_SEQ_MASK	GENMASK(1, 0)
362c8e2e9aSJeremy Kerr #define MCTP_HDR_TAG_SHIFT	0
372c8e2e9aSJeremy Kerr #define MCTP_HDR_TAG_MASK	GENMASK(2, 0)
382c8e2e9aSJeremy Kerr 
39889b7da2SJeremy Kerr #define MCTP_HEADER_MAXLEN	4
40889b7da2SJeremy Kerr 
4103f2bbc4SMatt Johnston #define MCTP_INITIAL_DEFAULT_NET	1
4203f2bbc4SMatt Johnston 
43583be982SJeremy Kerr static inline bool mctp_address_ok(mctp_eid_t eid)
44583be982SJeremy Kerr {
45583be982SJeremy Kerr 	return eid >= 8 && eid < 255;
46583be982SJeremy Kerr }
47583be982SJeremy Kerr 
488069b22dSJeremy Kerr static inline bool mctp_address_matches(mctp_eid_t match, mctp_eid_t eid)
498069b22dSJeremy Kerr {
508069b22dSJeremy Kerr 	return match == eid || match == MCTP_ADDR_ANY;
518069b22dSJeremy Kerr }
528069b22dSJeremy Kerr 
53583be982SJeremy Kerr static inline struct mctp_hdr *mctp_hdr(struct sk_buff *skb)
54583be982SJeremy Kerr {
55583be982SJeremy Kerr 	return (struct mctp_hdr *)skb_network_header(skb);
56583be982SJeremy Kerr }
57583be982SJeremy Kerr 
58833ef3b9SJeremy Kerr /* socket implementation */
59833ef3b9SJeremy Kerr struct mctp_sock {
60833ef3b9SJeremy Kerr 	struct sock	sk;
61833ef3b9SJeremy Kerr 
62833ef3b9SJeremy Kerr 	/* bind() params */
63b416beb2SJeremy Kerr 	unsigned int	bind_net;
64833ef3b9SJeremy Kerr 	mctp_eid_t	bind_addr;
65833ef3b9SJeremy Kerr 	__u8		bind_type;
66833ef3b9SJeremy Kerr 
6799ce45d5SJeremy Kerr 	/* sendmsg()/recvmsg() uses struct sockaddr_mctp_ext */
6899ce45d5SJeremy Kerr 	bool		addr_ext;
6999ce45d5SJeremy Kerr 
70833ef3b9SJeremy Kerr 	/* list of mctp_sk_key, for incoming tag lookup. updates protected
71833ef3b9SJeremy Kerr 	 * by sk->net->keys_lock
72833ef3b9SJeremy Kerr 	 */
73833ef3b9SJeremy Kerr 	struct hlist_head keys;
747b14e15aSJeremy Kerr 
757b14e15aSJeremy Kerr 	/* mechanism for expiring allocated keys; will release an allocated
767b14e15aSJeremy Kerr 	 * tag, and any netdev state for a request/response pairing
777b14e15aSJeremy Kerr 	 */
787b14e15aSJeremy Kerr 	struct timer_list key_expiry;
79833ef3b9SJeremy Kerr };
80833ef3b9SJeremy Kerr 
81833ef3b9SJeremy Kerr /* Key for matching incoming packets to sockets or reassembly contexts.
82833ef3b9SJeremy Kerr  * Packets are matched on (src,dest,tag).
83833ef3b9SJeremy Kerr  *
8473c61845SJeremy Kerr  * Lifetime / locking requirements:
85833ef3b9SJeremy Kerr  *
8673c61845SJeremy Kerr  *  - individual key data (ie, the struct itself) is protected by key->lock;
8773c61845SJeremy Kerr  *    changes must be made with that lock held.
8873c61845SJeremy Kerr  *
8973c61845SJeremy Kerr  *  - the lookup fields: peer_addr, local_addr and tag are set before the
9073c61845SJeremy Kerr  *    key is added to lookup lists, and never updated.
9173c61845SJeremy Kerr  *
9273c61845SJeremy Kerr  *  - A ref to the key must be held (throuh key->refs) if a pointer to the
9373c61845SJeremy Kerr  *    key is to be accessed after key->lock is released.
94833ef3b9SJeremy Kerr  *
95833ef3b9SJeremy Kerr  *  - a mctp_sk_key contains a reference to a struct sock; this is valid
96833ef3b9SJeremy Kerr  *    for the life of the key. On sock destruction (through unhash), the key is
9773c61845SJeremy Kerr  *    removed from lists (see below), and marked invalid.
98833ef3b9SJeremy Kerr  *
99833ef3b9SJeremy Kerr  * - these mctp_sk_keys appear on two lists:
100833ef3b9SJeremy Kerr  *     1) the struct mctp_sock->keys list
101833ef3b9SJeremy Kerr  *     2) the struct netns_mctp->keys list
102833ef3b9SJeremy Kerr  *
10373c61845SJeremy Kerr  *   presences on these lists requires a (single) refcount to be held; both
10473c61845SJeremy Kerr  *   lists are updated as a single operation.
10573c61845SJeremy Kerr  *
10673c61845SJeremy Kerr  *   Updates and lookups in either list are performed under the
10773c61845SJeremy Kerr  *   netns_mctp->keys lock. Lookup functions will need to lock the key and
10873c61845SJeremy Kerr  *   take a reference before unlocking the keys_lock. Consequently, the list's
10973c61845SJeremy Kerr  *   keys_lock *cannot* be acquired with the individual key->lock held.
110833ef3b9SJeremy Kerr  *
1114a992bbdSJeremy Kerr  * - a key may have a sk_buff attached as part of an in-progress message
11273c61845SJeremy Kerr  *   reassembly (->reasm_head). The reasm data is protected by the individual
11373c61845SJeremy Kerr  *   key->lock.
1144a992bbdSJeremy Kerr  *
1154a992bbdSJeremy Kerr  * - there are two destruction paths for a mctp_sk_key:
1164a992bbdSJeremy Kerr  *
1174a992bbdSJeremy Kerr  *    - through socket unhash (see mctp_sk_unhash). This performs the list
1184a992bbdSJeremy Kerr  *      removal under keys_lock.
1194a992bbdSJeremy Kerr  *
1204a992bbdSJeremy Kerr  *    - where a key is established to receive a reply message: after receiving
1214a992bbdSJeremy Kerr  *      the (complete) reply, or during reassembly errors. Here, we clean up
1224a992bbdSJeremy Kerr  *      the reassembly context (marking reasm_dead, to prevent another from
1234a992bbdSJeremy Kerr  *      starting), and remove the socket from the netns & socket lists.
1247b14e15aSJeremy Kerr  *
1257b14e15aSJeremy Kerr  *    - through an expiry timeout, on a per-socket timer
126833ef3b9SJeremy Kerr  */
127833ef3b9SJeremy Kerr struct mctp_sk_key {
128833ef3b9SJeremy Kerr 	mctp_eid_t	peer_addr;
129*63ed1aabSMatt Johnston 	mctp_eid_t	local_addr; /* MCTP_ADDR_ANY for local owned tags */
130833ef3b9SJeremy Kerr 	__u8		tag; /* incoming tag match; invert TO for local */
131833ef3b9SJeremy Kerr 
132833ef3b9SJeremy Kerr 	/* we hold a ref to sk when set */
133833ef3b9SJeremy Kerr 	struct sock	*sk;
134833ef3b9SJeremy Kerr 
135833ef3b9SJeremy Kerr 	/* routing lookup list */
136833ef3b9SJeremy Kerr 	struct hlist_node hlist;
137833ef3b9SJeremy Kerr 
138833ef3b9SJeremy Kerr 	/* per-socket list */
139833ef3b9SJeremy Kerr 	struct hlist_node sklist;
140833ef3b9SJeremy Kerr 
14173c61845SJeremy Kerr 	/* lock protects against concurrent updates to the reassembly and
14273c61845SJeremy Kerr 	 * expiry data below.
14373c61845SJeremy Kerr 	 */
14473c61845SJeremy Kerr 	spinlock_t	lock;
14573c61845SJeremy Kerr 
14673c61845SJeremy Kerr 	/* Keys are referenced during the output path, which may sleep */
14773c61845SJeremy Kerr 	refcount_t	refs;
14873c61845SJeremy Kerr 
1494a992bbdSJeremy Kerr 	/* incoming fragment reassembly context */
1504a992bbdSJeremy Kerr 	struct sk_buff	*reasm_head;
1514a992bbdSJeremy Kerr 	struct sk_buff	**reasm_tailp;
1524a992bbdSJeremy Kerr 	bool		reasm_dead;
1534a992bbdSJeremy Kerr 	u8		last_seq;
1544a992bbdSJeremy Kerr 
15573c61845SJeremy Kerr 	/* key validity */
15673c61845SJeremy Kerr 	bool		valid;
1577b14e15aSJeremy Kerr 
1587b14e15aSJeremy Kerr 	/* expiry timeout; valid (above) cleared on expiry */
1597b14e15aSJeremy Kerr 	unsigned long	expiry;
16067737c45SJeremy Kerr 
16167737c45SJeremy Kerr 	/* free to use for device flow state tracking. Initialised to
16267737c45SJeremy Kerr 	 * zero on initial key creation
16367737c45SJeremy Kerr 	 */
16467737c45SJeremy Kerr 	unsigned long	dev_flow_state;
16567737c45SJeremy Kerr 	struct mctp_dev	*dev;
166*63ed1aabSMatt Johnston 
167*63ed1aabSMatt Johnston 	/* a tag allocated with SIOCMCTPALLOCTAG ioctl will not expire
168*63ed1aabSMatt Johnston 	 * automatically on timeout or response, instead SIOCMCTPDROPTAG
169*63ed1aabSMatt Johnston 	 * is used.
170*63ed1aabSMatt Johnston 	 */
171*63ed1aabSMatt Johnston 	bool		manual_alloc;
172833ef3b9SJeremy Kerr };
173833ef3b9SJeremy Kerr 
174889b7da2SJeremy Kerr struct mctp_skb_cb {
175889b7da2SJeremy Kerr 	unsigned int	magic;
176889b7da2SJeremy Kerr 	unsigned int	net;
17799ce45d5SJeremy Kerr 	int		ifindex; /* extended/direct addressing if set */
178889b7da2SJeremy Kerr 	mctp_eid_t	src;
17999ce45d5SJeremy Kerr 	unsigned char	halen;
18099ce45d5SJeremy Kerr 	unsigned char	haddr[MAX_ADDR_LEN];
181889b7da2SJeremy Kerr };
182889b7da2SJeremy Kerr 
183889b7da2SJeremy Kerr /* skb control-block accessors with a little extra debugging for initial
184889b7da2SJeremy Kerr  * development.
185889b7da2SJeremy Kerr  *
186889b7da2SJeremy Kerr  * TODO: remove checks & mctp_skb_cb->magic; replace callers of __mctp_cb
187889b7da2SJeremy Kerr  * with mctp_cb().
188889b7da2SJeremy Kerr  *
189889b7da2SJeremy Kerr  * __mctp_cb() is only for the initial ingress code; we should see ->magic set
190889b7da2SJeremy Kerr  * at all times after this.
191889b7da2SJeremy Kerr  */
192889b7da2SJeremy Kerr static inline struct mctp_skb_cb *__mctp_cb(struct sk_buff *skb)
193889b7da2SJeremy Kerr {
194889b7da2SJeremy Kerr 	struct mctp_skb_cb *cb = (void *)skb->cb;
195889b7da2SJeremy Kerr 
196889b7da2SJeremy Kerr 	cb->magic = 0x4d435450;
197889b7da2SJeremy Kerr 	return cb;
198889b7da2SJeremy Kerr }
199889b7da2SJeremy Kerr 
200889b7da2SJeremy Kerr static inline struct mctp_skb_cb *mctp_cb(struct sk_buff *skb)
201889b7da2SJeremy Kerr {
202889b7da2SJeremy Kerr 	struct mctp_skb_cb *cb = (void *)skb->cb;
203889b7da2SJeremy Kerr 
20499ce45d5SJeremy Kerr 	BUILD_BUG_ON(sizeof(struct mctp_skb_cb) > sizeof(skb->cb));
205889b7da2SJeremy Kerr 	WARN_ON(cb->magic != 0x4d435450);
206889b7da2SJeremy Kerr 	return (void *)(skb->cb);
207889b7da2SJeremy Kerr }
208889b7da2SJeremy Kerr 
20978476d31SJeremy Kerr /* If CONFIG_MCTP_FLOWS, we may add one of these as a SKB extension,
21078476d31SJeremy Kerr  * indicating the flow to the device driver.
21178476d31SJeremy Kerr  */
21278476d31SJeremy Kerr struct mctp_flow {
21378476d31SJeremy Kerr 	struct mctp_sk_key *key;
21478476d31SJeremy Kerr };
21578476d31SJeremy Kerr 
216889b7da2SJeremy Kerr /* Route definition.
217889b7da2SJeremy Kerr  *
218889b7da2SJeremy Kerr  * These are held in the pernet->mctp.routes list, with RCU protection for
219889b7da2SJeremy Kerr  * removed routes. We hold a reference to the netdev; routes need to be
220889b7da2SJeremy Kerr  * dropped on NETDEV_UNREGISTER events.
221889b7da2SJeremy Kerr  *
222889b7da2SJeremy Kerr  * Updates to the route table are performed under rtnl; all reads under RCU,
223889b7da2SJeremy Kerr  * so routes cannot be referenced over a RCU grace period. Specifically: A
22499ce45d5SJeremy Kerr  * caller cannot block between mctp_route_lookup and mctp_route_release()
225889b7da2SJeremy Kerr  */
226889b7da2SJeremy Kerr struct mctp_route {
227889b7da2SJeremy Kerr 	mctp_eid_t		min, max;
228889b7da2SJeremy Kerr 
229889b7da2SJeremy Kerr 	struct mctp_dev		*dev;
230889b7da2SJeremy Kerr 	unsigned int		mtu;
23183f0a0b7SJeremy Kerr 	unsigned char		type;
232889b7da2SJeremy Kerr 	int			(*output)(struct mctp_route *route,
233889b7da2SJeremy Kerr 					  struct sk_buff *skb);
234889b7da2SJeremy Kerr 
235889b7da2SJeremy Kerr 	struct list_head	list;
236889b7da2SJeremy Kerr 	refcount_t		refs;
237889b7da2SJeremy Kerr 	struct rcu_head		rcu;
238889b7da2SJeremy Kerr };
239889b7da2SJeremy Kerr 
240889b7da2SJeremy Kerr /* route interfaces */
241889b7da2SJeremy Kerr struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
242889b7da2SJeremy Kerr 				     mctp_eid_t daddr);
243889b7da2SJeremy Kerr 
244889b7da2SJeremy Kerr int mctp_local_output(struct sock *sk, struct mctp_route *rt,
245889b7da2SJeremy Kerr 		      struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);
246889b7da2SJeremy Kerr 
24773c61845SJeremy Kerr void mctp_key_unref(struct mctp_sk_key *key);
248*63ed1aabSMatt Johnston struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk,
249*63ed1aabSMatt Johnston 					 mctp_eid_t daddr, mctp_eid_t saddr,
250*63ed1aabSMatt Johnston 					 bool manual, u8 *tagp);
25173c61845SJeremy Kerr 
252889b7da2SJeremy Kerr /* routing <--> device interface */
25306d2f4c5SMatt Johnston unsigned int mctp_default_net(struct net *net);
25406d2f4c5SMatt Johnston int mctp_default_net_set(struct net *net, unsigned int index);
255889b7da2SJeremy Kerr int mctp_route_add_local(struct mctp_dev *mdev, mctp_eid_t addr);
256889b7da2SJeremy Kerr int mctp_route_remove_local(struct mctp_dev *mdev, mctp_eid_t addr);
257889b7da2SJeremy Kerr void mctp_route_remove_dev(struct mctp_dev *mdev);
258889b7da2SJeremy Kerr 
2594d8b9319SMatt Johnston /* neighbour definitions */
2604d8b9319SMatt Johnston enum mctp_neigh_source {
2614d8b9319SMatt Johnston 	MCTP_NEIGH_STATIC,
2624d8b9319SMatt Johnston 	MCTP_NEIGH_DISCOVER,
2634d8b9319SMatt Johnston };
2644d8b9319SMatt Johnston 
2654d8b9319SMatt Johnston struct mctp_neigh {
2664d8b9319SMatt Johnston 	struct mctp_dev		*dev;
2674d8b9319SMatt Johnston 	mctp_eid_t		eid;
2684d8b9319SMatt Johnston 	enum mctp_neigh_source	source;
2694d8b9319SMatt Johnston 
2704d8b9319SMatt Johnston 	unsigned char		ha[MAX_ADDR_LEN];
2714d8b9319SMatt Johnston 
2724d8b9319SMatt Johnston 	struct list_head	list;
2734d8b9319SMatt Johnston 	struct rcu_head		rcu;
2744d8b9319SMatt Johnston };
2754d8b9319SMatt Johnston 
2764d8b9319SMatt Johnston int mctp_neigh_init(void);
2774d8b9319SMatt Johnston void mctp_neigh_exit(void);
2784d8b9319SMatt Johnston 
2794d8b9319SMatt Johnston // ret_hwaddr may be NULL, otherwise must have space for MAX_ADDR_LEN
2804d8b9319SMatt Johnston int mctp_neigh_lookup(struct mctp_dev *dev, mctp_eid_t eid,
2814d8b9319SMatt Johnston 		      void *ret_hwaddr);
2824d8b9319SMatt Johnston void mctp_neigh_remove_dev(struct mctp_dev *mdev);
2834d8b9319SMatt Johnston 
284889b7da2SJeremy Kerr int mctp_routes_init(void);
285889b7da2SJeremy Kerr void mctp_routes_exit(void);
286889b7da2SJeremy Kerr 
287583be982SJeremy Kerr void mctp_device_init(void);
288583be982SJeremy Kerr void mctp_device_exit(void);
289583be982SJeremy Kerr 
2902c8e2e9aSJeremy Kerr #endif /* __NET_MCTP_H */
291