diff options
Diffstat (limited to 'net/tipc/msg.c')
| -rw-r--r-- | net/tipc/msg.c | 159 |
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 | |||
| 65 | struct 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 | */ |
| 70 | int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) | 97 | int 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 | */ |
| 145 | int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | 173 | int 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; |
| 230 | error: | 258 | error: |
| 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 | */ |
| 244 | bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu) | 272 | bool 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 | */ |
| 286 | bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode) | 315 | bool 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 | */ |
| 402 | struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain) | 431 | struct 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; |
| 428 | error: | 457 | error: |
