18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Stream Parser 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Tom Herbert <tom@herbertland.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef __NET_STRPARSER_H_ 98c2ecf20Sopenharmony_ci#define __NET_STRPARSER_H_ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 128c2ecf20Sopenharmony_ci#include <net/sock.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define STRP_STATS_ADD(stat, count) ((stat) += (count)) 158c2ecf20Sopenharmony_ci#define STRP_STATS_INCR(stat) ((stat)++) 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct strp_stats { 188c2ecf20Sopenharmony_ci unsigned long long msgs; 198c2ecf20Sopenharmony_ci unsigned long long bytes; 208c2ecf20Sopenharmony_ci unsigned int mem_fail; 218c2ecf20Sopenharmony_ci unsigned int need_more_hdr; 228c2ecf20Sopenharmony_ci unsigned int msg_too_big; 238c2ecf20Sopenharmony_ci unsigned int msg_timeouts; 248c2ecf20Sopenharmony_ci unsigned int bad_hdr_len; 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct strp_aggr_stats { 288c2ecf20Sopenharmony_ci unsigned long long msgs; 298c2ecf20Sopenharmony_ci unsigned long long bytes; 308c2ecf20Sopenharmony_ci unsigned int mem_fail; 318c2ecf20Sopenharmony_ci unsigned int need_more_hdr; 328c2ecf20Sopenharmony_ci unsigned int msg_too_big; 338c2ecf20Sopenharmony_ci unsigned int msg_timeouts; 348c2ecf20Sopenharmony_ci unsigned int bad_hdr_len; 358c2ecf20Sopenharmony_ci unsigned int aborts; 368c2ecf20Sopenharmony_ci unsigned int interrupted; 378c2ecf20Sopenharmony_ci unsigned int unrecov_intr; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistruct strparser; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Callbacks are called with lock held for the attached socket */ 438c2ecf20Sopenharmony_cistruct strp_callbacks { 448c2ecf20Sopenharmony_ci int (*parse_msg)(struct strparser *strp, struct sk_buff *skb); 458c2ecf20Sopenharmony_ci void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb); 468c2ecf20Sopenharmony_ci int (*read_sock_done)(struct strparser *strp, int err); 478c2ecf20Sopenharmony_ci void (*abort_parser)(struct strparser *strp, int err); 488c2ecf20Sopenharmony_ci void (*lock)(struct strparser *strp); 498c2ecf20Sopenharmony_ci void (*unlock)(struct strparser *strp); 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct strp_msg { 538c2ecf20Sopenharmony_ci int full_len; 548c2ecf20Sopenharmony_ci int offset; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct _strp_msg { 588c2ecf20Sopenharmony_ci /* Internal cb structure. struct strp_msg must be first for passing 598c2ecf20Sopenharmony_ci * to upper layer. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_ci struct strp_msg strp; 628c2ecf20Sopenharmony_ci int accum_len; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct sk_skb_cb { 668c2ecf20Sopenharmony_ci#define SK_SKB_CB_PRIV_LEN 20 678c2ecf20Sopenharmony_ci unsigned char data[SK_SKB_CB_PRIV_LEN]; 688c2ecf20Sopenharmony_ci struct _strp_msg strp; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic inline struct strp_msg *strp_msg(struct sk_buff *skb) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci return (struct strp_msg *)((void *)skb->cb + 748c2ecf20Sopenharmony_ci offsetof(struct sk_skb_cb, strp)); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Structure for an attached lower socket */ 788c2ecf20Sopenharmony_cistruct strparser { 798c2ecf20Sopenharmony_ci struct sock *sk; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci u32 stopped : 1; 828c2ecf20Sopenharmony_ci u32 paused : 1; 838c2ecf20Sopenharmony_ci u32 aborted : 1; 848c2ecf20Sopenharmony_ci u32 interrupted : 1; 858c2ecf20Sopenharmony_ci u32 unrecov_intr : 1; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci struct sk_buff **skb_nextp; 888c2ecf20Sopenharmony_ci struct sk_buff *skb_head; 898c2ecf20Sopenharmony_ci unsigned int need_bytes; 908c2ecf20Sopenharmony_ci struct delayed_work msg_timer_work; 918c2ecf20Sopenharmony_ci struct work_struct work; 928c2ecf20Sopenharmony_ci struct strp_stats stats; 938c2ecf20Sopenharmony_ci struct strp_callbacks cb; 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* Must be called with lock held for attached socket */ 978c2ecf20Sopenharmony_cistatic inline void strp_pause(struct strparser *strp) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci strp->paused = 1; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* May be called without holding lock for attached socket */ 1038c2ecf20Sopenharmony_civoid strp_unpause(struct strparser *strp); 1048c2ecf20Sopenharmony_ci/* Must be called with process lock held (lock_sock) */ 1058c2ecf20Sopenharmony_civoid __strp_unpause(struct strparser *strp); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic inline void save_strp_stats(struct strparser *strp, 1088c2ecf20Sopenharmony_ci struct strp_aggr_stats *agg_stats) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci /* Save psock statistics in the mux when psock is being unattached. */ 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += \ 1138c2ecf20Sopenharmony_ci strp->stats._stat) 1148c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(msgs); 1158c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(bytes); 1168c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(mem_fail); 1178c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(need_more_hdr); 1188c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(msg_too_big); 1198c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(msg_timeouts); 1208c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(bad_hdr_len); 1218c2ecf20Sopenharmony_ci#undef SAVE_PSOCK_STATS 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (strp->aborted) 1248c2ecf20Sopenharmony_ci agg_stats->aborts++; 1258c2ecf20Sopenharmony_ci if (strp->interrupted) 1268c2ecf20Sopenharmony_ci agg_stats->interrupted++; 1278c2ecf20Sopenharmony_ci if (strp->unrecov_intr) 1288c2ecf20Sopenharmony_ci agg_stats->unrecov_intr++; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic inline void aggregate_strp_stats(struct strp_aggr_stats *stats, 1328c2ecf20Sopenharmony_ci struct strp_aggr_stats *agg_stats) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += stats->_stat) 1358c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(msgs); 1368c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(bytes); 1378c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(mem_fail); 1388c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(need_more_hdr); 1398c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(msg_too_big); 1408c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(msg_timeouts); 1418c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(bad_hdr_len); 1428c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(aborts); 1438c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(interrupted); 1448c2ecf20Sopenharmony_ci SAVE_PSOCK_STATS(unrecov_intr); 1458c2ecf20Sopenharmony_ci#undef SAVE_PSOCK_STATS 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_civoid strp_done(struct strparser *strp); 1508c2ecf20Sopenharmony_civoid strp_stop(struct strparser *strp); 1518c2ecf20Sopenharmony_civoid strp_check_rcv(struct strparser *strp); 1528c2ecf20Sopenharmony_ciint strp_init(struct strparser *strp, struct sock *sk, 1538c2ecf20Sopenharmony_ci const struct strp_callbacks *cb); 1548c2ecf20Sopenharmony_civoid strp_data_ready(struct strparser *strp); 1558c2ecf20Sopenharmony_ciint strp_process(struct strparser *strp, struct sk_buff *orig_skb, 1568c2ecf20Sopenharmony_ci unsigned int orig_offset, size_t orig_len, 1578c2ecf20Sopenharmony_ci size_t max_msg_size, long timeo); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#endif /* __NET_STRPARSER_H_ */ 160