diff options
Diffstat (limited to 'net/tipc/msg.c')
-rw-r--r-- | net/tipc/msg.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/net/tipc/msg.c b/net/tipc/msg.c index f48e5857210f..e6d49cdc61b4 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c | |||
@@ -244,6 +244,65 @@ bool tipc_msg_validate(struct sk_buff **_skb) | |||
244 | } | 244 | } |
245 | 245 | ||
246 | /** | 246 | /** |
247 | * tipc_msg_fragment - build a fragment skb list for TIPC message | ||
248 | * | ||
249 | * @skb: TIPC message skb | ||
250 | * @hdr: internal msg header to be put on the top of the fragments | ||
251 | * @pktmax: max size of a fragment incl. the header | ||
252 | * @frags: returned fragment skb list | ||
253 | * | ||
254 | * Returns 0 if the fragmentation is successful, otherwise: -EINVAL | ||
255 | * or -ENOMEM | ||
256 | */ | ||
257 | int tipc_msg_fragment(struct sk_buff *skb, const struct tipc_msg *hdr, | ||
258 | int pktmax, struct sk_buff_head *frags) | ||
259 | { | ||
260 | int pktno, nof_fragms, dsz, dmax, eat; | ||
261 | struct tipc_msg *_hdr; | ||
262 | struct sk_buff *_skb; | ||
263 | u8 *data; | ||
264 | |||
265 | /* Non-linear buffer? */ | ||
266 | if (skb_linearize(skb)) | ||
267 | return -ENOMEM; | ||
268 | |||
269 | data = (u8 *)skb->data; | ||
270 | dsz = msg_size(buf_msg(skb)); | ||
271 | dmax = pktmax - INT_H_SIZE; | ||
272 | if (dsz <= dmax || !dmax) | ||
273 | return -EINVAL; | ||
274 | |||
275 | nof_fragms = dsz / dmax + 1; | ||
276 | for (pktno = 1; pktno <= nof_fragms; pktno++) { | ||
277 | if (pktno < nof_fragms) | ||
278 | eat = dmax; | ||
279 | else | ||
280 | eat = dsz % dmax; | ||
281 | /* Allocate a new fragment */ | ||
282 | _skb = tipc_buf_acquire(INT_H_SIZE + eat, GFP_ATOMIC); | ||
283 | if (!_skb) | ||
284 | goto error; | ||
285 | skb_orphan(_skb); | ||
286 | __skb_queue_tail(frags, _skb); | ||
287 | /* Copy header & data to the fragment */ | ||
288 | skb_copy_to_linear_data(_skb, hdr, INT_H_SIZE); | ||
289 | skb_copy_to_linear_data_offset(_skb, INT_H_SIZE, data, eat); | ||
290 | data += eat; | ||
291 | /* Update the fragment's header */ | ||
292 | _hdr = buf_msg(_skb); | ||
293 | msg_set_fragm_no(_hdr, pktno); | ||
294 | msg_set_nof_fragms(_hdr, nof_fragms); | ||
295 | msg_set_size(_hdr, INT_H_SIZE + eat); | ||
296 | } | ||
297 | return 0; | ||
298 | |||
299 | error: | ||
300 | __skb_queue_purge(frags); | ||
301 | __skb_queue_head_init(frags); | ||
302 | return -ENOMEM; | ||
303 | } | ||
304 | |||
305 | /** | ||
247 | * tipc_msg_build - create buffer chain containing specified header and data | 306 | * tipc_msg_build - create buffer chain containing specified header and data |
248 | * @mhdr: Message header, to be prepended to data | 307 | * @mhdr: Message header, to be prepended to data |
249 | * @m: User message | 308 | * @m: User message |