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