xref: /openbmc/linux/include/net/mctp.h (revision cbebc55c)
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 
3903f2bbc4SMatt Johnston #define MCTP_INITIAL_DEFAULT_NET	1
4003f2bbc4SMatt Johnston 
mctp_address_unicast(mctp_eid_t eid)41cb196b72SJeremy Kerr static inline bool mctp_address_unicast(mctp_eid_t eid)
42583be982SJeremy Kerr {
43583be982SJeremy Kerr 	return eid >= 8 && eid < 255;
44583be982SJeremy Kerr }
45583be982SJeremy Kerr 
mctp_address_broadcast(mctp_eid_t eid)46cb196b72SJeremy Kerr static inline bool mctp_address_broadcast(mctp_eid_t eid)
47cb196b72SJeremy Kerr {
48cb196b72SJeremy Kerr 	return eid == 255;
49cb196b72SJeremy Kerr }
50cb196b72SJeremy Kerr 
mctp_address_null(mctp_eid_t eid)51cb196b72SJeremy Kerr static inline bool mctp_address_null(mctp_eid_t eid)
52cb196b72SJeremy Kerr {
53cb196b72SJeremy Kerr 	return eid == 0;
54cb196b72SJeremy Kerr }
55cb196b72SJeremy Kerr 
mctp_address_matches(mctp_eid_t match,mctp_eid_t eid)568069b22dSJeremy Kerr static inline bool mctp_address_matches(mctp_eid_t match, mctp_eid_t eid)
578069b22dSJeremy Kerr {
588069b22dSJeremy Kerr 	return match == eid || match == MCTP_ADDR_ANY;
598069b22dSJeremy Kerr }
608069b22dSJeremy Kerr 
mctp_hdr(struct sk_buff * skb)61583be982SJeremy Kerr static inline struct mctp_hdr *mctp_hdr(struct sk_buff *skb)
62583be982SJeremy Kerr {
63583be982SJeremy Kerr 	return (struct mctp_hdr *)skb_network_header(skb);
64583be982SJeremy Kerr }
65583be982SJeremy Kerr 
66833ef3b9SJeremy Kerr /* socket implementation */
67833ef3b9SJeremy Kerr struct mctp_sock {
68833ef3b9SJeremy Kerr 	struct sock	sk;
69833ef3b9SJeremy Kerr 
70833ef3b9SJeremy Kerr 	/* bind() params */
71b416beb2SJeremy Kerr 	unsigned int	bind_net;
72833ef3b9SJeremy Kerr 	mctp_eid_t	bind_addr;
73833ef3b9SJeremy Kerr 	__u8		bind_type;
74833ef3b9SJeremy Kerr 
7599ce45d5SJeremy Kerr 	/* sendmsg()/recvmsg() uses struct sockaddr_mctp_ext */
7699ce45d5SJeremy Kerr 	bool		addr_ext;
7799ce45d5SJeremy Kerr 
78833ef3b9SJeremy Kerr 	/* list of mctp_sk_key, for incoming tag lookup. updates protected
79833ef3b9SJeremy Kerr 	 * by sk->net->keys_lock
80833ef3b9SJeremy Kerr 	 */
81833ef3b9SJeremy Kerr 	struct hlist_head keys;
827b14e15aSJeremy Kerr 
837b14e15aSJeremy Kerr 	/* mechanism for expiring allocated keys; will release an allocated
847b14e15aSJeremy Kerr 	 * tag, and any netdev state for a request/response pairing
857b14e15aSJeremy Kerr 	 */
867b14e15aSJeremy Kerr 	struct timer_list key_expiry;
87833ef3b9SJeremy Kerr };
88833ef3b9SJeremy Kerr 
89833ef3b9SJeremy Kerr /* Key for matching incoming packets to sockets or reassembly contexts.
90833ef3b9SJeremy Kerr  * Packets are matched on (src,dest,tag).
91833ef3b9SJeremy Kerr  *
9273c61845SJeremy Kerr  * Lifetime / locking requirements:
93833ef3b9SJeremy Kerr  *
9473c61845SJeremy Kerr  *  - individual key data (ie, the struct itself) is protected by key->lock;
9573c61845SJeremy Kerr  *    changes must be made with that lock held.
9673c61845SJeremy Kerr  *
9773c61845SJeremy Kerr  *  - the lookup fields: peer_addr, local_addr and tag are set before the
9873c61845SJeremy Kerr  *    key is added to lookup lists, and never updated.
9973c61845SJeremy Kerr  *
10073c61845SJeremy Kerr  *  - A ref to the key must be held (throuh key->refs) if a pointer to the
10173c61845SJeremy Kerr  *    key is to be accessed after key->lock is released.
102833ef3b9SJeremy Kerr  *
103833ef3b9SJeremy Kerr  *  - a mctp_sk_key contains a reference to a struct sock; this is valid
104833ef3b9SJeremy Kerr  *    for the life of the key. On sock destruction (through unhash), the key is
10573c61845SJeremy Kerr  *    removed from lists (see below), and marked invalid.
106833ef3b9SJeremy Kerr  *
107833ef3b9SJeremy Kerr  * - these mctp_sk_keys appear on two lists:
108833ef3b9SJeremy Kerr  *     1) the struct mctp_sock->keys list
109833ef3b9SJeremy Kerr  *     2) the struct netns_mctp->keys list
110833ef3b9SJeremy Kerr  *
11173c61845SJeremy Kerr  *   presences on these lists requires a (single) refcount to be held; both
11273c61845SJeremy Kerr  *   lists are updated as a single operation.
11373c61845SJeremy Kerr  *
11473c61845SJeremy Kerr  *   Updates and lookups in either list are performed under the
11573c61845SJeremy Kerr  *   netns_mctp->keys lock. Lookup functions will need to lock the key and
11673c61845SJeremy Kerr  *   take a reference before unlocking the keys_lock. Consequently, the list's
11773c61845SJeremy Kerr  *   keys_lock *cannot* be acquired with the individual key->lock held.
118833ef3b9SJeremy Kerr  *
1194a992bbdSJeremy Kerr  * - a key may have a sk_buff attached as part of an in-progress message
12073c61845SJeremy Kerr  *   reassembly (->reasm_head). The reasm data is protected by the individual
12173c61845SJeremy Kerr  *   key->lock.
1224a992bbdSJeremy Kerr  *
1234a992bbdSJeremy Kerr  * - there are two destruction paths for a mctp_sk_key:
1244a992bbdSJeremy Kerr  *
1254a992bbdSJeremy Kerr  *    - through socket unhash (see mctp_sk_unhash). This performs the list
1264a992bbdSJeremy Kerr  *      removal under keys_lock.
1274a992bbdSJeremy Kerr  *
1284a992bbdSJeremy Kerr  *    - where a key is established to receive a reply message: after receiving
1294a992bbdSJeremy Kerr  *      the (complete) reply, or during reassembly errors. Here, we clean up
1304a992bbdSJeremy Kerr  *      the reassembly context (marking reasm_dead, to prevent another from
1314a992bbdSJeremy Kerr  *      starting), and remove the socket from the netns & socket lists.
1327b14e15aSJeremy Kerr  *
1337b14e15aSJeremy Kerr  *    - through an expiry timeout, on a per-socket timer
134833ef3b9SJeremy Kerr  */
135833ef3b9SJeremy Kerr struct mctp_sk_key {
136833ef3b9SJeremy Kerr 	mctp_eid_t	peer_addr;
13763ed1aabSMatt Johnston 	mctp_eid_t	local_addr; /* MCTP_ADDR_ANY for local owned tags */
138833ef3b9SJeremy Kerr 	__u8		tag; /* incoming tag match; invert TO for local */
139833ef3b9SJeremy Kerr 
140833ef3b9SJeremy Kerr 	/* we hold a ref to sk when set */
141833ef3b9SJeremy Kerr 	struct sock	*sk;
142833ef3b9SJeremy Kerr 
143833ef3b9SJeremy Kerr 	/* routing lookup list */
144833ef3b9SJeremy Kerr 	struct hlist_node hlist;
145833ef3b9SJeremy Kerr 
146833ef3b9SJeremy Kerr 	/* per-socket list */
147833ef3b9SJeremy Kerr 	struct hlist_node sklist;
148833ef3b9SJeremy Kerr 
14973c61845SJeremy Kerr 	/* lock protects against concurrent updates to the reassembly and
15073c61845SJeremy Kerr 	 * expiry data below.
15173c61845SJeremy Kerr 	 */
15273c61845SJeremy Kerr 	spinlock_t	lock;
15373c61845SJeremy Kerr 
15473c61845SJeremy Kerr 	/* Keys are referenced during the output path, which may sleep */
15573c61845SJeremy Kerr 	refcount_t	refs;
15673c61845SJeremy Kerr 
1574a992bbdSJeremy Kerr 	/* incoming fragment reassembly context */
1584a992bbdSJeremy Kerr 	struct sk_buff	*reasm_head;
1594a992bbdSJeremy Kerr 	struct sk_buff	**reasm_tailp;
1604a992bbdSJeremy Kerr 	bool		reasm_dead;
1614a992bbdSJeremy Kerr 	u8		last_seq;
1624a992bbdSJeremy Kerr 
16373c61845SJeremy Kerr 	/* key validity */
16473c61845SJeremy Kerr 	bool		valid;
1657b14e15aSJeremy Kerr 
1667b14e15aSJeremy Kerr 	/* expiry timeout; valid (above) cleared on expiry */
1677b14e15aSJeremy Kerr 	unsigned long	expiry;
16867737c45SJeremy Kerr 
16967737c45SJeremy Kerr 	/* free to use for device flow state tracking. Initialised to
17067737c45SJeremy Kerr 	 * zero on initial key creation
17167737c45SJeremy Kerr 	 */
17267737c45SJeremy Kerr 	unsigned long	dev_flow_state;
17367737c45SJeremy Kerr 	struct mctp_dev	*dev;
17463ed1aabSMatt Johnston 
17563ed1aabSMatt Johnston 	/* a tag allocated with SIOCMCTPALLOCTAG ioctl will not expire
17663ed1aabSMatt Johnston 	 * automatically on timeout or response, instead SIOCMCTPDROPTAG
17763ed1aabSMatt Johnston 	 * is used.
17863ed1aabSMatt Johnston 	 */
17963ed1aabSMatt Johnston 	bool		manual_alloc;
180833ef3b9SJeremy Kerr };
181833ef3b9SJeremy Kerr 
182889b7da2SJeremy Kerr struct mctp_skb_cb {
183889b7da2SJeremy Kerr 	unsigned int	magic;
184889b7da2SJeremy Kerr 	unsigned int	net;
18599ce45d5SJeremy Kerr 	int		ifindex; /* extended/direct addressing if set */
186889b7da2SJeremy Kerr 	mctp_eid_t	src;
18799ce45d5SJeremy Kerr 	unsigned char	halen;
18899ce45d5SJeremy Kerr 	unsigned char	haddr[MAX_ADDR_LEN];
189889b7da2SJeremy Kerr };
190889b7da2SJeremy Kerr 
191889b7da2SJeremy Kerr /* skb control-block accessors with a little extra debugging for initial
192889b7da2SJeremy Kerr  * development.
193889b7da2SJeremy Kerr  *
194889b7da2SJeremy Kerr  * TODO: remove checks & mctp_skb_cb->magic; replace callers of __mctp_cb
195889b7da2SJeremy Kerr  * with mctp_cb().
196889b7da2SJeremy Kerr  *
197889b7da2SJeremy Kerr  * __mctp_cb() is only for the initial ingress code; we should see ->magic set
198889b7da2SJeremy Kerr  * at all times after this.
199889b7da2SJeremy Kerr  */
__mctp_cb(struct sk_buff * skb)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 
204889b7da2SJeremy Kerr 	cb->magic = 0x4d435450;
205889b7da2SJeremy Kerr 	return cb;
206889b7da2SJeremy Kerr }
207889b7da2SJeremy Kerr 
mctp_cb(struct sk_buff * skb)208889b7da2SJeremy Kerr static inline struct mctp_skb_cb *mctp_cb(struct sk_buff *skb)
209889b7da2SJeremy Kerr {
210889b7da2SJeremy Kerr 	struct mctp_skb_cb *cb = (void *)skb->cb;
211889b7da2SJeremy Kerr 
21299ce45d5SJeremy Kerr 	BUILD_BUG_ON(sizeof(struct mctp_skb_cb) > sizeof(skb->cb));
213889b7da2SJeremy Kerr 	WARN_ON(cb->magic != 0x4d435450);
214889b7da2SJeremy Kerr 	return (void *)(skb->cb);
215889b7da2SJeremy Kerr }
216889b7da2SJeremy Kerr 
21778476d31SJeremy Kerr /* If CONFIG_MCTP_FLOWS, we may add one of these as a SKB extension,
21878476d31SJeremy Kerr  * indicating the flow to the device driver.
21978476d31SJeremy Kerr  */
22078476d31SJeremy Kerr struct mctp_flow {
22178476d31SJeremy Kerr 	struct mctp_sk_key *key;
22278476d31SJeremy Kerr };
22378476d31SJeremy Kerr 
224889b7da2SJeremy Kerr /* Route definition.
225889b7da2SJeremy Kerr  *
226889b7da2SJeremy Kerr  * These are held in the pernet->mctp.routes list, with RCU protection for
227889b7da2SJeremy Kerr  * removed routes. We hold a reference to the netdev; routes need to be
228889b7da2SJeremy Kerr  * dropped on NETDEV_UNREGISTER events.
229889b7da2SJeremy Kerr  *
230889b7da2SJeremy Kerr  * Updates to the route table are performed under rtnl; all reads under RCU,
231889b7da2SJeremy Kerr  * so routes cannot be referenced over a RCU grace period. Specifically: A
23299ce45d5SJeremy Kerr  * caller cannot block between mctp_route_lookup and mctp_route_release()
233889b7da2SJeremy Kerr  */
234889b7da2SJeremy Kerr struct mctp_route {
235889b7da2SJeremy Kerr 	mctp_eid_t		min, max;
236889b7da2SJeremy Kerr 
23783f0a0b7SJeremy Kerr 	unsigned char		type;
238066768b7SChristophe JAILLET 	unsigned int		mtu;
239066768b7SChristophe JAILLET 	struct mctp_dev		*dev;
240889b7da2SJeremy Kerr 	int			(*output)(struct mctp_route *route,
241889b7da2SJeremy Kerr 					  struct sk_buff *skb);
242889b7da2SJeremy Kerr 
243889b7da2SJeremy Kerr 	struct list_head	list;
244889b7da2SJeremy Kerr 	refcount_t		refs;
245889b7da2SJeremy Kerr 	struct rcu_head		rcu;
246889b7da2SJeremy Kerr };
247889b7da2SJeremy Kerr 
248889b7da2SJeremy Kerr /* route interfaces */
249889b7da2SJeremy Kerr struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
250889b7da2SJeremy Kerr 				     mctp_eid_t daddr);
251889b7da2SJeremy Kerr 
252*cbebc55cSJeremy Kerr /* always takes ownership of skb */
253889b7da2SJeremy Kerr int mctp_local_output(struct sock *sk, struct mctp_route *rt,
254889b7da2SJeremy Kerr 		      struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);
255889b7da2SJeremy Kerr 
25673c61845SJeremy Kerr void mctp_key_unref(struct mctp_sk_key *key);
25763ed1aabSMatt Johnston struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk,
25863ed1aabSMatt Johnston 					 mctp_eid_t daddr, mctp_eid_t saddr,
25963ed1aabSMatt Johnston 					 bool manual, u8 *tagp);
26073c61845SJeremy Kerr 
261889b7da2SJeremy Kerr /* routing <--> device interface */
26206d2f4c5SMatt Johnston unsigned int mctp_default_net(struct net *net);
26306d2f4c5SMatt Johnston int mctp_default_net_set(struct net *net, unsigned int index);
264889b7da2SJeremy Kerr int mctp_route_add_local(struct mctp_dev *mdev, mctp_eid_t addr);
265889b7da2SJeremy Kerr int mctp_route_remove_local(struct mctp_dev *mdev, mctp_eid_t addr);
266889b7da2SJeremy Kerr void mctp_route_remove_dev(struct mctp_dev *mdev);
267889b7da2SJeremy Kerr 
2684d8b9319SMatt Johnston /* neighbour definitions */
2694d8b9319SMatt Johnston enum mctp_neigh_source {
2704d8b9319SMatt Johnston 	MCTP_NEIGH_STATIC,
2714d8b9319SMatt Johnston 	MCTP_NEIGH_DISCOVER,
2724d8b9319SMatt Johnston };
2734d8b9319SMatt Johnston 
2744d8b9319SMatt Johnston struct mctp_neigh {
2754d8b9319SMatt Johnston 	struct mctp_dev		*dev;
2764d8b9319SMatt Johnston 	mctp_eid_t		eid;
2774d8b9319SMatt Johnston 	enum mctp_neigh_source	source;
2784d8b9319SMatt Johnston 
2794d8b9319SMatt Johnston 	unsigned char		ha[MAX_ADDR_LEN];
2804d8b9319SMatt Johnston 
2814d8b9319SMatt Johnston 	struct list_head	list;
2824d8b9319SMatt Johnston 	struct rcu_head		rcu;
2834d8b9319SMatt Johnston };
2844d8b9319SMatt Johnston 
2854d8b9319SMatt Johnston int mctp_neigh_init(void);
2864d8b9319SMatt Johnston void mctp_neigh_exit(void);
2874d8b9319SMatt Johnston 
2884d8b9319SMatt Johnston // ret_hwaddr may be NULL, otherwise must have space for MAX_ADDR_LEN
2894d8b9319SMatt Johnston int mctp_neigh_lookup(struct mctp_dev *dev, mctp_eid_t eid,
2904d8b9319SMatt Johnston 		      void *ret_hwaddr);
2914d8b9319SMatt Johnston void mctp_neigh_remove_dev(struct mctp_dev *mdev);
2924d8b9319SMatt Johnston 
293889b7da2SJeremy Kerr int mctp_routes_init(void);
294889b7da2SJeremy Kerr void mctp_routes_exit(void);
295889b7da2SJeremy Kerr 
296583be982SJeremy Kerr void mctp_device_init(void);
297583be982SJeremy Kerr void mctp_device_exit(void);
298583be982SJeremy Kerr 
2992c8e2e9aSJeremy Kerr #endif /* __NET_MCTP_H */
300