aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/msg.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/msg.c')
-rw-r--r--net/tipc/msg.c159
1 files changed, 94 insertions, 65 deletions
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 9680be6d388a..a687b30a699c 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -56,15 +56,42 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
56 msg_set_size(m, hsize); 56 msg_set_size(m, hsize);
57 msg_set_prevnode(m, tipc_own_addr); 57 msg_set_prevnode(m, tipc_own_addr);
58 msg_set_type(m, type); 58 msg_set_type(m, type);
59 msg_set_orignode(m, tipc_own_addr); 59 if (hsize > SHORT_H_SIZE) {
60 msg_set_destnode(m, destnode); 60 msg_set_orignode(m, tipc_own_addr);
61 msg_set_destnode(m, destnode);
62 }
63}
64
65struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
66 uint data_sz, u32 dnode, u32 onode,
67 u32 dport, u32 oport, int errcode)
68{
69 struct tipc_msg *msg;
70 struct sk_buff *buf;
71
72 buf = tipc_buf_acquire(hdr_sz + data_sz);
73 if (unlikely(!buf))
74 return NULL;
75
76 msg = buf_msg(buf);
77 tipc_msg_init(msg, user, type, hdr_sz, dnode);
78 msg_set_size(msg, hdr_sz + data_sz);
79 msg_set_prevnode(msg, onode);
80 msg_set_origport(msg, oport);
81 msg_set_destport(msg, dport);
82 msg_set_errcode(msg, errcode);
83 if (hdr_sz > SHORT_H_SIZE) {
84 msg_set_orignode(msg, onode);
85 msg_set_destnode(msg, dnode);
86 }
87 return buf;
61} 88}
62 89
63/* tipc_buf_append(): Append a buffer to the fragment list of another buffer 90/* tipc_buf_append(): Append a buffer to the fragment list of another buffer
64 * @*headbuf: in: NULL for first frag, otherwise value returned from prev call 91 * @*headbuf: in: NULL for first frag, otherwise value returned from prev call
65 * out: set when successful non-complete reassembly, otherwise NULL 92 * out: set when successful non-complete reassembly, otherwise NULL
66 * @*buf: in: the buffer to append. Always defined 93 * @*buf: in: the buffer to append. Always defined
67 * out: head buf after sucessful complete reassembly, otherwise NULL 94 * out: head buf after successful complete reassembly, otherwise NULL
68 * Returns 1 when reassembly complete, otherwise 0 95 * Returns 1 when reassembly complete, otherwise 0
69 */ 96 */
70int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) 97int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
@@ -135,15 +162,16 @@ err:
135/** 162/**
136 * tipc_msg_build - create buffer chain containing specified header and data 163 * tipc_msg_build - create buffer chain containing specified header and data
137 * @mhdr: Message header, to be prepended to data 164 * @mhdr: Message header, to be prepended to data
138 * @iov: User data 165 * @m: User message
139 * @offset: Posision in iov to start copying from 166 * @offset: Posision in iov to start copying from
140 * @dsz: Total length of user data 167 * @dsz: Total length of user data
141 * @pktmax: Max packet size that can be used 168 * @pktmax: Max packet size that can be used
142 * @chain: Buffer or chain of buffers to be returned to caller 169 * @list: Buffer or chain of buffers to be returned to caller
170 *
143 * Returns message data size or errno: -ENOMEM, -EFAULT 171 * Returns message data size or errno: -ENOMEM, -EFAULT
144 */ 172 */
145int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, 173int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
146 int offset, int dsz, int pktmax , struct sk_buff **chain) 174 int dsz, int pktmax, struct sk_buff_head *list)
147{ 175{
148 int mhsz = msg_hdr_sz(mhdr); 176 int mhsz = msg_hdr_sz(mhdr);
149 int msz = mhsz + dsz; 177 int msz = mhsz + dsz;
@@ -152,7 +180,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
152 int pktrem = pktmax; 180 int pktrem = pktmax;
153 int drem = dsz; 181 int drem = dsz;
154 struct tipc_msg pkthdr; 182 struct tipc_msg pkthdr;
155 struct sk_buff *buf, *prev; 183 struct sk_buff *skb;
156 char *pktpos; 184 char *pktpos;
157 int rc; 185 int rc;
158 186
@@ -160,13 +188,14 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
160 188
161 /* No fragmentation needed? */ 189 /* No fragmentation needed? */
162 if (likely(msz <= pktmax)) { 190 if (likely(msz <= pktmax)) {
163 buf = tipc_buf_acquire(msz); 191 skb = tipc_buf_acquire(msz);
164 *chain = buf; 192 if (unlikely(!skb))
165 if (unlikely(!buf))
166 return -ENOMEM; 193 return -ENOMEM;
167 skb_copy_to_linear_data(buf, mhdr, mhsz); 194 __skb_queue_tail(list, skb);
168 pktpos = buf->data + mhsz; 195 skb_copy_to_linear_data(skb, mhdr, mhsz);
169 if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz)) 196 pktpos = skb->data + mhsz;
197 if (!dsz || !memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset,
198 dsz))
170 return dsz; 199 return dsz;
171 rc = -EFAULT; 200 rc = -EFAULT;
172 goto error; 201 goto error;
@@ -179,14 +208,15 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
179 msg_set_fragm_no(&pkthdr, pktno); 208 msg_set_fragm_no(&pkthdr, pktno);
180 209
181 /* Prepare first fragment */ 210 /* Prepare first fragment */
182 *chain = buf = tipc_buf_acquire(pktmax); 211 skb = tipc_buf_acquire(pktmax);
183 if (!buf) 212 if (!skb)
184 return -ENOMEM; 213 return -ENOMEM;
185 pktpos = buf->data; 214 __skb_queue_tail(list, skb);
186 skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); 215 pktpos = skb->data;
216 skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE);
187 pktpos += INT_H_SIZE; 217 pktpos += INT_H_SIZE;
188 pktrem -= INT_H_SIZE; 218 pktrem -= INT_H_SIZE;
189 skb_copy_to_linear_data_offset(buf, INT_H_SIZE, mhdr, mhsz); 219 skb_copy_to_linear_data_offset(skb, INT_H_SIZE, mhdr, mhsz);
190 pktpos += mhsz; 220 pktpos += mhsz;
191 pktrem -= mhsz; 221 pktrem -= mhsz;
192 222
@@ -194,7 +224,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
194 if (drem < pktrem) 224 if (drem < pktrem)
195 pktrem = drem; 225 pktrem = drem;
196 226
197 if (memcpy_fromiovecend(pktpos, iov, offset, pktrem)) { 227 if (memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, pktrem)) {
198 rc = -EFAULT; 228 rc = -EFAULT;
199 goto error; 229 goto error;
200 } 230 }
@@ -209,42 +239,41 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
209 pktsz = drem + INT_H_SIZE; 239 pktsz = drem + INT_H_SIZE;
210 else 240 else
211 pktsz = pktmax; 241 pktsz = pktmax;
212 prev = buf; 242 skb = tipc_buf_acquire(pktsz);
213 buf = tipc_buf_acquire(pktsz); 243 if (!skb) {
214 if (!buf) {
215 rc = -ENOMEM; 244 rc = -ENOMEM;
216 goto error; 245 goto error;
217 } 246 }
218 prev->next = buf; 247 __skb_queue_tail(list, skb);
219 msg_set_type(&pkthdr, FRAGMENT); 248 msg_set_type(&pkthdr, FRAGMENT);
220 msg_set_size(&pkthdr, pktsz); 249 msg_set_size(&pkthdr, pktsz);
221 msg_set_fragm_no(&pkthdr, ++pktno); 250 msg_set_fragm_no(&pkthdr, ++pktno);
222 skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); 251 skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE);
223 pktpos = buf->data + INT_H_SIZE; 252 pktpos = skb->data + INT_H_SIZE;
224 pktrem = pktsz - INT_H_SIZE; 253 pktrem = pktsz - INT_H_SIZE;
225 254
226 } while (1); 255 } while (1);
227 256 msg_set_type(buf_msg(skb), LAST_FRAGMENT);
228 msg_set_type(buf_msg(buf), LAST_FRAGMENT);
229 return dsz; 257 return dsz;
230error: 258error:
231 kfree_skb_list(*chain); 259 __skb_queue_purge(list);
232 *chain = NULL; 260 __skb_queue_head_init(list);
233 return rc; 261 return rc;
234} 262}
235 263
236/** 264/**
237 * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one 265 * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one
238 * @bbuf: the existing buffer ("bundle") 266 * @list: the buffer chain of the existing buffer ("bundle")
239 * @buf: buffer to be appended 267 * @skb: buffer to be appended
240 * @mtu: max allowable size for the bundle buffer 268 * @mtu: max allowable size for the bundle buffer
241 * Consumes buffer if successful 269 * Consumes buffer if successful
242 * Returns true if bundling could be performed, otherwise false 270 * Returns true if bundling could be performed, otherwise false
243 */ 271 */
244bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu) 272bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu)
245{ 273{
246 struct tipc_msg *bmsg = buf_msg(bbuf); 274 struct sk_buff *bskb = skb_peek_tail(list);
247 struct tipc_msg *msg = buf_msg(buf); 275 struct tipc_msg *bmsg = buf_msg(bskb);
276 struct tipc_msg *msg = buf_msg(skb);
248 unsigned int bsz = msg_size(bmsg); 277 unsigned int bsz = msg_size(bmsg);
249 unsigned int msz = msg_size(msg); 278 unsigned int msz = msg_size(msg);
250 u32 start = align(bsz); 279 u32 start = align(bsz);
@@ -259,35 +288,36 @@ bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu)
259 return false; 288 return false;
260 if (likely(msg_user(bmsg) != MSG_BUNDLER)) 289 if (likely(msg_user(bmsg) != MSG_BUNDLER))
261 return false; 290 return false;
262 if (likely(msg_type(bmsg) != BUNDLE_OPEN)) 291 if (likely(!TIPC_SKB_CB(bskb)->bundling))
263 return false; 292 return false;
264 if (unlikely(skb_tailroom(bbuf) < (pad + msz))) 293 if (unlikely(skb_tailroom(bskb) < (pad + msz)))
265 return false; 294 return false;
266 if (unlikely(max < (start + msz))) 295 if (unlikely(max < (start + msz)))
267 return false; 296 return false;
268 297
269 skb_put(bbuf, pad + msz); 298 skb_put(bskb, pad + msz);
270 skb_copy_to_linear_data_offset(bbuf, start, buf->data, msz); 299 skb_copy_to_linear_data_offset(bskb, start, skb->data, msz);
271 msg_set_size(bmsg, start + msz); 300 msg_set_size(bmsg, start + msz);
272 msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1); 301 msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1);
273 bbuf->next = buf->next; 302 kfree_skb(skb);
274 kfree_skb(buf);
275 return true; 303 return true;
276} 304}
277 305
278/** 306/**
279 * tipc_msg_make_bundle(): Create bundle buf and append message to its tail 307 * tipc_msg_make_bundle(): Create bundle buf and append message to its tail
280 * @buf: buffer to be appended and replaced 308 * @list: the buffer chain
281 * @mtu: max allowable size for the bundle buffer, inclusive header 309 * @skb: buffer to be appended and replaced
310 * @mtu: max allowable size for the bundle buffer, inclusive header
282 * @dnode: destination node for message. (Not always present in header) 311 * @dnode: destination node for message. (Not always present in header)
283 * Replaces buffer if successful 312 * Replaces buffer if successful
284 * Returns true if sucess, otherwise false 313 * Returns true if success, otherwise false
285 */ 314 */
286bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode) 315bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb,
316 u32 mtu, u32 dnode)
287{ 317{
288 struct sk_buff *bbuf; 318 struct sk_buff *bskb;
289 struct tipc_msg *bmsg; 319 struct tipc_msg *bmsg;
290 struct tipc_msg *msg = buf_msg(*buf); 320 struct tipc_msg *msg = buf_msg(skb);
291 u32 msz = msg_size(msg); 321 u32 msz = msg_size(msg);
292 u32 max = mtu - INT_H_SIZE; 322 u32 max = mtu - INT_H_SIZE;
293 323
@@ -300,20 +330,19 @@ bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode)
300 if (msz > (max / 2)) 330 if (msz > (max / 2))
301 return false; 331 return false;
302 332
303 bbuf = tipc_buf_acquire(max); 333 bskb = tipc_buf_acquire(max);
304 if (!bbuf) 334 if (!bskb)
305 return false; 335 return false;
306 336
307 skb_trim(bbuf, INT_H_SIZE); 337 skb_trim(bskb, INT_H_SIZE);
308 bmsg = buf_msg(bbuf); 338 bmsg = buf_msg(bskb);
309 tipc_msg_init(bmsg, MSG_BUNDLER, BUNDLE_OPEN, INT_H_SIZE, dnode); 339 tipc_msg_init(bmsg, MSG_BUNDLER, 0, INT_H_SIZE, dnode);
310 msg_set_seqno(bmsg, msg_seqno(msg)); 340 msg_set_seqno(bmsg, msg_seqno(msg));
311 msg_set_ack(bmsg, msg_ack(msg)); 341 msg_set_ack(bmsg, msg_ack(msg));
312 msg_set_bcast_ack(bmsg, msg_bcast_ack(msg)); 342 msg_set_bcast_ack(bmsg, msg_bcast_ack(msg));
313 bbuf->next = (*buf)->next; 343 TIPC_SKB_CB(bskb)->bundling = true;
314 tipc_msg_bundle(bbuf, *buf, mtu); 344 __skb_queue_tail(list, bskb);
315 *buf = bbuf; 345 return tipc_msg_bundle(list, skb, mtu);
316 return true;
317} 346}
318 347
319/** 348/**
@@ -399,22 +428,23 @@ int tipc_msg_eval(struct sk_buff *buf, u32 *dnode)
399/* tipc_msg_reassemble() - clone a buffer chain of fragments and 428/* tipc_msg_reassemble() - clone a buffer chain of fragments and
400 * reassemble the clones into one message 429 * reassemble the clones into one message
401 */ 430 */
402struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain) 431struct sk_buff *tipc_msg_reassemble(struct sk_buff_head *list)
403{ 432{
404 struct sk_buff *buf = chain; 433 struct sk_buff *skb;
405 struct sk_buff *frag = buf; 434 struct sk_buff *frag = NULL;
406 struct sk_buff *head = NULL; 435 struct sk_buff *head = NULL;
407 int hdr_sz; 436 int hdr_sz;
408 437
409 /* Copy header if single buffer */ 438 /* Copy header if single buffer */
410 if (!buf->next) { 439 if (skb_queue_len(list) == 1) {
411 hdr_sz = skb_headroom(buf) + msg_hdr_sz(buf_msg(buf)); 440 skb = skb_peek(list);
412 return __pskb_copy(buf, hdr_sz, GFP_ATOMIC); 441 hdr_sz = skb_headroom(skb) + msg_hdr_sz(buf_msg(skb));
442 return __pskb_copy(skb, hdr_sz, GFP_ATOMIC);
413 } 443 }
414 444
415 /* Clone all fragments and reassemble */ 445 /* Clone all fragments and reassemble */
416 while (buf) { 446 skb_queue_walk(list, skb) {
417 frag = skb_clone(buf, GFP_ATOMIC); 447 frag = skb_clone(skb, GFP_ATOMIC);
418 if (!frag) 448 if (!frag)
419 goto error; 449 goto error;
420 frag->next = NULL; 450 frag->next = NULL;
@@ -422,7 +452,6 @@ struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain)
422 break; 452 break;
423 if (!head) 453 if (!head)
424 goto error; 454 goto error;
425 buf = buf->next;
426 } 455 }
427 return frag; 456 return frag;
428error: 457error: