blob: 8d9f4ff3e285cdf38121f21ce1a1aade23d19491 [file] [log] [blame]
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Management Component Transport Protocol (MCTP) - routing
4 * implementation.
5 *
6 * This is currently based on a simple routing table, with no dst cache. The
7 * number of routes should stay fairly small, so the lookup cost is small.
8 *
9 * Copyright (c) 2021 Code Construct
10 * Copyright (c) 2021 Google
11 */
12
13#include <linux/idr.h>
Jeremy Kerr161eba52021-10-03 11:17:04 +080014#include <linux/kconfig.h>
Jeremy Kerr889b7da2021-07-29 10:20:45 +080015#include <linux/mctp.h>
16#include <linux/netdevice.h>
17#include <linux/rtnetlink.h>
18#include <linux/skbuff.h>
19
20#include <uapi/linux/if_arp.h>
21
22#include <net/mctp.h>
23#include <net/mctpdevice.h>
Matt Johnston06d2f4c2021-07-29 10:20:46 +080024#include <net/netlink.h>
25#include <net/sock.h>
Jeremy Kerr889b7da2021-07-29 10:20:45 +080026
Jeremy Kerr4f9e1ba2021-09-29 15:26:10 +080027#include <trace/events/mctp.h>
28
Jeremy Kerr4a992bb2021-07-29 10:20:50 +080029static const unsigned int mctp_message_maxlen = 64 * 1024;
Jeremy Kerr7b14e152021-09-29 15:26:09 +080030static const unsigned long mctp_key_lifetime = 6 * CONFIG_HZ;
31
Jeremy Kerr67737c42021-10-29 11:01:45 +080032static void mctp_flow_prepare_output(struct sk_buff *skb, struct mctp_dev *dev);
33
Jeremy Kerr889b7da2021-07-29 10:20:45 +080034/* route output callbacks */
35static int mctp_route_discard(struct mctp_route *route, struct sk_buff *skb)
36{
37 kfree_skb(skb);
38 return 0;
39}
40
Jeremy Kerr833ef3b2021-07-29 10:20:49 +080041static struct mctp_sock *mctp_lookup_bind(struct net *net, struct sk_buff *skb)
42{
43 struct mctp_skb_cb *cb = mctp_cb(skb);
44 struct mctp_hdr *mh;
45 struct sock *sk;
46 u8 type;
47
48 WARN_ON(!rcu_read_lock_held());
49
50 /* TODO: look up in skb->cb? */
51 mh = mctp_hdr(skb);
52
53 if (!skb_headlen(skb))
54 return NULL;
55
56 type = (*(u8 *)skb->data) & 0x7f;
57
58 sk_for_each_rcu(sk, &net->mctp.binds) {
59 struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
60
61 if (msk->bind_net != MCTP_NET_ANY && msk->bind_net != cb->net)
62 continue;
63
64 if (msk->bind_type != type)
65 continue;
66
67 if (msk->bind_addr != MCTP_ADDR_ANY &&
68 msk->bind_addr != mh->dest)
69 continue;
70
71 return msk;
72 }
73
74 return NULL;
75}
76
77static bool mctp_key_match(struct mctp_sk_key *key, mctp_eid_t local,
78 mctp_eid_t peer, u8 tag)
79{
80 if (key->local_addr != local)
81 return false;
82
83 if (key->peer_addr != peer)
84 return false;
85
86 if (key->tag != tag)
87 return false;
88
89 return true;
90}
91
Jeremy Kerr73c61842021-09-29 15:26:07 +080092/* returns a key (with key->lock held, and refcounted), or NULL if no such
93 * key exists.
94 */
Jeremy Kerr833ef3b2021-07-29 10:20:49 +080095static struct mctp_sk_key *mctp_lookup_key(struct net *net, struct sk_buff *skb,
Jeremy Kerr73c61842021-09-29 15:26:07 +080096 mctp_eid_t peer,
97 unsigned long *irqflags)
98 __acquires(&key->lock)
Jeremy Kerr833ef3b2021-07-29 10:20:49 +080099{
100 struct mctp_sk_key *key, *ret;
Jeremy Kerr73c61842021-09-29 15:26:07 +0800101 unsigned long flags;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800102 struct mctp_hdr *mh;
103 u8 tag;
104
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800105 mh = mctp_hdr(skb);
106 tag = mh->flags_seq_tag & (MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO);
107
108 ret = NULL;
Jeremy Kerr73c61842021-09-29 15:26:07 +0800109 spin_lock_irqsave(&net->mctp.keys_lock, flags);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800110
Jeremy Kerr73c61842021-09-29 15:26:07 +0800111 hlist_for_each_entry(key, &net->mctp.keys, hlist) {
112 if (!mctp_key_match(key, mh->dest, peer, tag))
113 continue;
114
115 spin_lock(&key->lock);
116 if (key->valid) {
117 refcount_inc(&key->refs);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800118 ret = key;
119 break;
120 }
Jeremy Kerr73c61842021-09-29 15:26:07 +0800121 spin_unlock(&key->lock);
122 }
123
124 if (ret) {
125 spin_unlock(&net->mctp.keys_lock);
126 *irqflags = flags;
127 } else {
128 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800129 }
130
131 return ret;
132}
133
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800134static struct mctp_sk_key *mctp_key_alloc(struct mctp_sock *msk,
135 mctp_eid_t local, mctp_eid_t peer,
136 u8 tag, gfp_t gfp)
137{
138 struct mctp_sk_key *key;
139
140 key = kzalloc(sizeof(*key), gfp);
141 if (!key)
142 return NULL;
143
144 key->peer_addr = peer;
145 key->local_addr = local;
146 key->tag = tag;
147 key->sk = &msk->sk;
Jeremy Kerr73c61842021-09-29 15:26:07 +0800148 key->valid = true;
149 spin_lock_init(&key->lock);
150 refcount_set(&key->refs, 1);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800151
152 return key;
153}
154
Jeremy Kerr73c61842021-09-29 15:26:07 +0800155void mctp_key_unref(struct mctp_sk_key *key)
156{
Jeremy Kerr67737c42021-10-29 11:01:45 +0800157 unsigned long flags;
158
159 if (!refcount_dec_and_test(&key->refs))
160 return;
161
162 /* even though no refs exist here, the lock allows us to stay
163 * consistent with the locking requirement of mctp_dev_release_key
164 */
165 spin_lock_irqsave(&key->lock, flags);
166 mctp_dev_release_key(key->dev, key);
167 spin_unlock_irqrestore(&key->lock, flags);
168
169 kfree(key);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800170}
171
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800172static int mctp_key_add(struct mctp_sk_key *key, struct mctp_sock *msk)
173{
174 struct net *net = sock_net(&msk->sk);
175 struct mctp_sk_key *tmp;
176 unsigned long flags;
177 int rc = 0;
178
179 spin_lock_irqsave(&net->mctp.keys_lock, flags);
180
181 hlist_for_each_entry(tmp, &net->mctp.keys, hlist) {
182 if (mctp_key_match(tmp, key->local_addr, key->peer_addr,
183 key->tag)) {
Jeremy Kerr73c61842021-09-29 15:26:07 +0800184 spin_lock(&tmp->lock);
185 if (tmp->valid)
186 rc = -EEXIST;
187 spin_unlock(&tmp->lock);
188 if (rc)
189 break;
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800190 }
191 }
192
193 if (!rc) {
Jeremy Kerr73c61842021-09-29 15:26:07 +0800194 refcount_inc(&key->refs);
Jeremy Kerr7b14e152021-09-29 15:26:09 +0800195 key->expiry = jiffies + mctp_key_lifetime;
196 timer_reduce(&msk->key_expiry, key->expiry);
197
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800198 hlist_add_head(&key->hlist, &net->mctp.keys);
199 hlist_add_head(&key->sklist, &msk->keys);
200 }
201
202 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
203
204 return rc;
205}
206
Jeremy Kerr73c61842021-09-29 15:26:07 +0800207/* We're done with the key; unset valid and remove from lists. There may still
208 * be outstanding refs on the key though...
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800209 */
210static void __mctp_key_unlock_drop(struct mctp_sk_key *key, struct net *net,
211 unsigned long flags)
Jeremy Kerr73c61842021-09-29 15:26:07 +0800212 __releases(&key->lock)
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800213{
214 struct sk_buff *skb;
215
216 skb = key->reasm_head;
217 key->reasm_head = NULL;
218 key->reasm_dead = true;
Jeremy Kerr73c61842021-09-29 15:26:07 +0800219 key->valid = false;
Jeremy Kerr67737c42021-10-29 11:01:45 +0800220 mctp_dev_release_key(key->dev, key);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800221 spin_unlock_irqrestore(&key->lock, flags);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800222
223 spin_lock_irqsave(&net->mctp.keys_lock, flags);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800224 hlist_del(&key->hlist);
225 hlist_del(&key->sklist);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800226 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800227
228 /* one unref for the lists */
229 mctp_key_unref(key);
230
231 /* and one for the local reference */
232 mctp_key_unref(key);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800233
Yang Yingliang5cfe53c2021-11-30 11:12:43 +0800234 kfree_skb(skb);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800235}
236
Jeremy Kerr67737c42021-10-29 11:01:45 +0800237#ifdef CONFIG_MCTP_FLOWS
238static void mctp_skb_set_flow(struct sk_buff *skb, struct mctp_sk_key *key)
239{
240 struct mctp_flow *flow;
241
242 flow = skb_ext_add(skb, SKB_EXT_MCTP);
243 if (!flow)
244 return;
245
246 refcount_inc(&key->refs);
247 flow->key = key;
248}
249
250static void mctp_flow_prepare_output(struct sk_buff *skb, struct mctp_dev *dev)
251{
252 struct mctp_sk_key *key;
253 struct mctp_flow *flow;
254
255 flow = skb_ext_find(skb, SKB_EXT_MCTP);
256 if (!flow)
257 return;
258
259 key = flow->key;
260
261 if (WARN_ON(key->dev && key->dev != dev))
262 return;
263
264 mctp_dev_set_key(dev, key);
265}
266#else
267static void mctp_skb_set_flow(struct sk_buff *skb, struct mctp_sk_key *key) {}
268static void mctp_flow_prepare_output(struct sk_buff *skb, struct mctp_dev *dev) {}
269#endif
270
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800271static int mctp_frag_queue(struct mctp_sk_key *key, struct sk_buff *skb)
272{
273 struct mctp_hdr *hdr = mctp_hdr(skb);
274 u8 exp_seq, this_seq;
275
276 this_seq = (hdr->flags_seq_tag >> MCTP_HDR_SEQ_SHIFT)
277 & MCTP_HDR_SEQ_MASK;
278
279 if (!key->reasm_head) {
280 key->reasm_head = skb;
281 key->reasm_tailp = &(skb_shinfo(skb)->frag_list);
282 key->last_seq = this_seq;
283 return 0;
284 }
285
286 exp_seq = (key->last_seq + 1) & MCTP_HDR_SEQ_MASK;
287
288 if (this_seq != exp_seq)
289 return -EINVAL;
290
291 if (key->reasm_head->len + skb->len > mctp_message_maxlen)
292 return -EINVAL;
293
294 skb->next = NULL;
295 skb->sk = NULL;
296 *key->reasm_tailp = skb;
297 key->reasm_tailp = &skb->next;
298
299 key->last_seq = this_seq;
300
301 key->reasm_head->data_len += skb->len;
302 key->reasm_head->len += skb->len;
303 key->reasm_head->truesize += skb->truesize;
304
305 return 0;
306}
307
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800308static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb)
309{
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800310 struct net *net = dev_net(skb->dev);
311 struct mctp_sk_key *key;
312 struct mctp_sock *msk;
313 struct mctp_hdr *mh;
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800314 unsigned long f;
315 u8 tag, flags;
316 int rc;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800317
318 msk = NULL;
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800319 rc = -EINVAL;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800320
321 /* we may be receiving a locally-routed packet; drop source sk
322 * accounting
323 */
324 skb_orphan(skb);
325
326 /* ensure we have enough data for a header and a type */
327 if (skb->len < sizeof(struct mctp_hdr) + 1)
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800328 goto out;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800329
330 /* grab header, advance data ptr */
331 mh = mctp_hdr(skb);
332 skb_pull(skb, sizeof(struct mctp_hdr));
333
334 if (mh->ver != 1)
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800335 goto out;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800336
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800337 flags = mh->flags_seq_tag & (MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM);
338 tag = mh->flags_seq_tag & (MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800339
340 rcu_read_lock();
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800341
Jeremy Kerr73c61842021-09-29 15:26:07 +0800342 /* lookup socket / reasm context, exactly matching (src,dest,tag).
343 * we hold a ref on the key, and key->lock held.
344 */
345 key = mctp_lookup_key(net, skb, mh->src, &f);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800346
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800347 if (flags & MCTP_HDR_FLAG_SOM) {
348 if (key) {
349 msk = container_of(key->sk, struct mctp_sock, sk);
350 } else {
351 /* first response to a broadcast? do a more general
352 * key lookup to find the socket, but don't use this
353 * key for reassembly - we'll create a more specific
354 * one for future packets if required (ie, !EOM).
355 */
Jeremy Kerr73c61842021-09-29 15:26:07 +0800356 key = mctp_lookup_key(net, skb, MCTP_ADDR_ANY, &f);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800357 if (key) {
358 msk = container_of(key->sk,
359 struct mctp_sock, sk);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800360 spin_unlock_irqrestore(&key->lock, f);
361 mctp_key_unref(key);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800362 key = NULL;
363 }
364 }
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800365
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800366 if (!key && !msk && (tag & MCTP_HDR_FLAG_TO))
367 msk = mctp_lookup_bind(net, skb);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800368
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800369 if (!msk) {
370 rc = -ENOENT;
371 goto out_unlock;
372 }
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800373
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800374 /* single-packet message? deliver to socket, clean up any
375 * pending key.
376 */
377 if (flags & MCTP_HDR_FLAG_EOM) {
378 sock_queue_rcv_skb(&msk->sk, skb);
379 if (key) {
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800380 /* we've hit a pending reassembly; not much we
381 * can do but drop it
382 */
Jeremy Kerr4f9e1ba2021-09-29 15:26:10 +0800383 trace_mctp_key_release(key,
384 MCTP_TRACE_KEY_REPLIED);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800385 __mctp_key_unlock_drop(key, net, f);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800386 key = NULL;
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800387 }
388 rc = 0;
389 goto out_unlock;
390 }
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800391
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800392 /* broadcast response or a bind() - create a key for further
393 * packets for this message
394 */
395 if (!key) {
396 key = mctp_key_alloc(msk, mh->dest, mh->src,
397 tag, GFP_ATOMIC);
398 if (!key) {
399 rc = -ENOMEM;
400 goto out_unlock;
401 }
402
Jeremy Kerr73c61842021-09-29 15:26:07 +0800403 /* we can queue without the key lock here, as the
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800404 * key isn't observable yet
405 */
406 mctp_frag_queue(key, skb);
407
408 /* if the key_add fails, we've raced with another
409 * SOM packet with the same src, dest and tag. There's
410 * no way to distinguish future packets, so all we
411 * can do is drop; we'll free the skb on exit from
412 * this function.
413 */
414 rc = mctp_key_add(key, msk);
415 if (rc)
416 kfree(key);
417
Jeremy Kerr4f9e1ba2021-09-29 15:26:10 +0800418 trace_mctp_key_acquire(key);
419
Jeremy Kerr73c61842021-09-29 15:26:07 +0800420 /* we don't need to release key->lock on exit */
Matt Johnston0b93aed2021-10-14 16:10:50 +0800421 mctp_key_unref(key);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800422 key = NULL;
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800423
Jeremy Kerr73c61842021-09-29 15:26:07 +0800424 } else {
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800425 if (key->reasm_head || key->reasm_dead) {
426 /* duplicate start? drop everything */
Jeremy Kerr4f9e1ba2021-09-29 15:26:10 +0800427 trace_mctp_key_release(key,
428 MCTP_TRACE_KEY_INVALIDATED);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800429 __mctp_key_unlock_drop(key, net, f);
430 rc = -EEXIST;
Jeremy Kerr73c61842021-09-29 15:26:07 +0800431 key = NULL;
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800432 } else {
433 rc = mctp_frag_queue(key, skb);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800434 }
435 }
436
437 } else if (key) {
438 /* this packet continues a previous message; reassemble
439 * using the message-specific key
440 */
441
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800442 /* we need to be continuing an existing reassembly... */
443 if (!key->reasm_head)
444 rc = -EINVAL;
445 else
446 rc = mctp_frag_queue(key, skb);
447
448 /* end of message? deliver to socket, and we're done with
449 * the reassembly/response key
450 */
451 if (!rc && flags & MCTP_HDR_FLAG_EOM) {
452 sock_queue_rcv_skb(key->sk, key->reasm_head);
453 key->reasm_head = NULL;
Jeremy Kerr4f9e1ba2021-09-29 15:26:10 +0800454 trace_mctp_key_release(key, MCTP_TRACE_KEY_REPLIED);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800455 __mctp_key_unlock_drop(key, net, f);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800456 key = NULL;
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800457 }
458
459 } else {
460 /* not a start, no matching key */
461 rc = -ENOENT;
462 }
463
464out_unlock:
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800465 rcu_read_unlock();
Jeremy Kerr73c61842021-09-29 15:26:07 +0800466 if (key) {
467 spin_unlock_irqrestore(&key->lock, f);
468 mctp_key_unref(key);
469 }
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800470out:
471 if (rc)
472 kfree_skb(skb);
473 return rc;
474}
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800475
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800476static unsigned int mctp_route_mtu(struct mctp_route *rt)
477{
478 return rt->mtu ?: READ_ONCE(rt->dev->dev->mtu);
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800479}
480
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800481static int mctp_route_output(struct mctp_route *route, struct sk_buff *skb)
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800482{
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800483 struct mctp_skb_cb *cb = mctp_cb(skb);
Matt Johnston26ab3fc2021-07-29 10:20:51 +0800484 struct mctp_hdr *hdr = mctp_hdr(skb);
485 char daddr_buf[MAX_ADDR_LEN];
486 char *daddr = NULL;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800487 unsigned int mtu;
488 int rc;
489
490 skb->protocol = htons(ETH_P_MCTP);
491
492 mtu = READ_ONCE(skb->dev->mtu);
493 if (skb->len > mtu) {
494 kfree_skb(skb);
495 return -EMSGSIZE;
496 }
497
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800498 if (cb->ifindex) {
499 /* direct route; use the hwaddr we stashed in sendmsg */
500 daddr = cb->haddr;
501 } else {
502 /* If lookup fails let the device handle daddr==NULL */
503 if (mctp_neigh_lookup(route->dev, hdr->dest, daddr_buf) == 0)
504 daddr = daddr_buf;
505 }
Matt Johnston26ab3fc2021-07-29 10:20:51 +0800506
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800507 rc = dev_hard_header(skb, skb->dev, ntohs(skb->protocol),
Matt Johnston26ab3fc2021-07-29 10:20:51 +0800508 daddr, skb->dev->dev_addr, skb->len);
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800509 if (rc) {
510 kfree_skb(skb);
511 return -EHOSTUNREACH;
512 }
513
Jeremy Kerr67737c42021-10-29 11:01:45 +0800514 mctp_flow_prepare_output(skb, route->dev);
515
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800516 rc = dev_queue_xmit(skb);
517 if (rc)
518 rc = net_xmit_errno(rc);
519
520 return rc;
521}
522
523/* route alloc/release */
524static void mctp_route_release(struct mctp_route *rt)
525{
526 if (refcount_dec_and_test(&rt->refs)) {
Jeremy Kerr43f55f22021-09-29 15:26:08 +0800527 mctp_dev_put(rt->dev);
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800528 kfree_rcu(rt, rcu);
529 }
530}
531
532/* returns a route with the refcount at 1 */
533static struct mctp_route *mctp_route_alloc(void)
534{
535 struct mctp_route *rt;
536
537 rt = kzalloc(sizeof(*rt), GFP_KERNEL);
538 if (!rt)
539 return NULL;
540
541 INIT_LIST_HEAD(&rt->list);
542 refcount_set(&rt->refs, 1);
543 rt->output = mctp_route_discard;
544
545 return rt;
546}
547
Matt Johnston03f2bbc2021-07-29 10:20:52 +0800548unsigned int mctp_default_net(struct net *net)
549{
550 return READ_ONCE(net->mctp.default_net);
551}
552
553int mctp_default_net_set(struct net *net, unsigned int index)
554{
555 if (index == 0)
556 return -EINVAL;
557 WRITE_ONCE(net->mctp.default_net, index);
558 return 0;
559}
560
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800561/* tag management */
562static void mctp_reserve_tag(struct net *net, struct mctp_sk_key *key,
563 struct mctp_sock *msk)
564{
565 struct netns_mctp *mns = &net->mctp;
566
567 lockdep_assert_held(&mns->keys_lock);
568
Jeremy Kerr7b14e152021-09-29 15:26:09 +0800569 key->expiry = jiffies + mctp_key_lifetime;
570 timer_reduce(&msk->key_expiry, key->expiry);
571
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800572 /* we hold the net->key_lock here, allowing updates to both
573 * then net and sk
574 */
575 hlist_add_head_rcu(&key->hlist, &mns->keys);
576 hlist_add_head_rcu(&key->sklist, &msk->keys);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800577 refcount_inc(&key->refs);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800578}
579
580/* Allocate a locally-owned tag value for (saddr, daddr), and reserve
581 * it for the socket msk
582 */
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800583static struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk,
584 mctp_eid_t saddr,
585 mctp_eid_t daddr, u8 *tagp)
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800586{
587 struct net *net = sock_net(&msk->sk);
588 struct netns_mctp *mns = &net->mctp;
589 struct mctp_sk_key *key, *tmp;
590 unsigned long flags;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800591 u8 tagbits;
592
Jeremy Kerr1f6c77a2021-09-29 15:26:06 +0800593 /* for NULL destination EIDs, we may get a response from any peer */
594 if (daddr == MCTP_ADDR_NULL)
595 daddr = MCTP_ADDR_ANY;
596
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800597 /* be optimistic, alloc now */
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800598 key = mctp_key_alloc(msk, saddr, daddr, 0, GFP_KERNEL);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800599 if (!key)
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800600 return ERR_PTR(-ENOMEM);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800601
602 /* 8 possible tag values */
603 tagbits = 0xff;
604
605 spin_lock_irqsave(&mns->keys_lock, flags);
606
607 /* Walk through the existing keys, looking for potential conflicting
608 * tags. If we find a conflict, clear that bit from tagbits
609 */
610 hlist_for_each_entry(tmp, &mns->keys, hlist) {
Jeremy Kerr73c61842021-09-29 15:26:07 +0800611 /* We can check the lookup fields (*_addr, tag) without the
612 * lock held, they don't change over the lifetime of the key.
613 */
614
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800615 /* if we don't own the tag, it can't conflict */
616 if (tmp->tag & MCTP_HDR_FLAG_TO)
617 continue;
618
Jeremy Kerr73c61842021-09-29 15:26:07 +0800619 if (!((tmp->peer_addr == daddr ||
620 tmp->peer_addr == MCTP_ADDR_ANY) &&
621 tmp->local_addr == saddr))
622 continue;
623
624 spin_lock(&tmp->lock);
625 /* key must still be valid. If we find a match, clear the
626 * potential tag value
627 */
628 if (tmp->valid)
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800629 tagbits &= ~(1 << tmp->tag);
Jeremy Kerr73c61842021-09-29 15:26:07 +0800630 spin_unlock(&tmp->lock);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800631
632 if (!tagbits)
633 break;
634 }
635
636 if (tagbits) {
637 key->tag = __ffs(tagbits);
638 mctp_reserve_tag(net, key, msk);
Jeremy Kerr4f9e1ba2021-09-29 15:26:10 +0800639 trace_mctp_key_acquire(key);
640
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800641 *tagp = key->tag;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800642 }
643
644 spin_unlock_irqrestore(&mns->keys_lock, flags);
645
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800646 if (!tagbits) {
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800647 kfree(key);
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800648 return ERR_PTR(-EBUSY);
649 }
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800650
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800651 return key;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800652}
653
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800654/* routing lookups */
655static bool mctp_rt_match_eid(struct mctp_route *rt,
656 unsigned int net, mctp_eid_t eid)
657{
658 return READ_ONCE(rt->dev->net) == net &&
659 rt->min <= eid && rt->max >= eid;
660}
661
662/* compares match, used for duplicate prevention */
663static bool mctp_rt_compare_exact(struct mctp_route *rt1,
664 struct mctp_route *rt2)
665{
666 ASSERT_RTNL();
667 return rt1->dev->net == rt2->dev->net &&
668 rt1->min == rt2->min &&
669 rt1->max == rt2->max;
670}
671
672struct mctp_route *mctp_route_lookup(struct net *net, unsigned int dnet,
673 mctp_eid_t daddr)
674{
675 struct mctp_route *tmp, *rt = NULL;
676
677 list_for_each_entry_rcu(tmp, &net->mctp.routes, list) {
678 /* TODO: add metrics */
679 if (mctp_rt_match_eid(tmp, dnet, daddr)) {
680 if (refcount_inc_not_zero(&tmp->refs)) {
681 rt = tmp;
682 break;
683 }
684 }
685 }
686
687 return rt;
688}
689
Jeremy Kerr1f6c77a2021-09-29 15:26:06 +0800690static struct mctp_route *mctp_route_lookup_null(struct net *net,
691 struct net_device *dev)
692{
693 struct mctp_route *rt;
694
695 list_for_each_entry_rcu(rt, &net->mctp.routes, list) {
696 if (rt->dev->dev == dev && rt->type == RTN_LOCAL &&
697 refcount_inc_not_zero(&rt->refs))
698 return rt;
699 }
700
701 return NULL;
702}
703
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800704static int mctp_do_fragment_route(struct mctp_route *rt, struct sk_buff *skb,
705 unsigned int mtu, u8 tag)
706{
707 const unsigned int hlen = sizeof(struct mctp_hdr);
708 struct mctp_hdr *hdr, *hdr2;
709 unsigned int pos, size;
710 struct sk_buff *skb2;
711 int rc;
712 u8 seq;
713
714 hdr = mctp_hdr(skb);
715 seq = 0;
716 rc = 0;
717
718 if (mtu < hlen + 1) {
719 kfree_skb(skb);
720 return -EMSGSIZE;
721 }
722
723 /* we've got the header */
724 skb_pull(skb, hlen);
725
726 for (pos = 0; pos < skb->len;) {
727 /* size of message payload */
728 size = min(mtu - hlen, skb->len - pos);
729
730 skb2 = alloc_skb(MCTP_HEADER_MAXLEN + hlen + size, GFP_KERNEL);
731 if (!skb2) {
732 rc = -ENOMEM;
733 break;
734 }
735
736 /* generic skb copy */
737 skb2->protocol = skb->protocol;
738 skb2->priority = skb->priority;
739 skb2->dev = skb->dev;
740 memcpy(skb2->cb, skb->cb, sizeof(skb2->cb));
741
742 if (skb->sk)
743 skb_set_owner_w(skb2, skb->sk);
744
745 /* establish packet */
746 skb_reserve(skb2, MCTP_HEADER_MAXLEN);
747 skb_reset_network_header(skb2);
748 skb_put(skb2, hlen + size);
749 skb2->transport_header = skb2->network_header + hlen;
750
751 /* copy header fields, calculate SOM/EOM flags & seq */
752 hdr2 = mctp_hdr(skb2);
753 hdr2->ver = hdr->ver;
754 hdr2->dest = hdr->dest;
755 hdr2->src = hdr->src;
756 hdr2->flags_seq_tag = tag &
757 (MCTP_HDR_TAG_MASK | MCTP_HDR_FLAG_TO);
758
759 if (pos == 0)
760 hdr2->flags_seq_tag |= MCTP_HDR_FLAG_SOM;
761
762 if (pos + size == skb->len)
763 hdr2->flags_seq_tag |= MCTP_HDR_FLAG_EOM;
764
765 hdr2->flags_seq_tag |= seq << MCTP_HDR_SEQ_SHIFT;
766
767 /* copy message payload */
768 skb_copy_bits(skb, pos, skb_transport_header(skb2), size);
769
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800770 /* do route */
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800771 rc = rt->output(rt, skb2);
772 if (rc)
773 break;
774
775 seq = (seq + 1) & MCTP_HDR_SEQ_MASK;
776 pos += size;
777 }
778
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800779 consume_skb(skb);
780 return rc;
781}
782
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800783int mctp_local_output(struct sock *sk, struct mctp_route *rt,
784 struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag)
785{
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800786 struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800787 struct mctp_skb_cb *cb = mctp_cb(skb);
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800788 struct mctp_route tmp_rt;
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800789 struct mctp_sk_key *key;
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800790 struct net_device *dev;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800791 struct mctp_hdr *hdr;
792 unsigned long flags;
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800793 unsigned int mtu;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800794 mctp_eid_t saddr;
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800795 bool ext_rt;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800796 int rc;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800797 u8 tag;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800798
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800799 rc = -ENODEV;
800
801 if (rt) {
802 ext_rt = false;
803 dev = NULL;
804
805 if (WARN_ON(!rt->dev))
806 goto out_release;
807
808 } else if (cb->ifindex) {
809 ext_rt = true;
810 rt = &tmp_rt;
811
812 rcu_read_lock();
813 dev = dev_get_by_index_rcu(sock_net(sk), cb->ifindex);
814 if (!dev) {
815 rcu_read_unlock();
816 return rc;
817 }
818
819 rt->dev = __mctp_dev_get(dev);
820 rcu_read_unlock();
821
822 if (!rt->dev)
823 goto out_release;
824
825 /* establish temporary route - we set up enough to keep
826 * mctp_route_output happy
827 */
828 rt->output = mctp_route_output;
829 rt->mtu = 0;
830
831 } else {
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800832 return -EINVAL;
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800833 }
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800834
835 spin_lock_irqsave(&rt->dev->addrs_lock, flags);
836 if (rt->dev->num_addrs == 0) {
837 rc = -EHOSTUNREACH;
838 } else {
839 /* use the outbound interface's first address as our source */
840 saddr = rt->dev->addrs[0];
841 rc = 0;
842 }
843 spin_unlock_irqrestore(&rt->dev->addrs_lock, flags);
844
845 if (rc)
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800846 goto out_release;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800847
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800848 if (req_tag & MCTP_HDR_FLAG_TO) {
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800849 key = mctp_alloc_local_tag(msk, saddr, daddr, &tag);
850 if (IS_ERR(key)) {
851 rc = PTR_ERR(key);
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800852 goto out_release;
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800853 }
Jeremy Kerr67737c42021-10-29 11:01:45 +0800854 mctp_skb_set_flow(skb, key);
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800855 /* done with the key in this scope */
856 mctp_key_unref(key);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800857 tag |= MCTP_HDR_FLAG_TO;
858 } else {
Jeremy Kerr212c10c2021-10-29 11:01:43 +0800859 key = NULL;
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800860 tag = req_tag;
861 }
862
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800863 skb->protocol = htons(ETH_P_MCTP);
864 skb->priority = 0;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800865 skb_reset_transport_header(skb);
866 skb_push(skb, sizeof(struct mctp_hdr));
867 skb_reset_network_header(skb);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +0800868 skb->dev = rt->dev->dev;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800869
870 /* cb->net will have been set on initial ingress */
871 cb->src = saddr;
872
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800873 /* set up common header fields */
874 hdr = mctp_hdr(skb);
875 hdr->ver = 1;
876 hdr->dest = daddr;
877 hdr->src = saddr;
878
879 mtu = mctp_route_mtu(rt);
880
881 if (skb->len + sizeof(struct mctp_hdr) <= mtu) {
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800882 hdr->flags_seq_tag = MCTP_HDR_FLAG_SOM |
883 MCTP_HDR_FLAG_EOM | tag;
884 rc = rt->output(rt, skb);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800885 } else {
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800886 rc = mctp_do_fragment_route(rt, skb, mtu, tag);
Jeremy Kerr4a992bb2021-07-29 10:20:50 +0800887 }
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800888
889out_release:
890 if (!ext_rt)
891 mctp_route_release(rt);
892
Xu Wangd9e56d12021-12-02 07:55:35 +0000893 dev_put(dev);
Jeremy Kerr99ce45d2021-10-26 09:57:28 +0800894
895 return rc;
896
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800897}
898
899/* route management */
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800900static int mctp_route_add(struct mctp_dev *mdev, mctp_eid_t daddr_start,
901 unsigned int daddr_extent, unsigned int mtu,
Jeremy Kerr83f0a0b2021-08-10 10:38:34 +0800902 unsigned char type)
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800903{
Jeremy Kerr83f0a0b2021-08-10 10:38:34 +0800904 int (*rtfn)(struct mctp_route *rt, struct sk_buff *skb);
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800905 struct net *net = dev_net(mdev->dev);
906 struct mctp_route *rt, *ert;
907
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800908 if (!mctp_address_ok(daddr_start))
909 return -EINVAL;
910
911 if (daddr_extent > 0xff || daddr_start + daddr_extent >= 255)
912 return -EINVAL;
913
Jeremy Kerr83f0a0b2021-08-10 10:38:34 +0800914 switch (type) {
915 case RTN_LOCAL:
916 rtfn = mctp_route_input;
917 break;
918 case RTN_UNICAST:
919 rtfn = mctp_route_output;
920 break;
921 default:
922 return -EINVAL;
923 }
924
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800925 rt = mctp_route_alloc();
926 if (!rt)
927 return -ENOMEM;
928
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800929 rt->min = daddr_start;
930 rt->max = daddr_start + daddr_extent;
931 rt->mtu = mtu;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800932 rt->dev = mdev;
Jeremy Kerr43f55f22021-09-29 15:26:08 +0800933 mctp_dev_hold(rt->dev);
Jeremy Kerr83f0a0b2021-08-10 10:38:34 +0800934 rt->type = type;
935 rt->output = rtfn;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800936
937 ASSERT_RTNL();
938 /* Prevent duplicate identical routes. */
939 list_for_each_entry(ert, &net->mctp.routes, list) {
940 if (mctp_rt_compare_exact(rt, ert)) {
941 mctp_route_release(rt);
942 return -EEXIST;
943 }
944 }
945
946 list_add_rcu(&rt->list, &net->mctp.routes);
947
948 return 0;
949}
950
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800951static int mctp_route_remove(struct mctp_dev *mdev, mctp_eid_t daddr_start,
Matt Johnston76d00162021-12-01 16:07:42 +0800952 unsigned int daddr_extent, unsigned char type)
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800953{
954 struct net *net = dev_net(mdev->dev);
955 struct mctp_route *rt, *tmp;
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800956 mctp_eid_t daddr_end;
957 bool dropped;
958
959 if (daddr_extent > 0xff || daddr_start + daddr_extent >= 255)
960 return -EINVAL;
961
962 daddr_end = daddr_start + daddr_extent;
963 dropped = false;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800964
965 ASSERT_RTNL();
966
967 list_for_each_entry_safe(rt, tmp, &net->mctp.routes, list) {
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800968 if (rt->dev == mdev &&
Matt Johnston76d00162021-12-01 16:07:42 +0800969 rt->min == daddr_start && rt->max == daddr_end &&
970 rt->type == type) {
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800971 list_del_rcu(&rt->list);
972 /* TODO: immediate RTM_DELROUTE */
973 mctp_route_release(rt);
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800974 dropped = true;
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800975 }
976 }
977
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800978 return dropped ? 0 : -ENOENT;
979}
980
981int mctp_route_add_local(struct mctp_dev *mdev, mctp_eid_t addr)
982{
Jeremy Kerr83f0a0b2021-08-10 10:38:34 +0800983 return mctp_route_add(mdev, addr, 0, 0, RTN_LOCAL);
Matt Johnston06d2f4c2021-07-29 10:20:46 +0800984}
985
986int mctp_route_remove_local(struct mctp_dev *mdev, mctp_eid_t addr)
987{
Matt Johnston76d00162021-12-01 16:07:42 +0800988 return mctp_route_remove(mdev, addr, 0, RTN_LOCAL);
Jeremy Kerr889b7da2021-07-29 10:20:45 +0800989}
990
991/* removes all entries for a given device */
992void mctp_route_remove_dev(struct mctp_dev *mdev)
993{
994 struct net *net = dev_net(mdev->dev);
995 struct mctp_route *rt, *tmp;
996
997 ASSERT_RTNL();
998 list_for_each_entry_safe(rt, tmp, &net->mctp.routes, list) {
999 if (rt->dev == mdev) {
1000 list_del_rcu(&rt->list);
1001 /* TODO: immediate RTM_DELROUTE */
1002 mctp_route_release(rt);
1003 }
1004 }
1005}
1006
1007/* Incoming packet-handling */
1008
1009static int mctp_pkttype_receive(struct sk_buff *skb, struct net_device *dev,
1010 struct packet_type *pt,
1011 struct net_device *orig_dev)
1012{
1013 struct net *net = dev_net(dev);
Matt Johnstonf364dd72021-09-29 15:26:05 +08001014 struct mctp_dev *mdev;
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001015 struct mctp_skb_cb *cb;
1016 struct mctp_route *rt;
1017 struct mctp_hdr *mh;
1018
Matt Johnstonf364dd72021-09-29 15:26:05 +08001019 rcu_read_lock();
1020 mdev = __mctp_dev_get(dev);
1021 rcu_read_unlock();
1022 if (!mdev) {
1023 /* basic non-data sanity checks */
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001024 goto err_drop;
Matt Johnstonf364dd72021-09-29 15:26:05 +08001025 }
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001026
1027 if (!pskb_may_pull(skb, sizeof(struct mctp_hdr)))
1028 goto err_drop;
1029
1030 skb_reset_transport_header(skb);
1031 skb_reset_network_header(skb);
1032
1033 /* We have enough for a header; decode and route */
1034 mh = mctp_hdr(skb);
1035 if (mh->ver < MCTP_VER_MIN || mh->ver > MCTP_VER_MAX)
1036 goto err_drop;
1037
Jeremy Kerr99ce45d2021-10-26 09:57:28 +08001038 /* MCTP drivers must populate halen/haddr */
1039 if (dev->type == ARPHRD_MCTP) {
1040 cb = mctp_cb(skb);
1041 } else {
1042 cb = __mctp_cb(skb);
1043 cb->halen = 0;
1044 }
Matt Johnstonf364dd72021-09-29 15:26:05 +08001045 cb->net = READ_ONCE(mdev->net);
Jeremy Kerr99ce45d2021-10-26 09:57:28 +08001046 cb->ifindex = dev->ifindex;
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001047
1048 rt = mctp_route_lookup(net, cb->net, mh->dest);
Jeremy Kerr1f6c77a2021-09-29 15:26:06 +08001049
1050 /* NULL EID, but addressed to our physical address */
1051 if (!rt && mh->dest == MCTP_ADDR_NULL && skb->pkt_type == PACKET_HOST)
1052 rt = mctp_route_lookup_null(net, dev);
1053
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001054 if (!rt)
1055 goto err_drop;
1056
Jeremy Kerr99ce45d2021-10-26 09:57:28 +08001057 rt->output(rt, skb);
1058 mctp_route_release(rt);
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001059
1060 return NET_RX_SUCCESS;
1061
1062err_drop:
1063 kfree_skb(skb);
1064 return NET_RX_DROP;
1065}
1066
1067static struct packet_type mctp_packet_type = {
1068 .type = cpu_to_be16(ETH_P_MCTP),
1069 .func = mctp_pkttype_receive,
1070};
1071
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001072/* netlink interface */
1073
1074static const struct nla_policy rta_mctp_policy[RTA_MAX + 1] = {
1075 [RTA_DST] = { .type = NLA_U8 },
1076 [RTA_METRICS] = { .type = NLA_NESTED },
1077 [RTA_OIF] = { .type = NLA_U32 },
1078};
1079
1080/* Common part for RTM_NEWROUTE and RTM_DELROUTE parsing.
1081 * tb must hold RTA_MAX+1 elements.
1082 */
1083static int mctp_route_nlparse(struct sk_buff *skb, struct nlmsghdr *nlh,
1084 struct netlink_ext_ack *extack,
1085 struct nlattr **tb, struct rtmsg **rtm,
1086 struct mctp_dev **mdev, mctp_eid_t *daddr_start)
1087{
1088 struct net *net = sock_net(skb->sk);
1089 struct net_device *dev;
1090 unsigned int ifindex;
1091 int rc;
1092
1093 rc = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX,
1094 rta_mctp_policy, extack);
1095 if (rc < 0) {
1096 NL_SET_ERR_MSG(extack, "incorrect format");
1097 return rc;
1098 }
1099
1100 if (!tb[RTA_DST]) {
1101 NL_SET_ERR_MSG(extack, "dst EID missing");
1102 return -EINVAL;
1103 }
1104 *daddr_start = nla_get_u8(tb[RTA_DST]);
1105
1106 if (!tb[RTA_OIF]) {
1107 NL_SET_ERR_MSG(extack, "ifindex missing");
1108 return -EINVAL;
1109 }
1110 ifindex = nla_get_u32(tb[RTA_OIF]);
1111
1112 *rtm = nlmsg_data(nlh);
1113 if ((*rtm)->rtm_family != AF_MCTP) {
1114 NL_SET_ERR_MSG(extack, "route family must be AF_MCTP");
1115 return -EINVAL;
1116 }
1117
1118 dev = __dev_get_by_index(net, ifindex);
1119 if (!dev) {
1120 NL_SET_ERR_MSG(extack, "bad ifindex");
1121 return -ENODEV;
1122 }
1123 *mdev = mctp_dev_get_rtnl(dev);
1124 if (!*mdev)
1125 return -ENODEV;
1126
1127 if (dev->flags & IFF_LOOPBACK) {
1128 NL_SET_ERR_MSG(extack, "no routes to loopback");
1129 return -EINVAL;
1130 }
1131
1132 return 0;
1133}
1134
Matt Johnston61835692021-09-29 15:26:13 +08001135static const struct nla_policy rta_metrics_policy[RTAX_MAX + 1] = {
1136 [RTAX_MTU] = { .type = NLA_U32 },
1137};
1138
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001139static int mctp_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
1140 struct netlink_ext_ack *extack)
1141{
1142 struct nlattr *tb[RTA_MAX + 1];
Matt Johnston61835692021-09-29 15:26:13 +08001143 struct nlattr *tbx[RTAX_MAX + 1];
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001144 mctp_eid_t daddr_start;
1145 struct mctp_dev *mdev;
1146 struct rtmsg *rtm;
1147 unsigned int mtu;
1148 int rc;
1149
1150 rc = mctp_route_nlparse(skb, nlh, extack, tb,
1151 &rtm, &mdev, &daddr_start);
1152 if (rc < 0)
1153 return rc;
1154
1155 if (rtm->rtm_type != RTN_UNICAST) {
1156 NL_SET_ERR_MSG(extack, "rtm_type must be RTN_UNICAST");
1157 return -EINVAL;
1158 }
1159
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001160 mtu = 0;
Matt Johnston61835692021-09-29 15:26:13 +08001161 if (tb[RTA_METRICS]) {
1162 rc = nla_parse_nested(tbx, RTAX_MAX, tb[RTA_METRICS],
1163 rta_metrics_policy, NULL);
1164 if (rc < 0)
1165 return rc;
1166 if (tbx[RTAX_MTU])
1167 mtu = nla_get_u32(tbx[RTAX_MTU]);
1168 }
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001169
Jeremy Kerr83f0a0b2021-08-10 10:38:34 +08001170 if (rtm->rtm_type != RTN_UNICAST)
1171 return -EINVAL;
1172
1173 rc = mctp_route_add(mdev, daddr_start, rtm->rtm_dst_len, mtu,
1174 rtm->rtm_type);
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001175 return rc;
1176}
1177
1178static int mctp_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
1179 struct netlink_ext_ack *extack)
1180{
1181 struct nlattr *tb[RTA_MAX + 1];
1182 mctp_eid_t daddr_start;
1183 struct mctp_dev *mdev;
1184 struct rtmsg *rtm;
1185 int rc;
1186
1187 rc = mctp_route_nlparse(skb, nlh, extack, tb,
1188 &rtm, &mdev, &daddr_start);
1189 if (rc < 0)
1190 return rc;
1191
1192 /* we only have unicast routes */
1193 if (rtm->rtm_type != RTN_UNICAST)
1194 return -EINVAL;
1195
Matt Johnston76d00162021-12-01 16:07:42 +08001196 rc = mctp_route_remove(mdev, daddr_start, rtm->rtm_dst_len, RTN_UNICAST);
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001197 return rc;
1198}
1199
1200static int mctp_fill_rtinfo(struct sk_buff *skb, struct mctp_route *rt,
1201 u32 portid, u32 seq, int event, unsigned int flags)
1202{
1203 struct nlmsghdr *nlh;
1204 struct rtmsg *hdr;
1205 void *metrics;
1206
1207 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*hdr), flags);
1208 if (!nlh)
1209 return -EMSGSIZE;
1210
1211 hdr = nlmsg_data(nlh);
1212 hdr->rtm_family = AF_MCTP;
1213
1214 /* we use the _len fields as a number of EIDs, rather than
1215 * a number of bits in the address
1216 */
1217 hdr->rtm_dst_len = rt->max - rt->min;
1218 hdr->rtm_src_len = 0;
1219 hdr->rtm_tos = 0;
1220 hdr->rtm_table = RT_TABLE_DEFAULT;
1221 hdr->rtm_protocol = RTPROT_STATIC; /* everything is user-defined */
1222 hdr->rtm_scope = RT_SCOPE_LINK; /* TODO: scope in mctp_route? */
Jeremy Kerr83f0a0b2021-08-10 10:38:34 +08001223 hdr->rtm_type = rt->type;
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001224
1225 if (nla_put_u8(skb, RTA_DST, rt->min))
1226 goto cancel;
1227
1228 metrics = nla_nest_start_noflag(skb, RTA_METRICS);
1229 if (!metrics)
1230 goto cancel;
1231
1232 if (rt->mtu) {
1233 if (nla_put_u32(skb, RTAX_MTU, rt->mtu))
1234 goto cancel;
1235 }
1236
1237 nla_nest_end(skb, metrics);
1238
1239 if (rt->dev) {
1240 if (nla_put_u32(skb, RTA_OIF, rt->dev->dev->ifindex))
1241 goto cancel;
1242 }
1243
1244 /* TODO: conditional neighbour physaddr? */
1245
1246 nlmsg_end(skb, nlh);
1247
1248 return 0;
1249
1250cancel:
1251 nlmsg_cancel(skb, nlh);
1252 return -EMSGSIZE;
1253}
1254
1255static int mctp_dump_rtinfo(struct sk_buff *skb, struct netlink_callback *cb)
1256{
1257 struct net *net = sock_net(skb->sk);
1258 struct mctp_route *rt;
1259 int s_idx, idx;
1260
1261 /* TODO: allow filtering on route data, possibly under
1262 * cb->strict_check
1263 */
1264
1265 /* TODO: change to struct overlay */
1266 s_idx = cb->args[0];
1267 idx = 0;
1268
1269 rcu_read_lock();
1270 list_for_each_entry_rcu(rt, &net->mctp.routes, list) {
1271 if (idx++ < s_idx)
1272 continue;
1273 if (mctp_fill_rtinfo(skb, rt,
1274 NETLINK_CB(cb->skb).portid,
1275 cb->nlh->nlmsg_seq,
1276 RTM_NEWROUTE, NLM_F_MULTI) < 0)
1277 break;
1278 }
1279
1280 rcu_read_unlock();
1281 cb->args[0] = idx;
1282
1283 return skb->len;
1284}
1285
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001286/* net namespace implementation */
1287static int __net_init mctp_routes_net_init(struct net *net)
1288{
1289 struct netns_mctp *ns = &net->mctp;
1290
1291 INIT_LIST_HEAD(&ns->routes);
Jeremy Kerr833ef3b2021-07-29 10:20:49 +08001292 INIT_HLIST_HEAD(&ns->binds);
1293 mutex_init(&ns->bind_lock);
1294 INIT_HLIST_HEAD(&ns->keys);
1295 spin_lock_init(&ns->keys_lock);
Matt Johnston03f2bbc2021-07-29 10:20:52 +08001296 WARN_ON(mctp_default_net_set(net, MCTP_INITIAL_DEFAULT_NET));
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001297 return 0;
1298}
1299
1300static void __net_exit mctp_routes_net_exit(struct net *net)
1301{
1302 struct mctp_route *rt;
1303
Jeremy Kerr581edcd2021-09-08 12:13:10 +08001304 rcu_read_lock();
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001305 list_for_each_entry_rcu(rt, &net->mctp.routes, list)
1306 mctp_route_release(rt);
Jeremy Kerr581edcd2021-09-08 12:13:10 +08001307 rcu_read_unlock();
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001308}
1309
1310static struct pernet_operations mctp_net_ops = {
1311 .init = mctp_routes_net_init,
1312 .exit = mctp_routes_net_exit,
1313};
1314
1315int __init mctp_routes_init(void)
1316{
1317 dev_add_pack(&mctp_packet_type);
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001318
1319 rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_GETROUTE,
1320 NULL, mctp_dump_rtinfo, 0);
1321 rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_NEWROUTE,
1322 mctp_newroute, NULL, 0);
1323 rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_DELROUTE,
1324 mctp_delroute, NULL, 0);
1325
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001326 return register_pernet_subsys(&mctp_net_ops);
1327}
1328
1329void __exit mctp_routes_exit(void)
1330{
1331 unregister_pernet_subsys(&mctp_net_ops);
Matt Johnston06d2f4c2021-07-29 10:20:46 +08001332 rtnl_unregister(PF_MCTP, RTM_DELROUTE);
1333 rtnl_unregister(PF_MCTP, RTM_NEWROUTE);
1334 rtnl_unregister(PF_MCTP, RTM_GETROUTE);
Jeremy Kerr889b7da2021-07-29 10:20:45 +08001335 dev_remove_pack(&mctp_packet_type);
1336}
Jeremy Kerr161eba52021-10-03 11:17:04 +08001337
1338#if IS_ENABLED(CONFIG_MCTP_TEST)
1339#include "test/route-test.c"
1340#endif