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#ifndef __NET_STRPARSER_H_ 962306a36Sopenharmony_ci#define __NET_STRPARSER_H_ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/skbuff.h> 1262306a36Sopenharmony_ci#include <net/sock.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define STRP_STATS_ADD(stat, count) ((stat) += (count)) 1562306a36Sopenharmony_ci#define STRP_STATS_INCR(stat) ((stat)++) 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct strp_stats { 1862306a36Sopenharmony_ci unsigned long long msgs; 1962306a36Sopenharmony_ci unsigned long long bytes; 2062306a36Sopenharmony_ci unsigned int mem_fail; 2162306a36Sopenharmony_ci unsigned int need_more_hdr; 2262306a36Sopenharmony_ci unsigned int msg_too_big; 2362306a36Sopenharmony_ci unsigned int msg_timeouts; 2462306a36Sopenharmony_ci unsigned int bad_hdr_len; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct strp_aggr_stats { 2862306a36Sopenharmony_ci unsigned long long msgs; 2962306a36Sopenharmony_ci unsigned long long bytes; 3062306a36Sopenharmony_ci unsigned int mem_fail; 3162306a36Sopenharmony_ci unsigned int need_more_hdr; 3262306a36Sopenharmony_ci unsigned int msg_too_big; 3362306a36Sopenharmony_ci unsigned int msg_timeouts; 3462306a36Sopenharmony_ci unsigned int bad_hdr_len; 3562306a36Sopenharmony_ci unsigned int aborts; 3662306a36Sopenharmony_ci unsigned int interrupted; 3762306a36Sopenharmony_ci unsigned int unrecov_intr; 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct strparser; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Callbacks are called with lock held for the attached socket */ 4362306a36Sopenharmony_cistruct strp_callbacks { 4462306a36Sopenharmony_ci int (*parse_msg)(struct strparser *strp, struct sk_buff *skb); 4562306a36Sopenharmony_ci void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb); 4662306a36Sopenharmony_ci int (*read_sock_done)(struct strparser *strp, int err); 4762306a36Sopenharmony_ci void (*abort_parser)(struct strparser *strp, int err); 4862306a36Sopenharmony_ci void (*lock)(struct strparser *strp); 4962306a36Sopenharmony_ci void (*unlock)(struct strparser *strp); 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistruct strp_msg { 5362306a36Sopenharmony_ci int full_len; 5462306a36Sopenharmony_ci int offset; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct _strp_msg { 5862306a36Sopenharmony_ci /* Internal cb structure. struct strp_msg must be first for passing 5962306a36Sopenharmony_ci * to upper layer. 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci struct strp_msg strp; 6262306a36Sopenharmony_ci int accum_len; 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistruct sk_skb_cb { 6662306a36Sopenharmony_ci#define SK_SKB_CB_PRIV_LEN 20 6762306a36Sopenharmony_ci unsigned char data[SK_SKB_CB_PRIV_LEN]; 6862306a36Sopenharmony_ci /* align strp on cache line boundary within skb->cb[] */ 6962306a36Sopenharmony_ci unsigned char pad[4]; 7062306a36Sopenharmony_ci struct _strp_msg strp; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* strp users' data follows */ 7362306a36Sopenharmony_ci struct tls_msg { 7462306a36Sopenharmony_ci u8 control; 7562306a36Sopenharmony_ci } tls; 7662306a36Sopenharmony_ci /* temp_reg is a temporary register used for bpf_convert_data_end_access 7762306a36Sopenharmony_ci * when dst_reg == src_reg. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci u64 temp_reg; 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic inline struct strp_msg *strp_msg(struct sk_buff *skb) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci return (struct strp_msg *)((void *)skb->cb + 8562306a36Sopenharmony_ci offsetof(struct sk_skb_cb, strp)); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* Structure for an attached lower socket */ 8962306a36Sopenharmony_cistruct strparser { 9062306a36Sopenharmony_ci struct sock *sk; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci u32 stopped : 1; 9362306a36Sopenharmony_ci u32 paused : 1; 9462306a36Sopenharmony_ci u32 aborted : 1; 9562306a36Sopenharmony_ci u32 interrupted : 1; 9662306a36Sopenharmony_ci u32 unrecov_intr : 1; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci struct sk_buff **skb_nextp; 9962306a36Sopenharmony_ci struct sk_buff *skb_head; 10062306a36Sopenharmony_ci unsigned int need_bytes; 10162306a36Sopenharmony_ci struct delayed_work msg_timer_work; 10262306a36Sopenharmony_ci struct work_struct work; 10362306a36Sopenharmony_ci struct strp_stats stats; 10462306a36Sopenharmony_ci struct strp_callbacks cb; 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* Must be called with lock held for attached socket */ 10862306a36Sopenharmony_cistatic inline void strp_pause(struct strparser *strp) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci strp->paused = 1; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* May be called without holding lock for attached socket */ 11462306a36Sopenharmony_civoid strp_unpause(struct strparser *strp); 11562306a36Sopenharmony_ci/* Must be called with process lock held (lock_sock) */ 11662306a36Sopenharmony_civoid __strp_unpause(struct strparser *strp); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline void save_strp_stats(struct strparser *strp, 11962306a36Sopenharmony_ci struct strp_aggr_stats *agg_stats) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci /* Save psock statistics in the mux when psock is being unattached. */ 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += \ 12462306a36Sopenharmony_ci strp->stats._stat) 12562306a36Sopenharmony_ci SAVE_PSOCK_STATS(msgs); 12662306a36Sopenharmony_ci SAVE_PSOCK_STATS(bytes); 12762306a36Sopenharmony_ci SAVE_PSOCK_STATS(mem_fail); 12862306a36Sopenharmony_ci SAVE_PSOCK_STATS(need_more_hdr); 12962306a36Sopenharmony_ci SAVE_PSOCK_STATS(msg_too_big); 13062306a36Sopenharmony_ci SAVE_PSOCK_STATS(msg_timeouts); 13162306a36Sopenharmony_ci SAVE_PSOCK_STATS(bad_hdr_len); 13262306a36Sopenharmony_ci#undef SAVE_PSOCK_STATS 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (strp->aborted) 13562306a36Sopenharmony_ci agg_stats->aborts++; 13662306a36Sopenharmony_ci if (strp->interrupted) 13762306a36Sopenharmony_ci agg_stats->interrupted++; 13862306a36Sopenharmony_ci if (strp->unrecov_intr) 13962306a36Sopenharmony_ci agg_stats->unrecov_intr++; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic inline void aggregate_strp_stats(struct strp_aggr_stats *stats, 14362306a36Sopenharmony_ci struct strp_aggr_stats *agg_stats) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += stats->_stat) 14662306a36Sopenharmony_ci SAVE_PSOCK_STATS(msgs); 14762306a36Sopenharmony_ci SAVE_PSOCK_STATS(bytes); 14862306a36Sopenharmony_ci SAVE_PSOCK_STATS(mem_fail); 14962306a36Sopenharmony_ci SAVE_PSOCK_STATS(need_more_hdr); 15062306a36Sopenharmony_ci SAVE_PSOCK_STATS(msg_too_big); 15162306a36Sopenharmony_ci SAVE_PSOCK_STATS(msg_timeouts); 15262306a36Sopenharmony_ci SAVE_PSOCK_STATS(bad_hdr_len); 15362306a36Sopenharmony_ci SAVE_PSOCK_STATS(aborts); 15462306a36Sopenharmony_ci SAVE_PSOCK_STATS(interrupted); 15562306a36Sopenharmony_ci SAVE_PSOCK_STATS(unrecov_intr); 15662306a36Sopenharmony_ci#undef SAVE_PSOCK_STATS 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_civoid strp_done(struct strparser *strp); 16162306a36Sopenharmony_civoid strp_stop(struct strparser *strp); 16262306a36Sopenharmony_civoid strp_check_rcv(struct strparser *strp); 16362306a36Sopenharmony_ciint strp_init(struct strparser *strp, struct sock *sk, 16462306a36Sopenharmony_ci const struct strp_callbacks *cb); 16562306a36Sopenharmony_civoid strp_data_ready(struct strparser *strp); 16662306a36Sopenharmony_ciint strp_process(struct strparser *strp, struct sk_buff *orig_skb, 16762306a36Sopenharmony_ci unsigned int orig_offset, size_t orig_len, 16862306a36Sopenharmony_ci size_t max_msg_size, long timeo); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci#endif /* __NET_STRPARSER_H_ */ 171