/** * tipc_msg_make_bundle(): Create bundle buf and append message to its tail * @list: the buffer chain * @skb: buffer to be appended and replaced * @mtu: max allowable size for the bundle buffer, inclusive header * @dnode: destination node for message. (Not always present in header) * Replaces buffer if successful * Returns true if success, otherwise false */ bool tipc_msg_make_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu, u32 dnode) { struct sk_buff *bskb; struct tipc_msg *bmsg; struct tipc_msg *msg = buf_msg(skb); u32 msz = msg_size(msg); u32 max = mtu - INT_H_SIZE; if (msg_user(msg) == MSG_FRAGMENTER) return false; if (msg_user(msg) == CHANGEOVER_PROTOCOL) return false; if (msg_user(msg) == BCAST_PROTOCOL) return false; if (msz > (max / 2)) return false; bskb = tipc_buf_acquire(max); if (!bskb) return false; skb_trim(bskb, INT_H_SIZE); bmsg = buf_msg(bskb); tipc_msg_init(bmsg, MSG_BUNDLER, 0, INT_H_SIZE, dnode); msg_set_seqno(bmsg, msg_seqno(msg)); msg_set_ack(bmsg, msg_ack(msg)); msg_set_bcast_ack(bmsg, msg_bcast_ack(msg)); TIPC_SKB_CB(bskb)->bundling = true; __skb_queue_tail(list, bskb); return tipc_msg_bundle(list, skb, mtu); }
static void bclink_send_nack(struct tipc_node *n_ptr) { struct sk_buff *buf; struct tipc_msg *msg; if (!less(n_ptr->bclink.gap_after, n_ptr->bclink.gap_to)) return; buf = tipc_buf_acquire(INT_H_SIZE); if (buf) { msg = buf_msg(buf); tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, n_ptr->addr); msg_set_non_seq(msg, 1); msg_set_mc_netid(msg, tipc_net_id); msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in)); msg_set_bcgap_after(msg, n_ptr->bclink.gap_after); msg_set_bcgap_to(msg, n_ptr->bclink.gap_to); msg_set_bcast_tag(msg, tipc_own_tag); tipc_bearer_send(&bcbearer->bearer, buf, NULL); bcl->stats.sent_nacks++; buf_discard(buf); /* * Ensure we doesn't send another NACK msg to the node * until 16 more deferred messages arrive from it * (i.e. helps prevent all nodes from NACK'ing at same time) */ n_ptr->bclink.nack_sync = tipc_own_tag; } }
/** * tipc_bclink_update_link_state - update broadcast link state * * tipc_net_lock and node lock set */ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent) { struct sk_buff *buf; /* Ignore "stale" link state info */ if (less_eq(last_sent, n_ptr->bclink.last_in)) return; /* Update link synchronization state; quit if in sync */ bclink_update_last_sent(n_ptr, last_sent); if (n_ptr->bclink.last_sent == n_ptr->bclink.last_in) return; /* Update out-of-sync state; quit if loss is still unconfirmed */ if ((++n_ptr->bclink.oos_state) == 1) { if (n_ptr->bclink.deferred_size < (TIPC_MIN_LINK_WIN / 2)) return; n_ptr->bclink.oos_state++; } /* Don't NACK if one has been recently sent (or seen) */ if (n_ptr->bclink.oos_state & 0x1) return; /* Send NACK */ buf = tipc_buf_acquire(INT_H_SIZE); if (buf) { struct tipc_msg *msg = buf_msg(buf); tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, n_ptr->addr); msg_set_non_seq(msg, 1); msg_set_mc_netid(msg, tipc_net_id); msg_set_bcast_ack(msg, n_ptr->bclink.last_in); msg_set_bcgap_after(msg, n_ptr->bclink.last_in); msg_set_bcgap_to(msg, n_ptr->bclink.deferred_head ? buf_seqno(n_ptr->bclink.deferred_head) - 1 : n_ptr->bclink.last_sent); spin_lock_bh(&bc_lock); tipc_bearer_send(&bcbearer->bearer, buf, NULL); bcl->stats.sent_nacks++; spin_unlock_bh(&bc_lock); kfree_skb(buf); n_ptr->bclink.oos_state++; } }