History

mctp: Add SIOCMCTP{ALLOC,DROP}TAG ioctls for tag control

This change adds a couple of new ioctls for mctp sockets: SIOCMCTPALLOCTAG and SIOCMCTPDROPTAG. These ioctls provide facilities for explicit allocation / release of tags, overriding the automatic allocate-on-send/release-on-reply and timeout behaviours. This allows userspace more control over messages that may not fit a simple request/response model. In order to indicate a pre-allocated tag to the sendmsg() syscall, we introduce a new flag to the struct sockaddr_mctp.smctp_tag value: MCTP_TAG_PREALLOC. Additional changes from Jeremy Kerr <jk@codeconstruct.com.au>. Contains a fix that was: Reported-by: kernel test robot <lkp@intel.com>

Matt Johnston committed 4 years ago

Commit 63ed1aa1 parent 0de55a76 files · +329 −56Browse files

Unified · Split

6 files
  1. Documentation/networking/mctp.rst +48 −0
  2. include/net/mctp.h +10 −1
  3. include/trace/events/mctp.h +4 −1
  4. include/uapi/linux/mctp.h +18 −0
  5. net/mctp/af_mctp.c +163 −26
  6. net/mctp/route.c +86 −28
Documentation/networking/mctp.rst+48−0
@@ -212,6 +212,54 @@ remote address is already known, or the message does not require a reply. · 211 unmodified lines
212Like the send calls, sockets will only receive responses to requests they have212Like the send calls, sockets will only receive responses to requests they have
213sent (TO=1) and may only respond (TO=0) to requests they have received.213sent (TO=1) and may only respond (TO=0) to requests they have received.
214 214
215``ioctl(SIOCMCTPALLOCTAG)`` and ``ioctl(SIOCMCTPDROPTAG)``
216^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
217
218These tags give applications more control over MCTP message tags, by allocating
219(and dropping) tag values explicitly, rather than the kernel automatically
220allocating a per-message tag at ``sendmsg()`` time.
221
222In general, you will only need to use these ioctls if your MCTP protocol does
223not fit the usual request/response model. For example, if you need to persist
224tags across multiple requests, or a request may generate more than one response.
225In these cases, the ioctls allow you to decouple the tag allocation (and
226release) from individual message send and receive operations.
227
228Both ioctls are passed a pointer to a ``struct mctp_ioc_tag_ctl``:
229
230.. code-block:: C
231
232 struct mctp_ioc_tag_ctl {
233 mctp_eid_t peer_addr;
234 __u8 tag;
235 __u16 flags;
236 };
237
238``SIOCMCTPALLOCTAG`` allocates a tag for a specific peer, which an application
239can use in future ``sendmsg()`` calls. The application populates the
240``peer_addr`` member with the remote EID. Other fields must be zero.
241
242On return, the ``tag`` member will be populated with the allocated tag value.
243The allocated tag will have the following tag bits set:
244
245 - ``MCTP_TAG_OWNER``: it only makes sense to allocate tags if you're the tag
246 owner
247
248 - ``MCTP_TAG_PREALLOC``: to indicate to ``sendmsg()`` that this is a
249 preallocated tag.
250
251 - ... and the actual tag value, within the least-significant three bits
252 (``MCTP_TAG_MASK``). Note that zero is a valid tag value.
253
254The tag value should be used as-is for the ``smctp_tag`` member of ``struct
255sockaddr_mctp``.
256
257``SIOCMCTPDROPTAG`` releases a tag that has been previously allocated by a
258``SIOCMCTPALLOCTAG`` ioctl. The ``peer_addr`` must be the same as used for the
259allocation, and the ``tag`` value must match exactly the tag returned from the
260allocation (including the ``MCTP_TAG_OWNER`` and ``MCTP_TAG_PREALLOC`` bits).
261The ``flags`` field must be zero.
262
215Kernel internals263Kernel internals
216================264================
217 265
include/net/mctp.h+10−1
@@ -126,7 +126,7 @@ struct mctp_sock { · 125 unmodified lines
126 */126 */
127struct mctp_sk_key {127struct mctp_sk_key {
128 mctp_eid_t peer_addr;128 mctp_eid_t peer_addr;
129 mctp_eid_t local_addr;129 mctp_eid_t local_addr; /* MCTP_ADDR_ANY for local owned tags */
130 __u8 tag; /* incoming tag match; invert TO for local */130 __u8 tag; /* incoming tag match; invert TO for local */
131 131
132 /* we hold a ref to sk when set */132 /* we hold a ref to sk when set */
@@ -163,6 +163,12 @@ struct mctp_sk_key { · 30 unmodified lines
163 */163 */
164 unsigned long dev_flow_state;164 unsigned long dev_flow_state;
165 struct mctp_dev *dev;165 struct mctp_dev *dev;
166
167 /* a tag allocated with SIOCMCTPALLOCTAG ioctl will not expire
168 * automatically on timeout or response, instead SIOCMCTPDROPTAG
169 * is used.
170 */
171 bool manual_alloc;
166};172};
167 173
168struct mctp_skb_cb {174struct mctp_skb_cb {
@@ -239,6 +245,9 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt, · 70 unmodified lines
239 struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);245 struct sk_buff *skb, mctp_eid_t daddr, u8 req_tag);
240 246
241void mctp_key_unref(struct mctp_sk_key *key);247void mctp_key_unref(struct mctp_sk_key *key);
248struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk,
249 mctp_eid_t daddr, mctp_eid_t saddr,
250 bool manual, u8 *tagp);
242 251
243/* routing <--> device interface */252/* routing <--> device interface */
244unsigned int mctp_default_net(struct net *net);253unsigned int mctp_default_net(struct net *net);
include/trace/events/mctp.h+4−1
@@ -15,6 +15,7 @@ enum { · 14 unmodified lines
15 MCTP_TRACE_KEY_REPLIED,15 MCTP_TRACE_KEY_REPLIED,
16 MCTP_TRACE_KEY_INVALIDATED,16 MCTP_TRACE_KEY_INVALIDATED,
17 MCTP_TRACE_KEY_CLOSED,17 MCTP_TRACE_KEY_CLOSED,
18 MCTP_TRACE_KEY_DROPPED,
18};19};
19#endif /* __TRACE_MCTP_ENUMS */20#endif /* __TRACE_MCTP_ENUMS */
20 21
@@ -22,6 +23,7 @@ TRACE_DEFINE_ENUM(MCTP_TRACE_KEY_TIMEOUT); · 1 unmodified line
22TRACE_DEFINE_ENUM(MCTP_TRACE_KEY_REPLIED);23TRACE_DEFINE_ENUM(MCTP_TRACE_KEY_REPLIED);
23TRACE_DEFINE_ENUM(MCTP_TRACE_KEY_INVALIDATED);24TRACE_DEFINE_ENUM(MCTP_TRACE_KEY_INVALIDATED);
24TRACE_DEFINE_ENUM(MCTP_TRACE_KEY_CLOSED);25TRACE_DEFINE_ENUM(MCTP_TRACE_KEY_CLOSED);
26TRACE_DEFINE_ENUM(MCTP_TRACE_KEY_DROPPED);
25 27
26TRACE_EVENT(mctp_key_acquire,28TRACE_EVENT(mctp_key_acquire,
27 TP_PROTO(const struct mctp_sk_key *key),29 TP_PROTO(const struct mctp_sk_key *key),
@@ -66,7 +68,8 @@ TRACE_EVENT(mctp_key_release, · 38 unmodified lines
66 { MCTP_TRACE_KEY_TIMEOUT, "timeout" },68 { MCTP_TRACE_KEY_TIMEOUT, "timeout" },
67 { MCTP_TRACE_KEY_REPLIED, "replied" },69 { MCTP_TRACE_KEY_REPLIED, "replied" },
68 { MCTP_TRACE_KEY_INVALIDATED, "invalidated" },70 { MCTP_TRACE_KEY_INVALIDATED, "invalidated" },
69 { MCTP_TRACE_KEY_CLOSED, "closed" })71 { MCTP_TRACE_KEY_CLOSED, "closed" },
72 { MCTP_TRACE_KEY_DROPPED, "dropped" })
70 )73 )
71);74);
72 75
include/uapi/linux/mctp.h+18−0
@@ -44,7 +44,25 @@ struct sockaddr_mctp_ext { · 43 unmodified lines
44 44
45#define MCTP_TAG_MASK 0x0745#define MCTP_TAG_MASK 0x07
46#define MCTP_TAG_OWNER 0x0846#define MCTP_TAG_OWNER 0x08
47#define MCTP_TAG_PREALLOC 0x10
47 48
48#define MCTP_OPT_ADDR_EXT 149#define MCTP_OPT_ADDR_EXT 1
49 50
51#define SIOCMCTPALLOCTAG (SIOCPROTOPRIVATE + 0)
52#define SIOCMCTPDROPTAG (SIOCPROTOPRIVATE + 1)
53
54struct mctp_ioc_tag_ctl {
55 mctp_eid_t peer_addr;
56
57 /* For SIOCMCTPALLOCTAG: must be passed as zero, kernel will
58 * populate with the allocated tag value. Returned tag value will
59 * always have TO and PREALLOC set.
60 *
61 * For SIOCMCTPDROPTAG: userspace provides tag value to drop, from
62 * a prior SIOCMCTPALLOCTAG call (and so must have TO and PREALLOC set).
63 */
64 __u8 tag;
65 __u16 flags;
66};
67
50#endif /* __UAPI_MCTP_H */68#endif /* __UAPI_MCTP_H */
net/mctp/af_mctp.c+163−26
@@ -6,6 +6,7 @@ · 5 unmodified lines
6 * Copyright (c) 2021 Google6 * Copyright (c) 2021 Google
7 */7 */
8 8
9#include <linux/compat.h>
9#include <linux/if_arp.h>10#include <linux/if_arp.h>
10#include <linux/net.h>11#include <linux/net.h>
11#include <linux/mctp.h>12#include <linux/mctp.h>
@@ -21,6 +22,8 @@ · 9 unmodified lines
21 22
22/* socket implementation */23/* socket implementation */
23 24
25static void mctp_sk_expire_keys(struct timer_list *timer);
26
24static int mctp_release(struct socket *sock)27static int mctp_release(struct socket *sock)
25{28{
26 struct sock *sk = sock->sk;29 struct sock *sk = sock->sk;
@@ -99,13 +102,20 @@ static int mctp_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) · 72 unmodified lines
99 struct sk_buff *skb;102 struct sk_buff *skb;
100 103
101 if (addr) {104 if (addr) {
105 const u8 tagbits = MCTP_TAG_MASK | MCTP_TAG_OWNER |
106 MCTP_TAG_PREALLOC;
107
102 if (addrlen < sizeof(struct sockaddr_mctp))108 if (addrlen < sizeof(struct sockaddr_mctp))
103 return -EINVAL;109 return -EINVAL;
104 if (addr->smctp_family != AF_MCTP)110 if (addr->smctp_family != AF_MCTP)
105 return -EINVAL;111 return -EINVAL;
106 if (!mctp_sockaddr_is_ok(addr))112 if (!mctp_sockaddr_is_ok(addr))
107 return -EINVAL;113 return -EINVAL;
108 if (addr->smctp_tag & ~(MCTP_TAG_MASK | MCTP_TAG_OWNER))114 if (addr->smctp_tag & ~tagbits)
115 return -EINVAL;
116 /* can't preallocate a non-owned tag */
117 if (addr->smctp_tag & MCTP_TAG_PREALLOC &&
118 !(addr->smctp_tag & MCTP_TAG_OWNER))
109 return -EINVAL;119 return -EINVAL;
110 120
111 } else {121 } else {
@@ -248,6 +258,32 @@ out_free: · 136 unmodified lines
248 return rc;258 return rc;
249}259}
250 260
261/* We're done with the key; invalidate, stop reassembly, and remove from lists.
262 */
263static void __mctp_key_remove(struct mctp_sk_key *key, struct net *net,
264 unsigned long flags, unsigned long reason)
265__releases(&key->lock)
266__must_hold(&net->mctp.keys_lock)
267{
268 struct sk_buff *skb;
269
270 trace_mctp_key_release(key, reason);
271 skb = key->reasm_head;
272 key->reasm_head = NULL;
273 key->reasm_dead = true;
274 key->valid = false;
275 mctp_dev_release_key(key->dev, key);
276 spin_unlock_irqrestore(&key->lock, flags);
277
278 hlist_del(&key->hlist);
279 hlist_del(&key->sklist);
280
281 /* unref for the lists */
282 mctp_key_unref(key);
283
284 kfree_skb(skb);
285}
286
251static int mctp_setsockopt(struct socket *sock, int level, int optname,287static int mctp_setsockopt(struct socket *sock, int level, int optname,
252 sockptr_t optval, unsigned int optlen)288 sockptr_t optval, unsigned int optlen)
253{289{
@@ -293,6 +329,115 @@ static int mctp_getsockopt(struct socket *sock, int level, int optname, · 39 unmodified lines
293 return -EINVAL;329 return -EINVAL;
294}330}
295 331
332static int mctp_ioctl_alloctag(struct mctp_sock *msk, unsigned long arg)
333{
334 struct net *net = sock_net(&msk->sk);
335 struct mctp_sk_key *key = NULL;
336 struct mctp_ioc_tag_ctl ctl;
337 unsigned long flags;
338 u8 tag;
339
340 if (copy_from_user(&ctl, (void __user *)arg, sizeof(ctl)))
341 return -EFAULT;
342
343 if (ctl.tag)
344 return -EINVAL;
345
346 if (ctl.flags)
347 return -EINVAL;
348
349 key = mctp_alloc_local_tag(msk, ctl.peer_addr, MCTP_ADDR_ANY,
350 true, &tag);
351 if (IS_ERR(key))
352 return PTR_ERR(key);
353
354 ctl.tag = tag | MCTP_TAG_OWNER | MCTP_TAG_PREALLOC;
355 if (copy_to_user((void __user *)arg, &ctl, sizeof(ctl))) {
356 spin_lock_irqsave(&key->lock, flags);
357 __mctp_key_remove(key, net, flags, MCTP_TRACE_KEY_DROPPED);
358 mctp_key_unref(key);
359 return -EFAULT;
360 }
361
362 mctp_key_unref(key);
363 return 0;
364}
365
366static int mctp_ioctl_droptag(struct mctp_sock *msk, unsigned long arg)
367{
368 struct net *net = sock_net(&msk->sk);
369 struct mctp_ioc_tag_ctl ctl;
370 unsigned long flags, fl2;
371 struct mctp_sk_key *key;
372 struct hlist_node *tmp;
373 int rc;
374 u8 tag;
375
376 if (copy_from_user(&ctl, (void __user *)arg, sizeof(ctl)))
377 return -EFAULT;
378
379 if (ctl.flags)
380 return -EINVAL;
381
382 /* Must be a local tag, TO set, preallocated */
383 if ((ctl.tag & ~MCTP_TAG_MASK) != (MCTP_TAG_OWNER | MCTP_TAG_PREALLOC))
384 return -EINVAL;
385
386 tag = ctl.tag & MCTP_TAG_MASK;
387 rc = -EINVAL;
388
389 spin_lock_irqsave(&net->mctp.keys_lock, flags);
390 hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) {
391 /* we do an irqsave here, even though we know the irq state,
392 * so we have the flags to pass to __mctp_key_remove
393 */
394 spin_lock_irqsave(&key->lock, fl2);
395 if (key->manual_alloc &&
396 ctl.peer_addr == key->peer_addr &&
397 tag == key->tag) {
398 __mctp_key_remove(key, net, fl2,
399 MCTP_TRACE_KEY_DROPPED);
400 rc = 0;
401 } else {
402 spin_unlock_irqrestore(&key->lock, fl2);
403 }
404 }
405 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
406
407 return rc;
408}
409
410static int mctp_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
411{
412 struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk);
413
414 switch (cmd) {
415 case SIOCMCTPALLOCTAG:
416 return mctp_ioctl_alloctag(msk, arg);
417 case SIOCMCTPDROPTAG:
418 return mctp_ioctl_droptag(msk, arg);
419 }
420
421 return -EINVAL;
422}
423
424#ifdef CONFIG_COMPAT
425static int mctp_compat_ioctl(struct socket *sock, unsigned int cmd,
426 unsigned long arg)
427{
428 void __user *argp = compat_ptr(arg);
429
430 switch (cmd) {
431 /* These have compatible ptr layouts */
432 case SIOCMCTPALLOCTAG:
433 case SIOCMCTPDROPTAG:
434 return mctp_ioctl(sock, cmd, (unsigned long)argp);
435 }
436
437 return -ENOIOCTLCMD;
438}
439#endif
440
296static const struct proto_ops mctp_dgram_ops = {441static const struct proto_ops mctp_dgram_ops = {
297 .family = PF_MCTP,442 .family = PF_MCTP,
298 .release = mctp_release,443 .release = mctp_release,
@@ -302,7 +447,7 @@ static const struct proto_ops mctp_dgram_ops = { · 3 unmodified lines
302 .accept = sock_no_accept,447 .accept = sock_no_accept,
303 .getname = sock_no_getname,448 .getname = sock_no_getname,
304 .poll = datagram_poll,449 .poll = datagram_poll,
305 .ioctl = sock_no_ioctl,450 .ioctl = mctp_ioctl,
306 .gettstamp = sock_gettstamp,451 .gettstamp = sock_gettstamp,
307 .listen = sock_no_listen,452 .listen = sock_no_listen,
308 .shutdown = sock_no_shutdown,453 .shutdown = sock_no_shutdown,
@@ -312,6 +457,9 @@ static const struct proto_ops mctp_dgram_ops = { · 3 unmodified lines
312 .recvmsg = mctp_recvmsg,457 .recvmsg = mctp_recvmsg,
313 .mmap = sock_no_mmap,458 .mmap = sock_no_mmap,
314 .sendpage = sock_no_sendpage,459 .sendpage = sock_no_sendpage,
460#ifdef CONFIG_COMPAT
461 .compat_ioctl = mctp_compat_ioctl,
462#endif
315};463};
316 464
317static void mctp_sk_expire_keys(struct timer_list *timer)465static void mctp_sk_expire_keys(struct timer_list *timer)
@@ -319,7 +467,7 @@ static void mctp_sk_expire_keys(struct timer_list *timer) · 1 unmodified line
319 struct mctp_sock *msk = container_of(timer, struct mctp_sock,467 struct mctp_sock *msk = container_of(timer, struct mctp_sock,
320 key_expiry);468 key_expiry);
321 struct net *net = sock_net(&msk->sk);469 struct net *net = sock_net(&msk->sk);
322 unsigned long next_expiry, flags;470 unsigned long next_expiry, flags, fl2;
323 struct mctp_sk_key *key;471 struct mctp_sk_key *key;
324 struct hlist_node *tmp;472 struct hlist_node *tmp;
325 bool next_expiry_valid = false;473 bool next_expiry_valid = false;
@@ -327,15 +475,16 @@ static void mctp_sk_expire_keys(struct timer_list *timer) · 1 unmodified line
327 spin_lock_irqsave(&net->mctp.keys_lock, flags);475 spin_lock_irqsave(&net->mctp.keys_lock, flags);
328 476
329 hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) {477 hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) {
330 spin_lock(&key->lock);478 /* don't expire. manual_alloc is immutable, no locking
479 * required.
480 */
481 if (key->manual_alloc)
482 continue;
331 483
484 spin_lock_irqsave(&key->lock, fl2);
332 if (!time_after_eq(key->expiry, jiffies)) {485 if (!time_after_eq(key->expiry, jiffies)) {
333 trace_mctp_key_release(key, MCTP_TRACE_KEY_TIMEOUT);486 __mctp_key_remove(key, net, fl2,
334 key->valid = false;487 MCTP_TRACE_KEY_TIMEOUT);
335 hlist_del_rcu(&key->hlist);
336 hlist_del_rcu(&key->sklist);
337 spin_unlock(&key->lock);
338 mctp_key_unref(key);
339 continue;488 continue;
340 }489 }
341 490
@@ -346,7 +495,7 @@ static void mctp_sk_expire_keys(struct timer_list *timer) · 4 unmodified lines
346 next_expiry = key->expiry;495 next_expiry = key->expiry;
347 next_expiry_valid = true;496 next_expiry_valid = true;
348 }497 }
349 spin_unlock(&key->lock);498 spin_unlock_irqrestore(&key->lock, fl2);
350 }499 }
351 500
352 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);501 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
@@ -387,9 +536,9 @@ static void mctp_sk_unhash(struct sock *sk) · 34 unmodified lines
387{536{
388 struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);537 struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk);
389 struct net *net = sock_net(sk);538 struct net *net = sock_net(sk);
539 unsigned long flags, fl2;
390 struct mctp_sk_key *key;540 struct mctp_sk_key *key;
391 struct hlist_node *tmp;541 struct hlist_node *tmp;
392 unsigned long flags;
393 542
394 /* remove from any type-based binds */543 /* remove from any type-based binds */
395 mutex_lock(&net->mctp.bind_lock);544 mutex_lock(&net->mctp.bind_lock);
@@ -399,20 +548,8 @@ static void mctp_sk_unhash(struct sock *sk) · 3 unmodified lines
399 /* remove tag allocations */548 /* remove tag allocations */
400 spin_lock_irqsave(&net->mctp.keys_lock, flags);549 spin_lock_irqsave(&net->mctp.keys_lock, flags);
401 hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) {550 hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) {
402 hlist_del(&key->sklist);551 spin_lock_irqsave(&key->lock, fl2);
403 hlist_del(&key->hlist);552 __mctp_key_remove(key, net, fl2, MCTP_TRACE_KEY_CLOSED);
404
405 trace_mctp_key_release(key, MCTP_TRACE_KEY_CLOSED);
406
407 spin_lock(&key->lock);
408 kfree_skb(key->reasm_head);
409 key->reasm_head = NULL;
410 key->reasm_dead = true;
411 key->valid = false;
412 spin_unlock(&key->lock);
413
414 /* key is no longer on the lookup lists, unref */
415 mctp_key_unref(key);
416 }553 }
417 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);554 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
418}555}
net/mctp/route.c+86−28
@@ -203,29 +203,38 @@ static int mctp_key_add(struct mctp_sk_key *key, struct mctp_sock *msk) · 202 unmodified lines
203 return rc;203 return rc;
204}204}
205 205
206/* We're done with the key; unset valid and remove from lists. There may still206/* Helper for mctp_route_input().
207 * be outstanding refs on the key though...207 * We're done with the key; unlock and unref the key.
208 * For the usual case of automatic expiry we remove the key from lists.
209 * In the case that manual allocation is set on a key we release the lock
210 * and local ref, reset reassembly, but don't remove from lists.
208 */211 */
209static void __mctp_key_unlock_drop(struct mctp_sk_key *key, struct net *net,212static void __mctp_key_done_in(struct mctp_sk_key *key, struct net *net,
210 unsigned long flags)213 unsigned long flags, unsigned long reason)
211 __releases(&key->lock)214__releases(&key->lock)
212{215{
213 struct sk_buff *skb;216 struct sk_buff *skb;
214 217
218 trace_mctp_key_release(key, reason);
215 skb = key->reasm_head;219 skb = key->reasm_head;
216 key->reasm_head = NULL;220 key->reasm_head = NULL;
217 key->reasm_dead = true;221
218 key->valid = false;222 if (!key->manual_alloc) {
219 mctp_dev_release_key(key->dev, key);223 key->reasm_dead = true;
224 key->valid = false;
225 mctp_dev_release_key(key->dev, key);
226 }
220 spin_unlock_irqrestore(&key->lock, flags);227 spin_unlock_irqrestore(&key->lock, flags);
221 228
222 spin_lock_irqsave(&net->mctp.keys_lock, flags);229 if (!key->manual_alloc) {
223 hlist_del(&key->hlist);230 spin_lock_irqsave(&net->mctp.keys_lock, flags);
224 hlist_del(&key->sklist);231 hlist_del(&key->hlist);
225 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);232 hlist_del(&key->sklist);
233 spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
226 234
227 /* one unref for the lists */235 /* unref for the lists */
228 mctp_key_unref(key);236 mctp_key_unref(key);
237 }
229 238
230 /* and one for the local reference */239 /* and one for the local reference */
231 mctp_key_unref(key);240 mctp_key_unref(key);
@@ -379,9 +388,8 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) · 147 unmodified lines
379 /* we've hit a pending reassembly; not much we388 /* we've hit a pending reassembly; not much we
380 * can do but drop it389 * can do but drop it
381 */390 */
382 trace_mctp_key_release(key,391 __mctp_key_done_in(key, net, f,
383 MCTP_TRACE_KEY_REPLIED);392 MCTP_TRACE_KEY_REPLIED);
384 __mctp_key_unlock_drop(key, net, f);
385 key = NULL;393 key = NULL;
386 }394 }
387 rc = 0;395 rc = 0;
@@ -423,9 +431,8 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) · 35 unmodified lines
423 } else {431 } else {
424 if (key->reasm_head || key->reasm_dead) {432 if (key->reasm_head || key->reasm_dead) {
425 /* duplicate start? drop everything */433 /* duplicate start? drop everything */
426 trace_mctp_key_release(key,434 __mctp_key_done_in(key, net, f,
427 MCTP_TRACE_KEY_INVALIDATED);435 MCTP_TRACE_KEY_INVALIDATED);
428 __mctp_key_unlock_drop(key, net, f);
429 rc = -EEXIST;436 rc = -EEXIST;
430 key = NULL;437 key = NULL;
431 } else {438 } else {
@@ -448,10 +455,10 @@ static int mctp_route_input(struct mctp_route *route, struct sk_buff *skb) · 16 unmodified lines
448 * the reassembly/response key455 * the reassembly/response key
449 */456 */
450 if (!rc && flags & MCTP_HDR_FLAG_EOM) {457 if (!rc && flags & MCTP_HDR_FLAG_EOM) {
458 msk = container_of(key->sk, struct mctp_sock, sk);
451 sock_queue_rcv_skb(key->sk, key->reasm_head);459 sock_queue_rcv_skb(key->sk, key->reasm_head);
452 key->reasm_head = NULL;460 key->reasm_head = NULL;
453 trace_mctp_key_release(key, MCTP_TRACE_KEY_REPLIED);461 __mctp_key_done_in(key, net, f, MCTP_TRACE_KEY_REPLIED);
454 __mctp_key_unlock_drop(key, net, f);
455 key = NULL;462 key = NULL;
456 }463 }
457 464
@@ -579,9 +586,9 @@ static void mctp_reserve_tag(struct net *net, struct mctp_sk_key *key, · 121 unmodified lines
579/* Allocate a locally-owned tag value for (saddr, daddr), and reserve586/* Allocate a locally-owned tag value for (saddr, daddr), and reserve
580 * it for the socket msk587 * it for the socket msk
581 */588 */
582static struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk,589struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk,
583 mctp_eid_t saddr,590 mctp_eid_t daddr, mctp_eid_t saddr,
584 mctp_eid_t daddr, u8 *tagp)591 bool manual, u8 *tagp)
585{592{
586 struct net *net = sock_net(&msk->sk);593 struct net *net = sock_net(&msk->sk);
587 struct netns_mctp *mns = &net->mctp;594 struct netns_mctp *mns = &net->mctp;
@@ -636,6 +643,7 @@ static struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, · 48 unmodified lines
636 mctp_reserve_tag(net, key, msk);643 mctp_reserve_tag(net, key, msk);
637 trace_mctp_key_acquire(key);644 trace_mctp_key_acquire(key);
638 645
646 key->manual_alloc = manual;
639 *tagp = key->tag;647 *tagp = key->tag;
640 }648 }
641 649
@@ -649,6 +657,50 @@ static struct mctp_sk_key *mctp_alloc_local_tag(struct mctp_sock *msk, · 7 unmodified lines
649 return key;657 return key;
650}658}
651 659
660static struct mctp_sk_key *mctp_lookup_prealloc_tag(struct mctp_sock *msk,
661 mctp_eid_t daddr,
662 u8 req_tag, u8 *tagp)
663{
664 struct net *net = sock_net(&msk->sk);
665 struct netns_mctp *mns = &net->mctp;
666 struct mctp_sk_key *key, *tmp;
667 unsigned long flags;
668
669 req_tag &= ~(MCTP_TAG_PREALLOC | MCTP_TAG_OWNER);
670 key = NULL;
671
672 spin_lock_irqsave(&mns->keys_lock, flags);
673
674 hlist_for_each_entry(tmp, &mns->keys, hlist) {
675 if (tmp->tag != req_tag)
676 continue;
677
678 if (!mctp_address_matches(tmp->peer_addr, daddr))
679 continue;
680
681 if (!tmp->manual_alloc)
682 continue;
683
684 spin_lock(&tmp->lock);
685 if (tmp->valid) {
686 key = tmp;
687 refcount_inc(&key->refs);
688 spin_unlock(&tmp->lock);
689 break;
690 }
691 spin_unlock(&tmp->lock);
692 }
693 spin_unlock_irqrestore(&mns->keys_lock, flags);
694
695 if (!key)
696 return ERR_PTR(-ENOENT);
697
698 if (tagp)
699 *tagp = key->tag;
700
701 return key;
702}
703
652/* routing lookups */704/* routing lookups */
653static bool mctp_rt_match_eid(struct mctp_route *rt,705static bool mctp_rt_match_eid(struct mctp_route *rt,
654 unsigned int net, mctp_eid_t eid)706 unsigned int net, mctp_eid_t eid)
@@ -843,8 +895,14 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt, · 188 unmodified lines
843 if (rc)895 if (rc)
844 goto out_release;896 goto out_release;
845 897
846 if (req_tag & MCTP_HDR_FLAG_TO) {898 if (req_tag & MCTP_TAG_OWNER) {
847 key = mctp_alloc_local_tag(msk, saddr, daddr, &tag);899 if (req_tag & MCTP_TAG_PREALLOC)
900 key = mctp_lookup_prealloc_tag(msk, daddr,
901 req_tag, &tag);
902 else
903 key = mctp_alloc_local_tag(msk, daddr, saddr,
904 false, &tag);
905
848 if (IS_ERR(key)) {906 if (IS_ERR(key)) {
849 rc = PTR_ERR(key);907 rc = PTR_ERR(key);
850 goto out_release;908 goto out_release;
@@ -855,7 +913,7 @@ int mctp_local_output(struct sock *sk, struct mctp_route *rt, · 4 unmodified lines
855 tag |= MCTP_HDR_FLAG_TO;913 tag |= MCTP_HDR_FLAG_TO;
856 } else {914 } else {
857 key = NULL;915 key = NULL;
858 tag = req_tag;916 tag = req_tag & MCTP_TAG_MASK;
859 }917 }
860 918
861 skb->protocol = htons(ETH_P_MCTP);919 skb->protocol = htons(ETH_P_MCTP);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t