diff options
Diffstat (limited to 'net/tipc/node.c')
| -rw-r--r-- | net/tipc/node.c | 85 | 
1 files changed, 78 insertions, 7 deletions
diff --git a/net/tipc/node.c b/net/tipc/node.c index 7b0c99347406..4a95c8c155c6 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -115,6 +115,7 @@ struct tipc_node {  	u16 capabilities;  	u32 signature;  	u32 link_id; +	u8 peer_id[16];  	struct list_head publ_list;  	struct list_head conn_sks;  	unsigned long keepalive_intv; @@ -156,6 +157,7 @@ static void tipc_node_delete(struct tipc_node *node);  static void tipc_node_timeout(struct timer_list *t);  static void tipc_node_fsm_evt(struct tipc_node *n, int evt);  static struct tipc_node *tipc_node_find(struct net *net, u32 addr); +static struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id);  static void tipc_node_put(struct tipc_node *node);  static bool node_is_up(struct tipc_node *n); @@ -245,6 +247,30 @@ static struct tipc_node *tipc_node_find(struct net *net, u32 addr)  	return node;  } +/* tipc_node_find_by_id - locate specified node object by its 128-bit id + * Note: this function is called only when a discovery request failed + * to find the node by its 32-bit id, and is not time critical + */ +static struct tipc_node *tipc_node_find_by_id(struct net *net, u8 *id) +{ +	struct tipc_net *tn = tipc_net(net); +	struct tipc_node *n; +	bool found = false; + +	rcu_read_lock(); +	list_for_each_entry_rcu(n, &tn->node_list, list) { +		read_lock_bh(&n->lock); +		if (!memcmp(id, n->peer_id, 16) && +		    kref_get_unless_zero(&n->kref)) +			found = true; +		read_unlock_bh(&n->lock); +		if (found) +			break; +	} +	rcu_read_unlock(); +	return found ? n : NULL; +} +  static void tipc_node_read_lock(struct tipc_node *n)  {  	read_lock_bh(&n->lock); @@ -307,7 +333,8 @@ static void tipc_node_write_unlock(struct tipc_node *n)  	}  } -struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities) +struct tipc_node *tipc_node_create(struct net *net, u32 addr, +				   u8 *peer_id, u16 capabilities)  {  	struct tipc_net *tn = net_generic(net, tipc_net_id);  	struct tipc_node *n, *temp_node; @@ -326,6 +353,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities)  		goto exit;  	}  	n->addr = addr; +	memcpy(&n->peer_id, peer_id, 16);  	n->net = net;  	n->capabilities = capabilities;  	kref_init(&n->kref); @@ -344,8 +372,8 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities)  	n->signature = INVALID_NODE_SIG;  	n->active_links[0] = INVALID_BEARER_ID;  	n->active_links[1] = INVALID_BEARER_ID; -	if (!tipc_link_bc_create(net, tipc_own_addr(net), n->addr, -				 U16_MAX, +	if (!tipc_link_bc_create(net, tipc_own_addr(net), +				 addr, U16_MAX,  				 tipc_link_window(tipc_bc_sndlink(net)),  				 n->capabilities,  				 &n->bc_entry.inputq1, @@ -735,8 +763,51 @@ bool tipc_node_is_up(struct net *net, u32 addr)  	return retval;  } -void tipc_node_check_dest(struct net *net, u32 onode, -			  struct tipc_bearer *b, +static u32 tipc_node_suggest_addr(struct net *net, u32 addr) +{ +	struct tipc_node *n; + +	addr ^= tipc_net(net)->random; +	while ((n = tipc_node_find(net, addr))) { +		tipc_node_put(n); +		addr++; +	} +	return addr; +} + +/* tipc_node_try_addr(): Check if addr can be used by peer, suggest other if not + */ +u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr) +{ +	struct tipc_net *tn = tipc_net(net); +	struct tipc_node *n; + +	/* Suggest new address if some other peer is using this one */ +	n = tipc_node_find(net, addr); +	if (n) { +		if (!memcmp(n->peer_id, id, NODE_ID_LEN)) +			addr = 0; +		tipc_node_put(n); +		if (!addr) +			return 0; +		return tipc_node_suggest_addr(net, addr); +	} + +	/* Suggest previously used address if peer is known */ +	n = tipc_node_find_by_id(net, id); +	if (n) { +		addr = n->addr; +		tipc_node_put(n); +	} +	/* Even this node may be in trial phase */ +	if (tn->trial_addr == addr) +		return tipc_node_suggest_addr(net, addr); + +	return addr; +} + +void tipc_node_check_dest(struct net *net, u32 addr, +			  u8 *peer_id, struct tipc_bearer *b,  			  u16 capabilities, u32 signature,  			  struct tipc_media_addr *maddr,  			  bool *respond, bool *dupl_addr) @@ -755,7 +826,7 @@ void tipc_node_check_dest(struct net *net, u32 onode,  	*dupl_addr = false;  	*respond = false; -	n = tipc_node_create(net, onode, capabilities); +	n = tipc_node_create(net, addr, peer_id, capabilities);  	if (!n)  		return; @@ -840,7 +911,7 @@ void tipc_node_check_dest(struct net *net, u32 onode,  		if (!tipc_link_create(net, if_name, b->identity, b->tolerance,  				      b->net_plane, b->mtu, b->priority,  				      b->window, mod(tipc_net(net)->random), -				      tipc_own_addr(net), onode, +				      tipc_own_addr(net), addr, peer_id,  				      n->capabilities,  				      tipc_bc_sndlink(n->net), n->bc_entry.link,  				      &le->inputq,  | 
