{
struct tipc_node *n_ptr;
struct tipc_link *link;
- struct tipc_media_addr media_addr, *addr;
+ struct tipc_media_addr media_addr;
struct sk_buff *rbuf;
struct tipc_msg *msg = buf_msg(buf);
u32 dest = msg_dest_domain(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));
buf_discard(buf);
- /* Validate discovery message from requesting node */
+ /* Ensure message from node is valid and communication is permitted */
if (net_id != tipc_net_id)
return;
if (media_addr.broadcast)
}
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));
- /* Create a link endpoint for this bearer, if necessary */
- if (!link) {
- link = tipc_link_create(n_ptr, b_ptr, &media_addr);
- if (!link) {
+ /*
+ * 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;
}
/*
* 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)) {
+
+ 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;
}
- 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 */
- n_ptr->signature = signature;
link_fully_up = link_working_working(link);
if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) {