/** * 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); }
/** * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one * @list: the buffer chain of the existing buffer ("bundle") * @skb: buffer to be appended * @mtu: max allowable size for the bundle buffer * Consumes buffer if successful * Returns true if bundling could be performed, otherwise false */ bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu) { struct sk_buff *bskb = skb_peek_tail(list); struct tipc_msg *bmsg = buf_msg(bskb); struct tipc_msg *msg = buf_msg(skb); unsigned int bsz = msg_size(bmsg); unsigned int msz = msg_size(msg); u32 start = align(bsz); u32 max = mtu - INT_H_SIZE; u32 pad = start - bsz; if (likely(msg_user(msg) == MSG_FRAGMENTER)) return false; if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL)) return false; if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) return false; if (likely(msg_user(bmsg) != MSG_BUNDLER)) return false; if (likely(!TIPC_SKB_CB(bskb)->bundling)) return false; if (unlikely(skb_tailroom(bskb) < (pad + msz))) return false; if (unlikely(max < (start + msz))) return false; skb_put(bskb, pad + msz); skb_copy_to_linear_data_offset(bskb, start, skb->data, msz); msg_set_size(bmsg, start + msz); msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1); kfree_skb(skb); return true; }
void tipc_net_route_msg(struct sk_buff *buf) { struct tipc_msg *msg; u32 dnode; if (!buf) return; msg = buf_msg(buf); msg_incr_reroute_cnt(msg); if (msg_reroute_cnt(msg) > 6) { if (msg_errcode(msg)) { msg_dbg(msg, "NET>DISC>:"); buf_discard(buf); } else { msg_dbg(msg, "NET>REJ>:"); tipc_reject_msg(buf, msg_destport(msg) ? TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME); } return; } msg_dbg(msg, "tipc_net->rout: "); /* Handle message for this node */ dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg); if (tipc_in_scope(dnode, tipc_own_addr)) { if (msg_isdata(msg)) { if (msg_mcast(msg)) tipc_port_recv_mcast(buf, NULL); else if (msg_destport(msg)) tipc_port_recv_msg(buf); else net_route_named_msg(buf); return; } switch (msg_user(msg)) { case ROUTE_DISTRIBUTOR: tipc_cltr_recv_routing_table(buf); break; case NAME_DISTRIBUTOR: tipc_named_recv(buf); break; case CONN_MANAGER: tipc_port_recv_proto_msg(buf); break; default: msg_dbg(msg,"DROP/NET/<REC<"); buf_discard(buf); } return; } /* Handle message for another node */ msg_dbg(msg, "NET>SEND>: "); tipc_link_send(buf, dnode, msg_link_selector(msg)); }
u32 tipc_msg_tot_importance(struct tipc_msg *m) { if (likely(msg_isdata(m))) { if (likely(msg_orignode(m) == tipc_own_addr)) return msg_importance(m); return msg_importance(m) + 4; } if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT)) return msg_importance(msg_get_wrapped(m)); return msg_importance(m); }
void tipc_net_route_msg(struct sk_buff *buf) { struct tipc_msg *msg; u32 dnode; if (!buf) return; msg = buf_msg(buf); /* Handle message for this node */ dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg); if (tipc_in_scope(dnode, tipc_own_addr)) { if (msg_isdata(msg)) { if (msg_mcast(msg)) tipc_port_mcast_rcv(buf, NULL); else if (msg_destport(msg)) tipc_port_rcv(buf); else net_route_named_msg(buf); return; } switch (msg_user(msg)) { case NAME_DISTRIBUTOR: tipc_named_rcv(buf); break; case CONN_MANAGER: tipc_port_proto_rcv(buf); break; default: kfree_skb(buf); } return; } /* Handle message for another node */ skb_trim(buf, msg_size(msg)); tipc_link_xmit(buf, dnode, msg_link_selector(msg)); }
/** * tipc_bclink_recv_pkt - receive a broadcast packet, and deliver upwards * * tipc_net_lock is read_locked, no other locks set */ void tipc_bclink_recv_pkt(struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); struct tipc_node *node; u32 next_in; u32 seqno; int deferred; /* Screen out unwanted broadcast messages */ if (msg_mc_netid(msg) != tipc_net_id) goto exit; node = tipc_node_find(msg_prevnode(msg)); if (unlikely(!node)) goto exit; tipc_node_lock(node); if (unlikely(!node->bclink.recv_permitted)) goto unlock; /* Handle broadcast protocol message */ if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) { if (msg_type(msg) != STATE_MSG) goto unlock; if (msg_destnode(msg) == tipc_own_addr) { tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); tipc_node_unlock(node); spin_lock_bh(&bc_lock); bcl->stats.recv_nacks++; bclink->retransmit_to = node; bclink_retransmit_pkt(msg_bcgap_after(msg), msg_bcgap_to(msg)); spin_unlock_bh(&bc_lock); } else { tipc_node_unlock(node); bclink_peek_nack(msg); } goto exit; } /* Handle in-sequence broadcast message */ seqno = msg_seqno(msg); next_in = mod(node->bclink.last_in + 1); if (likely(seqno == next_in)) { receive: /* Deliver message to destination */ if (likely(msg_isdata(msg))) { spin_lock_bh(&bc_lock); bclink_accept_pkt(node, seqno); spin_unlock_bh(&bc_lock); tipc_node_unlock(node); if (likely(msg_mcast(msg))) tipc_port_recv_mcast(buf, NULL); else kfree_skb(buf); } else if (msg_user(msg) == MSG_BUNDLER) { spin_lock_bh(&bc_lock); bclink_accept_pkt(node, seqno); bcl->stats.recv_bundles++; bcl->stats.recv_bundled += msg_msgcnt(msg); spin_unlock_bh(&bc_lock); tipc_node_unlock(node); tipc_link_recv_bundle(buf); } else if (msg_user(msg) == MSG_FRAGMENTER) { int ret = tipc_link_recv_fragment(&node->bclink.defragm, &buf, &msg); if (ret < 0) goto unlock; spin_lock_bh(&bc_lock); bclink_accept_pkt(node, seqno); bcl->stats.recv_fragments++; if (ret > 0) bcl->stats.recv_fragmented++; spin_unlock_bh(&bc_lock); tipc_node_unlock(node); tipc_net_route_msg(buf); } else if (msg_user(msg) == NAME_DISTRIBUTOR) { spin_lock_bh(&bc_lock); bclink_accept_pkt(node, seqno); spin_unlock_bh(&bc_lock); tipc_node_unlock(node); tipc_named_recv(buf); } else { spin_lock_bh(&bc_lock); bclink_accept_pkt(node, seqno); spin_unlock_bh(&bc_lock); tipc_node_unlock(node); kfree_skb(buf); } buf = NULL; /* Determine new synchronization state */ tipc_node_lock(node); if (unlikely(!tipc_node_is_up(node))) goto unlock; if (node->bclink.last_in == node->bclink.last_sent) goto unlock; if (!node->bclink.deferred_head) { node->bclink.oos_state = 1; goto unlock; } msg = buf_msg(node->bclink.deferred_head); seqno = msg_seqno(msg); next_in = mod(next_in + 1); if (seqno != next_in) goto unlock; /* Take in-sequence message from deferred queue & deliver it */ buf = node->bclink.deferred_head; node->bclink.deferred_head = buf->next; buf->next = NULL; node->bclink.deferred_size--; goto receive; } /* Handle out-of-sequence broadcast message */ if (less(next_in, seqno)) { deferred = tipc_link_defer_pkt(&node->bclink.deferred_head, &node->bclink.deferred_tail, buf); node->bclink.deferred_size += deferred; bclink_update_last_sent(node, seqno); buf = NULL; } else deferred = 0; spin_lock_bh(&bc_lock); if (deferred) bcl->stats.deferred_recv++; else bcl->stats.duplicates++; spin_unlock_bh(&bc_lock); unlock: tipc_node_unlock(node); exit: kfree_skb(buf); }
void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str) { u32 usr = msg_user(msg); tipc_printf(buf, KERN_DEBUG); tipc_printf(buf, str); switch (usr) { case MSG_BUNDLER: tipc_printf(buf, "BNDL::"); tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg)); break; case BCAST_PROTOCOL: tipc_printf(buf, "BCASTP::"); break; case MSG_FRAGMENTER: tipc_printf(buf, "FRAGM::"); switch (msg_type(msg)) { case FIRST_FRAGMENT: tipc_printf(buf, "FIRST:"); break; case FRAGMENT: tipc_printf(buf, "BODY:"); break; case LAST_FRAGMENT: tipc_printf(buf, "LAST:"); break; default: tipc_printf(buf, "UNKNOWN:%x", msg_type(msg)); } tipc_printf(buf, "NO(%u/%u):", msg_long_msgno(msg), msg_fragm_no(msg)); break; case TIPC_LOW_IMPORTANCE: case TIPC_MEDIUM_IMPORTANCE: case TIPC_HIGH_IMPORTANCE: case TIPC_CRITICAL_IMPORTANCE: tipc_printf(buf, "DAT%u:", msg_user(msg)); if (msg_short(msg)) { tipc_printf(buf, "CON:"); break; } switch (msg_type(msg)) { case TIPC_CONN_MSG: tipc_printf(buf, "CON:"); break; case TIPC_MCAST_MSG: tipc_printf(buf, "MCST:"); break; case TIPC_NAMED_MSG: tipc_printf(buf, "NAM:"); break; case TIPC_DIRECT_MSG: tipc_printf(buf, "DIR:"); break; default: tipc_printf(buf, "UNKNOWN TYPE %u", msg_type(msg)); } if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case NAME_DISTRIBUTOR: tipc_printf(buf, "NMD::"); switch (msg_type(msg)) { case PUBLICATION: tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20); /* Items */ break; case WITHDRAWAL: tipc_printf(buf, "WDRW:"); break; default: tipc_printf(buf, "UNKNOWN:%x", msg_type(msg)); } if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case CONN_MANAGER: tipc_printf(buf, "CONN_MNG:"); switch (msg_type(msg)) { case CONN_PROBE: tipc_printf(buf, "PROBE:"); break; case CONN_PROBE_REPLY: tipc_printf(buf, "PROBE_REPLY:"); break; case CONN_ACK: tipc_printf(buf, "CONN_ACK:"); tipc_printf(buf, "ACK(%u):", msg_msgcnt(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); } if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case LINK_PROTOCOL: switch (msg_type(msg)) { case STATE_MSG: tipc_printf(buf, "STATE:"); tipc_printf(buf, "%s:", msg_probe(msg) ? "PRB" : ""); tipc_printf(buf, "NXS(%u):", msg_next_sent(msg)); tipc_printf(buf, "GAP(%u):", msg_seq_gap(msg)); tipc_printf(buf, "LSTBC(%u):", msg_last_bcast(msg)); break; case RESET_MSG: tipc_printf(buf, "RESET:"); if (msg_size(msg) != msg_hdr_sz(msg)) tipc_printf(buf, "BEAR:%s:", msg_data(msg)); break; case ACTIVATE_MSG: tipc_printf(buf, "ACTIVATE:"); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); } tipc_printf(buf, "PLANE(%c):", msg_net_plane(msg)); tipc_printf(buf, "SESS(%u):", msg_session(msg)); break; case CHANGEOVER_PROTOCOL: tipc_printf(buf, "TUNL:"); switch (msg_type(msg)) { case DUPLICATE_MSG: tipc_printf(buf, "DUPL:"); break; case ORIGINAL_MSG: tipc_printf(buf, "ORIG:"); tipc_printf(buf, "EXP(%u)", msg_msgcnt(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x", msg_type(msg)); } break; case LINK_CONFIG: tipc_printf(buf, "CFG:"); switch (msg_type(msg)) { case DSC_REQ_MSG: tipc_printf(buf, "DSC_REQ:"); break; case DSC_RESP_MSG: tipc_printf(buf, "DSC_RESP:"); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x:", msg_type(msg)); break; } break; default: tipc_printf(buf, "UNKNOWN USER:"******"NO_NAME:"); break; case TIPC_ERR_NO_PORT: tipc_printf(buf, "NO_PORT:"); break; case TIPC_ERR_NO_NODE: tipc_printf(buf, "NO_PROC:"); break; case TIPC_ERR_OVERLOAD: tipc_printf(buf, "OVERLOAD:"); break; case TIPC_CONN_SHUTDOWN: tipc_printf(buf, "SHUTDOWN:"); break; default: tipc_printf(buf, "UNKNOWN ERROR(%x):", msg_errcode(msg)); } default: break; } tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg
void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str) { u32 usr = msg_user(msg); tipc_printf(buf, str); switch (usr) { case MSG_BUNDLER: tipc_printf(buf, "BNDL::"); tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg)); break; case BCAST_PROTOCOL: tipc_printf(buf, "BCASTP::"); break; case MSG_FRAGMENTER: tipc_printf(buf, "FRAGM::"); switch (msg_type(msg)) { case FIRST_FRAGMENT: tipc_printf(buf, "FIRST:"); break; case FRAGMENT: tipc_printf(buf, "BODY:"); break; case LAST_FRAGMENT: tipc_printf(buf, "LAST:"); break; default: tipc_printf(buf, "UNKNOWN:%x",msg_type(msg)); } tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg), msg_fragm_no(msg)); break; case TIPC_LOW_IMPORTANCE: case TIPC_MEDIUM_IMPORTANCE: case TIPC_HIGH_IMPORTANCE: case TIPC_CRITICAL_IMPORTANCE: tipc_printf(buf, "DAT%u:", msg_user(msg)); if (msg_short(msg)) { tipc_printf(buf, "CON:"); break; } switch (msg_type(msg)) { case TIPC_CONN_MSG: tipc_printf(buf, "CON:"); break; case TIPC_MCAST_MSG: tipc_printf(buf, "MCST:"); break; case TIPC_NAMED_MSG: tipc_printf(buf, "NAM:"); break; case TIPC_DIRECT_MSG: tipc_printf(buf, "DIR:"); break; default: tipc_printf(buf, "UNKNOWN TYPE %u",msg_type(msg)); } if (msg_routed(msg) && !msg_non_seq(msg)) tipc_printf(buf, "ROUT:"); if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case NAME_DISTRIBUTOR: tipc_printf(buf, "NMD::"); switch (msg_type(msg)) { case PUBLICATION: tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20); /* Items */ break; case WITHDRAWAL: tipc_printf(buf, "WDRW:"); break; default: tipc_printf(buf, "UNKNOWN:%x",msg_type(msg)); } if (msg_routed(msg)) tipc_printf(buf, "ROUT:"); if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):", msg_reroute_cnt(msg)); break; case CONN_MANAGER: tipc_printf(buf, "CONN_MNG:"); switch (msg_type(msg)) { case CONN_PROBE: tipc_printf(buf, "PROBE:"); break; case CONN_PROBE_REPLY: tipc_printf(buf, "PROBE_REPLY:"); break; case CONN_ACK: tipc_printf(buf, "CONN_ACK:"); tipc_printf(buf, "ACK(%u):",msg_msgcnt(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); } if (msg_routed(msg)) tipc_printf(buf, "ROUT:"); if (msg_reroute_cnt(msg)) tipc_printf(buf, "REROUTED(%u):",msg_reroute_cnt(msg)); break; case LINK_PROTOCOL: tipc_printf(buf, "PROT:TIM(%u):",msg_timestamp(msg)); switch (msg_type(msg)) { case STATE_MSG: tipc_printf(buf, "STATE:"); tipc_printf(buf, "%s:",msg_probe(msg) ? "PRB" :""); tipc_printf(buf, "NXS(%u):",msg_next_sent(msg)); tipc_printf(buf, "GAP(%u):",msg_seq_gap(msg)); tipc_printf(buf, "LSTBC(%u):",msg_last_bcast(msg)); break; case RESET_MSG: tipc_printf(buf, "RESET:"); if (msg_size(msg) != msg_hdr_sz(msg)) tipc_printf(buf, "BEAR:%s:",msg_data(msg)); break; case ACTIVATE_MSG: tipc_printf(buf, "ACTIVATE:"); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); } tipc_printf(buf, "PLANE(%c):",msg_net_plane(msg)); tipc_printf(buf, "SESS(%u):",msg_session(msg)); break; case CHANGEOVER_PROTOCOL: tipc_printf(buf, "TUNL:"); switch (msg_type(msg)) { case DUPLICATE_MSG: tipc_printf(buf, "DUPL:"); break; case ORIGINAL_MSG: tipc_printf(buf, "ORIG:"); tipc_printf(buf, "EXP(%u)",msg_msgcnt(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); } break; case ROUTE_DISTRIBUTOR: tipc_printf(buf, "ROUTING_MNG:"); switch (msg_type(msg)) { case EXT_ROUTING_TABLE: tipc_printf(buf, "EXT_TBL:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; case LOCAL_ROUTING_TABLE: tipc_printf(buf, "LOCAL_TBL:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; case SLAVE_ROUTING_TABLE: tipc_printf(buf, "DP_TBL:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; case ROUTE_ADDITION: tipc_printf(buf, "ADD:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; case ROUTE_REMOVAL: tipc_printf(buf, "REMOVE:"); tipc_printf(buf, "TO:%x:",msg_remote_node(msg)); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg)); } break; case LINK_CONFIG: tipc_printf(buf, "CFG:"); switch (msg_type(msg)) { case DSC_REQ_MSG: tipc_printf(buf, "DSC_REQ:"); break; case DSC_RESP_MSG: tipc_printf(buf, "DSC_RESP:"); break; default: tipc_printf(buf, "UNKNOWN TYPE:%x:",msg_type(msg)); break; } break; default: tipc_printf(buf, "UNKNOWN USER:"******"NO_NAME:"); break; case TIPC_ERR_NO_PORT: tipc_printf(buf, "NO_PORT:"); break; case TIPC_ERR_NO_NODE: tipc_printf(buf, "NO_PROC:"); break; case TIPC_ERR_OVERLOAD: tipc_printf(buf, "OVERLOAD:"); break; case TIPC_CONN_SHUTDOWN: tipc_printf(buf, "SHUTDOWN:"); break; default: tipc_printf(buf, "UNKNOWN ERROR(%x):", msg_errcode(msg)); } default:{} } tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg)); tipc_printf(buf, "SZ(%u):", msg_size(msg)); tipc_printf(buf, "SQNO(%u):", msg_seqno(msg)); if (msg_non_seq(msg)) tipc_printf(buf, "NOSEQ:"); else { tipc_printf(buf, "ACK(%u):", msg_ack(msg)); } tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg)); tipc_printf(buf, "PRND(%x)", msg_prevnode(msg)); if (msg_isdata(msg)) { if (msg_named(msg)) { tipc_printf(buf, "NTYP(%u):", msg_nametype(msg)); tipc_printf(buf, "NINST(%u)", msg_nameinst(msg)); } } if ((usr != LINK_PROTOCOL) && (usr != LINK_CONFIG) && (usr != MSG_BUNDLER)) { if (!msg_short(msg)) { tipc_printf(buf, ":ORIG(%x:%u):", msg_orignode(msg), msg_origport(msg)); tipc_printf(buf, ":DEST(%x:%u):", msg_destnode(msg), msg_destport(msg)); } else { tipc_printf(buf, ":OPRT(%u):", msg_origport(msg)); tipc_printf(buf, ":DPRT(%u):", msg_destport(msg)); } if (msg_routed(msg) && !msg_non_seq(msg)) tipc_printf(buf, ":TSEQN(%u)", msg_transp_seqno(msg)); } if (msg_user(msg) == NAME_DISTRIBUTOR) { tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg)); tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg)); if (msg_routed(msg)) { tipc_printf(buf, ":CSEQN(%u)", msg_transp_seqno(msg)); } } if (msg_user(msg) == LINK_CONFIG) { u32* raw = (u32*)msg; struct tipc_media_addr* orig = (struct tipc_media_addr*)&raw[5]; tipc_printf(buf, ":REQL(%u):", msg_req_links(msg)); tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg)); tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg)); tipc_media_addr_printf(buf, orig); } if (msg_user(msg) == BCAST_PROTOCOL) { tipc_printf(buf, "BCNACK:AFTER(%u):", msg_bcgap_after(msg)); tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg)); } tipc_printf(buf, "\n"); if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) { tipc_msg_print(buf,msg_get_wrapped(msg)," /"); } if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) { tipc_msg_print(buf,msg_get_wrapped(msg)," /"); } }
/* tipc_send_msg - enqueue a send request */ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, struct tipc_bearer *b, struct tipc_media_addr *dest) { int ttl, err = 0; struct udp_bearer *ub; struct udp_media_addr *dst = (struct udp_media_addr *)&dest->value; struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value; struct rtable *rt; if (skb_headroom(skb) < UDP_MIN_HEADROOM) { err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC); if (err) goto tx_error; } skb_set_inner_protocol(skb, htons(ETH_P_TIPC)); ub = rcu_dereference_rtnl(b->media_ptr); if (!ub) { err = -ENODEV; goto tx_error; } if (dst->proto == htons(ETH_P_IP)) { struct flowi4 fl = { .daddr = dst->ipv4.s_addr, .saddr = src->ipv4.s_addr, .flowi4_mark = skb->mark, .flowi4_proto = IPPROTO_UDP }; rt = ip_route_output_key(net, &fl); if (IS_ERR(rt)) { err = PTR_ERR(rt); goto tx_error; } ttl = ip4_dst_hoplimit(&rt->dst); err = udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr, dst->ipv4.s_addr, 0, ttl, 0, src->udp_port, dst->udp_port, false, true); if (err < 0) { ip_rt_put(rt); goto tx_error; } #if IS_ENABLED(CONFIG_IPV6) } else { struct dst_entry *ndst; struct flowi6 fl6 = { .flowi6_oif = ub->ifindex, .daddr = dst->ipv6, .saddr = src->ipv6, .flowi6_proto = IPPROTO_UDP }; err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk, &ndst, &fl6); if (err) goto tx_error; ttl = ip6_dst_hoplimit(ndst); err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, ndst->dev, &src->ipv6, &dst->ipv6, 0, ttl, src->udp_port, dst->udp_port, false); #endif } return err; tx_error: kfree_skb(skb); return err; } /* tipc_udp_recv - read data from bearer socket */ static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb) { struct udp_bearer *ub; struct tipc_bearer *b; int usr = msg_user(buf_msg(skb)); if ((usr == LINK_PROTOCOL) || (usr == NAME_DISTRIBUTOR)) skb_linearize(skb); ub = rcu_dereference_sk_user_data(sk); if (!ub) { pr_err_ratelimited("Failed to get UDP bearer reference"); kfree_skb(skb); return 0; } skb_pull(skb, sizeof(struct udphdr)); rcu_read_lock(); b = rcu_dereference_rtnl(ub->bearer); if (b) { tipc_rcv(sock_net(sk), skb, b); rcu_read_unlock(); return 0; } rcu_read_unlock(); kfree_skb(skb); return 0; } static int enable_mcast(struct udp_bearer *ub, struct udp_media_addr *remote) { int err = 0; struct ip_mreqn mreqn; struct sock *sk = ub->ubsock->sk; if (ntohs(remote->proto) == ETH_P_IP) { if (!ipv4_is_multicast(remote->ipv4.s_addr)) return 0; mreqn.imr_multiaddr = remote->ipv4; mreqn.imr_ifindex = ub->ifindex; err = ip_mc_join_group(sk, &mreqn); #if IS_ENABLED(CONFIG_IPV6) } else { if (!ipv6_addr_is_multicast(&remote->ipv6)) return 0; err = ipv6_stub->ipv6_sock_mc_join(sk, ub->ifindex, &remote->ipv6); #endif } return err; }
void tipc_bclink_recv_pkt(struct sk_buff *buf) { #if (TIPC_BCAST_LOSS_RATE) static int rx_count = 0; #endif struct tipc_msg *msg = buf_msg(buf); struct tipc_node* node = tipc_node_find(msg_prevnode(msg)); u32 next_in; u32 seqno; struct sk_buff *deferred; msg_dbg(msg, "<BC<<<"); if (unlikely(!node || !tipc_node_is_up(node) || !node->bclink.supported || (msg_mc_netid(msg) != tipc_net_id))) { buf_discard(buf); return; } if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) { msg_dbg(msg, "<BCNACK<<<"); if (msg_destnode(msg) == tipc_own_addr) { tipc_node_lock(node); tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); tipc_node_unlock(node); spin_lock_bh(&bc_lock); bcl->stats.recv_nacks++; bcl->owner->next = node; /* remember requestor */ bclink_retransmit_pkt(msg_bcgap_after(msg), msg_bcgap_to(msg)); bcl->owner->next = NULL; spin_unlock_bh(&bc_lock); } else { tipc_bclink_peek_nack(msg_destnode(msg), msg_bcast_tag(msg), msg_bcgap_after(msg), msg_bcgap_to(msg)); } buf_discard(buf); return; } #if (TIPC_BCAST_LOSS_RATE) if (++rx_count == TIPC_BCAST_LOSS_RATE) { rx_count = 0; buf_discard(buf); return; } #endif tipc_node_lock(node); receive: deferred = node->bclink.deferred_head; next_in = mod(node->bclink.last_in + 1); seqno = msg_seqno(msg); if (likely(seqno == next_in)) { bcl->stats.recv_info++; node->bclink.last_in++; bclink_set_gap(node); if (unlikely(bclink_ack_allowed(seqno))) { bclink_send_ack(node); bcl->stats.sent_acks++; } if (likely(msg_isdata(msg))) { tipc_node_unlock(node); tipc_port_recv_mcast(buf, NULL); } else if (msg_user(msg) == MSG_BUNDLER) { bcl->stats.recv_bundles++; bcl->stats.recv_bundled += msg_msgcnt(msg); tipc_node_unlock(node); tipc_link_recv_bundle(buf); } else if (msg_user(msg) == MSG_FRAGMENTER) { bcl->stats.recv_fragments++; if (tipc_link_recv_fragment(&node->bclink.defragm, &buf, &msg)) bcl->stats.recv_fragmented++; tipc_node_unlock(node); tipc_net_route_msg(buf); } else { tipc_node_unlock(node); tipc_net_route_msg(buf); } if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) { tipc_node_lock(node); buf = deferred; msg = buf_msg(buf); node->bclink.deferred_head = deferred->next; goto receive; } return; } else if (less(next_in, seqno)) { u32 gap_after = node->bclink.gap_after; u32 gap_to = node->bclink.gap_to; if (tipc_link_defer_pkt(&node->bclink.deferred_head, &node->bclink.deferred_tail, buf)) { node->bclink.nack_sync++; bcl->stats.deferred_recv++; if (seqno == mod(gap_after + 1)) node->bclink.gap_after = seqno; else if (less(gap_after, seqno) && less(seqno, gap_to)) node->bclink.gap_to = seqno; } if (bclink_ack_allowed(node->bclink.nack_sync)) { if (gap_to != gap_after) bclink_send_nack(node); bclink_set_gap(node); } } else { bcl->stats.duplicates++; buf_discard(buf); } tipc_node_unlock(node); }
void tipc_bclink_recv_pkt(struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); struct tipc_node *node; u32 next_in; u32 seqno; struct sk_buff *deferred; /* Screen out unwanted broadcast messages */ if (msg_mc_netid(msg) != tipc_net_id) goto exit; node = tipc_node_find(msg_prevnode(msg)); if (unlikely(!node)) goto exit; tipc_node_lock(node); if (unlikely(!node->bclink.supported)) goto unlock; if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) { if (msg_type(msg) != STATE_MSG) goto unlock; if (msg_destnode(msg) == tipc_own_addr) { tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); tipc_node_unlock(node); spin_lock_bh(&bc_lock); bcl->stats.recv_nacks++; bclink->retransmit_to = node; bclink_retransmit_pkt(msg_bcgap_after(msg), msg_bcgap_to(msg)); spin_unlock_bh(&bc_lock); } else { tipc_node_unlock(node); tipc_bclink_peek_nack(msg_destnode(msg), msg_bcast_tag(msg), msg_bcgap_after(msg), msg_bcgap_to(msg)); } goto exit; } /* Handle in-sequence broadcast message */ receive: next_in = mod(node->bclink.last_in + 1); seqno = msg_seqno(msg); if (likely(seqno == next_in)) { bcl->stats.recv_info++; node->bclink.last_in++; bclink_set_gap(node); if (unlikely(bclink_ack_allowed(seqno))) { bclink_send_ack(node); bcl->stats.sent_acks++; } if (likely(msg_isdata(msg))) { tipc_node_unlock(node); if (likely(msg_mcast(msg))) tipc_port_recv_mcast(buf, NULL); else buf_discard(buf); } else if (msg_user(msg) == MSG_BUNDLER) { bcl->stats.recv_bundles++; bcl->stats.recv_bundled += msg_msgcnt(msg); tipc_node_unlock(node); tipc_link_recv_bundle(buf); } else if (msg_user(msg) == MSG_FRAGMENTER) { bcl->stats.recv_fragments++; if (tipc_link_recv_fragment(&node->bclink.defragm, &buf, &msg)) bcl->stats.recv_fragmented++; tipc_node_unlock(node); tipc_net_route_msg(buf); } else if (msg_user(msg) == NAME_DISTRIBUTOR) { tipc_node_unlock(node); tipc_named_recv(buf); } else { tipc_node_unlock(node); buf_discard(buf); } buf = NULL; tipc_node_lock(node); deferred = node->bclink.deferred_head; if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) { buf = deferred; msg = buf_msg(buf); node->bclink.deferred_head = deferred->next; goto receive; } } else if (less(next_in, seqno)) { u32 gap_after = node->bclink.gap_after; u32 gap_to = node->bclink.gap_to; if (tipc_link_defer_pkt(&node->bclink.deferred_head, &node->bclink.deferred_tail, buf)) { node->bclink.nack_sync++; bcl->stats.deferred_recv++; if (seqno == mod(gap_after + 1)) node->bclink.gap_after = seqno; else if (less(gap_after, seqno) && less(seqno, gap_to)) node->bclink.gap_to = seqno; } buf = NULL; if (bclink_ack_allowed(node->bclink.nack_sync)) { if (gap_to != gap_after) bclink_send_nack(node); bclink_set_gap(node); } } else { bcl->stats.duplicates++; } unlock: tipc_node_unlock(node); exit: buf_discard(buf); }