1b97bf3fdSPer Liden /*
2b97bf3fdSPer Liden * net/tipc/msg.c: TIPC message header routines
3b97bf3fdSPer Liden *
4cf2157f8SJon Paul Maloy * Copyright (c) 2000-2006, 2014-2015, Ericsson AB
5741de3e9SAllan Stephens * Copyright (c) 2005, 2010-2011, Wind River Systems
6b97bf3fdSPer Liden * All rights reserved.
7b97bf3fdSPer Liden *
8b97bf3fdSPer Liden * Redistribution and use in source and binary forms, with or without
9b97bf3fdSPer Liden * modification, are permitted provided that the following conditions are met:
10b97bf3fdSPer Liden *
119ea1fd3cSPer Liden * 1. Redistributions of source code must retain the above copyright
129ea1fd3cSPer Liden * notice, this list of conditions and the following disclaimer.
139ea1fd3cSPer Liden * 2. Redistributions in binary form must reproduce the above copyright
149ea1fd3cSPer Liden * notice, this list of conditions and the following disclaimer in the
159ea1fd3cSPer Liden * documentation and/or other materials provided with the distribution.
169ea1fd3cSPer Liden * 3. Neither the names of the copyright holders nor the names of its
179ea1fd3cSPer Liden * contributors may be used to endorse or promote products derived from
189ea1fd3cSPer Liden * this software without specific prior written permission.
199ea1fd3cSPer Liden *
209ea1fd3cSPer Liden * Alternatively, this software may be distributed under the terms of the
219ea1fd3cSPer Liden * GNU General Public License ("GPL") version 2 as published by the Free
229ea1fd3cSPer Liden * Software Foundation.
23b97bf3fdSPer Liden *
24b97bf3fdSPer Liden * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25b97bf3fdSPer Liden * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26b97bf3fdSPer Liden * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27b97bf3fdSPer Liden * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28b97bf3fdSPer Liden * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29b97bf3fdSPer Liden * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30b97bf3fdSPer Liden * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31b97bf3fdSPer Liden * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32b97bf3fdSPer Liden * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33b97bf3fdSPer Liden * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34b97bf3fdSPer Liden * POSSIBILITY OF SUCH DAMAGE.
35b97bf3fdSPer Liden */
36b97bf3fdSPer Liden
37c93d3baaSYing Xue #include <net/sock.h>
38b97bf3fdSPer Liden #include "core.h"
39b97bf3fdSPer Liden #include "msg.h"
405a379074SJon Paul Maloy #include "addr.h"
415a379074SJon Paul Maloy #include "name_table.h"
42fc1b6d6dSTuong Lien #include "crypto.h"
43b97bf3fdSPer Liden
44d4cfb7feSMenglong Dong #define BUF_ALIGN(x) ALIGN(x, 4)
458db1bae3SJon Paul Maloy #define MAX_FORWARD_SIZE 1024
46fc1b6d6dSTuong Lien #ifdef CONFIG_TIPC_CRYPTO
47fc1b6d6dSTuong Lien #define BUF_HEADROOM ALIGN(((LL_MAX_HEADER + 48) + EHDR_MAX_SIZE), 16)
480c6de0c9SMenglong Dong #define BUF_OVERHEAD (BUF_HEADROOM + TIPC_AES_GCM_TAG_SIZE)
49fc1b6d6dSTuong Lien #else
5027777daaSJon Paul Maloy #define BUF_HEADROOM (LL_MAX_HEADER + 48)
510c6de0c9SMenglong Dong #define BUF_OVERHEAD BUF_HEADROOM
52fc1b6d6dSTuong Lien #endif
538db1bae3SJon Paul Maloy
540c6de0c9SMenglong Dong const int one_page_mtu = PAGE_SIZE - SKB_DATA_ALIGN(BUF_OVERHEAD) -
550c6de0c9SMenglong Dong SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
560c6de0c9SMenglong Dong
57859fc7c0SYing Xue /**
58859fc7c0SYing Xue * tipc_buf_acquire - creates a TIPC message buffer
59859fc7c0SYing Xue * @size: message size (including TIPC header)
605fcb7d47SRandy Dunlap * @gfp: memory allocation flags
61859fc7c0SYing Xue *
62637b77fdSRandy Dunlap * Return: a new buffer with data pointers set to the specified size.
63859fc7c0SYing Xue *
645fcb7d47SRandy Dunlap * NOTE:
655fcb7d47SRandy Dunlap * Headroom is reserved to allow prepending of a data link header.
66859fc7c0SYing Xue * There may also be unrequested tailroom present at the buffer's end.
67859fc7c0SYing Xue */
tipc_buf_acquire(u32 size,gfp_t gfp)6857d5f64dSParthasarathy Bhuvaragan struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp)
69859fc7c0SYing Xue {
70859fc7c0SYing Xue struct sk_buff *skb;
71859fc7c0SYing Xue
720c6de0c9SMenglong Dong skb = alloc_skb_fclone(BUF_OVERHEAD + size, gfp);
73859fc7c0SYing Xue if (skb) {
74859fc7c0SYing Xue skb_reserve(skb, BUF_HEADROOM);
75859fc7c0SYing Xue skb_put(skb, size);
76859fc7c0SYing Xue skb->next = NULL;
77859fc7c0SYing Xue }
78859fc7c0SYing Xue return skb;
79859fc7c0SYing Xue }
80859fc7c0SYing Xue
tipc_msg_init(u32 own_node,struct tipc_msg * m,u32 user,u32 type,u32 hsize,u32 dnode)81c5898636SJon Paul Maloy void tipc_msg_init(u32 own_node, struct tipc_msg *m, u32 user, u32 type,
82c5898636SJon Paul Maloy u32 hsize, u32 dnode)
8323461e83SAllan Stephens {
8423461e83SAllan Stephens memset(m, 0, hsize);
8523461e83SAllan Stephens msg_set_version(m);
8623461e83SAllan Stephens msg_set_user(m, user);
8723461e83SAllan Stephens msg_set_hdr_sz(m, hsize);
8823461e83SAllan Stephens msg_set_size(m, hsize);
89c5898636SJon Paul Maloy msg_set_prevnode(m, own_node);
9023461e83SAllan Stephens msg_set_type(m, type);
911dd0bd2bSJon Paul Maloy if (hsize > SHORT_H_SIZE) {
92c5898636SJon Paul Maloy msg_set_orignode(m, own_node);
93c5898636SJon Paul Maloy msg_set_destnode(m, dnode);
9423461e83SAllan Stephens }
951dd0bd2bSJon Paul Maloy }
961dd0bd2bSJon Paul Maloy
tipc_msg_create(uint user,uint type,uint hdr_sz,uint data_sz,u32 dnode,u32 onode,u32 dport,u32 oport,int errcode)97c5898636SJon Paul Maloy struct sk_buff *tipc_msg_create(uint user, uint type,
9834747539SYing Xue uint hdr_sz, uint data_sz, u32 dnode,
9934747539SYing Xue u32 onode, u32 dport, u32 oport, int errcode)
1001dd0bd2bSJon Paul Maloy {
1011dd0bd2bSJon Paul Maloy struct tipc_msg *msg;
1021dd0bd2bSJon Paul Maloy struct sk_buff *buf;
1031dd0bd2bSJon Paul Maloy
10457d5f64dSParthasarathy Bhuvaragan buf = tipc_buf_acquire(hdr_sz + data_sz, GFP_ATOMIC);
1051dd0bd2bSJon Paul Maloy if (unlikely(!buf))
1061dd0bd2bSJon Paul Maloy return NULL;
1071dd0bd2bSJon Paul Maloy
1081dd0bd2bSJon Paul Maloy msg = buf_msg(buf);
109c5898636SJon Paul Maloy tipc_msg_init(onode, msg, user, type, hdr_sz, dnode);
1101dd0bd2bSJon Paul Maloy msg_set_size(msg, hdr_sz + data_sz);
1111dd0bd2bSJon Paul Maloy msg_set_origport(msg, oport);
1121dd0bd2bSJon Paul Maloy msg_set_destport(msg, dport);
1131dd0bd2bSJon Paul Maloy msg_set_errcode(msg, errcode);
1141dd0bd2bSJon Paul Maloy return buf;
1151dd0bd2bSJon Paul Maloy }
11623461e83SAllan Stephens
11737e22164SJon Paul Maloy /* tipc_buf_append(): Append a buffer to the fragment list of another buffer
11829322d0dSJon Paul Maloy * @*headbuf: in: NULL for first frag, otherwise value returned from prev call
11929322d0dSJon Paul Maloy * out: set when successful non-complete reassembly, otherwise NULL
12029322d0dSJon Paul Maloy * @*buf: in: the buffer to append. Always defined
121b2ad5e5fSstephen hemminger * out: head buf after successful complete reassembly, otherwise NULL
12229322d0dSJon Paul Maloy * Returns 1 when reassembly complete, otherwise 0
12337e22164SJon Paul Maloy */
tipc_buf_append(struct sk_buff ** headbuf,struct sk_buff ** buf)12437e22164SJon Paul Maloy int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
12537e22164SJon Paul Maloy {
12637e22164SJon Paul Maloy struct sk_buff *head = *headbuf;
12737e22164SJon Paul Maloy struct sk_buff *frag = *buf;
12845c8b7b1SJon Paul Maloy struct sk_buff *tail = NULL;
12913e9b997SJon Paul Maloy struct tipc_msg *msg;
13013e9b997SJon Paul Maloy u32 fragid;
13137e22164SJon Paul Maloy int delta;
13213e9b997SJon Paul Maloy bool headstolen;
13337e22164SJon Paul Maloy
13413e9b997SJon Paul Maloy if (!frag)
13513e9b997SJon Paul Maloy goto err;
13613e9b997SJon Paul Maloy
13713e9b997SJon Paul Maloy msg = buf_msg(frag);
13813e9b997SJon Paul Maloy fragid = msg_type(msg);
13913e9b997SJon Paul Maloy frag->next = NULL;
14037e22164SJon Paul Maloy skb_pull(frag, msg_hdr_sz(msg));
14137e22164SJon Paul Maloy
14237e22164SJon Paul Maloy if (fragid == FIRST_FRAGMENT) {
14313e9b997SJon Paul Maloy if (unlikely(head))
14413e9b997SJon Paul Maloy goto err;
145b7df21cfSXin Long if (skb_has_frag_list(frag) && __skb_linearize(frag))
146b7df21cfSXin Long goto err;
147614c5a5aSXin Long *buf = NULL;
148ceb1eb2fSTung Nguyen frag = skb_unshare(frag, GFP_ATOMIC);
149ff48b622SXin Long if (unlikely(!frag))
15013e9b997SJon Paul Maloy goto err;
15137e22164SJon Paul Maloy head = *headbuf = frag;
15245c8b7b1SJon Paul Maloy TIPC_SKB_CB(head)->tail = NULL;
15337e22164SJon Paul Maloy return 0;
15437e22164SJon Paul Maloy }
15513e9b997SJon Paul Maloy
15637e22164SJon Paul Maloy if (!head)
15713e9b997SJon Paul Maloy goto err;
15813e9b997SJon Paul Maloy
159*ffd4917cSPaolo Abeni /* Either the input skb ownership is transferred to headskb
160*ffd4917cSPaolo Abeni * or the input skb is freed, clear the reference to avoid
161*ffd4917cSPaolo Abeni * bad access on error path.
162*ffd4917cSPaolo Abeni */
163*ffd4917cSPaolo Abeni *buf = NULL;
16437e22164SJon Paul Maloy if (skb_try_coalesce(head, frag, &headstolen, &delta)) {
16537e22164SJon Paul Maloy kfree_skb_partial(frag, headstolen);
16637e22164SJon Paul Maloy } else {
16713e9b997SJon Paul Maloy tail = TIPC_SKB_CB(head)->tail;
16837e22164SJon Paul Maloy if (!skb_has_frag_list(head))
16937e22164SJon Paul Maloy skb_shinfo(head)->frag_list = frag;
17037e22164SJon Paul Maloy else
17137e22164SJon Paul Maloy tail->next = frag;
17237e22164SJon Paul Maloy head->truesize += frag->truesize;
17337e22164SJon Paul Maloy head->data_len += frag->len;
17437e22164SJon Paul Maloy head->len += frag->len;
17537e22164SJon Paul Maloy TIPC_SKB_CB(head)->tail = frag;
17637e22164SJon Paul Maloy }
17713e9b997SJon Paul Maloy
17837e22164SJon Paul Maloy if (fragid == LAST_FRAGMENT) {
179fc1b6d6dSTuong Lien TIPC_SKB_CB(head)->validated = 0;
180d618d09aSJon Maloy if (unlikely(!tipc_msg_validate(&head)))
1811149557dSJon Paul Maloy goto err;
18237e22164SJon Paul Maloy *buf = head;
18337e22164SJon Paul Maloy TIPC_SKB_CB(head)->tail = NULL;
18437e22164SJon Paul Maloy *headbuf = NULL;
18537e22164SJon Paul Maloy return 1;
18637e22164SJon Paul Maloy }
18737e22164SJon Paul Maloy return 0;
18813e9b997SJon Paul Maloy err:
18937e22164SJon Paul Maloy kfree_skb(*buf);
19029322d0dSJon Paul Maloy kfree_skb(*headbuf);
19129322d0dSJon Paul Maloy *buf = *headbuf = NULL;
19237e22164SJon Paul Maloy return 0;
19337e22164SJon Paul Maloy }
1944f1688b2SJon Paul Maloy
195c0bceb97SJon Maloy /**
196c0bceb97SJon Maloy * tipc_msg_append(): Append data to tail of an existing buffer queue
197d8141208SAndrew Lunn * @_hdr: header to be used
198c0bceb97SJon Maloy * @m: the data to be appended
199c0bceb97SJon Maloy * @mss: max allowable size of buffer
200c0bceb97SJon Maloy * @dlen: size of data to be appended
201637b77fdSRandy Dunlap * @txq: queue to append to
202637b77fdSRandy Dunlap *
203637b77fdSRandy Dunlap * Return: the number of 1k blocks appended or errno value
204c0bceb97SJon Maloy */
tipc_msg_append(struct tipc_msg * _hdr,struct msghdr * m,int dlen,int mss,struct sk_buff_head * txq)205c0bceb97SJon Maloy int tipc_msg_append(struct tipc_msg *_hdr, struct msghdr *m, int dlen,
206c0bceb97SJon Maloy int mss, struct sk_buff_head *txq)
207c0bceb97SJon Maloy {
2088298a419SYueHaibing struct sk_buff *skb;
209c0bceb97SJon Maloy int accounted, total, curr;
210c0bceb97SJon Maloy int mlen, cpy, rem = dlen;
211c0bceb97SJon Maloy struct tipc_msg *hdr;
212c0bceb97SJon Maloy
213c0bceb97SJon Maloy skb = skb_peek_tail(txq);
214c0bceb97SJon Maloy accounted = skb ? msg_blocks(buf_msg(skb)) : 0;
215c0bceb97SJon Maloy total = accounted;
216c0bceb97SJon Maloy
2175e9eecccSTuong Lien do {
218c0bceb97SJon Maloy if (!skb || skb->len >= mss) {
219c0bceb97SJon Maloy skb = tipc_buf_acquire(mss, GFP_KERNEL);
220c0bceb97SJon Maloy if (unlikely(!skb))
221c0bceb97SJon Maloy return -ENOMEM;
222c0bceb97SJon Maloy skb_orphan(skb);
223c0bceb97SJon Maloy skb_trim(skb, MIN_H_SIZE);
224c0bceb97SJon Maloy hdr = buf_msg(skb);
225c0bceb97SJon Maloy skb_copy_to_linear_data(skb, _hdr, MIN_H_SIZE);
226c0bceb97SJon Maloy msg_set_hdr_sz(hdr, MIN_H_SIZE);
227c0bceb97SJon Maloy msg_set_size(hdr, MIN_H_SIZE);
228c0bceb97SJon Maloy __skb_queue_tail(txq, skb);
229c0bceb97SJon Maloy total += 1;
230c0bceb97SJon Maloy }
231c0bceb97SJon Maloy hdr = buf_msg(skb);
232c0bceb97SJon Maloy curr = msg_blocks(hdr);
233c0bceb97SJon Maloy mlen = msg_size(hdr);
234c9aa81faSTuong Lien cpy = min_t(size_t, rem, mss - mlen);
235c0bceb97SJon Maloy if (cpy != copy_from_iter(skb->data + mlen, cpy, &m->msg_iter))
236c0bceb97SJon Maloy return -EFAULT;
237c0bceb97SJon Maloy msg_set_size(hdr, mlen + cpy);
238c0bceb97SJon Maloy skb_put(skb, cpy);
239c0bceb97SJon Maloy rem -= cpy;
240c0bceb97SJon Maloy total += msg_blocks(hdr) - curr;
241c9aa81faSTuong Lien } while (rem > 0);
242c0bceb97SJon Maloy return total - accounted;
243c0bceb97SJon Maloy }
244c0bceb97SJon Maloy
245cf2157f8SJon Paul Maloy /* tipc_msg_validate - validate basic format of received message
246cf2157f8SJon Paul Maloy *
247cf2157f8SJon Paul Maloy * This routine ensures a TIPC message has an acceptable header, and at least
248cf2157f8SJon Paul Maloy * as much data as the header indicates it should. The routine also ensures
249cf2157f8SJon Paul Maloy * that the entire message header is stored in the main fragment of the message
250cf2157f8SJon Paul Maloy * buffer, to simplify future access to message header fields.
251cf2157f8SJon Paul Maloy *
252cf2157f8SJon Paul Maloy * Note: Having extra info present in the message header or data areas is OK.
253cf2157f8SJon Paul Maloy * TIPC will ignore the excess, under the assumption that it is optional info
254cf2157f8SJon Paul Maloy * introduced by a later release of the protocol.
255cf2157f8SJon Paul Maloy */
tipc_msg_validate(struct sk_buff ** _skb)256d618d09aSJon Maloy bool tipc_msg_validate(struct sk_buff **_skb)
257cf2157f8SJon Paul Maloy {
258d618d09aSJon Maloy struct sk_buff *skb = *_skb;
259d618d09aSJon Maloy struct tipc_msg *hdr;
260cf2157f8SJon Paul Maloy int msz, hsz;
261cf2157f8SJon Paul Maloy
262d618d09aSJon Maloy /* Ensure that flow control ratio condition is satisfied */
26355b3280dSHoang Le if (unlikely(skb->truesize / buf_roundup_len(skb) >= 4)) {
26455b3280dSHoang Le skb = skb_copy_expand(skb, BUF_HEADROOM, 0, GFP_ATOMIC);
265d618d09aSJon Maloy if (!skb)
266d618d09aSJon Maloy return false;
267d618d09aSJon Maloy kfree_skb(*_skb);
268d618d09aSJon Maloy *_skb = skb;
269d618d09aSJon Maloy }
270d618d09aSJon Maloy
271cf2157f8SJon Paul Maloy if (unlikely(TIPC_SKB_CB(skb)->validated))
272cf2157f8SJon Paul Maloy return true;
273fc1b6d6dSTuong Lien
274cf2157f8SJon Paul Maloy if (unlikely(!pskb_may_pull(skb, MIN_H_SIZE)))
275cf2157f8SJon Paul Maloy return false;
276cf2157f8SJon Paul Maloy
277cf2157f8SJon Paul Maloy hsz = msg_hdr_sz(buf_msg(skb));
278cf2157f8SJon Paul Maloy if (unlikely(hsz < MIN_H_SIZE) || (hsz > MAX_H_SIZE))
279cf2157f8SJon Paul Maloy return false;
280cf2157f8SJon Paul Maloy if (unlikely(!pskb_may_pull(skb, hsz)))
281cf2157f8SJon Paul Maloy return false;
282cf2157f8SJon Paul Maloy
283d618d09aSJon Maloy hdr = buf_msg(skb);
284d618d09aSJon Maloy if (unlikely(msg_version(hdr) != TIPC_VERSION))
285cf2157f8SJon Paul Maloy return false;
286cf2157f8SJon Paul Maloy
287d618d09aSJon Maloy msz = msg_size(hdr);
288cf2157f8SJon Paul Maloy if (unlikely(msz < hsz))
289cf2157f8SJon Paul Maloy return false;
290cf2157f8SJon Paul Maloy if (unlikely((msz - hsz) > TIPC_MAX_USER_MSG_SIZE))
291cf2157f8SJon Paul Maloy return false;
292cf2157f8SJon Paul Maloy if (unlikely(skb->len < msz))
293cf2157f8SJon Paul Maloy return false;
294cf2157f8SJon Paul Maloy
295fc1b6d6dSTuong Lien TIPC_SKB_CB(skb)->validated = 1;
296cf2157f8SJon Paul Maloy return true;
297cf2157f8SJon Paul Maloy }
298067608e9SJon Paul Maloy
299067608e9SJon Paul Maloy /**
3002320bcdaSTuong Lien * tipc_msg_fragment - build a fragment skb list for TIPC message
3012320bcdaSTuong Lien *
3022320bcdaSTuong Lien * @skb: TIPC message skb
3032320bcdaSTuong Lien * @hdr: internal msg header to be put on the top of the fragments
3042320bcdaSTuong Lien * @pktmax: max size of a fragment incl. the header
3052320bcdaSTuong Lien * @frags: returned fragment skb list
3062320bcdaSTuong Lien *
307637b77fdSRandy Dunlap * Return: 0 if the fragmentation is successful, otherwise: -EINVAL
3082320bcdaSTuong Lien * or -ENOMEM
3092320bcdaSTuong Lien */
tipc_msg_fragment(struct sk_buff * skb,const struct tipc_msg * hdr,int pktmax,struct sk_buff_head * frags)3102320bcdaSTuong Lien int tipc_msg_fragment(struct sk_buff *skb, const struct tipc_msg *hdr,
3112320bcdaSTuong Lien int pktmax, struct sk_buff_head *frags)
3122320bcdaSTuong Lien {
3132320bcdaSTuong Lien int pktno, nof_fragms, dsz, dmax, eat;
3142320bcdaSTuong Lien struct tipc_msg *_hdr;
3152320bcdaSTuong Lien struct sk_buff *_skb;
3162320bcdaSTuong Lien u8 *data;
3172320bcdaSTuong Lien
3182320bcdaSTuong Lien /* Non-linear buffer? */
3192320bcdaSTuong Lien if (skb_linearize(skb))
3202320bcdaSTuong Lien return -ENOMEM;
3212320bcdaSTuong Lien
3222320bcdaSTuong Lien data = (u8 *)skb->data;
3232320bcdaSTuong Lien dsz = msg_size(buf_msg(skb));
3242320bcdaSTuong Lien dmax = pktmax - INT_H_SIZE;
3252320bcdaSTuong Lien if (dsz <= dmax || !dmax)
3262320bcdaSTuong Lien return -EINVAL;
3272320bcdaSTuong Lien
3282320bcdaSTuong Lien nof_fragms = dsz / dmax + 1;
3292320bcdaSTuong Lien for (pktno = 1; pktno <= nof_fragms; pktno++) {
3302320bcdaSTuong Lien if (pktno < nof_fragms)
3312320bcdaSTuong Lien eat = dmax;
3322320bcdaSTuong Lien else
3332320bcdaSTuong Lien eat = dsz % dmax;
3342320bcdaSTuong Lien /* Allocate a new fragment */
3352320bcdaSTuong Lien _skb = tipc_buf_acquire(INT_H_SIZE + eat, GFP_ATOMIC);
3362320bcdaSTuong Lien if (!_skb)
3372320bcdaSTuong Lien goto error;
3382320bcdaSTuong Lien skb_orphan(_skb);
3392320bcdaSTuong Lien __skb_queue_tail(frags, _skb);
3402320bcdaSTuong Lien /* Copy header & data to the fragment */
3412320bcdaSTuong Lien skb_copy_to_linear_data(_skb, hdr, INT_H_SIZE);
3422320bcdaSTuong Lien skb_copy_to_linear_data_offset(_skb, INT_H_SIZE, data, eat);
3432320bcdaSTuong Lien data += eat;
3442320bcdaSTuong Lien /* Update the fragment's header */
3452320bcdaSTuong Lien _hdr = buf_msg(_skb);
3462320bcdaSTuong Lien msg_set_fragm_no(_hdr, pktno);
3472320bcdaSTuong Lien msg_set_nof_fragms(_hdr, nof_fragms);
3482320bcdaSTuong Lien msg_set_size(_hdr, INT_H_SIZE + eat);
3492320bcdaSTuong Lien }
3502320bcdaSTuong Lien return 0;
3512320bcdaSTuong Lien
3522320bcdaSTuong Lien error:
3532320bcdaSTuong Lien __skb_queue_purge(frags);
3542320bcdaSTuong Lien __skb_queue_head_init(frags);
3552320bcdaSTuong Lien return -ENOMEM;
3562320bcdaSTuong Lien }
3572320bcdaSTuong Lien
3582320bcdaSTuong Lien /**
3599fbfb8b1SJon Paul Maloy * tipc_msg_build - create buffer chain containing specified header and data
360067608e9SJon Paul Maloy * @mhdr: Message header, to be prepended to data
36145dcc687SAl Viro * @m: User message
3625fcb7d47SRandy Dunlap * @offset: buffer offset for fragmented messages (FIXME)
363067608e9SJon Paul Maloy * @dsz: Total length of user data
364067608e9SJon Paul Maloy * @pktmax: Max packet size that can be used
365a6ca1094SYing Xue * @list: Buffer or chain of buffers to be returned to caller
366a6ca1094SYing Xue *
3674c94cc2dSJon Maloy * Note that the recursive call we are making here is safe, since it can
3684c94cc2dSJon Maloy * logically go only one further level down.
3694c94cc2dSJon Maloy *
370637b77fdSRandy Dunlap * Return: message data size or errno: -ENOMEM, -EFAULT
371067608e9SJon Paul Maloy */
tipc_msg_build(struct tipc_msg * mhdr,struct msghdr * m,int offset,int dsz,int pktmax,struct sk_buff_head * list)3724c94cc2dSJon Maloy int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
3734c94cc2dSJon Maloy int dsz, int pktmax, struct sk_buff_head *list)
374067608e9SJon Paul Maloy {
375067608e9SJon Paul Maloy int mhsz = msg_hdr_sz(mhdr);
376067608e9SJon Paul Maloy struct tipc_msg pkthdr;
3774c94cc2dSJon Maloy int msz = mhsz + dsz;
3784c94cc2dSJon Maloy int pktrem = pktmax;
379a6ca1094SYing Xue struct sk_buff *skb;
3804c94cc2dSJon Maloy int drem = dsz;
3814c94cc2dSJon Maloy int pktno = 1;
382067608e9SJon Paul Maloy char *pktpos;
3834c94cc2dSJon Maloy int pktsz;
384067608e9SJon Paul Maloy int rc;
385a6ca1094SYing Xue
386067608e9SJon Paul Maloy msg_set_size(mhdr, msz);
387067608e9SJon Paul Maloy
388067608e9SJon Paul Maloy /* No fragmentation needed? */
389067608e9SJon Paul Maloy if (likely(msz <= pktmax)) {
39057d5f64dSParthasarathy Bhuvaragan skb = tipc_buf_acquire(msz, GFP_KERNEL);
3914c94cc2dSJon Maloy
3924c94cc2dSJon Maloy /* Fall back to smaller MTU if node local message */
3934c94cc2dSJon Maloy if (unlikely(!skb)) {
3944c94cc2dSJon Maloy if (pktmax != MAX_MSG_SIZE)
395067608e9SJon Paul Maloy return -ENOMEM;
3960c6de0c9SMenglong Dong rc = tipc_msg_build(mhdr, m, offset, dsz,
3970c6de0c9SMenglong Dong one_page_mtu, list);
3984c94cc2dSJon Maloy if (rc != dsz)
3994c94cc2dSJon Maloy return rc;
4004c94cc2dSJon Maloy if (tipc_msg_assemble(list))
4014c94cc2dSJon Maloy return dsz;
4024c94cc2dSJon Maloy return -ENOMEM;
4034c94cc2dSJon Maloy }
404c93d3baaSYing Xue skb_orphan(skb);
405a6ca1094SYing Xue __skb_queue_tail(list, skb);
406a6ca1094SYing Xue skb_copy_to_linear_data(skb, mhdr, mhsz);
407a6ca1094SYing Xue pktpos = skb->data + mhsz;
408cbbd26b8SAl Viro if (copy_from_iter_full(pktpos, dsz, &m->msg_iter))
409067608e9SJon Paul Maloy return dsz;
410067608e9SJon Paul Maloy rc = -EFAULT;
411067608e9SJon Paul Maloy goto error;
412067608e9SJon Paul Maloy }
413067608e9SJon Paul Maloy
414067608e9SJon Paul Maloy /* Prepare reusable fragment header */
415c5898636SJon Paul Maloy tipc_msg_init(msg_prevnode(mhdr), &pkthdr, MSG_FRAGMENTER,
416c5898636SJon Paul Maloy FIRST_FRAGMENT, INT_H_SIZE, msg_destnode(mhdr));
417067608e9SJon Paul Maloy msg_set_size(&pkthdr, pktmax);
418067608e9SJon Paul Maloy msg_set_fragm_no(&pkthdr, pktno);
419e3eea1ebSJon Paul Maloy msg_set_importance(&pkthdr, msg_importance(mhdr));
420067608e9SJon Paul Maloy
421067608e9SJon Paul Maloy /* Prepare first fragment */
42257d5f64dSParthasarathy Bhuvaragan skb = tipc_buf_acquire(pktmax, GFP_KERNEL);
423a6ca1094SYing Xue if (!skb)
424067608e9SJon Paul Maloy return -ENOMEM;
425c93d3baaSYing Xue skb_orphan(skb);
426a6ca1094SYing Xue __skb_queue_tail(list, skb);
427a6ca1094SYing Xue pktpos = skb->data;
428a6ca1094SYing Xue skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE);
429067608e9SJon Paul Maloy pktpos += INT_H_SIZE;
430067608e9SJon Paul Maloy pktrem -= INT_H_SIZE;
431a6ca1094SYing Xue skb_copy_to_linear_data_offset(skb, INT_H_SIZE, mhdr, mhsz);
432067608e9SJon Paul Maloy pktpos += mhsz;
433067608e9SJon Paul Maloy pktrem -= mhsz;
434067608e9SJon Paul Maloy
435067608e9SJon Paul Maloy do {
436067608e9SJon Paul Maloy if (drem < pktrem)
437067608e9SJon Paul Maloy pktrem = drem;
438067608e9SJon Paul Maloy
439cbbd26b8SAl Viro if (!copy_from_iter_full(pktpos, pktrem, &m->msg_iter)) {
440067608e9SJon Paul Maloy rc = -EFAULT;
441067608e9SJon Paul Maloy goto error;
442067608e9SJon Paul Maloy }
443067608e9SJon Paul Maloy drem -= pktrem;
444067608e9SJon Paul Maloy
445067608e9SJon Paul Maloy if (!drem)
446067608e9SJon Paul Maloy break;
447067608e9SJon Paul Maloy
448067608e9SJon Paul Maloy /* Prepare new fragment: */
449067608e9SJon Paul Maloy if (drem < (pktmax - INT_H_SIZE))
450067608e9SJon Paul Maloy pktsz = drem + INT_H_SIZE;
451067608e9SJon Paul Maloy else
452067608e9SJon Paul Maloy pktsz = pktmax;
45357d5f64dSParthasarathy Bhuvaragan skb = tipc_buf_acquire(pktsz, GFP_KERNEL);
454a6ca1094SYing Xue if (!skb) {
455067608e9SJon Paul Maloy rc = -ENOMEM;
456067608e9SJon Paul Maloy goto error;
457067608e9SJon Paul Maloy }
458c93d3baaSYing Xue skb_orphan(skb);
459a6ca1094SYing Xue __skb_queue_tail(list, skb);
460067608e9SJon Paul Maloy msg_set_type(&pkthdr, FRAGMENT);
461067608e9SJon Paul Maloy msg_set_size(&pkthdr, pktsz);
462067608e9SJon Paul Maloy msg_set_fragm_no(&pkthdr, ++pktno);
463a6ca1094SYing Xue skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE);
464a6ca1094SYing Xue pktpos = skb->data + INT_H_SIZE;
465067608e9SJon Paul Maloy pktrem = pktsz - INT_H_SIZE;
466067608e9SJon Paul Maloy
467067608e9SJon Paul Maloy } while (1);
468a6ca1094SYing Xue msg_set_type(buf_msg(skb), LAST_FRAGMENT);
469067608e9SJon Paul Maloy return dsz;
470067608e9SJon Paul Maloy error:
471a6ca1094SYing Xue __skb_queue_purge(list);
472a6ca1094SYing Xue __skb_queue_head_init(list);
473067608e9SJon Paul Maloy return rc;
474067608e9SJon Paul Maloy }
475067608e9SJon Paul Maloy
4764f1688b2SJon Paul Maloy /**
47706e7c70cSTuong Lien * tipc_msg_bundle - Append contents of a buffer to tail of an existing one
47806e7c70cSTuong Lien * @bskb: the bundle buffer to append to
479dd3f9e70SJon Paul Maloy * @msg: message to be appended
48006e7c70cSTuong Lien * @max: max allowable size for the bundle buffer
48106e7c70cSTuong Lien *
482637b77fdSRandy Dunlap * Return: "true" if bundling has been performed, otherwise "false"
4834f1688b2SJon Paul Maloy */
tipc_msg_bundle(struct sk_buff * bskb,struct tipc_msg * msg,u32 max)48406e7c70cSTuong Lien static bool tipc_msg_bundle(struct sk_buff *bskb, struct tipc_msg *msg,
48506e7c70cSTuong Lien u32 max)
4864f1688b2SJon Paul Maloy {
48706e7c70cSTuong Lien struct tipc_msg *bmsg = buf_msg(bskb);
48806e7c70cSTuong Lien u32 msz, bsz, offset, pad;
4894f1688b2SJon Paul Maloy
49006e7c70cSTuong Lien msz = msg_size(msg);
49105dcc5aaSJon Paul Maloy bsz = msg_size(bmsg);
492d4cfb7feSMenglong Dong offset = BUF_ALIGN(bsz);
49306e7c70cSTuong Lien pad = offset - bsz;
49405dcc5aaSJon Paul Maloy
49506e7c70cSTuong Lien if (unlikely(skb_tailroom(bskb) < (pad + msz)))
4964f1688b2SJon Paul Maloy return false;
49706e7c70cSTuong Lien if (unlikely(max < (offset + msz)))
498f21e897eSJon Paul Maloy return false;
4994f1688b2SJon Paul Maloy
50006e7c70cSTuong Lien skb_put(bskb, pad + msz);
50106e7c70cSTuong Lien skb_copy_to_linear_data_offset(bskb, offset, msg, msz);
50206e7c70cSTuong Lien msg_set_size(bmsg, offset + msz);
5034f1688b2SJon Paul Maloy msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1);
5044f1688b2SJon Paul Maloy return true;
5054f1688b2SJon Paul Maloy }
5064f1688b2SJon Paul Maloy
5074f1688b2SJon Paul Maloy /**
50806e7c70cSTuong Lien * tipc_msg_try_bundle - Try to bundle a new message to the last one
50906e7c70cSTuong Lien * @tskb: the last/target message to which the new one will be appended
51006e7c70cSTuong Lien * @skb: the new message skb pointer
51106e7c70cSTuong Lien * @mss: max message size (header inclusive)
51206e7c70cSTuong Lien * @dnode: destination node for the message
51306e7c70cSTuong Lien * @new_bundle: if this call made a new bundle or not
51406e7c70cSTuong Lien *
51506e7c70cSTuong Lien * Return: "true" if the new message skb is potential for bundling this time or
51606e7c70cSTuong Lien * later, in the case a bundling has been done this time, the skb is consumed
51706e7c70cSTuong Lien * (the skb pointer = NULL).
51806e7c70cSTuong Lien * Otherwise, "false" if the skb cannot be bundled at all.
51906e7c70cSTuong Lien */
tipc_msg_try_bundle(struct sk_buff * tskb,struct sk_buff ** skb,u32 mss,u32 dnode,bool * new_bundle)52006e7c70cSTuong Lien bool tipc_msg_try_bundle(struct sk_buff *tskb, struct sk_buff **skb, u32 mss,
52106e7c70cSTuong Lien u32 dnode, bool *new_bundle)
52206e7c70cSTuong Lien {
52306e7c70cSTuong Lien struct tipc_msg *msg, *inner, *outer;
52406e7c70cSTuong Lien u32 tsz;
52506e7c70cSTuong Lien
52606e7c70cSTuong Lien /* First, check if the new buffer is suitable for bundling */
52706e7c70cSTuong Lien msg = buf_msg(*skb);
52806e7c70cSTuong Lien if (msg_user(msg) == MSG_FRAGMENTER)
52906e7c70cSTuong Lien return false;
53006e7c70cSTuong Lien if (msg_user(msg) == TUNNEL_PROTOCOL)
53106e7c70cSTuong Lien return false;
53206e7c70cSTuong Lien if (msg_user(msg) == BCAST_PROTOCOL)
53306e7c70cSTuong Lien return false;
53406e7c70cSTuong Lien if (mss <= INT_H_SIZE + msg_size(msg))
53506e7c70cSTuong Lien return false;
53606e7c70cSTuong Lien
53706e7c70cSTuong Lien /* Ok, but the last/target buffer can be empty? */
53806e7c70cSTuong Lien if (unlikely(!tskb))
53906e7c70cSTuong Lien return true;
54006e7c70cSTuong Lien
54106e7c70cSTuong Lien /* Is it a bundle already? Try to bundle the new message to it */
54206e7c70cSTuong Lien if (msg_user(buf_msg(tskb)) == MSG_BUNDLER) {
54306e7c70cSTuong Lien *new_bundle = false;
54406e7c70cSTuong Lien goto bundle;
54506e7c70cSTuong Lien }
54606e7c70cSTuong Lien
54706e7c70cSTuong Lien /* Make a new bundle of the two messages if possible */
54806e7c70cSTuong Lien tsz = msg_size(buf_msg(tskb));
549d4cfb7feSMenglong Dong if (unlikely(mss < BUF_ALIGN(INT_H_SIZE + tsz) + msg_size(msg)))
55006e7c70cSTuong Lien return true;
55106e7c70cSTuong Lien if (unlikely(pskb_expand_head(tskb, INT_H_SIZE, mss - tsz - INT_H_SIZE,
55206e7c70cSTuong Lien GFP_ATOMIC)))
55306e7c70cSTuong Lien return true;
55406e7c70cSTuong Lien inner = buf_msg(tskb);
55506e7c70cSTuong Lien skb_push(tskb, INT_H_SIZE);
55606e7c70cSTuong Lien outer = buf_msg(tskb);
55706e7c70cSTuong Lien tipc_msg_init(msg_prevnode(inner), outer, MSG_BUNDLER, 0, INT_H_SIZE,
55806e7c70cSTuong Lien dnode);
55906e7c70cSTuong Lien msg_set_importance(outer, msg_importance(inner));
56006e7c70cSTuong Lien msg_set_size(outer, INT_H_SIZE + tsz);
56106e7c70cSTuong Lien msg_set_msgcnt(outer, 1);
56206e7c70cSTuong Lien *new_bundle = true;
56306e7c70cSTuong Lien
56406e7c70cSTuong Lien bundle:
56506e7c70cSTuong Lien if (likely(tipc_msg_bundle(tskb, msg, mss))) {
56606e7c70cSTuong Lien consume_skb(*skb);
56706e7c70cSTuong Lien *skb = NULL;
56806e7c70cSTuong Lien }
56906e7c70cSTuong Lien return true;
57006e7c70cSTuong Lien }
57106e7c70cSTuong Lien
57206e7c70cSTuong Lien /**
573c637c103SJon Paul Maloy * tipc_msg_extract(): extract bundled inner packet from buffer
574c1336ee4SJon Paul Maloy * @skb: buffer to be extracted from.
575c637c103SJon Paul Maloy * @iskb: extracted inner buffer, to be returned
576c1336ee4SJon Paul Maloy * @pos: position in outer message of msg to be extracted.
5775fcb7d47SRandy Dunlap * Returns position of next msg.
578c637c103SJon Paul Maloy * Consumes outer buffer when last packet extracted
579637b77fdSRandy Dunlap * Return: true when there is an extracted buffer, otherwise false
580c637c103SJon Paul Maloy */
tipc_msg_extract(struct sk_buff * skb,struct sk_buff ** iskb,int * pos)581c637c103SJon Paul Maloy bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos)
582c637c103SJon Paul Maloy {
583ef9be755STung Nguyen struct tipc_msg *hdr, *ihdr;
584ef9be755STung Nguyen int imsz;
585c637c103SJon Paul Maloy
586c1336ee4SJon Paul Maloy *iskb = NULL;
5871149557dSJon Paul Maloy if (unlikely(skb_linearize(skb)))
588c637c103SJon Paul Maloy goto none;
589c637c103SJon Paul Maloy
590ef9be755STung Nguyen hdr = buf_msg(skb);
591ef9be755STung Nguyen if (unlikely(*pos > (msg_data_sz(hdr) - MIN_H_SIZE)))
592c637c103SJon Paul Maloy goto none;
593c1336ee4SJon Paul Maloy
594ef9be755STung Nguyen ihdr = (struct tipc_msg *)(msg_data(hdr) + *pos);
595ef9be755STung Nguyen imsz = msg_size(ihdr);
596ef9be755STung Nguyen
597ef9be755STung Nguyen if ((*pos + imsz) > msg_data_sz(hdr))
598c637c103SJon Paul Maloy goto none;
599ef9be755STung Nguyen
600ef9be755STung Nguyen *iskb = tipc_buf_acquire(imsz, GFP_ATOMIC);
601ef9be755STung Nguyen if (!*iskb)
602ef9be755STung Nguyen goto none;
603ef9be755STung Nguyen
604ef9be755STung Nguyen skb_copy_to_linear_data(*iskb, ihdr, imsz);
605d618d09aSJon Maloy if (unlikely(!tipc_msg_validate(iskb)))
606c1336ee4SJon Paul Maloy goto none;
607ef9be755STung Nguyen
608d4cfb7feSMenglong Dong *pos += BUF_ALIGN(imsz);
609c637c103SJon Paul Maloy return true;
610c637c103SJon Paul Maloy none:
611c637c103SJon Paul Maloy kfree_skb(skb);
612c1336ee4SJon Paul Maloy kfree_skb(*iskb);
613c637c103SJon Paul Maloy *iskb = NULL;
614c637c103SJon Paul Maloy return false;
615c637c103SJon Paul Maloy }
616c637c103SJon Paul Maloy
617c637c103SJon Paul Maloy /**
6188db1bae3SJon Paul Maloy * tipc_msg_reverse(): swap source and destination addresses and add error code
61929042e19SJon Paul Maloy * @own_node: originating node id for reversed message
6205cbdbd1aSJon Maloy * @skb: buffer containing message to be reversed; will be consumed
62129042e19SJon Paul Maloy * @err: error code to be set in message, if any
6225cbdbd1aSJon Maloy * Replaces consumed buffer with new one when successful
623637b77fdSRandy Dunlap * Return: true if success, otherwise false
6248db1bae3SJon Paul Maloy */
tipc_msg_reverse(u32 own_node,struct sk_buff ** skb,int err)625bcd3ffd4SJon Paul Maloy bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, int err)
6268db1bae3SJon Paul Maloy {
62729042e19SJon Paul Maloy struct sk_buff *_skb = *skb;
6285cbdbd1aSJon Maloy struct tipc_msg *_hdr, *hdr;
6295cbdbd1aSJon Maloy int hlen, dlen;
6308db1bae3SJon Paul Maloy
63129042e19SJon Paul Maloy if (skb_linearize(_skb))
6328db1bae3SJon Paul Maloy goto exit;
6335cbdbd1aSJon Maloy _hdr = buf_msg(_skb);
6345cbdbd1aSJon Maloy dlen = min_t(uint, msg_data_sz(_hdr), MAX_FORWARD_SIZE);
6355cbdbd1aSJon Maloy hlen = msg_hdr_sz(_hdr);
6365cbdbd1aSJon Maloy
6375cbdbd1aSJon Maloy if (msg_dest_droppable(_hdr))
638ac0074eeSJon Paul Maloy goto exit;
6395cbdbd1aSJon Maloy if (msg_errcode(_hdr))
6408db1bae3SJon Paul Maloy goto exit;
64129042e19SJon Paul Maloy
6425cbdbd1aSJon Maloy /* Never return SHORT header */
6435cbdbd1aSJon Maloy if (hlen == SHORT_H_SIZE)
6445cbdbd1aSJon Maloy hlen = BASIC_H_SIZE;
64529042e19SJon Paul Maloy
64667879274STung Nguyen /* Don't return data along with SYN+, - sender has a clone */
64767879274STung Nguyen if (msg_is_syn(_hdr) && err == TIPC_ERR_OVERLOAD)
64867879274STung Nguyen dlen = 0;
64967879274STung Nguyen
6505cbdbd1aSJon Maloy /* Allocate new buffer to return */
6515cbdbd1aSJon Maloy *skb = tipc_buf_acquire(hlen + dlen, GFP_ATOMIC);
65229042e19SJon Paul Maloy if (!*skb)
65329042e19SJon Paul Maloy goto exit;
6545cbdbd1aSJon Maloy memcpy((*skb)->data, _skb->data, msg_hdr_sz(_hdr));
6555cbdbd1aSJon Maloy memcpy((*skb)->data + hlen, msg_data(_hdr), dlen);
65629042e19SJon Paul Maloy
6575cbdbd1aSJon Maloy /* Build reverse header in new buffer */
6585cbdbd1aSJon Maloy hdr = buf_msg(*skb);
6595cbdbd1aSJon Maloy msg_set_hdr_sz(hdr, hlen);
66029042e19SJon Paul Maloy msg_set_errcode(hdr, err);
66159a361bcSJon Paul Maloy msg_set_non_seq(hdr, 0);
6625cbdbd1aSJon Maloy msg_set_origport(hdr, msg_destport(_hdr));
6635cbdbd1aSJon Maloy msg_set_destport(hdr, msg_origport(_hdr));
6645cbdbd1aSJon Maloy msg_set_destnode(hdr, msg_prevnode(_hdr));
66529042e19SJon Paul Maloy msg_set_prevnode(hdr, own_node);
66629042e19SJon Paul Maloy msg_set_orignode(hdr, own_node);
6675cbdbd1aSJon Maloy msg_set_size(hdr, hlen + dlen);
66829042e19SJon Paul Maloy skb_orphan(_skb);
6695cbdbd1aSJon Maloy kfree_skb(_skb);
6708db1bae3SJon Paul Maloy return true;
6718db1bae3SJon Paul Maloy exit:
67229042e19SJon Paul Maloy kfree_skb(_skb);
67329042e19SJon Paul Maloy *skb = NULL;
6748db1bae3SJon Paul Maloy return false;
6758db1bae3SJon Paul Maloy }
6765a379074SJon Paul Maloy
tipc_msg_skb_clone(struct sk_buff_head * msg,struct sk_buff_head * cpy)67767879274STung Nguyen bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy)
67867879274STung Nguyen {
67967879274STung Nguyen struct sk_buff *skb, *_skb;
68067879274STung Nguyen
68167879274STung Nguyen skb_queue_walk(msg, skb) {
68267879274STung Nguyen _skb = skb_clone(skb, GFP_ATOMIC);
68367879274STung Nguyen if (!_skb) {
68467879274STung Nguyen __skb_queue_purge(cpy);
68567879274STung Nguyen pr_err_ratelimited("Failed to clone buffer chain\n");
68667879274STung Nguyen return false;
68767879274STung Nguyen }
68867879274STung Nguyen __skb_queue_tail(cpy, _skb);
68967879274STung Nguyen }
69067879274STung Nguyen return true;
69167879274STung Nguyen }
69267879274STung Nguyen
6935a379074SJon Paul Maloy /**
694e3a77561SJon Paul Maloy * tipc_msg_lookup_dest(): try to find new destination for named message
6955fcb7d47SRandy Dunlap * @net: pointer to associated network namespace
696e3a77561SJon Paul Maloy * @skb: the buffer containing the message.
697cda3696dSJon Paul Maloy * @err: error code to be used by caller if lookup fails
6985a379074SJon Paul Maloy * Does not consume buffer
699637b77fdSRandy Dunlap * Return: true if a destination is found, false otherwise
7005a379074SJon Paul Maloy */
tipc_msg_lookup_dest(struct net * net,struct sk_buff * skb,int * err)701cda3696dSJon Paul Maloy bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err)
7025a379074SJon Paul Maloy {
703e3a77561SJon Paul Maloy struct tipc_msg *msg = buf_msg(skb);
704908148bcSJon Maloy u32 scope = msg_lookup_scope(msg);
705908148bcSJon Maloy u32 self = tipc_own_addr(net);
706908148bcSJon Maloy u32 inst = msg_nameinst(msg);
707908148bcSJon Maloy struct tipc_socket_addr sk;
708908148bcSJon Maloy struct tipc_uaddr ua;
7095a379074SJon Paul Maloy
710e3a77561SJon Paul Maloy if (!msg_isdata(msg))
711e3a77561SJon Paul Maloy return false;
712e3a77561SJon Paul Maloy if (!msg_named(msg))
713e3a77561SJon Paul Maloy return false;
714d482994fSJon Paul Maloy if (msg_errcode(msg))
715d482994fSJon Paul Maloy return false;
716aad06212SParthasarathy Bhuvaragan *err = TIPC_ERR_NO_NAME;
717e3a77561SJon Paul Maloy if (skb_linearize(skb))
718e3a77561SJon Paul Maloy return false;
7194e3ae001SErik Hugne msg = buf_msg(skb);
720d482994fSJon Paul Maloy if (msg_reroute_cnt(msg))
721e3a77561SJon Paul Maloy return false;
722908148bcSJon Maloy tipc_uaddr(&ua, TIPC_SERVICE_RANGE, scope,
723908148bcSJon Maloy msg_nametype(msg), inst, inst);
724908148bcSJon Maloy sk.node = tipc_scope2node(net, scope);
725908148bcSJon Maloy if (!tipc_nametbl_lookup_anycast(net, &ua, &sk))
726e3a77561SJon Paul Maloy return false;
7275a379074SJon Paul Maloy msg_incr_reroute_cnt(msg);
728908148bcSJon Maloy if (sk.node != self)
729908148bcSJon Maloy msg_set_prevnode(msg, self);
730908148bcSJon Maloy msg_set_destnode(msg, sk.node);
731908148bcSJon Maloy msg_set_destport(msg, sk.ref);
732e3a77561SJon Paul Maloy *err = TIPC_OK;
733a9e2971bSJon Maloy
734e3a77561SJon Paul Maloy return true;
7355a379074SJon Paul Maloy }
736078bec82SJon Paul Maloy
7374c94cc2dSJon Maloy /* tipc_msg_assemble() - assemble chain of fragments into one message
7384c94cc2dSJon Maloy */
tipc_msg_assemble(struct sk_buff_head * list)7394c94cc2dSJon Maloy bool tipc_msg_assemble(struct sk_buff_head *list)
7404c94cc2dSJon Maloy {
7414c94cc2dSJon Maloy struct sk_buff *skb, *tmp = NULL;
7424c94cc2dSJon Maloy
7434c94cc2dSJon Maloy if (skb_queue_len(list) == 1)
7444c94cc2dSJon Maloy return true;
7454c94cc2dSJon Maloy
7464c94cc2dSJon Maloy while ((skb = __skb_dequeue(list))) {
7474c94cc2dSJon Maloy skb->next = NULL;
7484c94cc2dSJon Maloy if (tipc_buf_append(&tmp, &skb)) {
7494c94cc2dSJon Maloy __skb_queue_tail(list, skb);
7504c94cc2dSJon Maloy return true;
7514c94cc2dSJon Maloy }
7524c94cc2dSJon Maloy if (!tmp)
7534c94cc2dSJon Maloy break;
7544c94cc2dSJon Maloy }
7554c94cc2dSJon Maloy __skb_queue_purge(list);
7564c94cc2dSJon Maloy __skb_queue_head_init(list);
7574c94cc2dSJon Maloy pr_warn("Failed do assemble buffer\n");
7584c94cc2dSJon Maloy return false;
7594c94cc2dSJon Maloy }
7604c94cc2dSJon Maloy
761078bec82SJon Paul Maloy /* tipc_msg_reassemble() - clone a buffer chain of fragments and
762078bec82SJon Paul Maloy * reassemble the clones into one message
763078bec82SJon Paul Maloy */
tipc_msg_reassemble(struct sk_buff_head * list,struct sk_buff_head * rcvq)7642f566124SJon Paul Maloy bool tipc_msg_reassemble(struct sk_buff_head *list, struct sk_buff_head *rcvq)
765078bec82SJon Paul Maloy {
7662f566124SJon Paul Maloy struct sk_buff *skb, *_skb;
767a6ca1094SYing Xue struct sk_buff *frag = NULL;
768078bec82SJon Paul Maloy struct sk_buff *head = NULL;
7692f566124SJon Paul Maloy int hdr_len;
770078bec82SJon Paul Maloy
771078bec82SJon Paul Maloy /* Copy header if single buffer */
772a6ca1094SYing Xue if (skb_queue_len(list) == 1) {
773a6ca1094SYing Xue skb = skb_peek(list);
7742f566124SJon Paul Maloy hdr_len = skb_headroom(skb) + msg_hdr_sz(buf_msg(skb));
7752f566124SJon Paul Maloy _skb = __pskb_copy(skb, hdr_len, GFP_ATOMIC);
7762f566124SJon Paul Maloy if (!_skb)
7772f566124SJon Paul Maloy return false;
7782f566124SJon Paul Maloy __skb_queue_tail(rcvq, _skb);
7792f566124SJon Paul Maloy return true;
780078bec82SJon Paul Maloy }
781078bec82SJon Paul Maloy
782078bec82SJon Paul Maloy /* Clone all fragments and reassemble */
783a6ca1094SYing Xue skb_queue_walk(list, skb) {
784a6ca1094SYing Xue frag = skb_clone(skb, GFP_ATOMIC);
785078bec82SJon Paul Maloy if (!frag)
786078bec82SJon Paul Maloy goto error;
787078bec82SJon Paul Maloy frag->next = NULL;
788078bec82SJon Paul Maloy if (tipc_buf_append(&head, &frag))
789078bec82SJon Paul Maloy break;
790078bec82SJon Paul Maloy if (!head)
791078bec82SJon Paul Maloy goto error;
792078bec82SJon Paul Maloy }
7932f566124SJon Paul Maloy __skb_queue_tail(rcvq, frag);
7942f566124SJon Paul Maloy return true;
795078bec82SJon Paul Maloy error:
796078bec82SJon Paul Maloy pr_warn("Failed do clone local mcast rcv buffer\n");
797078bec82SJon Paul Maloy kfree_skb(head);
7982f566124SJon Paul Maloy return false;
799078bec82SJon Paul Maloy }
8008306f99aSJon Paul Maloy
tipc_msg_pskb_copy(u32 dst,struct sk_buff_head * msg,struct sk_buff_head * cpy)801a853e4c6SJon Paul Maloy bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg,
802a853e4c6SJon Paul Maloy struct sk_buff_head *cpy)
803a853e4c6SJon Paul Maloy {
804a853e4c6SJon Paul Maloy struct sk_buff *skb, *_skb;
805a853e4c6SJon Paul Maloy
806a853e4c6SJon Paul Maloy skb_queue_walk(msg, skb) {
807a853e4c6SJon Paul Maloy _skb = pskb_copy(skb, GFP_ATOMIC);
808a853e4c6SJon Paul Maloy if (!_skb) {
809a853e4c6SJon Paul Maloy __skb_queue_purge(cpy);
810a853e4c6SJon Paul Maloy return false;
811a853e4c6SJon Paul Maloy }
812a853e4c6SJon Paul Maloy msg_set_destnode(buf_msg(_skb), dst);
813a853e4c6SJon Paul Maloy __skb_queue_tail(cpy, _skb);
814a853e4c6SJon Paul Maloy }
815a853e4c6SJon Paul Maloy return true;
816a853e4c6SJon Paul Maloy }
817a853e4c6SJon Paul Maloy
8188306f99aSJon Paul Maloy /* tipc_skb_queue_sorted(); sort pkt into list according to sequence number
8198306f99aSJon Paul Maloy * @list: list to be appended to
8208306f99aSJon Paul Maloy * @seqno: sequence number of buffer to add
8218306f99aSJon Paul Maloy * @skb: buffer to add
8228306f99aSJon Paul Maloy */
__tipc_skb_queue_sorted(struct sk_buff_head * list,u16 seqno,struct sk_buff * skb)82303b6fefdSTuong Lien bool __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
8248306f99aSJon Paul Maloy struct sk_buff *skb)
8258306f99aSJon Paul Maloy {
8268306f99aSJon Paul Maloy struct sk_buff *_skb, *tmp;
8278306f99aSJon Paul Maloy
8288306f99aSJon Paul Maloy if (skb_queue_empty(list) || less(seqno, buf_seqno(skb_peek(list)))) {
8298306f99aSJon Paul Maloy __skb_queue_head(list, skb);
83003b6fefdSTuong Lien return true;
8318306f99aSJon Paul Maloy }
8328306f99aSJon Paul Maloy
8338306f99aSJon Paul Maloy if (more(seqno, buf_seqno(skb_peek_tail(list)))) {
8348306f99aSJon Paul Maloy __skb_queue_tail(list, skb);
83503b6fefdSTuong Lien return true;
8368306f99aSJon Paul Maloy }
8378306f99aSJon Paul Maloy
8388306f99aSJon Paul Maloy skb_queue_walk_safe(list, _skb, tmp) {
8398306f99aSJon Paul Maloy if (more(seqno, buf_seqno(_skb)))
8408306f99aSJon Paul Maloy continue;
8418306f99aSJon Paul Maloy if (seqno == buf_seqno(_skb))
8428306f99aSJon Paul Maloy break;
8438306f99aSJon Paul Maloy __skb_queue_before(list, _skb, skb);
84403b6fefdSTuong Lien return true;
8458306f99aSJon Paul Maloy }
8468306f99aSJon Paul Maloy kfree_skb(skb);
84703b6fefdSTuong Lien return false;
8488306f99aSJon Paul Maloy }
84964ac5f59SJon Maloy
tipc_skb_reject(struct net * net,int err,struct sk_buff * skb,struct sk_buff_head * xmitq)85064ac5f59SJon Maloy void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb,
85164ac5f59SJon Maloy struct sk_buff_head *xmitq)
85264ac5f59SJon Maloy {
85364ac5f59SJon Maloy if (tipc_msg_reverse(tipc_own_addr(net), &skb, err))
85464ac5f59SJon Maloy __skb_queue_tail(xmitq, skb);
85564ac5f59SJon Maloy }
856