1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) ST-Ericsson AB 2010
4*4882a593Smuzhiyun * Author: Sjur Brendeland
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/string.h>
10*4882a593Smuzhiyun #include <linux/skbuff.h>
11*4882a593Smuzhiyun #include <linux/export.h>
12*4882a593Smuzhiyun #include <net/caif/cfpkt.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define PKT_PREFIX 48
15*4882a593Smuzhiyun #define PKT_POSTFIX 2
16*4882a593Smuzhiyun #define PKT_LEN_WHEN_EXTENDING 128
17*4882a593Smuzhiyun #define PKT_ERROR(pkt, errmsg) \
18*4882a593Smuzhiyun do { \
19*4882a593Smuzhiyun cfpkt_priv(pkt)->erronous = true; \
20*4882a593Smuzhiyun skb_reset_tail_pointer(&pkt->skb); \
21*4882a593Smuzhiyun pr_warn(errmsg); \
22*4882a593Smuzhiyun } while (0)
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun struct cfpktq {
25*4882a593Smuzhiyun struct sk_buff_head head;
26*4882a593Smuzhiyun atomic_t count;
27*4882a593Smuzhiyun /* Lock protects count updates */
28*4882a593Smuzhiyun spinlock_t lock;
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun * net/caif/ is generic and does not
33*4882a593Smuzhiyun * understand SKB, so we do this typecast
34*4882a593Smuzhiyun */
35*4882a593Smuzhiyun struct cfpkt {
36*4882a593Smuzhiyun struct sk_buff skb;
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /* Private data inside SKB */
40*4882a593Smuzhiyun struct cfpkt_priv_data {
41*4882a593Smuzhiyun struct dev_info dev_info;
42*4882a593Smuzhiyun bool erronous;
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun
cfpkt_priv(struct cfpkt * pkt)45*4882a593Smuzhiyun static inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun return (struct cfpkt_priv_data *) pkt->skb.cb;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
is_erronous(struct cfpkt * pkt)50*4882a593Smuzhiyun static inline bool is_erronous(struct cfpkt *pkt)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun return cfpkt_priv(pkt)->erronous;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
pkt_to_skb(struct cfpkt * pkt)55*4882a593Smuzhiyun static inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun return &pkt->skb;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
skb_to_pkt(struct sk_buff * skb)60*4882a593Smuzhiyun static inline struct cfpkt *skb_to_pkt(struct sk_buff *skb)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun return (struct cfpkt *) skb;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
cfpkt_fromnative(enum caif_direction dir,void * nativepkt)65*4882a593Smuzhiyun struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun struct cfpkt *pkt = skb_to_pkt(nativepkt);
68*4882a593Smuzhiyun cfpkt_priv(pkt)->erronous = false;
69*4882a593Smuzhiyun return pkt;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun EXPORT_SYMBOL(cfpkt_fromnative);
72*4882a593Smuzhiyun
cfpkt_tonative(struct cfpkt * pkt)73*4882a593Smuzhiyun void *cfpkt_tonative(struct cfpkt *pkt)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun return (void *) pkt;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun EXPORT_SYMBOL(cfpkt_tonative);
78*4882a593Smuzhiyun
cfpkt_create_pfx(u16 len,u16 pfx)79*4882a593Smuzhiyun static struct cfpkt *cfpkt_create_pfx(u16 len, u16 pfx)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun struct sk_buff *skb;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun skb = alloc_skb(len + pfx, GFP_ATOMIC);
84*4882a593Smuzhiyun if (unlikely(skb == NULL))
85*4882a593Smuzhiyun return NULL;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun skb_reserve(skb, pfx);
88*4882a593Smuzhiyun return skb_to_pkt(skb);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
cfpkt_create(u16 len)91*4882a593Smuzhiyun inline struct cfpkt *cfpkt_create(u16 len)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun return cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
cfpkt_destroy(struct cfpkt * pkt)96*4882a593Smuzhiyun void cfpkt_destroy(struct cfpkt *pkt)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
99*4882a593Smuzhiyun kfree_skb(skb);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
cfpkt_more(struct cfpkt * pkt)102*4882a593Smuzhiyun inline bool cfpkt_more(struct cfpkt *pkt)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
105*4882a593Smuzhiyun return skb->len > 0;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
cfpkt_peek_head(struct cfpkt * pkt,void * data,u16 len)108*4882a593Smuzhiyun int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
111*4882a593Smuzhiyun if (skb_headlen(skb) >= len) {
112*4882a593Smuzhiyun memcpy(data, skb->data, len);
113*4882a593Smuzhiyun return 0;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun return !cfpkt_extr_head(pkt, data, len) &&
116*4882a593Smuzhiyun !cfpkt_add_head(pkt, data, len);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
cfpkt_extr_head(struct cfpkt * pkt,void * data,u16 len)119*4882a593Smuzhiyun int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
122*4882a593Smuzhiyun u8 *from;
123*4882a593Smuzhiyun if (unlikely(is_erronous(pkt)))
124*4882a593Smuzhiyun return -EPROTO;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun if (unlikely(len > skb->len)) {
127*4882a593Smuzhiyun PKT_ERROR(pkt, "read beyond end of packet\n");
128*4882a593Smuzhiyun return -EPROTO;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (unlikely(len > skb_headlen(skb))) {
132*4882a593Smuzhiyun if (unlikely(skb_linearize(skb) != 0)) {
133*4882a593Smuzhiyun PKT_ERROR(pkt, "linearize failed\n");
134*4882a593Smuzhiyun return -EPROTO;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun from = skb_pull(skb, len);
138*4882a593Smuzhiyun from -= len;
139*4882a593Smuzhiyun if (data)
140*4882a593Smuzhiyun memcpy(data, from, len);
141*4882a593Smuzhiyun return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun EXPORT_SYMBOL(cfpkt_extr_head);
144*4882a593Smuzhiyun
cfpkt_extr_trail(struct cfpkt * pkt,void * dta,u16 len)145*4882a593Smuzhiyun int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
148*4882a593Smuzhiyun u8 *data = dta;
149*4882a593Smuzhiyun u8 *from;
150*4882a593Smuzhiyun if (unlikely(is_erronous(pkt)))
151*4882a593Smuzhiyun return -EPROTO;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (unlikely(skb_linearize(skb) != 0)) {
154*4882a593Smuzhiyun PKT_ERROR(pkt, "linearize failed\n");
155*4882a593Smuzhiyun return -EPROTO;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun if (unlikely(skb->data + len > skb_tail_pointer(skb))) {
158*4882a593Smuzhiyun PKT_ERROR(pkt, "read beyond end of packet\n");
159*4882a593Smuzhiyun return -EPROTO;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun from = skb_tail_pointer(skb) - len;
162*4882a593Smuzhiyun skb_trim(skb, skb->len - len);
163*4882a593Smuzhiyun memcpy(data, from, len);
164*4882a593Smuzhiyun return 0;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
cfpkt_pad_trail(struct cfpkt * pkt,u16 len)167*4882a593Smuzhiyun int cfpkt_pad_trail(struct cfpkt *pkt, u16 len)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun return cfpkt_add_body(pkt, NULL, len);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
cfpkt_add_body(struct cfpkt * pkt,const void * data,u16 len)172*4882a593Smuzhiyun int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
175*4882a593Smuzhiyun struct sk_buff *lastskb;
176*4882a593Smuzhiyun u8 *to;
177*4882a593Smuzhiyun u16 addlen = 0;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun if (unlikely(is_erronous(pkt)))
181*4882a593Smuzhiyun return -EPROTO;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun lastskb = skb;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun /* Check whether we need to add space at the tail */
186*4882a593Smuzhiyun if (unlikely(skb_tailroom(skb) < len)) {
187*4882a593Smuzhiyun if (likely(len < PKT_LEN_WHEN_EXTENDING))
188*4882a593Smuzhiyun addlen = PKT_LEN_WHEN_EXTENDING;
189*4882a593Smuzhiyun else
190*4882a593Smuzhiyun addlen = len;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* Check whether we need to change the SKB before writing to the tail */
194*4882a593Smuzhiyun if (unlikely((addlen > 0) || skb_cloned(skb) || skb_shared(skb))) {
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* Make sure data is writable */
197*4882a593Smuzhiyun if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) {
198*4882a593Smuzhiyun PKT_ERROR(pkt, "cow failed\n");
199*4882a593Smuzhiyun return -EPROTO;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /* All set to put the last SKB and optionally write data there. */
204*4882a593Smuzhiyun to = pskb_put(skb, lastskb, len);
205*4882a593Smuzhiyun if (likely(data))
206*4882a593Smuzhiyun memcpy(to, data, len);
207*4882a593Smuzhiyun return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
cfpkt_addbdy(struct cfpkt * pkt,u8 data)210*4882a593Smuzhiyun inline int cfpkt_addbdy(struct cfpkt *pkt, u8 data)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun return cfpkt_add_body(pkt, &data, 1);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
cfpkt_add_head(struct cfpkt * pkt,const void * data2,u16 len)215*4882a593Smuzhiyun int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
218*4882a593Smuzhiyun struct sk_buff *lastskb;
219*4882a593Smuzhiyun u8 *to;
220*4882a593Smuzhiyun const u8 *data = data2;
221*4882a593Smuzhiyun int ret;
222*4882a593Smuzhiyun if (unlikely(is_erronous(pkt)))
223*4882a593Smuzhiyun return -EPROTO;
224*4882a593Smuzhiyun if (unlikely(skb_headroom(skb) < len)) {
225*4882a593Smuzhiyun PKT_ERROR(pkt, "no headroom\n");
226*4882a593Smuzhiyun return -EPROTO;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /* Make sure data is writable */
230*4882a593Smuzhiyun ret = skb_cow_data(skb, 0, &lastskb);
231*4882a593Smuzhiyun if (unlikely(ret < 0)) {
232*4882a593Smuzhiyun PKT_ERROR(pkt, "cow failed\n");
233*4882a593Smuzhiyun return ret;
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun to = skb_push(skb, len);
237*4882a593Smuzhiyun memcpy(to, data, len);
238*4882a593Smuzhiyun return 0;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun EXPORT_SYMBOL(cfpkt_add_head);
241*4882a593Smuzhiyun
cfpkt_add_trail(struct cfpkt * pkt,const void * data,u16 len)242*4882a593Smuzhiyun inline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun return cfpkt_add_body(pkt, data, len);
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
cfpkt_getlen(struct cfpkt * pkt)247*4882a593Smuzhiyun inline u16 cfpkt_getlen(struct cfpkt *pkt)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
250*4882a593Smuzhiyun return skb->len;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
cfpkt_iterate(struct cfpkt * pkt,u16 (* iter_func)(u16,void *,u16),u16 data)253*4882a593Smuzhiyun int cfpkt_iterate(struct cfpkt *pkt,
254*4882a593Smuzhiyun u16 (*iter_func)(u16, void *, u16),
255*4882a593Smuzhiyun u16 data)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun /*
258*4882a593Smuzhiyun * Don't care about the performance hit of linearizing,
259*4882a593Smuzhiyun * Checksum should not be used on high-speed interfaces anyway.
260*4882a593Smuzhiyun */
261*4882a593Smuzhiyun if (unlikely(is_erronous(pkt)))
262*4882a593Smuzhiyun return -EPROTO;
263*4882a593Smuzhiyun if (unlikely(skb_linearize(&pkt->skb) != 0)) {
264*4882a593Smuzhiyun PKT_ERROR(pkt, "linearize failed\n");
265*4882a593Smuzhiyun return -EPROTO;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt));
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
cfpkt_setlen(struct cfpkt * pkt,u16 len)270*4882a593Smuzhiyun int cfpkt_setlen(struct cfpkt *pkt, u16 len)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun if (unlikely(is_erronous(pkt)))
276*4882a593Smuzhiyun return -EPROTO;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (likely(len <= skb->len)) {
279*4882a593Smuzhiyun if (unlikely(skb->data_len))
280*4882a593Smuzhiyun ___pskb_trim(skb, len);
281*4882a593Smuzhiyun else
282*4882a593Smuzhiyun skb_trim(skb, len);
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun return cfpkt_getlen(pkt);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun /* Need to expand SKB */
288*4882a593Smuzhiyun if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len)))
289*4882a593Smuzhiyun PKT_ERROR(pkt, "skb_pad_trail failed\n");
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun return cfpkt_getlen(pkt);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
cfpkt_append(struct cfpkt * dstpkt,struct cfpkt * addpkt,u16 expectlen)294*4882a593Smuzhiyun struct cfpkt *cfpkt_append(struct cfpkt *dstpkt,
295*4882a593Smuzhiyun struct cfpkt *addpkt,
296*4882a593Smuzhiyun u16 expectlen)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun struct sk_buff *dst = pkt_to_skb(dstpkt);
299*4882a593Smuzhiyun struct sk_buff *add = pkt_to_skb(addpkt);
300*4882a593Smuzhiyun u16 addlen = skb_headlen(add);
301*4882a593Smuzhiyun u16 neededtailspace;
302*4882a593Smuzhiyun struct sk_buff *tmp;
303*4882a593Smuzhiyun u16 dstlen;
304*4882a593Smuzhiyun u16 createlen;
305*4882a593Smuzhiyun if (unlikely(is_erronous(dstpkt) || is_erronous(addpkt))) {
306*4882a593Smuzhiyun return dstpkt;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun if (expectlen > addlen)
309*4882a593Smuzhiyun neededtailspace = expectlen;
310*4882a593Smuzhiyun else
311*4882a593Smuzhiyun neededtailspace = addlen;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun if (dst->tail + neededtailspace > dst->end) {
314*4882a593Smuzhiyun /* Create a dumplicate of 'dst' with more tail space */
315*4882a593Smuzhiyun struct cfpkt *tmppkt;
316*4882a593Smuzhiyun dstlen = skb_headlen(dst);
317*4882a593Smuzhiyun createlen = dstlen + neededtailspace;
318*4882a593Smuzhiyun tmppkt = cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX);
319*4882a593Smuzhiyun if (tmppkt == NULL)
320*4882a593Smuzhiyun return NULL;
321*4882a593Smuzhiyun tmp = pkt_to_skb(tmppkt);
322*4882a593Smuzhiyun skb_put_data(tmp, dst->data, dstlen);
323*4882a593Smuzhiyun cfpkt_destroy(dstpkt);
324*4882a593Smuzhiyun dst = tmp;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun skb_put_data(dst, add->data, skb_headlen(add));
327*4882a593Smuzhiyun cfpkt_destroy(addpkt);
328*4882a593Smuzhiyun return skb_to_pkt(dst);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
cfpkt_split(struct cfpkt * pkt,u16 pos)331*4882a593Smuzhiyun struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun struct sk_buff *skb2;
334*4882a593Smuzhiyun struct sk_buff *skb = pkt_to_skb(pkt);
335*4882a593Smuzhiyun struct cfpkt *tmppkt;
336*4882a593Smuzhiyun u8 *split = skb->data + pos;
337*4882a593Smuzhiyun u16 len2nd = skb_tail_pointer(skb) - split;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun if (unlikely(is_erronous(pkt)))
340*4882a593Smuzhiyun return NULL;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (skb->data + pos > skb_tail_pointer(skb)) {
343*4882a593Smuzhiyun PKT_ERROR(pkt, "trying to split beyond end of packet\n");
344*4882a593Smuzhiyun return NULL;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /* Create a new packet for the second part of the data */
348*4882a593Smuzhiyun tmppkt = cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX,
349*4882a593Smuzhiyun PKT_PREFIX);
350*4882a593Smuzhiyun if (tmppkt == NULL)
351*4882a593Smuzhiyun return NULL;
352*4882a593Smuzhiyun skb2 = pkt_to_skb(tmppkt);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun if (skb2 == NULL)
356*4882a593Smuzhiyun return NULL;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun skb_put_data(skb2, split, len2nd);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /* Reduce the length of the original packet */
361*4882a593Smuzhiyun skb_trim(skb, pos);
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun skb2->priority = skb->priority;
364*4882a593Smuzhiyun return skb_to_pkt(skb2);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
cfpkt_erroneous(struct cfpkt * pkt)367*4882a593Smuzhiyun bool cfpkt_erroneous(struct cfpkt *pkt)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun return cfpkt_priv(pkt)->erronous;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
cfpkt_info(struct cfpkt * pkt)372*4882a593Smuzhiyun struct caif_payload_info *cfpkt_info(struct cfpkt *pkt)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb;
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun EXPORT_SYMBOL(cfpkt_info);
377*4882a593Smuzhiyun
cfpkt_set_prio(struct cfpkt * pkt,int prio)378*4882a593Smuzhiyun void cfpkt_set_prio(struct cfpkt *pkt, int prio)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun pkt_to_skb(pkt)->priority = prio;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun EXPORT_SYMBOL(cfpkt_set_prio);
383