.. | .. |
---|
46 | 46 | #define BCLINK_WIN_MIN 32 /* bcast minimum link window size */ |
---|
47 | 47 | |
---|
48 | 48 | const char tipc_bclink_name[] = "broadcast-link"; |
---|
| 49 | +unsigned long sysctl_tipc_bc_retruni __read_mostly; |
---|
49 | 50 | |
---|
50 | 51 | /** |
---|
51 | 52 | * struct tipc_bc_base - base structure for keeping broadcast send state |
---|
.. | .. |
---|
54 | 55 | * @dests: array keeping number of reachable destinations per bearer |
---|
55 | 56 | * @primary_bearer: a bearer having links to all broadcast destinations, if any |
---|
56 | 57 | * @bcast_support: indicates if primary bearer, if any, supports broadcast |
---|
| 58 | + * @force_bcast: forces broadcast for multicast traffic |
---|
57 | 59 | * @rcast_support: indicates if all peer nodes support replicast |
---|
| 60 | + * @force_rcast: forces replicast for multicast traffic |
---|
58 | 61 | * @rc_ratio: dest count as percentage of cluster size where send method changes |
---|
59 | 62 | * @bc_threshold: calculated from rc_ratio; if dests > threshold use broadcast |
---|
60 | 63 | */ |
---|
.. | .. |
---|
64 | 67 | int dests[MAX_BEARERS]; |
---|
65 | 68 | int primary_bearer; |
---|
66 | 69 | bool bcast_support; |
---|
| 70 | + bool force_bcast; |
---|
67 | 71 | bool rcast_support; |
---|
| 72 | + bool force_rcast; |
---|
68 | 73 | int rc_ratio; |
---|
69 | 74 | int bc_threshold; |
---|
70 | 75 | }; |
---|
.. | .. |
---|
80 | 85 | */ |
---|
81 | 86 | int tipc_bcast_get_mtu(struct net *net) |
---|
82 | 87 | { |
---|
83 | | - return tipc_link_mtu(tipc_bc_sndlink(net)) - INT_H_SIZE; |
---|
| 88 | + return tipc_link_mss(tipc_bc_sndlink(net)); |
---|
84 | 89 | } |
---|
85 | 90 | |
---|
86 | | -void tipc_bcast_disable_rcast(struct net *net) |
---|
| 91 | +void tipc_bcast_toggle_rcast(struct net *net, bool supp) |
---|
87 | 92 | { |
---|
88 | | - tipc_bc_base(net)->rcast_support = false; |
---|
| 93 | + tipc_bc_base(net)->rcast_support = supp; |
---|
89 | 94 | } |
---|
90 | 95 | |
---|
91 | 96 | static void tipc_bcbase_calc_bc_threshold(struct net *net) |
---|
.. | .. |
---|
103 | 108 | { |
---|
104 | 109 | struct tipc_bc_base *bb = tipc_bc_base(net); |
---|
105 | 110 | int all_dests = tipc_link_bc_peers(bb->link); |
---|
| 111 | + int max_win = tipc_link_max_win(bb->link); |
---|
| 112 | + int min_win = tipc_link_min_win(bb->link); |
---|
106 | 113 | int i, mtu, prim; |
---|
107 | 114 | |
---|
108 | 115 | bb->primary_bearer = INVALID_BEARER_ID; |
---|
.. | .. |
---|
116 | 123 | continue; |
---|
117 | 124 | |
---|
118 | 125 | mtu = tipc_bearer_mtu(net, i); |
---|
119 | | - if (mtu < tipc_link_mtu(bb->link)) |
---|
| 126 | + if (mtu < tipc_link_mtu(bb->link)) { |
---|
120 | 127 | tipc_link_set_mtu(bb->link, mtu); |
---|
| 128 | + tipc_link_set_queue_limits(bb->link, |
---|
| 129 | + min_win, |
---|
| 130 | + max_win); |
---|
| 131 | + } |
---|
121 | 132 | bb->bcast_support &= tipc_bearer_bcast_support(net, i); |
---|
122 | 133 | if (bb->dests[i] < all_dests) |
---|
123 | 134 | continue; |
---|
.. | .. |
---|
216 | 227 | } |
---|
217 | 228 | /* Can current method be changed ? */ |
---|
218 | 229 | method->expires = jiffies + TIPC_METHOD_EXPIRE; |
---|
219 | | - if (method->mandatory || time_before(jiffies, exp)) |
---|
| 230 | + if (method->mandatory) |
---|
220 | 231 | return; |
---|
221 | 232 | |
---|
| 233 | + if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL) && |
---|
| 234 | + time_before(jiffies, exp)) |
---|
| 235 | + return; |
---|
| 236 | + |
---|
| 237 | + /* Configuration as force 'broadcast' method */ |
---|
| 238 | + if (bb->force_bcast) { |
---|
| 239 | + method->rcast = false; |
---|
| 240 | + return; |
---|
| 241 | + } |
---|
| 242 | + /* Configuration as force 'replicast' method */ |
---|
| 243 | + if (bb->force_rcast) { |
---|
| 244 | + method->rcast = true; |
---|
| 245 | + return; |
---|
| 246 | + } |
---|
| 247 | + /* Configuration as 'autoselect' or default method */ |
---|
222 | 248 | /* Determine method to use now */ |
---|
223 | 249 | method->rcast = dests <= bb->bc_threshold; |
---|
224 | 250 | } |
---|
.. | .. |
---|
230 | 256 | * Consumes the buffer chain. |
---|
231 | 257 | * Returns 0 if success, otherwise errno: -EHOSTUNREACH,-EMSGSIZE |
---|
232 | 258 | */ |
---|
233 | | -static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts, |
---|
234 | | - u16 *cong_link_cnt) |
---|
| 259 | +int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts, |
---|
| 260 | + u16 *cong_link_cnt) |
---|
235 | 261 | { |
---|
236 | 262 | struct tipc_link *l = tipc_bc_sndlink(net); |
---|
237 | 263 | struct sk_buff_head xmitq; |
---|
.. | .. |
---|
281 | 307 | return 0; |
---|
282 | 308 | } |
---|
283 | 309 | |
---|
| 310 | +/* tipc_mcast_send_sync - deliver a dummy message with SYN bit |
---|
| 311 | + * @net: the applicable net namespace |
---|
| 312 | + * @skb: socket buffer to copy |
---|
| 313 | + * @method: send method to be used |
---|
| 314 | + * @dests: destination nodes for message. |
---|
| 315 | + * Returns 0 if success, otherwise errno |
---|
| 316 | + */ |
---|
| 317 | +static int tipc_mcast_send_sync(struct net *net, struct sk_buff *skb, |
---|
| 318 | + struct tipc_mc_method *method, |
---|
| 319 | + struct tipc_nlist *dests) |
---|
| 320 | +{ |
---|
| 321 | + struct tipc_msg *hdr, *_hdr; |
---|
| 322 | + struct sk_buff_head tmpq; |
---|
| 323 | + struct sk_buff *_skb; |
---|
| 324 | + u16 cong_link_cnt; |
---|
| 325 | + int rc = 0; |
---|
| 326 | + |
---|
| 327 | + /* Is a cluster supporting with new capabilities ? */ |
---|
| 328 | + if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL)) |
---|
| 329 | + return 0; |
---|
| 330 | + |
---|
| 331 | + hdr = buf_msg(skb); |
---|
| 332 | + if (msg_user(hdr) == MSG_FRAGMENTER) |
---|
| 333 | + hdr = msg_inner_hdr(hdr); |
---|
| 334 | + if (msg_type(hdr) != TIPC_MCAST_MSG) |
---|
| 335 | + return 0; |
---|
| 336 | + |
---|
| 337 | + /* Allocate dummy message */ |
---|
| 338 | + _skb = tipc_buf_acquire(MCAST_H_SIZE, GFP_KERNEL); |
---|
| 339 | + if (!_skb) |
---|
| 340 | + return -ENOMEM; |
---|
| 341 | + |
---|
| 342 | + /* Preparing for 'synching' header */ |
---|
| 343 | + msg_set_syn(hdr, 1); |
---|
| 344 | + |
---|
| 345 | + /* Copy skb's header into a dummy header */ |
---|
| 346 | + skb_copy_to_linear_data(_skb, hdr, MCAST_H_SIZE); |
---|
| 347 | + skb_orphan(_skb); |
---|
| 348 | + |
---|
| 349 | + /* Reverse method for dummy message */ |
---|
| 350 | + _hdr = buf_msg(_skb); |
---|
| 351 | + msg_set_size(_hdr, MCAST_H_SIZE); |
---|
| 352 | + msg_set_is_rcast(_hdr, !msg_is_rcast(hdr)); |
---|
| 353 | + msg_set_errcode(_hdr, TIPC_ERR_NO_PORT); |
---|
| 354 | + |
---|
| 355 | + __skb_queue_head_init(&tmpq); |
---|
| 356 | + __skb_queue_tail(&tmpq, _skb); |
---|
| 357 | + if (method->rcast) |
---|
| 358 | + rc = tipc_bcast_xmit(net, &tmpq, &cong_link_cnt); |
---|
| 359 | + else |
---|
| 360 | + rc = tipc_rcast_xmit(net, &tmpq, dests, &cong_link_cnt); |
---|
| 361 | + |
---|
| 362 | + /* This queue should normally be empty by now */ |
---|
| 363 | + __skb_queue_purge(&tmpq); |
---|
| 364 | + |
---|
| 365 | + return rc; |
---|
| 366 | +} |
---|
| 367 | + |
---|
284 | 368 | /* tipc_mcast_xmit - deliver message to indicated destination nodes |
---|
285 | 369 | * and to identified node local sockets |
---|
286 | 370 | * @net: the applicable net namespace |
---|
.. | .. |
---|
296 | 380 | u16 *cong_link_cnt) |
---|
297 | 381 | { |
---|
298 | 382 | struct sk_buff_head inputq, localq; |
---|
| 383 | + bool rcast = method->rcast; |
---|
| 384 | + struct tipc_msg *hdr; |
---|
| 385 | + struct sk_buff *skb; |
---|
299 | 386 | int rc = 0; |
---|
300 | 387 | |
---|
301 | 388 | skb_queue_head_init(&inputq); |
---|
.. | .. |
---|
309 | 396 | /* Send according to determined transmit method */ |
---|
310 | 397 | if (dests->remote) { |
---|
311 | 398 | tipc_bcast_select_xmit_method(net, dests->remote, method); |
---|
| 399 | + |
---|
| 400 | + skb = skb_peek(pkts); |
---|
| 401 | + hdr = buf_msg(skb); |
---|
| 402 | + if (msg_user(hdr) == MSG_FRAGMENTER) |
---|
| 403 | + hdr = msg_inner_hdr(hdr); |
---|
| 404 | + msg_set_is_rcast(hdr, method->rcast); |
---|
| 405 | + |
---|
| 406 | + /* Switch method ? */ |
---|
| 407 | + if (rcast != method->rcast) { |
---|
| 408 | + rc = tipc_mcast_send_sync(net, skb, method, dests); |
---|
| 409 | + if (unlikely(rc)) { |
---|
| 410 | + pr_err("Unable to send SYN: method %d, rc %d\n", |
---|
| 411 | + rcast, rc); |
---|
| 412 | + goto exit; |
---|
| 413 | + } |
---|
| 414 | + } |
---|
| 415 | + |
---|
312 | 416 | if (method->rcast) |
---|
313 | 417 | rc = tipc_rcast_xmit(net, pkts, dests, cong_link_cnt); |
---|
314 | 418 | else |
---|
315 | 419 | rc = tipc_bcast_xmit(net, pkts, cong_link_cnt); |
---|
316 | 420 | } |
---|
317 | 421 | |
---|
318 | | - if (dests->local) |
---|
| 422 | + if (dests->local) { |
---|
| 423 | + tipc_loopback_trace(net, &localq); |
---|
319 | 424 | tipc_sk_mcast_rcv(net, &localq, &inputq); |
---|
| 425 | + } |
---|
320 | 426 | exit: |
---|
321 | 427 | /* This queue should normally be empty by now */ |
---|
322 | 428 | __skb_queue_purge(pkts); |
---|
.. | .. |
---|
375 | 481 | __skb_queue_head_init(&xmitq); |
---|
376 | 482 | |
---|
377 | 483 | tipc_bcast_lock(net); |
---|
378 | | - tipc_link_bc_ack_rcv(l, acked, &xmitq); |
---|
| 484 | + tipc_link_bc_ack_rcv(l, acked, 0, NULL, &xmitq, NULL); |
---|
379 | 485 | tipc_bcast_unlock(net); |
---|
380 | 486 | |
---|
381 | 487 | tipc_bcbase_xmit(net, &xmitq); |
---|
.. | .. |
---|
390 | 496 | * RCU is locked, no other locks set |
---|
391 | 497 | */ |
---|
392 | 498 | int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l, |
---|
393 | | - struct tipc_msg *hdr) |
---|
| 499 | + struct tipc_msg *hdr, |
---|
| 500 | + struct sk_buff_head *retrq) |
---|
394 | 501 | { |
---|
395 | 502 | struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq; |
---|
| 503 | + struct tipc_gap_ack_blks *ga; |
---|
396 | 504 | struct sk_buff_head xmitq; |
---|
397 | 505 | int rc = 0; |
---|
398 | 506 | |
---|
.. | .. |
---|
402 | 510 | if (msg_type(hdr) != STATE_MSG) { |
---|
403 | 511 | tipc_link_bc_init_rcv(l, hdr); |
---|
404 | 512 | } else if (!msg_bc_ack_invalid(hdr)) { |
---|
405 | | - tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), &xmitq); |
---|
406 | | - rc = tipc_link_bc_sync_rcv(l, hdr, &xmitq); |
---|
| 513 | + tipc_get_gap_ack_blks(&ga, l, hdr, false); |
---|
| 514 | + if (!sysctl_tipc_bc_retruni) |
---|
| 515 | + retrq = &xmitq; |
---|
| 516 | + rc = tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), |
---|
| 517 | + msg_bc_gap(hdr), ga, &xmitq, |
---|
| 518 | + retrq); |
---|
| 519 | + rc |= tipc_link_bc_sync_rcv(l, hdr, &xmitq); |
---|
407 | 520 | } |
---|
408 | 521 | tipc_bcast_unlock(net); |
---|
409 | 522 | |
---|
.. | .. |
---|
456 | 569 | tipc_sk_rcv(net, inputq); |
---|
457 | 570 | } |
---|
458 | 571 | |
---|
459 | | -int tipc_bclink_reset_stats(struct net *net) |
---|
| 572 | +int tipc_bclink_reset_stats(struct net *net, struct tipc_link *l) |
---|
460 | 573 | { |
---|
461 | | - struct tipc_link *l = tipc_bc_sndlink(net); |
---|
462 | | - |
---|
463 | 574 | if (!l) |
---|
464 | 575 | return -ENOPROTOOPT; |
---|
465 | 576 | |
---|
.. | .. |
---|
469 | 580 | return 0; |
---|
470 | 581 | } |
---|
471 | 582 | |
---|
472 | | -static int tipc_bc_link_set_queue_limits(struct net *net, u32 limit) |
---|
| 583 | +static int tipc_bc_link_set_queue_limits(struct net *net, u32 max_win) |
---|
473 | 584 | { |
---|
474 | 585 | struct tipc_link *l = tipc_bc_sndlink(net); |
---|
475 | 586 | |
---|
476 | 587 | if (!l) |
---|
477 | 588 | return -ENOPROTOOPT; |
---|
478 | | - if (limit < BCLINK_WIN_MIN) |
---|
479 | | - limit = BCLINK_WIN_MIN; |
---|
480 | | - if (limit > TIPC_MAX_LINK_WIN) |
---|
| 589 | + if (max_win < BCLINK_WIN_MIN) |
---|
| 590 | + max_win = BCLINK_WIN_MIN; |
---|
| 591 | + if (max_win > TIPC_MAX_LINK_WIN) |
---|
481 | 592 | return -EINVAL; |
---|
482 | 593 | tipc_bcast_lock(net); |
---|
483 | | - tipc_link_set_queue_limits(l, limit); |
---|
| 594 | + tipc_link_set_queue_limits(l, tipc_link_min_win(l), max_win); |
---|
484 | 595 | tipc_bcast_unlock(net); |
---|
| 596 | + return 0; |
---|
| 597 | +} |
---|
| 598 | + |
---|
| 599 | +static int tipc_bc_link_set_broadcast_mode(struct net *net, u32 bc_mode) |
---|
| 600 | +{ |
---|
| 601 | + struct tipc_bc_base *bb = tipc_bc_base(net); |
---|
| 602 | + |
---|
| 603 | + switch (bc_mode) { |
---|
| 604 | + case BCLINK_MODE_BCAST: |
---|
| 605 | + if (!bb->bcast_support) |
---|
| 606 | + return -ENOPROTOOPT; |
---|
| 607 | + |
---|
| 608 | + bb->force_bcast = true; |
---|
| 609 | + bb->force_rcast = false; |
---|
| 610 | + break; |
---|
| 611 | + case BCLINK_MODE_RCAST: |
---|
| 612 | + if (!bb->rcast_support) |
---|
| 613 | + return -ENOPROTOOPT; |
---|
| 614 | + |
---|
| 615 | + bb->force_bcast = false; |
---|
| 616 | + bb->force_rcast = true; |
---|
| 617 | + break; |
---|
| 618 | + case BCLINK_MODE_SEL: |
---|
| 619 | + if (!bb->bcast_support || !bb->rcast_support) |
---|
| 620 | + return -ENOPROTOOPT; |
---|
| 621 | + |
---|
| 622 | + bb->force_bcast = false; |
---|
| 623 | + bb->force_rcast = false; |
---|
| 624 | + break; |
---|
| 625 | + default: |
---|
| 626 | + return -EINVAL; |
---|
| 627 | + } |
---|
| 628 | + |
---|
| 629 | + return 0; |
---|
| 630 | +} |
---|
| 631 | + |
---|
| 632 | +static int tipc_bc_link_set_broadcast_ratio(struct net *net, u32 bc_ratio) |
---|
| 633 | +{ |
---|
| 634 | + struct tipc_bc_base *bb = tipc_bc_base(net); |
---|
| 635 | + |
---|
| 636 | + if (!bb->bcast_support || !bb->rcast_support) |
---|
| 637 | + return -ENOPROTOOPT; |
---|
| 638 | + |
---|
| 639 | + if (bc_ratio > 100 || bc_ratio <= 0) |
---|
| 640 | + return -EINVAL; |
---|
| 641 | + |
---|
| 642 | + bb->rc_ratio = bc_ratio; |
---|
| 643 | + tipc_bcast_lock(net); |
---|
| 644 | + tipc_bcbase_calc_bc_threshold(net); |
---|
| 645 | + tipc_bcast_unlock(net); |
---|
| 646 | + |
---|
485 | 647 | return 0; |
---|
486 | 648 | } |
---|
487 | 649 | |
---|
.. | .. |
---|
489 | 651 | { |
---|
490 | 652 | int err; |
---|
491 | 653 | u32 win; |
---|
| 654 | + u32 bc_mode; |
---|
| 655 | + u32 bc_ratio; |
---|
492 | 656 | struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; |
---|
493 | 657 | |
---|
494 | 658 | if (!attrs[TIPC_NLA_LINK_PROP]) |
---|
.. | .. |
---|
498 | 662 | if (err) |
---|
499 | 663 | return err; |
---|
500 | 664 | |
---|
501 | | - if (!props[TIPC_NLA_PROP_WIN]) |
---|
| 665 | + if (!props[TIPC_NLA_PROP_WIN] && |
---|
| 666 | + !props[TIPC_NLA_PROP_BROADCAST] && |
---|
| 667 | + !props[TIPC_NLA_PROP_BROADCAST_RATIO]) { |
---|
502 | 668 | return -EOPNOTSUPP; |
---|
| 669 | + } |
---|
503 | 670 | |
---|
504 | | - win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); |
---|
| 671 | + if (props[TIPC_NLA_PROP_BROADCAST]) { |
---|
| 672 | + bc_mode = nla_get_u32(props[TIPC_NLA_PROP_BROADCAST]); |
---|
| 673 | + err = tipc_bc_link_set_broadcast_mode(net, bc_mode); |
---|
| 674 | + } |
---|
505 | 675 | |
---|
506 | | - return tipc_bc_link_set_queue_limits(net, win); |
---|
| 676 | + if (!err && props[TIPC_NLA_PROP_BROADCAST_RATIO]) { |
---|
| 677 | + bc_ratio = nla_get_u32(props[TIPC_NLA_PROP_BROADCAST_RATIO]); |
---|
| 678 | + err = tipc_bc_link_set_broadcast_ratio(net, bc_ratio); |
---|
| 679 | + } |
---|
| 680 | + |
---|
| 681 | + if (!err && props[TIPC_NLA_PROP_WIN]) { |
---|
| 682 | + win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); |
---|
| 683 | + err = tipc_bc_link_set_queue_limits(net, win); |
---|
| 684 | + } |
---|
| 685 | + |
---|
| 686 | + return err; |
---|
507 | 687 | } |
---|
508 | 688 | |
---|
509 | 689 | int tipc_bcast_init(struct net *net) |
---|
.. | .. |
---|
518 | 698 | tn->bcbase = bb; |
---|
519 | 699 | spin_lock_init(&tipc_net(net)->bclock); |
---|
520 | 700 | |
---|
521 | | - if (!tipc_link_bc_create(net, 0, 0, |
---|
522 | | - FB_MTU, |
---|
| 701 | + if (!tipc_link_bc_create(net, 0, 0, NULL, |
---|
| 702 | + one_page_mtu, |
---|
| 703 | + BCLINK_WIN_DEFAULT, |
---|
523 | 704 | BCLINK_WIN_DEFAULT, |
---|
524 | 705 | 0, |
---|
525 | 706 | &bb->inputq, |
---|
.. | .. |
---|
529 | 710 | goto enomem; |
---|
530 | 711 | bb->link = l; |
---|
531 | 712 | tn->bcl = l; |
---|
532 | | - bb->rc_ratio = 25; |
---|
| 713 | + bb->rc_ratio = 10; |
---|
533 | 714 | bb->rcast_support = true; |
---|
534 | 715 | return 0; |
---|
535 | 716 | enomem: |
---|
.. | .. |
---|
576 | 757 | nl->remote = 0; |
---|
577 | 758 | nl->local = false; |
---|
578 | 759 | } |
---|
| 760 | + |
---|
| 761 | +u32 tipc_bcast_get_mode(struct net *net) |
---|
| 762 | +{ |
---|
| 763 | + struct tipc_bc_base *bb = tipc_bc_base(net); |
---|
| 764 | + |
---|
| 765 | + if (bb->force_bcast) |
---|
| 766 | + return BCLINK_MODE_BCAST; |
---|
| 767 | + |
---|
| 768 | + if (bb->force_rcast) |
---|
| 769 | + return BCLINK_MODE_RCAST; |
---|
| 770 | + |
---|
| 771 | + if (bb->bcast_support && bb->rcast_support) |
---|
| 772 | + return BCLINK_MODE_SEL; |
---|
| 773 | + |
---|
| 774 | + return 0; |
---|
| 775 | +} |
---|
| 776 | + |
---|
| 777 | +u32 tipc_bcast_get_broadcast_ratio(struct net *net) |
---|
| 778 | +{ |
---|
| 779 | + struct tipc_bc_base *bb = tipc_bc_base(net); |
---|
| 780 | + |
---|
| 781 | + return bb->rc_ratio; |
---|
| 782 | +} |
---|
| 783 | + |
---|
| 784 | +void tipc_mcast_filter_msg(struct net *net, struct sk_buff_head *defq, |
---|
| 785 | + struct sk_buff_head *inputq) |
---|
| 786 | +{ |
---|
| 787 | + struct sk_buff *skb, *_skb, *tmp; |
---|
| 788 | + struct tipc_msg *hdr, *_hdr; |
---|
| 789 | + bool match = false; |
---|
| 790 | + u32 node, port; |
---|
| 791 | + |
---|
| 792 | + skb = skb_peek(inputq); |
---|
| 793 | + if (!skb) |
---|
| 794 | + return; |
---|
| 795 | + |
---|
| 796 | + hdr = buf_msg(skb); |
---|
| 797 | + |
---|
| 798 | + if (likely(!msg_is_syn(hdr) && skb_queue_empty(defq))) |
---|
| 799 | + return; |
---|
| 800 | + |
---|
| 801 | + node = msg_orignode(hdr); |
---|
| 802 | + if (node == tipc_own_addr(net)) |
---|
| 803 | + return; |
---|
| 804 | + |
---|
| 805 | + port = msg_origport(hdr); |
---|
| 806 | + |
---|
| 807 | + /* Has the twin SYN message already arrived ? */ |
---|
| 808 | + skb_queue_walk(defq, _skb) { |
---|
| 809 | + _hdr = buf_msg(_skb); |
---|
| 810 | + if (msg_orignode(_hdr) != node) |
---|
| 811 | + continue; |
---|
| 812 | + if (msg_origport(_hdr) != port) |
---|
| 813 | + continue; |
---|
| 814 | + match = true; |
---|
| 815 | + break; |
---|
| 816 | + } |
---|
| 817 | + |
---|
| 818 | + if (!match) { |
---|
| 819 | + if (!msg_is_syn(hdr)) |
---|
| 820 | + return; |
---|
| 821 | + __skb_dequeue(inputq); |
---|
| 822 | + __skb_queue_tail(defq, skb); |
---|
| 823 | + return; |
---|
| 824 | + } |
---|
| 825 | + |
---|
| 826 | + /* Deliver non-SYN message from other link, otherwise queue it */ |
---|
| 827 | + if (!msg_is_syn(hdr)) { |
---|
| 828 | + if (msg_is_rcast(hdr) != msg_is_rcast(_hdr)) |
---|
| 829 | + return; |
---|
| 830 | + __skb_dequeue(inputq); |
---|
| 831 | + __skb_queue_tail(defq, skb); |
---|
| 832 | + return; |
---|
| 833 | + } |
---|
| 834 | + |
---|
| 835 | + /* Queue non-SYN/SYN message from same link */ |
---|
| 836 | + if (msg_is_rcast(hdr) == msg_is_rcast(_hdr)) { |
---|
| 837 | + __skb_dequeue(inputq); |
---|
| 838 | + __skb_queue_tail(defq, skb); |
---|
| 839 | + return; |
---|
| 840 | + } |
---|
| 841 | + |
---|
| 842 | + /* Matching SYN messages => return the one with data, if any */ |
---|
| 843 | + __skb_unlink(_skb, defq); |
---|
| 844 | + if (msg_data_sz(hdr)) { |
---|
| 845 | + kfree_skb(_skb); |
---|
| 846 | + } else { |
---|
| 847 | + __skb_dequeue(inputq); |
---|
| 848 | + kfree_skb(skb); |
---|
| 849 | + __skb_queue_tail(inputq, _skb); |
---|
| 850 | + } |
---|
| 851 | + |
---|
| 852 | + /* Deliver subsequent non-SYN messages from same peer */ |
---|
| 853 | + skb_queue_walk_safe(defq, _skb, tmp) { |
---|
| 854 | + _hdr = buf_msg(_skb); |
---|
| 855 | + if (msg_orignode(_hdr) != node) |
---|
| 856 | + continue; |
---|
| 857 | + if (msg_origport(_hdr) != port) |
---|
| 858 | + continue; |
---|
| 859 | + if (msg_is_syn(_hdr)) |
---|
| 860 | + break; |
---|
| 861 | + __skb_unlink(_skb, defq); |
---|
| 862 | + __skb_queue_tail(inputq, _skb); |
---|
| 863 | + } |
---|
| 864 | +} |
---|