162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Stream Parser
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2016 Tom Herbert <tom@herbertland.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bpf.h>
962306a36Sopenharmony_ci#include <linux/errno.h>
1062306a36Sopenharmony_ci#include <linux/errqueue.h>
1162306a36Sopenharmony_ci#include <linux/file.h>
1262306a36Sopenharmony_ci#include <linux/in.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/export.h>
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/net.h>
1762306a36Sopenharmony_ci#include <linux/netdevice.h>
1862306a36Sopenharmony_ci#include <linux/poll.h>
1962306a36Sopenharmony_ci#include <linux/rculist.h>
2062306a36Sopenharmony_ci#include <linux/skbuff.h>
2162306a36Sopenharmony_ci#include <linux/socket.h>
2262306a36Sopenharmony_ci#include <linux/uaccess.h>
2362306a36Sopenharmony_ci#include <linux/workqueue.h>
2462306a36Sopenharmony_ci#include <net/strparser.h>
2562306a36Sopenharmony_ci#include <net/netns/generic.h>
2662306a36Sopenharmony_ci#include <net/sock.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic struct workqueue_struct *strp_wq;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic inline struct _strp_msg *_strp_msg(struct sk_buff *skb)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	return (struct _strp_msg *)((void *)skb->cb +
3362306a36Sopenharmony_ci		offsetof(struct sk_skb_cb, strp));
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Lower lock held */
3762306a36Sopenharmony_cistatic void strp_abort_strp(struct strparser *strp, int err)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	/* Unrecoverable error in receive */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	cancel_delayed_work(&strp->msg_timer_work);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (strp->stopped)
4462306a36Sopenharmony_ci		return;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	strp->stopped = 1;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	if (strp->sk) {
4962306a36Sopenharmony_ci		struct sock *sk = strp->sk;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		/* Report an error on the lower socket */
5262306a36Sopenharmony_ci		sk->sk_err = -err;
5362306a36Sopenharmony_ci		sk_error_report(sk);
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic void strp_start_timer(struct strparser *strp, long timeo)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	if (timeo && timeo != LONG_MAX)
6062306a36Sopenharmony_ci		mod_delayed_work(strp_wq, &strp->msg_timer_work, timeo);
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/* Lower lock held */
6462306a36Sopenharmony_cistatic void strp_parser_err(struct strparser *strp, int err,
6562306a36Sopenharmony_ci			    read_descriptor_t *desc)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	desc->error = err;
6862306a36Sopenharmony_ci	kfree_skb(strp->skb_head);
6962306a36Sopenharmony_ci	strp->skb_head = NULL;
7062306a36Sopenharmony_ci	strp->cb.abort_parser(strp, err);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic inline int strp_peek_len(struct strparser *strp)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	if (strp->sk) {
7662306a36Sopenharmony_ci		struct socket *sock = strp->sk->sk_socket;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		return sock->ops->peek_len(sock);
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* If we don't have an associated socket there's nothing to peek.
8262306a36Sopenharmony_ci	 * Return int max to avoid stopping the strparser.
8362306a36Sopenharmony_ci	 */
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return INT_MAX;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/* Lower socket lock held */
8962306a36Sopenharmony_cistatic int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
9062306a36Sopenharmony_ci		       unsigned int orig_offset, size_t orig_len,
9162306a36Sopenharmony_ci		       size_t max_msg_size, long timeo)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct strparser *strp = (struct strparser *)desc->arg.data;
9462306a36Sopenharmony_ci	struct _strp_msg *stm;
9562306a36Sopenharmony_ci	struct sk_buff *head, *skb;
9662306a36Sopenharmony_ci	size_t eaten = 0, cand_len;
9762306a36Sopenharmony_ci	ssize_t extra;
9862306a36Sopenharmony_ci	int err;
9962306a36Sopenharmony_ci	bool cloned_orig = false;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (strp->paused)
10262306a36Sopenharmony_ci		return 0;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	head = strp->skb_head;
10562306a36Sopenharmony_ci	if (head) {
10662306a36Sopenharmony_ci		/* Message already in progress */
10762306a36Sopenharmony_ci		if (unlikely(orig_offset)) {
10862306a36Sopenharmony_ci			/* Getting data with a non-zero offset when a message is
10962306a36Sopenharmony_ci			 * in progress is not expected. If it does happen, we
11062306a36Sopenharmony_ci			 * need to clone and pull since we can't deal with
11162306a36Sopenharmony_ci			 * offsets in the skbs for a message expect in the head.
11262306a36Sopenharmony_ci			 */
11362306a36Sopenharmony_ci			orig_skb = skb_clone(orig_skb, GFP_ATOMIC);
11462306a36Sopenharmony_ci			if (!orig_skb) {
11562306a36Sopenharmony_ci				STRP_STATS_INCR(strp->stats.mem_fail);
11662306a36Sopenharmony_ci				desc->error = -ENOMEM;
11762306a36Sopenharmony_ci				return 0;
11862306a36Sopenharmony_ci			}
11962306a36Sopenharmony_ci			if (!pskb_pull(orig_skb, orig_offset)) {
12062306a36Sopenharmony_ci				STRP_STATS_INCR(strp->stats.mem_fail);
12162306a36Sopenharmony_ci				kfree_skb(orig_skb);
12262306a36Sopenharmony_ci				desc->error = -ENOMEM;
12362306a36Sopenharmony_ci				return 0;
12462306a36Sopenharmony_ci			}
12562306a36Sopenharmony_ci			cloned_orig = true;
12662306a36Sopenharmony_ci			orig_offset = 0;
12762306a36Sopenharmony_ci		}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		if (!strp->skb_nextp) {
13062306a36Sopenharmony_ci			/* We are going to append to the frags_list of head.
13162306a36Sopenharmony_ci			 * Need to unshare the frag_list.
13262306a36Sopenharmony_ci			 */
13362306a36Sopenharmony_ci			err = skb_unclone(head, GFP_ATOMIC);
13462306a36Sopenharmony_ci			if (err) {
13562306a36Sopenharmony_ci				STRP_STATS_INCR(strp->stats.mem_fail);
13662306a36Sopenharmony_ci				desc->error = err;
13762306a36Sopenharmony_ci				return 0;
13862306a36Sopenharmony_ci			}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci			if (unlikely(skb_shinfo(head)->frag_list)) {
14162306a36Sopenharmony_ci				/* We can't append to an sk_buff that already
14262306a36Sopenharmony_ci				 * has a frag_list. We create a new head, point
14362306a36Sopenharmony_ci				 * the frag_list of that to the old head, and
14462306a36Sopenharmony_ci				 * then are able to use the old head->next for
14562306a36Sopenharmony_ci				 * appending to the message.
14662306a36Sopenharmony_ci				 */
14762306a36Sopenharmony_ci				if (WARN_ON(head->next)) {
14862306a36Sopenharmony_ci					desc->error = -EINVAL;
14962306a36Sopenharmony_ci					return 0;
15062306a36Sopenharmony_ci				}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci				skb = alloc_skb_for_msg(head);
15362306a36Sopenharmony_ci				if (!skb) {
15462306a36Sopenharmony_ci					STRP_STATS_INCR(strp->stats.mem_fail);
15562306a36Sopenharmony_ci					desc->error = -ENOMEM;
15662306a36Sopenharmony_ci					return 0;
15762306a36Sopenharmony_ci				}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci				strp->skb_nextp = &head->next;
16062306a36Sopenharmony_ci				strp->skb_head = skb;
16162306a36Sopenharmony_ci				head = skb;
16262306a36Sopenharmony_ci			} else {
16362306a36Sopenharmony_ci				strp->skb_nextp =
16462306a36Sopenharmony_ci				    &skb_shinfo(head)->frag_list;
16562306a36Sopenharmony_ci			}
16662306a36Sopenharmony_ci		}
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	while (eaten < orig_len) {
17062306a36Sopenharmony_ci		/* Always clone since we will consume something */
17162306a36Sopenharmony_ci		skb = skb_clone(orig_skb, GFP_ATOMIC);
17262306a36Sopenharmony_ci		if (!skb) {
17362306a36Sopenharmony_ci			STRP_STATS_INCR(strp->stats.mem_fail);
17462306a36Sopenharmony_ci			desc->error = -ENOMEM;
17562306a36Sopenharmony_ci			break;
17662306a36Sopenharmony_ci		}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci		cand_len = orig_len - eaten;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		head = strp->skb_head;
18162306a36Sopenharmony_ci		if (!head) {
18262306a36Sopenharmony_ci			head = skb;
18362306a36Sopenharmony_ci			strp->skb_head = head;
18462306a36Sopenharmony_ci			/* Will set skb_nextp on next packet if needed */
18562306a36Sopenharmony_ci			strp->skb_nextp = NULL;
18662306a36Sopenharmony_ci			stm = _strp_msg(head);
18762306a36Sopenharmony_ci			memset(stm, 0, sizeof(*stm));
18862306a36Sopenharmony_ci			stm->strp.offset = orig_offset + eaten;
18962306a36Sopenharmony_ci		} else {
19062306a36Sopenharmony_ci			/* Unclone if we are appending to an skb that we
19162306a36Sopenharmony_ci			 * already share a frag_list with.
19262306a36Sopenharmony_ci			 */
19362306a36Sopenharmony_ci			if (skb_has_frag_list(skb)) {
19462306a36Sopenharmony_ci				err = skb_unclone(skb, GFP_ATOMIC);
19562306a36Sopenharmony_ci				if (err) {
19662306a36Sopenharmony_ci					STRP_STATS_INCR(strp->stats.mem_fail);
19762306a36Sopenharmony_ci					desc->error = err;
19862306a36Sopenharmony_ci					break;
19962306a36Sopenharmony_ci				}
20062306a36Sopenharmony_ci			}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci			stm = _strp_msg(head);
20362306a36Sopenharmony_ci			*strp->skb_nextp = skb;
20462306a36Sopenharmony_ci			strp->skb_nextp = &skb->next;
20562306a36Sopenharmony_ci			head->data_len += skb->len;
20662306a36Sopenharmony_ci			head->len += skb->len;
20762306a36Sopenharmony_ci			head->truesize += skb->truesize;
20862306a36Sopenharmony_ci		}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		if (!stm->strp.full_len) {
21162306a36Sopenharmony_ci			ssize_t len;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci			len = (*strp->cb.parse_msg)(strp, head);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci			if (!len) {
21662306a36Sopenharmony_ci				/* Need more header to determine length */
21762306a36Sopenharmony_ci				if (!stm->accum_len) {
21862306a36Sopenharmony_ci					/* Start RX timer for new message */
21962306a36Sopenharmony_ci					strp_start_timer(strp, timeo);
22062306a36Sopenharmony_ci				}
22162306a36Sopenharmony_ci				stm->accum_len += cand_len;
22262306a36Sopenharmony_ci				eaten += cand_len;
22362306a36Sopenharmony_ci				STRP_STATS_INCR(strp->stats.need_more_hdr);
22462306a36Sopenharmony_ci				WARN_ON(eaten != orig_len);
22562306a36Sopenharmony_ci				break;
22662306a36Sopenharmony_ci			} else if (len < 0) {
22762306a36Sopenharmony_ci				if (len == -ESTRPIPE && stm->accum_len) {
22862306a36Sopenharmony_ci					len = -ENODATA;
22962306a36Sopenharmony_ci					strp->unrecov_intr = 1;
23062306a36Sopenharmony_ci				} else {
23162306a36Sopenharmony_ci					strp->interrupted = 1;
23262306a36Sopenharmony_ci				}
23362306a36Sopenharmony_ci				strp_parser_err(strp, len, desc);
23462306a36Sopenharmony_ci				break;
23562306a36Sopenharmony_ci			} else if (len > max_msg_size) {
23662306a36Sopenharmony_ci				/* Message length exceeds maximum allowed */
23762306a36Sopenharmony_ci				STRP_STATS_INCR(strp->stats.msg_too_big);
23862306a36Sopenharmony_ci				strp_parser_err(strp, -EMSGSIZE, desc);
23962306a36Sopenharmony_ci				break;
24062306a36Sopenharmony_ci			} else if (len <= (ssize_t)head->len -
24162306a36Sopenharmony_ci					  skb->len - stm->strp.offset) {
24262306a36Sopenharmony_ci				/* Length must be into new skb (and also
24362306a36Sopenharmony_ci				 * greater than zero)
24462306a36Sopenharmony_ci				 */
24562306a36Sopenharmony_ci				STRP_STATS_INCR(strp->stats.bad_hdr_len);
24662306a36Sopenharmony_ci				strp_parser_err(strp, -EPROTO, desc);
24762306a36Sopenharmony_ci				break;
24862306a36Sopenharmony_ci			}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci			stm->strp.full_len = len;
25162306a36Sopenharmony_ci		}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		extra = (ssize_t)(stm->accum_len + cand_len) -
25462306a36Sopenharmony_ci			stm->strp.full_len;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		if (extra < 0) {
25762306a36Sopenharmony_ci			/* Message not complete yet. */
25862306a36Sopenharmony_ci			if (stm->strp.full_len - stm->accum_len >
25962306a36Sopenharmony_ci			    strp_peek_len(strp)) {
26062306a36Sopenharmony_ci				/* Don't have the whole message in the socket
26162306a36Sopenharmony_ci				 * buffer. Set strp->need_bytes to wait for
26262306a36Sopenharmony_ci				 * the rest of the message. Also, set "early
26362306a36Sopenharmony_ci				 * eaten" since we've already buffered the skb
26462306a36Sopenharmony_ci				 * but don't consume yet per strp_read_sock.
26562306a36Sopenharmony_ci				 */
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci				if (!stm->accum_len) {
26862306a36Sopenharmony_ci					/* Start RX timer for new message */
26962306a36Sopenharmony_ci					strp_start_timer(strp, timeo);
27062306a36Sopenharmony_ci				}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci				stm->accum_len += cand_len;
27362306a36Sopenharmony_ci				eaten += cand_len;
27462306a36Sopenharmony_ci				strp->need_bytes = stm->strp.full_len -
27562306a36Sopenharmony_ci						       stm->accum_len;
27662306a36Sopenharmony_ci				STRP_STATS_ADD(strp->stats.bytes, cand_len);
27762306a36Sopenharmony_ci				desc->count = 0; /* Stop reading socket */
27862306a36Sopenharmony_ci				break;
27962306a36Sopenharmony_ci			}
28062306a36Sopenharmony_ci			stm->accum_len += cand_len;
28162306a36Sopenharmony_ci			eaten += cand_len;
28262306a36Sopenharmony_ci			WARN_ON(eaten != orig_len);
28362306a36Sopenharmony_ci			break;
28462306a36Sopenharmony_ci		}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		/* Positive extra indicates more bytes than needed for the
28762306a36Sopenharmony_ci		 * message
28862306a36Sopenharmony_ci		 */
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci		WARN_ON(extra > cand_len);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		eaten += (cand_len - extra);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		/* Hurray, we have a new message! */
29562306a36Sopenharmony_ci		cancel_delayed_work(&strp->msg_timer_work);
29662306a36Sopenharmony_ci		strp->skb_head = NULL;
29762306a36Sopenharmony_ci		strp->need_bytes = 0;
29862306a36Sopenharmony_ci		STRP_STATS_INCR(strp->stats.msgs);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		/* Give skb to upper layer */
30162306a36Sopenharmony_ci		strp->cb.rcv_msg(strp, head);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci		if (unlikely(strp->paused)) {
30462306a36Sopenharmony_ci			/* Upper layer paused strp */
30562306a36Sopenharmony_ci			break;
30662306a36Sopenharmony_ci		}
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (cloned_orig)
31062306a36Sopenharmony_ci		kfree_skb(orig_skb);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	STRP_STATS_ADD(strp->stats.bytes, eaten);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return eaten;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ciint strp_process(struct strparser *strp, struct sk_buff *orig_skb,
31862306a36Sopenharmony_ci		 unsigned int orig_offset, size_t orig_len,
31962306a36Sopenharmony_ci		 size_t max_msg_size, long timeo)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	read_descriptor_t desc; /* Dummy arg to strp_recv */
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	desc.arg.data = strp;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	return __strp_recv(&desc, orig_skb, orig_offset, orig_len,
32662306a36Sopenharmony_ci			   max_msg_size, timeo);
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(strp_process);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
33162306a36Sopenharmony_ci		     unsigned int orig_offset, size_t orig_len)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct strparser *strp = (struct strparser *)desc->arg.data;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	return __strp_recv(desc, orig_skb, orig_offset, orig_len,
33662306a36Sopenharmony_ci			   strp->sk->sk_rcvbuf, strp->sk->sk_rcvtimeo);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic int default_read_sock_done(struct strparser *strp, int err)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	return err;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci/* Called with lock held on lower socket */
34562306a36Sopenharmony_cistatic int strp_read_sock(struct strparser *strp)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct socket *sock = strp->sk->sk_socket;
34862306a36Sopenharmony_ci	read_descriptor_t desc;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (unlikely(!sock || !sock->ops || !sock->ops->read_sock))
35162306a36Sopenharmony_ci		return -EBUSY;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	desc.arg.data = strp;
35462306a36Sopenharmony_ci	desc.error = 0;
35562306a36Sopenharmony_ci	desc.count = 1; /* give more than one skb per call */
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* sk should be locked here, so okay to do read_sock */
35862306a36Sopenharmony_ci	sock->ops->read_sock(strp->sk, &desc, strp_recv);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	desc.error = strp->cb.read_sock_done(strp, desc.error);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	return desc.error;
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci/* Lower sock lock held */
36662306a36Sopenharmony_civoid strp_data_ready(struct strparser *strp)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	if (unlikely(strp->stopped) || strp->paused)
36962306a36Sopenharmony_ci		return;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* This check is needed to synchronize with do_strp_work.
37262306a36Sopenharmony_ci	 * do_strp_work acquires a process lock (lock_sock) whereas
37362306a36Sopenharmony_ci	 * the lock held here is bh_lock_sock. The two locks can be
37462306a36Sopenharmony_ci	 * held by different threads at the same time, but bh_lock_sock
37562306a36Sopenharmony_ci	 * allows a thread in BH context to safely check if the process
37662306a36Sopenharmony_ci	 * lock is held. In this case, if the lock is held, queue work.
37762306a36Sopenharmony_ci	 */
37862306a36Sopenharmony_ci	if (sock_owned_by_user_nocheck(strp->sk)) {
37962306a36Sopenharmony_ci		queue_work(strp_wq, &strp->work);
38062306a36Sopenharmony_ci		return;
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (strp->need_bytes) {
38462306a36Sopenharmony_ci		if (strp_peek_len(strp) < strp->need_bytes)
38562306a36Sopenharmony_ci			return;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (strp_read_sock(strp) == -ENOMEM)
38962306a36Sopenharmony_ci		queue_work(strp_wq, &strp->work);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(strp_data_ready);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic void do_strp_work(struct strparser *strp)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	/* We need the read lock to synchronize with strp_data_ready. We
39662306a36Sopenharmony_ci	 * need the socket lock for calling strp_read_sock.
39762306a36Sopenharmony_ci	 */
39862306a36Sopenharmony_ci	strp->cb.lock(strp);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (unlikely(strp->stopped))
40162306a36Sopenharmony_ci		goto out;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (strp->paused)
40462306a36Sopenharmony_ci		goto out;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (strp_read_sock(strp) == -ENOMEM)
40762306a36Sopenharmony_ci		queue_work(strp_wq, &strp->work);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ciout:
41062306a36Sopenharmony_ci	strp->cb.unlock(strp);
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic void strp_work(struct work_struct *w)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	do_strp_work(container_of(w, struct strparser, work));
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic void strp_msg_timeout(struct work_struct *w)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct strparser *strp = container_of(w, struct strparser,
42162306a36Sopenharmony_ci					      msg_timer_work.work);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* Message assembly timed out */
42462306a36Sopenharmony_ci	STRP_STATS_INCR(strp->stats.msg_timeouts);
42562306a36Sopenharmony_ci	strp->cb.lock(strp);
42662306a36Sopenharmony_ci	strp->cb.abort_parser(strp, -ETIMEDOUT);
42762306a36Sopenharmony_ci	strp->cb.unlock(strp);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void strp_sock_lock(struct strparser *strp)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	lock_sock(strp->sk);
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic void strp_sock_unlock(struct strparser *strp)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	release_sock(strp->sk);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ciint strp_init(struct strparser *strp, struct sock *sk,
44162306a36Sopenharmony_ci	      const struct strp_callbacks *cb)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (!cb || !cb->rcv_msg || !cb->parse_msg)
44562306a36Sopenharmony_ci		return -EINVAL;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	/* The sk (sock) arg determines the mode of the stream parser.
44862306a36Sopenharmony_ci	 *
44962306a36Sopenharmony_ci	 * If the sock is set then the strparser is in receive callback mode.
45062306a36Sopenharmony_ci	 * The upper layer calls strp_data_ready to kick receive processing
45162306a36Sopenharmony_ci	 * and strparser calls the read_sock function on the socket to
45262306a36Sopenharmony_ci	 * get packets.
45362306a36Sopenharmony_ci	 *
45462306a36Sopenharmony_ci	 * If the sock is not set then the strparser is in general mode.
45562306a36Sopenharmony_ci	 * The upper layer calls strp_process for each skb to be parsed.
45662306a36Sopenharmony_ci	 */
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (!sk) {
45962306a36Sopenharmony_ci		if (!cb->lock || !cb->unlock)
46062306a36Sopenharmony_ci			return -EINVAL;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	memset(strp, 0, sizeof(*strp));
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	strp->sk = sk;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	strp->cb.lock = cb->lock ? : strp_sock_lock;
46862306a36Sopenharmony_ci	strp->cb.unlock = cb->unlock ? : strp_sock_unlock;
46962306a36Sopenharmony_ci	strp->cb.rcv_msg = cb->rcv_msg;
47062306a36Sopenharmony_ci	strp->cb.parse_msg = cb->parse_msg;
47162306a36Sopenharmony_ci	strp->cb.read_sock_done = cb->read_sock_done ? : default_read_sock_done;
47262306a36Sopenharmony_ci	strp->cb.abort_parser = cb->abort_parser ? : strp_abort_strp;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	INIT_DELAYED_WORK(&strp->msg_timer_work, strp_msg_timeout);
47562306a36Sopenharmony_ci	INIT_WORK(&strp->work, strp_work);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return 0;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(strp_init);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci/* Sock process lock held (lock_sock) */
48262306a36Sopenharmony_civoid __strp_unpause(struct strparser *strp)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	strp->paused = 0;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (strp->need_bytes) {
48762306a36Sopenharmony_ci		if (strp_peek_len(strp) < strp->need_bytes)
48862306a36Sopenharmony_ci			return;
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci	strp_read_sock(strp);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__strp_unpause);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_civoid strp_unpause(struct strparser *strp)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	strp->paused = 0;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* Sync setting paused with RX work */
49962306a36Sopenharmony_ci	smp_mb();
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	queue_work(strp_wq, &strp->work);
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(strp_unpause);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci/* strp must already be stopped so that strp_recv will no longer be called.
50662306a36Sopenharmony_ci * Note that strp_done is not called with the lower socket held.
50762306a36Sopenharmony_ci */
50862306a36Sopenharmony_civoid strp_done(struct strparser *strp)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	WARN_ON(!strp->stopped);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	cancel_delayed_work_sync(&strp->msg_timer_work);
51362306a36Sopenharmony_ci	cancel_work_sync(&strp->work);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (strp->skb_head) {
51662306a36Sopenharmony_ci		kfree_skb(strp->skb_head);
51762306a36Sopenharmony_ci		strp->skb_head = NULL;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(strp_done);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_civoid strp_stop(struct strparser *strp)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	strp->stopped = 1;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(strp_stop);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_civoid strp_check_rcv(struct strparser *strp)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	queue_work(strp_wq, &strp->work);
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(strp_check_rcv);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic int __init strp_dev_init(void)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct sk_skb_cb) >
53762306a36Sopenharmony_ci		     sizeof_field(struct sk_buff, cb));
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	strp_wq = create_singlethread_workqueue("kstrp");
54062306a36Sopenharmony_ci	if (unlikely(!strp_wq))
54162306a36Sopenharmony_ci		return -ENOMEM;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	return 0;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_cidevice_initcall(strp_dev_init);
546