18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) ST-Ericsson AB 2010 48c2ecf20Sopenharmony_ci * Author: Sjur Brendeland 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/string.h> 108c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 118c2ecf20Sopenharmony_ci#include <linux/export.h> 128c2ecf20Sopenharmony_ci#include <net/caif/cfpkt.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define PKT_PREFIX 48 158c2ecf20Sopenharmony_ci#define PKT_POSTFIX 2 168c2ecf20Sopenharmony_ci#define PKT_LEN_WHEN_EXTENDING 128 178c2ecf20Sopenharmony_ci#define PKT_ERROR(pkt, errmsg) \ 188c2ecf20Sopenharmony_cido { \ 198c2ecf20Sopenharmony_ci cfpkt_priv(pkt)->erronous = true; \ 208c2ecf20Sopenharmony_ci skb_reset_tail_pointer(&pkt->skb); \ 218c2ecf20Sopenharmony_ci pr_warn(errmsg); \ 228c2ecf20Sopenharmony_ci} while (0) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct cfpktq { 258c2ecf20Sopenharmony_ci struct sk_buff_head head; 268c2ecf20Sopenharmony_ci atomic_t count; 278c2ecf20Sopenharmony_ci /* Lock protects count updates */ 288c2ecf20Sopenharmony_ci spinlock_t lock; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * net/caif/ is generic and does not 338c2ecf20Sopenharmony_ci * understand SKB, so we do this typecast 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistruct cfpkt { 368c2ecf20Sopenharmony_ci struct sk_buff skb; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Private data inside SKB */ 408c2ecf20Sopenharmony_cistruct cfpkt_priv_data { 418c2ecf20Sopenharmony_ci struct dev_info dev_info; 428c2ecf20Sopenharmony_ci bool erronous; 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return (struct cfpkt_priv_data *) pkt->skb.cb; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline bool is_erronous(struct cfpkt *pkt) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return cfpkt_priv(pkt)->erronous; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci return &pkt->skb; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic inline struct cfpkt *skb_to_pkt(struct sk_buff *skb) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci return (struct cfpkt *) skb; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct cfpkt *pkt = skb_to_pkt(nativepkt); 688c2ecf20Sopenharmony_ci cfpkt_priv(pkt)->erronous = false; 698c2ecf20Sopenharmony_ci return pkt; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfpkt_fromnative); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_civoid *cfpkt_tonative(struct cfpkt *pkt) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci return (void *) pkt; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfpkt_tonative); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic struct cfpkt *cfpkt_create_pfx(u16 len, u16 pfx) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct sk_buff *skb; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci skb = alloc_skb(len + pfx, GFP_ATOMIC); 848c2ecf20Sopenharmony_ci if (unlikely(skb == NULL)) 858c2ecf20Sopenharmony_ci return NULL; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci skb_reserve(skb, pfx); 888c2ecf20Sopenharmony_ci return skb_to_pkt(skb); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ciinline struct cfpkt *cfpkt_create(u16 len) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci return cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_civoid cfpkt_destroy(struct cfpkt *pkt) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 998c2ecf20Sopenharmony_ci kfree_skb(skb); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ciinline bool cfpkt_more(struct cfpkt *pkt) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 1058c2ecf20Sopenharmony_ci return skb->len > 0; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciint cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 1118c2ecf20Sopenharmony_ci if (skb_headlen(skb) >= len) { 1128c2ecf20Sopenharmony_ci memcpy(data, skb->data, len); 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci return !cfpkt_extr_head(pkt, data, len) && 1168c2ecf20Sopenharmony_ci !cfpkt_add_head(pkt, data, len); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ciint cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 1228c2ecf20Sopenharmony_ci u8 *from; 1238c2ecf20Sopenharmony_ci if (unlikely(is_erronous(pkt))) 1248c2ecf20Sopenharmony_ci return -EPROTO; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (unlikely(len > skb->len)) { 1278c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "read beyond end of packet\n"); 1288c2ecf20Sopenharmony_ci return -EPROTO; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (unlikely(len > skb_headlen(skb))) { 1328c2ecf20Sopenharmony_ci if (unlikely(skb_linearize(skb) != 0)) { 1338c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "linearize failed\n"); 1348c2ecf20Sopenharmony_ci return -EPROTO; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci from = skb_pull(skb, len); 1388c2ecf20Sopenharmony_ci from -= len; 1398c2ecf20Sopenharmony_ci if (data) 1408c2ecf20Sopenharmony_ci memcpy(data, from, len); 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfpkt_extr_head); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ciint cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 1488c2ecf20Sopenharmony_ci u8 *data = dta; 1498c2ecf20Sopenharmony_ci u8 *from; 1508c2ecf20Sopenharmony_ci if (unlikely(is_erronous(pkt))) 1518c2ecf20Sopenharmony_ci return -EPROTO; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (unlikely(skb_linearize(skb) != 0)) { 1548c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "linearize failed\n"); 1558c2ecf20Sopenharmony_ci return -EPROTO; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci if (unlikely(skb->data + len > skb_tail_pointer(skb))) { 1588c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "read beyond end of packet\n"); 1598c2ecf20Sopenharmony_ci return -EPROTO; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci from = skb_tail_pointer(skb) - len; 1628c2ecf20Sopenharmony_ci skb_trim(skb, skb->len - len); 1638c2ecf20Sopenharmony_ci memcpy(data, from, len); 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciint cfpkt_pad_trail(struct cfpkt *pkt, u16 len) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci return cfpkt_add_body(pkt, NULL, len); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ciint cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 1758c2ecf20Sopenharmony_ci struct sk_buff *lastskb; 1768c2ecf20Sopenharmony_ci u8 *to; 1778c2ecf20Sopenharmony_ci u16 addlen = 0; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (unlikely(is_erronous(pkt))) 1818c2ecf20Sopenharmony_ci return -EPROTO; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci lastskb = skb; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* Check whether we need to add space at the tail */ 1868c2ecf20Sopenharmony_ci if (unlikely(skb_tailroom(skb) < len)) { 1878c2ecf20Sopenharmony_ci if (likely(len < PKT_LEN_WHEN_EXTENDING)) 1888c2ecf20Sopenharmony_ci addlen = PKT_LEN_WHEN_EXTENDING; 1898c2ecf20Sopenharmony_ci else 1908c2ecf20Sopenharmony_ci addlen = len; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Check whether we need to change the SKB before writing to the tail */ 1948c2ecf20Sopenharmony_ci if (unlikely((addlen > 0) || skb_cloned(skb) || skb_shared(skb))) { 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* Make sure data is writable */ 1978c2ecf20Sopenharmony_ci if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) { 1988c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "cow failed\n"); 1998c2ecf20Sopenharmony_ci return -EPROTO; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* All set to put the last SKB and optionally write data there. */ 2048c2ecf20Sopenharmony_ci to = pskb_put(skb, lastskb, len); 2058c2ecf20Sopenharmony_ci if (likely(data)) 2068c2ecf20Sopenharmony_ci memcpy(to, data, len); 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ciinline int cfpkt_addbdy(struct cfpkt *pkt, u8 data) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci return cfpkt_add_body(pkt, &data, 1); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ciint cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 2188c2ecf20Sopenharmony_ci struct sk_buff *lastskb; 2198c2ecf20Sopenharmony_ci u8 *to; 2208c2ecf20Sopenharmony_ci const u8 *data = data2; 2218c2ecf20Sopenharmony_ci int ret; 2228c2ecf20Sopenharmony_ci if (unlikely(is_erronous(pkt))) 2238c2ecf20Sopenharmony_ci return -EPROTO; 2248c2ecf20Sopenharmony_ci if (unlikely(skb_headroom(skb) < len)) { 2258c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "no headroom\n"); 2268c2ecf20Sopenharmony_ci return -EPROTO; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Make sure data is writable */ 2308c2ecf20Sopenharmony_ci ret = skb_cow_data(skb, 0, &lastskb); 2318c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) { 2328c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "cow failed\n"); 2338c2ecf20Sopenharmony_ci return ret; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci to = skb_push(skb, len); 2378c2ecf20Sopenharmony_ci memcpy(to, data, len); 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfpkt_add_head); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciinline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci return cfpkt_add_body(pkt, data, len); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciinline u16 cfpkt_getlen(struct cfpkt *pkt) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 2508c2ecf20Sopenharmony_ci return skb->len; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ciint cfpkt_iterate(struct cfpkt *pkt, 2548c2ecf20Sopenharmony_ci u16 (*iter_func)(u16, void *, u16), 2558c2ecf20Sopenharmony_ci u16 data) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci /* 2588c2ecf20Sopenharmony_ci * Don't care about the performance hit of linearizing, 2598c2ecf20Sopenharmony_ci * Checksum should not be used on high-speed interfaces anyway. 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci if (unlikely(is_erronous(pkt))) 2628c2ecf20Sopenharmony_ci return -EPROTO; 2638c2ecf20Sopenharmony_ci if (unlikely(skb_linearize(&pkt->skb) != 0)) { 2648c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "linearize failed\n"); 2658c2ecf20Sopenharmony_ci return -EPROTO; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt)); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ciint cfpkt_setlen(struct cfpkt *pkt, u16 len) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (unlikely(is_erronous(pkt))) 2768c2ecf20Sopenharmony_ci return -EPROTO; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (likely(len <= skb->len)) { 2798c2ecf20Sopenharmony_ci if (unlikely(skb->data_len)) 2808c2ecf20Sopenharmony_ci ___pskb_trim(skb, len); 2818c2ecf20Sopenharmony_ci else 2828c2ecf20Sopenharmony_ci skb_trim(skb, len); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return cfpkt_getlen(pkt); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* Need to expand SKB */ 2888c2ecf20Sopenharmony_ci if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len))) 2898c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "skb_pad_trail failed\n"); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return cfpkt_getlen(pkt); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistruct cfpkt *cfpkt_append(struct cfpkt *dstpkt, 2958c2ecf20Sopenharmony_ci struct cfpkt *addpkt, 2968c2ecf20Sopenharmony_ci u16 expectlen) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct sk_buff *dst = pkt_to_skb(dstpkt); 2998c2ecf20Sopenharmony_ci struct sk_buff *add = pkt_to_skb(addpkt); 3008c2ecf20Sopenharmony_ci u16 addlen = skb_headlen(add); 3018c2ecf20Sopenharmony_ci u16 neededtailspace; 3028c2ecf20Sopenharmony_ci struct sk_buff *tmp; 3038c2ecf20Sopenharmony_ci u16 dstlen; 3048c2ecf20Sopenharmony_ci u16 createlen; 3058c2ecf20Sopenharmony_ci if (unlikely(is_erronous(dstpkt) || is_erronous(addpkt))) { 3068c2ecf20Sopenharmony_ci return dstpkt; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci if (expectlen > addlen) 3098c2ecf20Sopenharmony_ci neededtailspace = expectlen; 3108c2ecf20Sopenharmony_ci else 3118c2ecf20Sopenharmony_ci neededtailspace = addlen; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (dst->tail + neededtailspace > dst->end) { 3148c2ecf20Sopenharmony_ci /* Create a dumplicate of 'dst' with more tail space */ 3158c2ecf20Sopenharmony_ci struct cfpkt *tmppkt; 3168c2ecf20Sopenharmony_ci dstlen = skb_headlen(dst); 3178c2ecf20Sopenharmony_ci createlen = dstlen + neededtailspace; 3188c2ecf20Sopenharmony_ci tmppkt = cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX); 3198c2ecf20Sopenharmony_ci if (tmppkt == NULL) 3208c2ecf20Sopenharmony_ci return NULL; 3218c2ecf20Sopenharmony_ci tmp = pkt_to_skb(tmppkt); 3228c2ecf20Sopenharmony_ci skb_put_data(tmp, dst->data, dstlen); 3238c2ecf20Sopenharmony_ci cfpkt_destroy(dstpkt); 3248c2ecf20Sopenharmony_ci dst = tmp; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci skb_put_data(dst, add->data, skb_headlen(add)); 3278c2ecf20Sopenharmony_ci cfpkt_destroy(addpkt); 3288c2ecf20Sopenharmony_ci return skb_to_pkt(dst); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistruct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct sk_buff *skb2; 3348c2ecf20Sopenharmony_ci struct sk_buff *skb = pkt_to_skb(pkt); 3358c2ecf20Sopenharmony_ci struct cfpkt *tmppkt; 3368c2ecf20Sopenharmony_ci u8 *split = skb->data + pos; 3378c2ecf20Sopenharmony_ci u16 len2nd = skb_tail_pointer(skb) - split; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (unlikely(is_erronous(pkt))) 3408c2ecf20Sopenharmony_ci return NULL; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (skb->data + pos > skb_tail_pointer(skb)) { 3438c2ecf20Sopenharmony_ci PKT_ERROR(pkt, "trying to split beyond end of packet\n"); 3448c2ecf20Sopenharmony_ci return NULL; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Create a new packet for the second part of the data */ 3488c2ecf20Sopenharmony_ci tmppkt = cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX, 3498c2ecf20Sopenharmony_ci PKT_PREFIX); 3508c2ecf20Sopenharmony_ci if (tmppkt == NULL) 3518c2ecf20Sopenharmony_ci return NULL; 3528c2ecf20Sopenharmony_ci skb2 = pkt_to_skb(tmppkt); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (skb2 == NULL) 3568c2ecf20Sopenharmony_ci return NULL; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci skb_put_data(skb2, split, len2nd); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Reduce the length of the original packet */ 3618c2ecf20Sopenharmony_ci skb_trim(skb, pos); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci skb2->priority = skb->priority; 3648c2ecf20Sopenharmony_ci return skb_to_pkt(skb2); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cibool cfpkt_erroneous(struct cfpkt *pkt) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci return cfpkt_priv(pkt)->erronous; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistruct caif_payload_info *cfpkt_info(struct cfpkt *pkt) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfpkt_info); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_civoid cfpkt_set_prio(struct cfpkt *pkt, int prio) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci pkt_to_skb(pkt)->priority = prio; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cfpkt_set_prio); 383