diff options
Diffstat (limited to 'net/tipc/discover.c')
| -rw-r--r-- | net/tipc/discover.c | 79 | 
1 files changed, 63 insertions, 16 deletions
diff --git a/net/tipc/discover.c b/net/tipc/discover.c index a00e5f81156..c630a21b2be 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -82,6 +82,7 @@ static struct sk_buff *tipc_disc_init_msg(u32 type,  		msg = buf_msg(buf);  		tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);  		msg_set_non_seq(msg, 1); +		msg_set_node_sig(msg, tipc_random);  		msg_set_dest_domain(msg, dest_domain);  		msg_set_bc_netid(msg, tipc_net_id);  		b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg)); @@ -121,20 +122,22 @@ 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 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)); -	buf_discard(buf); +	kfree_skb(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) @@ -162,15 +165,50 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)  	}  	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;  	}  	/* @@ -183,17 +221,26 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)  	 * 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 */ @@ -203,7 +250,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)  		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); +			kfree_skb(rbuf);  		}  	} @@ -349,7 +396,7 @@ void tipc_disc_delete(struct tipc_link_req *req)  {  	k_cancel_timer(&req->timer);  	k_term_timer(&req->timer); -	buf_discard(req->buf); +	kfree_skb(req->buf);  	kfree(req);  }  | 
