static void bclink_peek_nack(struct tipc_msg *msg) { struct tipc_node *n_ptr = tipc_node_find(msg_destnode(msg)); if (unlikely(!n_ptr)) return; tipc_node_lock(n_ptr); if (n_ptr->bclink.supported && (n_ptr->bclink.last_in != n_ptr->bclink.last_sent) && (n_ptr->bclink.last_in == msg_bcgap_after(msg))) n_ptr->bclink.oos_state = 2; tipc_node_unlock(n_ptr); }
void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr, void *usr_handle, net_ev_handler handle_down) { if (addr == tipc_own_addr) { node_sub->node = NULL; return; } node_sub->node = tipc_node_find(addr); if (!node_sub->node) { warn("Node subscription rejected, unknown node 0x%x\n", addr); return; } node_sub->handle_node_down = handle_down; node_sub->usr_handle = usr_handle; tipc_node_lock(node_sub->node); list_add_tail(&node_sub->nodesub_list, &node_sub->node->nsub); tipc_node_unlock(node_sub->node); }
/** * 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_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) { struct tipc_node *n_ptr; struct tipc_link *link; struct tipc_media_addr media_addr; struct sk_buff *rbuf; struct tipc_msg *msg = buf_msg(buf); u32 dest = msg_dest_domain(msg); u32 orig = msg_prevnode(msg); u32 net_id = msg_bc_netid(msg); u32 type = msg_type(msg); u32 signature = msg_node_sig(msg); int addr_mismatch; int link_fully_up; media_addr.broadcast = 1; b_ptr->media->msg2addr(&media_addr, msg_media_addr(msg)); kfree_skb(buf); /* Ensure message from node is valid and communication is permitted */ if (net_id != tipc_net_id) return; if (media_addr.broadcast) return; if (!tipc_addr_domain_valid(dest)) return; if (!tipc_addr_node_valid(orig)) return; if (orig == tipc_own_addr) { if (memcmp(&media_addr, &b_ptr->addr, sizeof(media_addr))) disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr); return; } if (!tipc_in_scope(dest, tipc_own_addr)) return; if (!tipc_in_scope(b_ptr->link_req->domain, orig)) return; /* Locate structure corresponding to requesting node */ n_ptr = tipc_node_find(orig); if (!n_ptr) { n_ptr = tipc_node_create(orig); if (!n_ptr) return; } tipc_node_lock(n_ptr); /* Prepare to validate requesting node's signature and media address */ link = n_ptr->links[b_ptr->identity]; addr_mismatch = (link != NULL) && memcmp(&link->media_addr, &media_addr, sizeof(media_addr)); /* * Ensure discovery message's signature is correct * * If signature is incorrect and there is no working link to the node, * accept the new signature but invalidate all existing links to the * node so they won't re-activate without a new discovery message. * * If signature is incorrect and the requested link to the node is * working, accept the new signature. (This is an instance of delayed * rediscovery, where a link endpoint was able to re-establish contact * with its peer endpoint on a node that rebooted before receiving a * discovery message from that node.) * * If signature is incorrect and there is a working link to the node * that is not the requested link, reject the request (must be from * a duplicate node). */ if (signature != n_ptr->signature) { if (n_ptr->working_links == 0) { struct tipc_link *curr_link; int i; for (i = 0; i < MAX_BEARERS; i++) { curr_link = n_ptr->links[i]; if (curr_link) { memset(&curr_link->media_addr, 0, sizeof(media_addr)); tipc_link_reset(curr_link); } } addr_mismatch = (link != NULL); } else if (tipc_link_is_up(link) && !addr_mismatch) { /* delayed rediscovery */ } else { disc_dupl_alert(b_ptr, orig, &media_addr); tipc_node_unlock(n_ptr); return; } n_ptr->signature = signature; } /* * Ensure requesting node's media address is correct * * If media address doesn't match and the link is working, reject the * request (must be from a duplicate node). * * If media address doesn't match and the link is not working, accept * the new media address and reset the link to ensure it starts up * cleanly. */ if (addr_mismatch) { if (tipc_link_is_up(link)) { disc_dupl_alert(b_ptr, orig, &media_addr); tipc_node_unlock(n_ptr); return; } else { memcpy(&link->media_addr, &media_addr, sizeof(media_addr)); tipc_link_reset(link); } } /* Create a link endpoint for this bearer, if necessary */ if (!link) { link = tipc_link_create(n_ptr, b_ptr, &media_addr); if (!link) { tipc_node_unlock(n_ptr); return; } } /* Accept discovery message & send response, if necessary */ link_fully_up = link_working_working(link); if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); if (rbuf) { b_ptr->media->send_msg(rbuf, b_ptr, &media_addr); kfree_skb(rbuf); } } tipc_node_unlock(n_ptr); }
void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) { struct tipc_node *n_ptr; struct tipc_link *link; struct tipc_media_addr media_addr, *addr; struct sk_buff *rbuf; struct tipc_msg *msg = buf_msg(buf); u32 dest = msg_dest_domain(msg); u32 orig = msg_prevnode(msg); u32 net_id = msg_bc_netid(msg); u32 type = msg_type(msg); int link_fully_up; media_addr.broadcast = 1; b_ptr->media->msg2addr(&media_addr, msg_media_addr(msg)); buf_discard(buf); /* Validate discovery message from requesting node */ if (net_id != tipc_net_id) return; if (media_addr.broadcast) return; if (!tipc_addr_domain_valid(dest)) return; if (!tipc_addr_node_valid(orig)) return; if (orig == tipc_own_addr) { if (memcmp(&media_addr, &b_ptr->addr, sizeof(media_addr))) disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr); return; } if (!tipc_in_scope(dest, tipc_own_addr)) return; if (!tipc_in_scope(b_ptr->link_req->domain, orig)) return; /* Locate structure corresponding to requesting node */ n_ptr = tipc_node_find(orig); if (!n_ptr) { n_ptr = tipc_node_create(orig); if (!n_ptr) return; } tipc_node_lock(n_ptr); link = n_ptr->links[b_ptr->identity]; /* Create a link endpoint for this bearer, if necessary */ if (!link) { link = tipc_link_create(n_ptr, b_ptr, &media_addr); if (!link) { tipc_node_unlock(n_ptr); return; } } /* * Ensure requesting node's media address is correct * * If media address doesn't match and the link is working, reject the * request (must be from a duplicate node). * * If media address doesn't match and the link is not working, accept * the new media address and reset the link to ensure it starts up * cleanly. */ addr = &link->media_addr; if (memcmp(addr, &media_addr, sizeof(*addr))) { if (tipc_link_is_up(link) || (!link->started)) { disc_dupl_alert(b_ptr, orig, &media_addr); tipc_node_unlock(n_ptr); return; } warn("Resetting link <%s>, peer interface address changed\n", link->name); memcpy(addr, &media_addr, sizeof(*addr)); tipc_link_reset(link); } /* Accept discovery message & send response, if necessary */ link_fully_up = link_working_working(link); if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) { rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr); if (rbuf) { b_ptr->media->send_msg(rbuf, b_ptr, &media_addr); buf_discard(rbuf); } } tipc_node_unlock(n_ptr); }
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); }