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