18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2017 - 2018 Covalent IO, Inc. http://covalent.io */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/skmsg.h> 58c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 68c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <net/sock.h> 98c2ecf20Sopenharmony_ci#include <net/tcp.h> 108c2ecf20Sopenharmony_ci#include <net/tls.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic bool sk_msg_try_coalesce_ok(struct sk_msg *msg, int elem_first_coalesce) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci if (msg->sg.end > msg->sg.start && 158c2ecf20Sopenharmony_ci elem_first_coalesce < msg->sg.end) 168c2ecf20Sopenharmony_ci return true; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci if (msg->sg.end < msg->sg.start && 198c2ecf20Sopenharmony_ci (elem_first_coalesce > msg->sg.start || 208c2ecf20Sopenharmony_ci elem_first_coalesce < msg->sg.end)) 218c2ecf20Sopenharmony_ci return true; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci return false; 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciint sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, 278c2ecf20Sopenharmony_ci int elem_first_coalesce) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct page_frag *pfrag = sk_page_frag(sk); 308c2ecf20Sopenharmony_ci u32 osize = msg->sg.size; 318c2ecf20Sopenharmony_ci int ret = 0; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci len -= msg->sg.size; 348c2ecf20Sopenharmony_ci while (len > 0) { 358c2ecf20Sopenharmony_ci struct scatterlist *sge; 368c2ecf20Sopenharmony_ci u32 orig_offset; 378c2ecf20Sopenharmony_ci int use, i; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (!sk_page_frag_refill(sk, pfrag)) { 408c2ecf20Sopenharmony_ci ret = -ENOMEM; 418c2ecf20Sopenharmony_ci goto msg_trim; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci orig_offset = pfrag->offset; 458c2ecf20Sopenharmony_ci use = min_t(int, len, pfrag->size - orig_offset); 468c2ecf20Sopenharmony_ci if (!sk_wmem_schedule(sk, use)) { 478c2ecf20Sopenharmony_ci ret = -ENOMEM; 488c2ecf20Sopenharmony_ci goto msg_trim; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci i = msg->sg.end; 528c2ecf20Sopenharmony_ci sk_msg_iter_var_prev(i); 538c2ecf20Sopenharmony_ci sge = &msg->sg.data[i]; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (sk_msg_try_coalesce_ok(msg, elem_first_coalesce) && 568c2ecf20Sopenharmony_ci sg_page(sge) == pfrag->page && 578c2ecf20Sopenharmony_ci sge->offset + sge->length == orig_offset) { 588c2ecf20Sopenharmony_ci sge->length += use; 598c2ecf20Sopenharmony_ci } else { 608c2ecf20Sopenharmony_ci if (sk_msg_full(msg)) { 618c2ecf20Sopenharmony_ci ret = -ENOSPC; 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci sge = &msg->sg.data[msg->sg.end]; 668c2ecf20Sopenharmony_ci sg_unmark_end(sge); 678c2ecf20Sopenharmony_ci sg_set_page(sge, pfrag->page, use, orig_offset); 688c2ecf20Sopenharmony_ci get_page(pfrag->page); 698c2ecf20Sopenharmony_ci sk_msg_iter_next(msg, end); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci sk_mem_charge(sk, use); 738c2ecf20Sopenharmony_ci msg->sg.size += use; 748c2ecf20Sopenharmony_ci pfrag->offset += use; 758c2ecf20Sopenharmony_ci len -= use; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return ret; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cimsg_trim: 818c2ecf20Sopenharmony_ci sk_msg_trim(sk, msg, osize); 828c2ecf20Sopenharmony_ci return ret; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_alloc); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciint sk_msg_clone(struct sock *sk, struct sk_msg *dst, struct sk_msg *src, 878c2ecf20Sopenharmony_ci u32 off, u32 len) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci int i = src->sg.start; 908c2ecf20Sopenharmony_ci struct scatterlist *sge = sk_msg_elem(src, i); 918c2ecf20Sopenharmony_ci struct scatterlist *sgd = NULL; 928c2ecf20Sopenharmony_ci u32 sge_len, sge_off; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci while (off) { 958c2ecf20Sopenharmony_ci if (sge->length > off) 968c2ecf20Sopenharmony_ci break; 978c2ecf20Sopenharmony_ci off -= sge->length; 988c2ecf20Sopenharmony_ci sk_msg_iter_var_next(i); 998c2ecf20Sopenharmony_ci if (i == src->sg.end && off) 1008c2ecf20Sopenharmony_ci return -ENOSPC; 1018c2ecf20Sopenharmony_ci sge = sk_msg_elem(src, i); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci while (len) { 1058c2ecf20Sopenharmony_ci sge_len = sge->length - off; 1068c2ecf20Sopenharmony_ci if (sge_len > len) 1078c2ecf20Sopenharmony_ci sge_len = len; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (dst->sg.end) 1108c2ecf20Sopenharmony_ci sgd = sk_msg_elem(dst, dst->sg.end - 1); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (sgd && 1138c2ecf20Sopenharmony_ci (sg_page(sge) == sg_page(sgd)) && 1148c2ecf20Sopenharmony_ci (sg_virt(sge) + off == sg_virt(sgd) + sgd->length)) { 1158c2ecf20Sopenharmony_ci sgd->length += sge_len; 1168c2ecf20Sopenharmony_ci dst->sg.size += sge_len; 1178c2ecf20Sopenharmony_ci } else if (!sk_msg_full(dst)) { 1188c2ecf20Sopenharmony_ci sge_off = sge->offset + off; 1198c2ecf20Sopenharmony_ci sk_msg_page_add(dst, sg_page(sge), sge_len, sge_off); 1208c2ecf20Sopenharmony_ci } else { 1218c2ecf20Sopenharmony_ci return -ENOSPC; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci off = 0; 1258c2ecf20Sopenharmony_ci len -= sge_len; 1268c2ecf20Sopenharmony_ci sk_mem_charge(sk, sge_len); 1278c2ecf20Sopenharmony_ci sk_msg_iter_var_next(i); 1288c2ecf20Sopenharmony_ci if (i == src->sg.end && len) 1298c2ecf20Sopenharmony_ci return -ENOSPC; 1308c2ecf20Sopenharmony_ci sge = sk_msg_elem(src, i); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_clone); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_civoid sk_msg_return_zero(struct sock *sk, struct sk_msg *msg, int bytes) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci int i = msg->sg.start; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci do { 1428c2ecf20Sopenharmony_ci struct scatterlist *sge = sk_msg_elem(msg, i); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (bytes < sge->length) { 1458c2ecf20Sopenharmony_ci sge->length -= bytes; 1468c2ecf20Sopenharmony_ci sge->offset += bytes; 1478c2ecf20Sopenharmony_ci sk_mem_uncharge(sk, bytes); 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci sk_mem_uncharge(sk, sge->length); 1528c2ecf20Sopenharmony_ci bytes -= sge->length; 1538c2ecf20Sopenharmony_ci sge->length = 0; 1548c2ecf20Sopenharmony_ci sge->offset = 0; 1558c2ecf20Sopenharmony_ci sk_msg_iter_var_next(i); 1568c2ecf20Sopenharmony_ci } while (bytes && i != msg->sg.end); 1578c2ecf20Sopenharmony_ci msg->sg.start = i; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_return_zero); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_civoid sk_msg_return(struct sock *sk, struct sk_msg *msg, int bytes) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci int i = msg->sg.start; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci do { 1668c2ecf20Sopenharmony_ci struct scatterlist *sge = &msg->sg.data[i]; 1678c2ecf20Sopenharmony_ci int uncharge = (bytes < sge->length) ? bytes : sge->length; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci sk_mem_uncharge(sk, uncharge); 1708c2ecf20Sopenharmony_ci bytes -= uncharge; 1718c2ecf20Sopenharmony_ci sk_msg_iter_var_next(i); 1728c2ecf20Sopenharmony_ci } while (i != msg->sg.end); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_return); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int sk_msg_free_elem(struct sock *sk, struct sk_msg *msg, u32 i, 1778c2ecf20Sopenharmony_ci bool charge) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct scatterlist *sge = sk_msg_elem(msg, i); 1808c2ecf20Sopenharmony_ci u32 len = sge->length; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* When the skb owns the memory we free it from consume_skb path. */ 1838c2ecf20Sopenharmony_ci if (!msg->skb) { 1848c2ecf20Sopenharmony_ci if (charge) 1858c2ecf20Sopenharmony_ci sk_mem_uncharge(sk, len); 1868c2ecf20Sopenharmony_ci put_page(sg_page(sge)); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci memset(sge, 0, sizeof(*sge)); 1898c2ecf20Sopenharmony_ci return len; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int __sk_msg_free(struct sock *sk, struct sk_msg *msg, u32 i, 1938c2ecf20Sopenharmony_ci bool charge) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct scatterlist *sge = sk_msg_elem(msg, i); 1968c2ecf20Sopenharmony_ci int freed = 0; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci while (msg->sg.size) { 1998c2ecf20Sopenharmony_ci msg->sg.size -= sge->length; 2008c2ecf20Sopenharmony_ci freed += sk_msg_free_elem(sk, msg, i, charge); 2018c2ecf20Sopenharmony_ci sk_msg_iter_var_next(i); 2028c2ecf20Sopenharmony_ci sk_msg_check_to_free(msg, i, msg->sg.size); 2038c2ecf20Sopenharmony_ci sge = sk_msg_elem(msg, i); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci consume_skb(msg->skb); 2068c2ecf20Sopenharmony_ci sk_msg_init(msg); 2078c2ecf20Sopenharmony_ci return freed; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ciint sk_msg_free_nocharge(struct sock *sk, struct sk_msg *msg) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci return __sk_msg_free(sk, msg, msg->sg.start, false); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_free_nocharge); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ciint sk_msg_free(struct sock *sk, struct sk_msg *msg) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci return __sk_msg_free(sk, msg, msg->sg.start, true); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_free); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void __sk_msg_free_partial(struct sock *sk, struct sk_msg *msg, 2238c2ecf20Sopenharmony_ci u32 bytes, bool charge) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct scatterlist *sge; 2268c2ecf20Sopenharmony_ci u32 i = msg->sg.start; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci while (bytes) { 2298c2ecf20Sopenharmony_ci sge = sk_msg_elem(msg, i); 2308c2ecf20Sopenharmony_ci if (!sge->length) 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci if (bytes < sge->length) { 2338c2ecf20Sopenharmony_ci if (charge) 2348c2ecf20Sopenharmony_ci sk_mem_uncharge(sk, bytes); 2358c2ecf20Sopenharmony_ci sge->length -= bytes; 2368c2ecf20Sopenharmony_ci sge->offset += bytes; 2378c2ecf20Sopenharmony_ci msg->sg.size -= bytes; 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci msg->sg.size -= sge->length; 2428c2ecf20Sopenharmony_ci bytes -= sge->length; 2438c2ecf20Sopenharmony_ci sk_msg_free_elem(sk, msg, i, charge); 2448c2ecf20Sopenharmony_ci sk_msg_iter_var_next(i); 2458c2ecf20Sopenharmony_ci sk_msg_check_to_free(msg, i, bytes); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci msg->sg.start = i; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_civoid sk_msg_free_partial(struct sock *sk, struct sk_msg *msg, u32 bytes) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci __sk_msg_free_partial(sk, msg, bytes, true); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_free_partial); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_civoid sk_msg_free_partial_nocharge(struct sock *sk, struct sk_msg *msg, 2578c2ecf20Sopenharmony_ci u32 bytes) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci __sk_msg_free_partial(sk, msg, bytes, false); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_civoid sk_msg_trim(struct sock *sk, struct sk_msg *msg, int len) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci int trim = msg->sg.size - len; 2658c2ecf20Sopenharmony_ci u32 i = msg->sg.end; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (trim <= 0) { 2688c2ecf20Sopenharmony_ci WARN_ON(trim < 0); 2698c2ecf20Sopenharmony_ci return; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci sk_msg_iter_var_prev(i); 2738c2ecf20Sopenharmony_ci msg->sg.size = len; 2748c2ecf20Sopenharmony_ci while (msg->sg.data[i].length && 2758c2ecf20Sopenharmony_ci trim >= msg->sg.data[i].length) { 2768c2ecf20Sopenharmony_ci trim -= msg->sg.data[i].length; 2778c2ecf20Sopenharmony_ci sk_msg_free_elem(sk, msg, i, true); 2788c2ecf20Sopenharmony_ci sk_msg_iter_var_prev(i); 2798c2ecf20Sopenharmony_ci if (!trim) 2808c2ecf20Sopenharmony_ci goto out; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci msg->sg.data[i].length -= trim; 2848c2ecf20Sopenharmony_ci sk_mem_uncharge(sk, trim); 2858c2ecf20Sopenharmony_ci /* Adjust copybreak if it falls into the trimmed part of last buf */ 2868c2ecf20Sopenharmony_ci if (msg->sg.curr == i && msg->sg.copybreak > msg->sg.data[i].length) 2878c2ecf20Sopenharmony_ci msg->sg.copybreak = msg->sg.data[i].length; 2888c2ecf20Sopenharmony_ciout: 2898c2ecf20Sopenharmony_ci sk_msg_iter_var_next(i); 2908c2ecf20Sopenharmony_ci msg->sg.end = i; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* If we trim data a full sg elem before curr pointer update 2938c2ecf20Sopenharmony_ci * copybreak and current so that any future copy operations 2948c2ecf20Sopenharmony_ci * start at new copy location. 2958c2ecf20Sopenharmony_ci * However trimed data that has not yet been used in a copy op 2968c2ecf20Sopenharmony_ci * does not require an update. 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_ci if (!msg->sg.size) { 2998c2ecf20Sopenharmony_ci msg->sg.curr = msg->sg.start; 3008c2ecf20Sopenharmony_ci msg->sg.copybreak = 0; 3018c2ecf20Sopenharmony_ci } else if (sk_msg_iter_dist(msg->sg.start, msg->sg.curr) >= 3028c2ecf20Sopenharmony_ci sk_msg_iter_dist(msg->sg.start, msg->sg.end)) { 3038c2ecf20Sopenharmony_ci sk_msg_iter_var_prev(i); 3048c2ecf20Sopenharmony_ci msg->sg.curr = i; 3058c2ecf20Sopenharmony_ci msg->sg.copybreak = msg->sg.data[i].length; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_trim); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciint sk_msg_zerocopy_from_iter(struct sock *sk, struct iov_iter *from, 3118c2ecf20Sopenharmony_ci struct sk_msg *msg, u32 bytes) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci int i, maxpages, ret = 0, num_elems = sk_msg_elem_used(msg); 3148c2ecf20Sopenharmony_ci const int to_max_pages = MAX_MSG_FRAGS; 3158c2ecf20Sopenharmony_ci struct page *pages[MAX_MSG_FRAGS]; 3168c2ecf20Sopenharmony_ci ssize_t orig, copied, use, offset; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci orig = msg->sg.size; 3198c2ecf20Sopenharmony_ci while (bytes > 0) { 3208c2ecf20Sopenharmony_ci i = 0; 3218c2ecf20Sopenharmony_ci maxpages = to_max_pages - num_elems; 3228c2ecf20Sopenharmony_ci if (maxpages == 0) { 3238c2ecf20Sopenharmony_ci ret = -EFAULT; 3248c2ecf20Sopenharmony_ci goto out; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci copied = iov_iter_get_pages(from, pages, bytes, maxpages, 3288c2ecf20Sopenharmony_ci &offset); 3298c2ecf20Sopenharmony_ci if (copied <= 0) { 3308c2ecf20Sopenharmony_ci ret = -EFAULT; 3318c2ecf20Sopenharmony_ci goto out; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci iov_iter_advance(from, copied); 3358c2ecf20Sopenharmony_ci bytes -= copied; 3368c2ecf20Sopenharmony_ci msg->sg.size += copied; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci while (copied) { 3398c2ecf20Sopenharmony_ci use = min_t(int, copied, PAGE_SIZE - offset); 3408c2ecf20Sopenharmony_ci sg_set_page(&msg->sg.data[msg->sg.end], 3418c2ecf20Sopenharmony_ci pages[i], use, offset); 3428c2ecf20Sopenharmony_ci sg_unmark_end(&msg->sg.data[msg->sg.end]); 3438c2ecf20Sopenharmony_ci sk_mem_charge(sk, use); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci offset = 0; 3468c2ecf20Sopenharmony_ci copied -= use; 3478c2ecf20Sopenharmony_ci sk_msg_iter_next(msg, end); 3488c2ecf20Sopenharmony_ci num_elems++; 3498c2ecf20Sopenharmony_ci i++; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci /* When zerocopy is mixed with sk_msg_*copy* operations we 3528c2ecf20Sopenharmony_ci * may have a copybreak set in this case clear and prefer 3538c2ecf20Sopenharmony_ci * zerocopy remainder when possible. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci msg->sg.copybreak = 0; 3568c2ecf20Sopenharmony_ci msg->sg.curr = msg->sg.end; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ciout: 3598c2ecf20Sopenharmony_ci /* Revert iov_iter updates, msg will need to use 'trim' later if it 3608c2ecf20Sopenharmony_ci * also needs to be cleared. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci if (ret) 3638c2ecf20Sopenharmony_ci iov_iter_revert(from, msg->sg.size - orig); 3648c2ecf20Sopenharmony_ci return ret; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_zerocopy_from_iter); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ciint sk_msg_memcopy_from_iter(struct sock *sk, struct iov_iter *from, 3698c2ecf20Sopenharmony_ci struct sk_msg *msg, u32 bytes) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci int ret = -ENOSPC, i = msg->sg.curr; 3728c2ecf20Sopenharmony_ci struct scatterlist *sge; 3738c2ecf20Sopenharmony_ci u32 copy, buf_size; 3748c2ecf20Sopenharmony_ci void *to; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci do { 3778c2ecf20Sopenharmony_ci sge = sk_msg_elem(msg, i); 3788c2ecf20Sopenharmony_ci /* This is possible if a trim operation shrunk the buffer */ 3798c2ecf20Sopenharmony_ci if (msg->sg.copybreak >= sge->length) { 3808c2ecf20Sopenharmony_ci msg->sg.copybreak = 0; 3818c2ecf20Sopenharmony_ci sk_msg_iter_var_next(i); 3828c2ecf20Sopenharmony_ci if (i == msg->sg.end) 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci sge = sk_msg_elem(msg, i); 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci buf_size = sge->length - msg->sg.copybreak; 3888c2ecf20Sopenharmony_ci copy = (buf_size > bytes) ? bytes : buf_size; 3898c2ecf20Sopenharmony_ci to = sg_virt(sge) + msg->sg.copybreak; 3908c2ecf20Sopenharmony_ci msg->sg.copybreak += copy; 3918c2ecf20Sopenharmony_ci if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) 3928c2ecf20Sopenharmony_ci ret = copy_from_iter_nocache(to, copy, from); 3938c2ecf20Sopenharmony_ci else 3948c2ecf20Sopenharmony_ci ret = copy_from_iter(to, copy, from); 3958c2ecf20Sopenharmony_ci if (ret != copy) { 3968c2ecf20Sopenharmony_ci ret = -EFAULT; 3978c2ecf20Sopenharmony_ci goto out; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci bytes -= copy; 4008c2ecf20Sopenharmony_ci if (!bytes) 4018c2ecf20Sopenharmony_ci break; 4028c2ecf20Sopenharmony_ci msg->sg.copybreak = 0; 4038c2ecf20Sopenharmony_ci sk_msg_iter_var_next(i); 4048c2ecf20Sopenharmony_ci } while (i != msg->sg.end); 4058c2ecf20Sopenharmony_ciout: 4068c2ecf20Sopenharmony_ci msg->sg.curr = i; 4078c2ecf20Sopenharmony_ci return ret; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_msg_memcopy_from_iter); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic struct sk_msg *sk_psock_create_ingress_msg(struct sock *sk, 4128c2ecf20Sopenharmony_ci struct sk_buff *skb) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct sk_msg *msg; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) 4178c2ecf20Sopenharmony_ci return NULL; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (!sk_rmem_schedule(sk, skb, skb->truesize)) 4208c2ecf20Sopenharmony_ci return NULL; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci msg = kzalloc(sizeof(*msg), __GFP_NOWARN | GFP_ATOMIC); 4238c2ecf20Sopenharmony_ci if (unlikely(!msg)) 4248c2ecf20Sopenharmony_ci return NULL; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci sk_msg_init(msg); 4278c2ecf20Sopenharmony_ci return msg; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int sk_psock_skb_ingress_enqueue(struct sk_buff *skb, 4318c2ecf20Sopenharmony_ci struct sk_psock *psock, 4328c2ecf20Sopenharmony_ci struct sock *sk, 4338c2ecf20Sopenharmony_ci struct sk_msg *msg) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci int num_sge, copied; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* skb linearize may fail with ENOMEM, but lets simply try again 4388c2ecf20Sopenharmony_ci * later if this happens. Under memory pressure we don't want to 4398c2ecf20Sopenharmony_ci * drop the skb. We need to linearize the skb so that the mapping 4408c2ecf20Sopenharmony_ci * in skb_to_sgvec can not error. 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_ci if (skb_linearize(skb)) 4438c2ecf20Sopenharmony_ci return -EAGAIN; 4448c2ecf20Sopenharmony_ci num_sge = skb_to_sgvec(skb, msg->sg.data, 0, skb->len); 4458c2ecf20Sopenharmony_ci if (unlikely(num_sge < 0)) 4468c2ecf20Sopenharmony_ci return num_sge; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci copied = skb->len; 4498c2ecf20Sopenharmony_ci msg->sg.start = 0; 4508c2ecf20Sopenharmony_ci msg->sg.size = copied; 4518c2ecf20Sopenharmony_ci msg->sg.end = num_sge; 4528c2ecf20Sopenharmony_ci msg->skb = skb; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci sk_psock_queue_msg(psock, msg); 4558c2ecf20Sopenharmony_ci sk_psock_data_ready(sk, psock); 4568c2ecf20Sopenharmony_ci return copied; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int sk_psock_skb_ingress(struct sk_psock *psock, struct sk_buff *skb) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct sock *sk = psock->sk; 4648c2ecf20Sopenharmony_ci struct sk_msg *msg; 4658c2ecf20Sopenharmony_ci int err; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* If we are receiving on the same sock skb->sk is already assigned, 4688c2ecf20Sopenharmony_ci * skip memory accounting and owner transition seeing it already set 4698c2ecf20Sopenharmony_ci * correctly. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci if (unlikely(skb->sk == sk)) 4728c2ecf20Sopenharmony_ci return sk_psock_skb_ingress_self(psock, skb); 4738c2ecf20Sopenharmony_ci msg = sk_psock_create_ingress_msg(sk, skb); 4748c2ecf20Sopenharmony_ci if (!msg) 4758c2ecf20Sopenharmony_ci return -EAGAIN; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* This will transition ownership of the data from the socket where 4788c2ecf20Sopenharmony_ci * the BPF program was run initiating the redirect to the socket 4798c2ecf20Sopenharmony_ci * we will eventually receive this data on. The data will be released 4808c2ecf20Sopenharmony_ci * from skb_consume found in __tcp_bpf_recvmsg() after its been copied 4818c2ecf20Sopenharmony_ci * into user buffers. 4828c2ecf20Sopenharmony_ci */ 4838c2ecf20Sopenharmony_ci skb_set_owner_r(skb, sk); 4848c2ecf20Sopenharmony_ci err = sk_psock_skb_ingress_enqueue(skb, psock, sk, msg); 4858c2ecf20Sopenharmony_ci if (err < 0) 4868c2ecf20Sopenharmony_ci kfree(msg); 4878c2ecf20Sopenharmony_ci return err; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* Puts an skb on the ingress queue of the socket already assigned to the 4918c2ecf20Sopenharmony_ci * skb. In this case we do not need to check memory limits or skb_set_owner_r 4928c2ecf20Sopenharmony_ci * because the skb is already accounted for here. 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_cistatic int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct sk_msg *msg = kzalloc(sizeof(*msg), __GFP_NOWARN | GFP_ATOMIC); 4978c2ecf20Sopenharmony_ci struct sock *sk = psock->sk; 4988c2ecf20Sopenharmony_ci int err; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (unlikely(!msg)) 5018c2ecf20Sopenharmony_ci return -EAGAIN; 5028c2ecf20Sopenharmony_ci sk_msg_init(msg); 5038c2ecf20Sopenharmony_ci skb_set_owner_r(skb, sk); 5048c2ecf20Sopenharmony_ci err = sk_psock_skb_ingress_enqueue(skb, psock, sk, msg); 5058c2ecf20Sopenharmony_ci if (err < 0) 5068c2ecf20Sopenharmony_ci kfree(msg); 5078c2ecf20Sopenharmony_ci return err; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int sk_psock_handle_skb(struct sk_psock *psock, struct sk_buff *skb, 5118c2ecf20Sopenharmony_ci u32 off, u32 len, bool ingress) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci if (!ingress) { 5148c2ecf20Sopenharmony_ci if (!sock_writeable(psock->sk)) 5158c2ecf20Sopenharmony_ci return -EAGAIN; 5168c2ecf20Sopenharmony_ci return skb_send_sock_locked(psock->sk, skb, off, len); 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci return sk_psock_skb_ingress(psock, skb); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic void sk_psock_backlog(struct work_struct *work) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct sk_psock *psock = container_of(work, struct sk_psock, work); 5248c2ecf20Sopenharmony_ci struct sk_psock_work_state *state = &psock->work_state; 5258c2ecf20Sopenharmony_ci struct sk_buff *skb; 5268c2ecf20Sopenharmony_ci bool ingress; 5278c2ecf20Sopenharmony_ci u32 len, off; 5288c2ecf20Sopenharmony_ci int ret; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci /* Lock sock to avoid losing sk_socket during loop. */ 5318c2ecf20Sopenharmony_ci lock_sock(psock->sk); 5328c2ecf20Sopenharmony_ci if (state->skb) { 5338c2ecf20Sopenharmony_ci skb = state->skb; 5348c2ecf20Sopenharmony_ci len = state->len; 5358c2ecf20Sopenharmony_ci off = state->off; 5368c2ecf20Sopenharmony_ci state->skb = NULL; 5378c2ecf20Sopenharmony_ci goto start; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&psock->ingress_skb))) { 5418c2ecf20Sopenharmony_ci len = skb->len; 5428c2ecf20Sopenharmony_ci off = 0; 5438c2ecf20Sopenharmony_cistart: 5448c2ecf20Sopenharmony_ci ingress = tcp_skb_bpf_ingress(skb); 5458c2ecf20Sopenharmony_ci do { 5468c2ecf20Sopenharmony_ci ret = -EIO; 5478c2ecf20Sopenharmony_ci if (likely(psock->sk->sk_socket)) 5488c2ecf20Sopenharmony_ci ret = sk_psock_handle_skb(psock, skb, off, 5498c2ecf20Sopenharmony_ci len, ingress); 5508c2ecf20Sopenharmony_ci if (ret <= 0) { 5518c2ecf20Sopenharmony_ci if (ret == -EAGAIN) { 5528c2ecf20Sopenharmony_ci state->skb = skb; 5538c2ecf20Sopenharmony_ci state->len = len; 5548c2ecf20Sopenharmony_ci state->off = off; 5558c2ecf20Sopenharmony_ci goto end; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci /* Hard errors break pipe and stop xmit. */ 5588c2ecf20Sopenharmony_ci sk_psock_report_error(psock, ret ? -ret : EPIPE); 5598c2ecf20Sopenharmony_ci sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED); 5608c2ecf20Sopenharmony_ci kfree_skb(skb); 5618c2ecf20Sopenharmony_ci goto end; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci off += ret; 5648c2ecf20Sopenharmony_ci len -= ret; 5658c2ecf20Sopenharmony_ci } while (len); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (!ingress) 5688c2ecf20Sopenharmony_ci kfree_skb(skb); 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ciend: 5718c2ecf20Sopenharmony_ci release_sock(psock->sk); 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistruct sk_psock *sk_psock_init(struct sock *sk, int node) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct sk_psock *psock; 5778c2ecf20Sopenharmony_ci struct proto *prot; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (inet_csk_has_ulp(sk)) { 5828c2ecf20Sopenharmony_ci psock = ERR_PTR(-EINVAL); 5838c2ecf20Sopenharmony_ci goto out; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (sk->sk_user_data) { 5878c2ecf20Sopenharmony_ci psock = ERR_PTR(-EBUSY); 5888c2ecf20Sopenharmony_ci goto out; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci psock = kzalloc_node(sizeof(*psock), GFP_ATOMIC | __GFP_NOWARN, node); 5928c2ecf20Sopenharmony_ci if (!psock) { 5938c2ecf20Sopenharmony_ci psock = ERR_PTR(-ENOMEM); 5948c2ecf20Sopenharmony_ci goto out; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci prot = READ_ONCE(sk->sk_prot); 5988c2ecf20Sopenharmony_ci psock->sk = sk; 5998c2ecf20Sopenharmony_ci psock->eval = __SK_NONE; 6008c2ecf20Sopenharmony_ci psock->sk_proto = prot; 6018c2ecf20Sopenharmony_ci psock->saved_unhash = prot->unhash; 6028c2ecf20Sopenharmony_ci psock->saved_close = prot->close; 6038c2ecf20Sopenharmony_ci psock->saved_write_space = sk->sk_write_space; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&psock->link); 6068c2ecf20Sopenharmony_ci spin_lock_init(&psock->link_lock); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci INIT_WORK(&psock->work, sk_psock_backlog); 6098c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&psock->ingress_msg); 6108c2ecf20Sopenharmony_ci skb_queue_head_init(&psock->ingress_skb); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci sk_psock_set_state(psock, SK_PSOCK_TX_ENABLED); 6138c2ecf20Sopenharmony_ci refcount_set(&psock->refcnt, 1); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci __rcu_assign_sk_user_data_with_flags(sk, psock, 6168c2ecf20Sopenharmony_ci SK_USER_DATA_NOCOPY | 6178c2ecf20Sopenharmony_ci SK_USER_DATA_PSOCK); 6188c2ecf20Sopenharmony_ci sock_hold(sk); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ciout: 6218c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 6228c2ecf20Sopenharmony_ci return psock; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_psock_init); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistruct sk_psock_link *sk_psock_link_pop(struct sk_psock *psock) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct sk_psock_link *link; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci spin_lock_bh(&psock->link_lock); 6318c2ecf20Sopenharmony_ci link = list_first_entry_or_null(&psock->link, struct sk_psock_link, 6328c2ecf20Sopenharmony_ci list); 6338c2ecf20Sopenharmony_ci if (link) 6348c2ecf20Sopenharmony_ci list_del(&link->list); 6358c2ecf20Sopenharmony_ci spin_unlock_bh(&psock->link_lock); 6368c2ecf20Sopenharmony_ci return link; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_civoid __sk_psock_purge_ingress_msg(struct sk_psock *psock) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct sk_msg *msg, *tmp; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci list_for_each_entry_safe(msg, tmp, &psock->ingress_msg, list) { 6448c2ecf20Sopenharmony_ci list_del(&msg->list); 6458c2ecf20Sopenharmony_ci sk_msg_free(psock->sk, msg); 6468c2ecf20Sopenharmony_ci kfree(msg); 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic void sk_psock_zap_ingress(struct sk_psock *psock) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci __skb_queue_purge(&psock->ingress_skb); 6538c2ecf20Sopenharmony_ci __sk_psock_purge_ingress_msg(psock); 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic void sk_psock_link_destroy(struct sk_psock *psock) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct sk_psock_link *link, *tmp; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci list_for_each_entry_safe(link, tmp, &psock->link, list) { 6618c2ecf20Sopenharmony_ci list_del(&link->list); 6628c2ecf20Sopenharmony_ci sk_psock_free_link(link); 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic void sk_psock_destroy_deferred(struct work_struct *gc) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct sk_psock *psock = container_of(gc, struct sk_psock, gc); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* No sk_callback_lock since already detached. */ 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* Parser has been stopped */ 6738c2ecf20Sopenharmony_ci if (psock->progs.skb_parser) 6748c2ecf20Sopenharmony_ci strp_done(&psock->parser.strp); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci cancel_work_sync(&psock->work); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci psock_progs_drop(&psock->progs); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci sk_psock_link_destroy(psock); 6818c2ecf20Sopenharmony_ci sk_psock_cork_free(psock); 6828c2ecf20Sopenharmony_ci sk_psock_zap_ingress(psock); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (psock->sk_redir) 6858c2ecf20Sopenharmony_ci sock_put(psock->sk_redir); 6868c2ecf20Sopenharmony_ci sock_put(psock->sk); 6878c2ecf20Sopenharmony_ci kfree(psock); 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic void sk_psock_destroy(struct rcu_head *rcu) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci struct sk_psock *psock = container_of(rcu, struct sk_psock, rcu); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci INIT_WORK(&psock->gc, sk_psock_destroy_deferred); 6958c2ecf20Sopenharmony_ci schedule_work(&psock->gc); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_civoid sk_psock_drop(struct sock *sk, struct sk_psock *psock) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci sk_psock_cork_free(psock); 7018c2ecf20Sopenharmony_ci sk_psock_zap_ingress(psock); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 7048c2ecf20Sopenharmony_ci sk_psock_restore_proto(sk, psock); 7058c2ecf20Sopenharmony_ci rcu_assign_sk_user_data(sk, NULL); 7068c2ecf20Sopenharmony_ci if (psock->progs.skb_parser) 7078c2ecf20Sopenharmony_ci sk_psock_stop_strp(sk, psock); 7088c2ecf20Sopenharmony_ci else if (psock->progs.skb_verdict) 7098c2ecf20Sopenharmony_ci sk_psock_stop_verdict(sk, psock); 7108c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 7118c2ecf20Sopenharmony_ci sk_psock_clear_state(psock, SK_PSOCK_TX_ENABLED); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci call_rcu(&psock->rcu, sk_psock_destroy); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_psock_drop); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic int sk_psock_map_verd(int verdict, bool redir) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci switch (verdict) { 7208c2ecf20Sopenharmony_ci case SK_PASS: 7218c2ecf20Sopenharmony_ci return redir ? __SK_REDIRECT : __SK_PASS; 7228c2ecf20Sopenharmony_ci case SK_DROP: 7238c2ecf20Sopenharmony_ci default: 7248c2ecf20Sopenharmony_ci break; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return __SK_DROP; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ciint sk_psock_msg_verdict(struct sock *sk, struct sk_psock *psock, 7318c2ecf20Sopenharmony_ci struct sk_msg *msg) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct bpf_prog *prog; 7348c2ecf20Sopenharmony_ci int ret; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci rcu_read_lock(); 7378c2ecf20Sopenharmony_ci prog = READ_ONCE(psock->progs.msg_parser); 7388c2ecf20Sopenharmony_ci if (unlikely(!prog)) { 7398c2ecf20Sopenharmony_ci ret = __SK_PASS; 7408c2ecf20Sopenharmony_ci goto out; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci sk_msg_compute_data_pointers(msg); 7448c2ecf20Sopenharmony_ci msg->sk = sk; 7458c2ecf20Sopenharmony_ci ret = bpf_prog_run_pin_on_cpu(prog, msg); 7468c2ecf20Sopenharmony_ci ret = sk_psock_map_verd(ret, msg->sk_redir); 7478c2ecf20Sopenharmony_ci psock->apply_bytes = msg->apply_bytes; 7488c2ecf20Sopenharmony_ci if (ret == __SK_REDIRECT) { 7498c2ecf20Sopenharmony_ci if (psock->sk_redir) 7508c2ecf20Sopenharmony_ci sock_put(psock->sk_redir); 7518c2ecf20Sopenharmony_ci psock->sk_redir = msg->sk_redir; 7528c2ecf20Sopenharmony_ci if (!psock->sk_redir) { 7538c2ecf20Sopenharmony_ci ret = __SK_DROP; 7548c2ecf20Sopenharmony_ci goto out; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci sock_hold(psock->sk_redir); 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ciout: 7598c2ecf20Sopenharmony_ci rcu_read_unlock(); 7608c2ecf20Sopenharmony_ci return ret; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_psock_msg_verdict); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int sk_psock_bpf_run(struct sk_psock *psock, struct bpf_prog *prog, 7658c2ecf20Sopenharmony_ci struct sk_buff *skb) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci bpf_compute_data_end_sk_skb(skb); 7688c2ecf20Sopenharmony_ci return bpf_prog_run_pin_on_cpu(prog, skb); 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic struct sk_psock *sk_psock_from_strp(struct strparser *strp) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci struct sk_psock_parser *parser; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci parser = container_of(strp, struct sk_psock_parser, strp); 7768c2ecf20Sopenharmony_ci return container_of(parser, struct sk_psock, parser); 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic void sk_psock_skb_redirect(struct sk_buff *skb) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci struct sk_psock *psock_other; 7828c2ecf20Sopenharmony_ci struct sock *sk_other; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci sk_other = tcp_skb_bpf_redirect_fetch(skb); 7858c2ecf20Sopenharmony_ci /* This error is a buggy BPF program, it returned a redirect 7868c2ecf20Sopenharmony_ci * return code, but then didn't set a redirect interface. 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_ci if (unlikely(!sk_other)) { 7898c2ecf20Sopenharmony_ci kfree_skb(skb); 7908c2ecf20Sopenharmony_ci return; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci psock_other = sk_psock(sk_other); 7938c2ecf20Sopenharmony_ci /* This error indicates the socket is being torn down or had another 7948c2ecf20Sopenharmony_ci * error that caused the pipe to break. We can't send a packet on 7958c2ecf20Sopenharmony_ci * a socket that is in this state so we drop the skb. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci if (!psock_other || sock_flag(sk_other, SOCK_DEAD) || 7988c2ecf20Sopenharmony_ci !sk_psock_test_state(psock_other, SK_PSOCK_TX_ENABLED)) { 7998c2ecf20Sopenharmony_ci kfree_skb(skb); 8008c2ecf20Sopenharmony_ci return; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci skb_queue_tail(&psock_other->ingress_skb, skb); 8048c2ecf20Sopenharmony_ci schedule_work(&psock_other->work); 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic void sk_psock_tls_verdict_apply(struct sk_buff *skb, struct sock *sk, int verdict) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci switch (verdict) { 8108c2ecf20Sopenharmony_ci case __SK_REDIRECT: 8118c2ecf20Sopenharmony_ci sk_psock_skb_redirect(skb); 8128c2ecf20Sopenharmony_ci break; 8138c2ecf20Sopenharmony_ci case __SK_PASS: 8148c2ecf20Sopenharmony_ci case __SK_DROP: 8158c2ecf20Sopenharmony_ci default: 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ciint sk_psock_tls_strp_read(struct sk_psock *psock, struct sk_buff *skb) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci struct bpf_prog *prog; 8238c2ecf20Sopenharmony_ci int ret = __SK_PASS; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci rcu_read_lock(); 8268c2ecf20Sopenharmony_ci prog = READ_ONCE(psock->progs.skb_verdict); 8278c2ecf20Sopenharmony_ci if (likely(prog)) { 8288c2ecf20Sopenharmony_ci skb->sk = psock->sk; 8298c2ecf20Sopenharmony_ci tcp_skb_bpf_redirect_clear(skb); 8308c2ecf20Sopenharmony_ci ret = sk_psock_bpf_run(psock, prog, skb); 8318c2ecf20Sopenharmony_ci ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb)); 8328c2ecf20Sopenharmony_ci skb->sk = NULL; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci sk_psock_tls_verdict_apply(skb, psock->sk, ret); 8358c2ecf20Sopenharmony_ci rcu_read_unlock(); 8368c2ecf20Sopenharmony_ci return ret; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sk_psock_tls_strp_read); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic void sk_psock_verdict_apply(struct sk_psock *psock, 8418c2ecf20Sopenharmony_ci struct sk_buff *skb, int verdict) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct tcp_skb_cb *tcp; 8448c2ecf20Sopenharmony_ci struct sock *sk_other; 8458c2ecf20Sopenharmony_ci int err = -EIO; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci switch (verdict) { 8488c2ecf20Sopenharmony_ci case __SK_PASS: 8498c2ecf20Sopenharmony_ci sk_other = psock->sk; 8508c2ecf20Sopenharmony_ci if (sock_flag(sk_other, SOCK_DEAD) || 8518c2ecf20Sopenharmony_ci !sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) { 8528c2ecf20Sopenharmony_ci goto out_free; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci tcp = TCP_SKB_CB(skb); 8568c2ecf20Sopenharmony_ci tcp->bpf.flags |= BPF_F_INGRESS; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* If the queue is empty then we can submit directly 8598c2ecf20Sopenharmony_ci * into the msg queue. If its not empty we have to 8608c2ecf20Sopenharmony_ci * queue work otherwise we may get OOO data. Otherwise, 8618c2ecf20Sopenharmony_ci * if sk_psock_skb_ingress errors will be handled by 8628c2ecf20Sopenharmony_ci * retrying later from workqueue. 8638c2ecf20Sopenharmony_ci */ 8648c2ecf20Sopenharmony_ci if (skb_queue_empty(&psock->ingress_skb)) { 8658c2ecf20Sopenharmony_ci err = sk_psock_skb_ingress_self(psock, skb); 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci if (err < 0) { 8688c2ecf20Sopenharmony_ci skb_queue_tail(&psock->ingress_skb, skb); 8698c2ecf20Sopenharmony_ci schedule_work(&psock->work); 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci break; 8728c2ecf20Sopenharmony_ci case __SK_REDIRECT: 8738c2ecf20Sopenharmony_ci sk_psock_skb_redirect(skb); 8748c2ecf20Sopenharmony_ci break; 8758c2ecf20Sopenharmony_ci case __SK_DROP: 8768c2ecf20Sopenharmony_ci default: 8778c2ecf20Sopenharmony_ciout_free: 8788c2ecf20Sopenharmony_ci kfree_skb(skb); 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic void sk_psock_strp_read(struct strparser *strp, struct sk_buff *skb) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct sk_psock *psock; 8858c2ecf20Sopenharmony_ci struct bpf_prog *prog; 8868c2ecf20Sopenharmony_ci int ret = __SK_DROP; 8878c2ecf20Sopenharmony_ci struct sock *sk; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci rcu_read_lock(); 8908c2ecf20Sopenharmony_ci sk = strp->sk; 8918c2ecf20Sopenharmony_ci psock = sk_psock(sk); 8928c2ecf20Sopenharmony_ci if (unlikely(!psock)) { 8938c2ecf20Sopenharmony_ci kfree_skb(skb); 8948c2ecf20Sopenharmony_ci goto out; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci prog = READ_ONCE(psock->progs.skb_verdict); 8978c2ecf20Sopenharmony_ci if (likely(prog)) { 8988c2ecf20Sopenharmony_ci skb->sk = sk; 8998c2ecf20Sopenharmony_ci tcp_skb_bpf_redirect_clear(skb); 9008c2ecf20Sopenharmony_ci ret = sk_psock_bpf_run(psock, prog, skb); 9018c2ecf20Sopenharmony_ci ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb)); 9028c2ecf20Sopenharmony_ci skb->sk = NULL; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci sk_psock_verdict_apply(psock, skb, ret); 9058c2ecf20Sopenharmony_ciout: 9068c2ecf20Sopenharmony_ci rcu_read_unlock(); 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic int sk_psock_strp_read_done(struct strparser *strp, int err) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci return err; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic int sk_psock_strp_parse(struct strparser *strp, struct sk_buff *skb) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci struct sk_psock *psock = sk_psock_from_strp(strp); 9178c2ecf20Sopenharmony_ci struct bpf_prog *prog; 9188c2ecf20Sopenharmony_ci int ret = skb->len; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci rcu_read_lock(); 9218c2ecf20Sopenharmony_ci prog = READ_ONCE(psock->progs.skb_parser); 9228c2ecf20Sopenharmony_ci if (likely(prog)) { 9238c2ecf20Sopenharmony_ci skb->sk = psock->sk; 9248c2ecf20Sopenharmony_ci ret = sk_psock_bpf_run(psock, prog, skb); 9258c2ecf20Sopenharmony_ci skb->sk = NULL; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci rcu_read_unlock(); 9288c2ecf20Sopenharmony_ci return ret; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci/* Called with socket lock held. */ 9328c2ecf20Sopenharmony_cistatic void sk_psock_strp_data_ready(struct sock *sk) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci struct sk_psock *psock; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci rcu_read_lock(); 9378c2ecf20Sopenharmony_ci psock = sk_psock(sk); 9388c2ecf20Sopenharmony_ci if (likely(psock)) { 9398c2ecf20Sopenharmony_ci if (tls_sw_has_ctx_rx(sk)) { 9408c2ecf20Sopenharmony_ci psock->parser.saved_data_ready(sk); 9418c2ecf20Sopenharmony_ci } else { 9428c2ecf20Sopenharmony_ci write_lock_bh(&sk->sk_callback_lock); 9438c2ecf20Sopenharmony_ci strp_data_ready(&psock->parser.strp); 9448c2ecf20Sopenharmony_ci write_unlock_bh(&sk->sk_callback_lock); 9458c2ecf20Sopenharmony_ci } 9468c2ecf20Sopenharmony_ci } 9478c2ecf20Sopenharmony_ci rcu_read_unlock(); 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic int sk_psock_verdict_recv(read_descriptor_t *desc, struct sk_buff *skb, 9518c2ecf20Sopenharmony_ci unsigned int offset, size_t orig_len) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci struct sock *sk = (struct sock *)desc->arg.data; 9548c2ecf20Sopenharmony_ci struct sk_psock *psock; 9558c2ecf20Sopenharmony_ci struct bpf_prog *prog; 9568c2ecf20Sopenharmony_ci int ret = __SK_DROP; 9578c2ecf20Sopenharmony_ci int len = orig_len; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci /* clone here so sk_eat_skb() in tcp_read_sock does not drop our data */ 9608c2ecf20Sopenharmony_ci skb = skb_clone(skb, GFP_ATOMIC); 9618c2ecf20Sopenharmony_ci if (!skb) { 9628c2ecf20Sopenharmony_ci desc->error = -ENOMEM; 9638c2ecf20Sopenharmony_ci return 0; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci rcu_read_lock(); 9678c2ecf20Sopenharmony_ci psock = sk_psock(sk); 9688c2ecf20Sopenharmony_ci if (unlikely(!psock)) { 9698c2ecf20Sopenharmony_ci len = 0; 9708c2ecf20Sopenharmony_ci kfree_skb(skb); 9718c2ecf20Sopenharmony_ci goto out; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci prog = READ_ONCE(psock->progs.skb_verdict); 9748c2ecf20Sopenharmony_ci if (likely(prog)) { 9758c2ecf20Sopenharmony_ci skb->sk = sk; 9768c2ecf20Sopenharmony_ci tcp_skb_bpf_redirect_clear(skb); 9778c2ecf20Sopenharmony_ci ret = sk_psock_bpf_run(psock, prog, skb); 9788c2ecf20Sopenharmony_ci ret = sk_psock_map_verd(ret, tcp_skb_bpf_redirect_fetch(skb)); 9798c2ecf20Sopenharmony_ci skb->sk = NULL; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci sk_psock_verdict_apply(psock, skb, ret); 9828c2ecf20Sopenharmony_ciout: 9838c2ecf20Sopenharmony_ci rcu_read_unlock(); 9848c2ecf20Sopenharmony_ci return len; 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic void sk_psock_verdict_data_ready(struct sock *sk) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct socket *sock = sk->sk_socket; 9908c2ecf20Sopenharmony_ci read_descriptor_t desc; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (unlikely(!sock || !sock->ops || !sock->ops->read_sock)) 9938c2ecf20Sopenharmony_ci return; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci desc.arg.data = sk; 9968c2ecf20Sopenharmony_ci desc.error = 0; 9978c2ecf20Sopenharmony_ci desc.count = 1; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci sock->ops->read_sock(sk, &desc, sk_psock_verdict_recv); 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistatic void sk_psock_write_space(struct sock *sk) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci struct sk_psock *psock; 10058c2ecf20Sopenharmony_ci void (*write_space)(struct sock *sk) = NULL; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci rcu_read_lock(); 10088c2ecf20Sopenharmony_ci psock = sk_psock(sk); 10098c2ecf20Sopenharmony_ci if (likely(psock)) { 10108c2ecf20Sopenharmony_ci if (sk_psock_test_state(psock, SK_PSOCK_TX_ENABLED)) 10118c2ecf20Sopenharmony_ci schedule_work(&psock->work); 10128c2ecf20Sopenharmony_ci write_space = psock->saved_write_space; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci rcu_read_unlock(); 10158c2ecf20Sopenharmony_ci if (write_space) 10168c2ecf20Sopenharmony_ci write_space(sk); 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ciint sk_psock_init_strp(struct sock *sk, struct sk_psock *psock) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci static const struct strp_callbacks cb = { 10228c2ecf20Sopenharmony_ci .rcv_msg = sk_psock_strp_read, 10238c2ecf20Sopenharmony_ci .read_sock_done = sk_psock_strp_read_done, 10248c2ecf20Sopenharmony_ci .parse_msg = sk_psock_strp_parse, 10258c2ecf20Sopenharmony_ci }; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci psock->parser.enabled = false; 10288c2ecf20Sopenharmony_ci return strp_init(&psock->parser.strp, sk, &cb); 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_civoid sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct sk_psock_parser *parser = &psock->parser; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (parser->enabled) 10368c2ecf20Sopenharmony_ci return; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci parser->saved_data_ready = sk->sk_data_ready; 10398c2ecf20Sopenharmony_ci sk->sk_data_ready = sk_psock_verdict_data_ready; 10408c2ecf20Sopenharmony_ci sk->sk_write_space = sk_psock_write_space; 10418c2ecf20Sopenharmony_ci parser->enabled = true; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_civoid sk_psock_start_strp(struct sock *sk, struct sk_psock *psock) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci struct sk_psock_parser *parser = &psock->parser; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (parser->enabled) 10498c2ecf20Sopenharmony_ci return; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci parser->saved_data_ready = sk->sk_data_ready; 10528c2ecf20Sopenharmony_ci sk->sk_data_ready = sk_psock_strp_data_ready; 10538c2ecf20Sopenharmony_ci sk->sk_write_space = sk_psock_write_space; 10548c2ecf20Sopenharmony_ci parser->enabled = true; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_civoid sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci struct sk_psock_parser *parser = &psock->parser; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (!parser->enabled) 10628c2ecf20Sopenharmony_ci return; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci sk->sk_data_ready = parser->saved_data_ready; 10658c2ecf20Sopenharmony_ci parser->saved_data_ready = NULL; 10668c2ecf20Sopenharmony_ci strp_stop(&parser->strp); 10678c2ecf20Sopenharmony_ci parser->enabled = false; 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_civoid sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci struct sk_psock_parser *parser = &psock->parser; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (!parser->enabled) 10758c2ecf20Sopenharmony_ci return; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci sk->sk_data_ready = parser->saved_data_ready; 10788c2ecf20Sopenharmony_ci parser->saved_data_ready = NULL; 10798c2ecf20Sopenharmony_ci parser->enabled = false; 10808c2ecf20Sopenharmony_ci} 1081