/** * tipc_disc_rcv - handle incoming discovery message (request or response) * @net: the applicable net namespace * @buf: buffer containing message * @bearer: bearer that message arrived on */ void tipc_disc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *bearer) { struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_media_addr maddr; struct sk_buff *rskb; struct tipc_msg *hdr = buf_msg(skb); u32 ddom = msg_dest_domain(hdr); u32 onode = msg_prevnode(hdr); u32 net_id = msg_bc_netid(hdr); u32 mtyp = msg_type(hdr); u32 signature = msg_node_sig(hdr); u16 caps = msg_node_capabilities(hdr); bool respond = false; bool dupl_addr = false; int err; err = bearer->media->msg2addr(bearer, &maddr, msg_media_addr(hdr)); kfree_skb(skb); if (err) return; /* Ensure message from node is valid and communication is permitted */ if (net_id != tn->net_id) return; if (maddr.broadcast) return; if (!tipc_addr_domain_valid(ddom)) return; if (!tipc_addr_node_valid(onode)) return; if (in_own_node(net, onode)) { if (memcmp(&maddr, &bearer->addr, sizeof(maddr))) disc_dupl_alert(bearer, tn->own_addr, &maddr); return; } if (!tipc_in_scope(ddom, tn->own_addr)) return; if (!tipc_in_scope(bearer->domain, onode)) return; tipc_node_check_dest(net, onode, bearer, caps, signature, &maddr, &respond, &dupl_addr); if (dupl_addr) disc_dupl_alert(bearer, onode, &maddr); /* Send response, if necessary */ if (respond && (mtyp == DSC_REQ_MSG)) { rskb = tipc_buf_acquire(MAX_H_SIZE, GFP_ATOMIC); if (!rskb) return; tipc_disc_init_msg(net, rskb, DSC_RESP_MSG, bearer); tipc_bearer_xmit_skb(net, bearer->identity, rskb, &maddr); } }
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); }