diff options
Diffstat (limited to 'net/tipc/link.c')
| -rw-r--r-- | net/tipc/link.c | 881 | 
1 files changed, 283 insertions, 598 deletions
| diff --git a/net/tipc/link.c b/net/tipc/link.c index 23bcc1132365..a4cf364316de 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -40,7 +40,6 @@  #include "socket.h"  #include "name_distr.h"  #include "discover.h" -#include "config.h"  #include "netlink.h"  #include <linux/pkt_sched.h> @@ -101,19 +100,20 @@ static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {   */  #define START_CHANGEOVER 100000u -static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, -				       struct sk_buff *buf); -static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf); -static int  tipc_link_tunnel_rcv(struct tipc_node *n_ptr, -				 struct sk_buff **buf); -static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance); +static void link_handle_out_of_seq_msg(struct tipc_link *link, +				       struct sk_buff *skb); +static void tipc_link_proto_rcv(struct tipc_link *link, +				struct sk_buff *skb); +static int  tipc_link_tunnel_rcv(struct tipc_node *node, +				 struct sk_buff **skb); +static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol);  static void link_state_event(struct tipc_link *l_ptr, u32 event);  static void link_reset_statistics(struct tipc_link *l_ptr);  static void link_print(struct tipc_link *l_ptr, const char *str);  static void tipc_link_sync_xmit(struct tipc_link *l);  static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); -static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf); -static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf); +static void tipc_link_input(struct tipc_link *l, struct sk_buff *skb); +static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb);  /*   *  Simple link routines @@ -123,13 +123,30 @@ static unsigned int align(unsigned int i)  	return (i + 3) & ~3u;  } +static void tipc_link_release(struct kref *kref) +{ +	kfree(container_of(kref, struct tipc_link, ref)); +} + +static void tipc_link_get(struct tipc_link *l_ptr) +{ +	kref_get(&l_ptr->ref); +} + +static void tipc_link_put(struct tipc_link *l_ptr) +{ +	kref_put(&l_ptr->ref, tipc_link_release); +} +  static void link_init_max_pkt(struct tipc_link *l_ptr)  { +	struct tipc_node *node = l_ptr->owner; +	struct tipc_net *tn = net_generic(node->net, tipc_net_id);  	struct tipc_bearer *b_ptr;  	u32 max_pkt;  	rcu_read_lock(); -	b_ptr = rcu_dereference_rtnl(bearer_list[l_ptr->bearer_id]); +	b_ptr = rcu_dereference_rtnl(tn->bearer_list[l_ptr->bearer_id]);  	if (!b_ptr) {  		rcu_read_unlock();  		return; @@ -169,8 +186,9 @@ int tipc_link_is_active(struct tipc_link *l_ptr)   * link_timeout - handle expiration of link timer   * @l_ptr: pointer to link   */ -static void link_timeout(struct tipc_link *l_ptr) +static void link_timeout(unsigned long data)  { +	struct tipc_link *l_ptr = (struct tipc_link *)data;  	struct sk_buff *skb;  	tipc_node_lock(l_ptr->owner); @@ -215,11 +233,13 @@ static void link_timeout(struct tipc_link *l_ptr)  		tipc_link_push_packets(l_ptr);  	tipc_node_unlock(l_ptr->owner); +	tipc_link_put(l_ptr);  } -static void link_set_timer(struct tipc_link *l_ptr, u32 time) +static void link_set_timer(struct tipc_link *link, unsigned long time)  { -	k_start_timer(&l_ptr->timer, time); +	if (!mod_timer(&link->timer, jiffies + time)) +		tipc_link_get(link);  }  /** @@ -234,6 +254,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,  				   struct tipc_bearer *b_ptr,  				   const struct tipc_media_addr *media_addr)  { +	struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);  	struct tipc_link *l_ptr;  	struct tipc_msg *msg;  	char *if_name; @@ -259,12 +280,12 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,  		pr_warn("Link creation failed, no memory\n");  		return NULL;  	} - +	kref_init(&l_ptr->ref);  	l_ptr->addr = peer;  	if_name = strchr(b_ptr->name, ':') + 1;  	sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown", -		tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr), -		tipc_node(tipc_own_addr), +		tipc_zone(tn->own_addr), tipc_cluster(tn->own_addr), +		tipc_node(tn->own_addr),  		if_name,  		tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));  		/* note: peer i/f name is updated by reset/activate message */ @@ -278,9 +299,10 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,  	l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;  	msg = l_ptr->pmsg; -	tipc_msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr); +	tipc_msg_init(tn->own_addr, msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, +		      l_ptr->addr);  	msg_set_size(msg, sizeof(l_ptr->proto_msg)); -	msg_set_session(msg, (tipc_random & 0xffff)); +	msg_set_session(msg, (tn->random & 0xffff));  	msg_set_bearer_id(msg, b_ptr->identity);  	strcpy((char *)msg_data(msg), if_name); @@ -293,48 +315,52 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,  	l_ptr->next_out_no = 1;  	__skb_queue_head_init(&l_ptr->outqueue);  	__skb_queue_head_init(&l_ptr->deferred_queue); -	skb_queue_head_init(&l_ptr->waiting_sks); - +	skb_queue_head_init(&l_ptr->wakeupq); +	skb_queue_head_init(&l_ptr->inputq); +	skb_queue_head_init(&l_ptr->namedq);  	link_reset_statistics(l_ptr); -  	tipc_node_attach_link(n_ptr, l_ptr); - -	k_init_timer(&l_ptr->timer, (Handler)link_timeout, -		     (unsigned long)l_ptr); - +	setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr);  	link_state_event(l_ptr, STARTING_EVT);  	return l_ptr;  } -void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) +/** + * link_delete - Conditional deletion of link. + *               If timer still running, real delete is done when it expires + * @link: link to be deleted + */ +void tipc_link_delete(struct tipc_link *link) +{ +	tipc_link_reset_fragments(link); +	tipc_node_detach_link(link->owner, link); +	tipc_link_put(link); +} + +void tipc_link_delete_list(struct net *net, unsigned int bearer_id, +			   bool shutting_down)  { -	struct tipc_link *l_ptr; -	struct tipc_node *n_ptr; +	struct tipc_net *tn = net_generic(net, tipc_net_id); +	struct tipc_link *link; +	struct tipc_node *node;  	rcu_read_lock(); -	list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { -		tipc_node_lock(n_ptr); -		l_ptr = n_ptr->links[bearer_id]; -		if (l_ptr) { -			tipc_link_reset(l_ptr); -			if (shutting_down || !tipc_node_is_up(n_ptr)) { -				tipc_node_detach_link(l_ptr->owner, l_ptr); -				tipc_link_reset_fragments(l_ptr); -				tipc_node_unlock(n_ptr); - -				/* Nobody else can access this link now: */ -				del_timer_sync(&l_ptr->timer); -				kfree(l_ptr); -			} else { -				/* Detach/delete when failover is finished: */ -				l_ptr->flags |= LINK_STOPPED; -				tipc_node_unlock(n_ptr); -				del_timer_sync(&l_ptr->timer); -			} +	list_for_each_entry_rcu(node, &tn->node_list, list) { +		tipc_node_lock(node); +		link = node->links[bearer_id]; +		if (!link) { +			tipc_node_unlock(node);  			continue;  		} -		tipc_node_unlock(n_ptr); +		tipc_link_reset(link); +		if (del_timer(&link->timer)) +			tipc_link_put(link); +		link->flags |= LINK_STOPPED; +		/* Delete link now, or when failover is finished: */ +		if (shutting_down || !tipc_node_is_up(node)) +			tipc_link_delete(link); +		tipc_node_unlock(node);  	}  	rcu_read_unlock();  } @@ -352,13 +378,14 @@ static bool link_schedule_user(struct tipc_link *link, u32 oport,  {  	struct sk_buff *buf; -	buf = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, tipc_own_addr, -			      tipc_own_addr, oport, 0, 0); +	buf = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, +			      link_own_addr(link), link_own_addr(link), +			      oport, 0, 0);  	if (!buf)  		return false;  	TIPC_SKB_CB(buf)->chain_sz = chain_sz;  	TIPC_SKB_CB(buf)->chain_imp = imp; -	skb_queue_tail(&link->waiting_sks, buf); +	skb_queue_tail(&link->wakeupq, buf);  	link->stats.link_congs++;  	return true;  } @@ -369,17 +396,19 @@ static bool link_schedule_user(struct tipc_link *link, u32 oport,   * Move a number of waiting users, as permitted by available space in   * the send queue, from link wait queue to node wait queue for wakeup   */ -static void link_prepare_wakeup(struct tipc_link *link) +void link_prepare_wakeup(struct tipc_link *link)  {  	uint pend_qsz = skb_queue_len(&link->outqueue);  	struct sk_buff *skb, *tmp; -	skb_queue_walk_safe(&link->waiting_sks, skb, tmp) { +	skb_queue_walk_safe(&link->wakeupq, skb, tmp) {  		if (pend_qsz >= link->queue_limit[TIPC_SKB_CB(skb)->chain_imp])  			break;  		pend_qsz += TIPC_SKB_CB(skb)->chain_sz; -		skb_unlink(skb, &link->waiting_sks); -		skb_queue_tail(&link->owner->waiting_sks, skb); +		skb_unlink(skb, &link->wakeupq); +		skb_queue_tail(&link->inputq, skb); +		link->owner->inputq = &link->inputq; +		link->owner->action_flags |= TIPC_MSG_EVT;  	}  } @@ -425,20 +454,20 @@ void tipc_link_reset(struct tipc_link *l_ptr)  		return;  	tipc_node_link_down(l_ptr->owner, l_ptr); -	tipc_bearer_remove_dest(l_ptr->bearer_id, l_ptr->addr); +	tipc_bearer_remove_dest(owner->net, l_ptr->bearer_id, l_ptr->addr);  	if (was_active_link && tipc_node_active_links(l_ptr->owner)) {  		l_ptr->reset_checkpoint = checkpoint;  		l_ptr->exp_msg_count = START_CHANGEOVER;  	} -	/* Clean up all queues: */ +	/* Clean up all queues, except inputq: */  	__skb_queue_purge(&l_ptr->outqueue);  	__skb_queue_purge(&l_ptr->deferred_queue); -	if (!skb_queue_empty(&l_ptr->waiting_sks)) { -		skb_queue_splice_init(&l_ptr->waiting_sks, &owner->waiting_sks); -		owner->action_flags |= TIPC_WAKEUP_USERS; -	} +	skb_queue_splice_init(&l_ptr->wakeupq, &l_ptr->inputq); +	if (!skb_queue_empty(&l_ptr->inputq)) +		owner->action_flags |= TIPC_MSG_EVT; +	owner->inputq = &l_ptr->inputq;  	l_ptr->next_out = NULL;  	l_ptr->unacked_window = 0;  	l_ptr->checkpoint = 1; @@ -448,13 +477,14 @@ void tipc_link_reset(struct tipc_link *l_ptr)  	link_reset_statistics(l_ptr);  } -void tipc_link_reset_list(unsigned int bearer_id) +void tipc_link_reset_list(struct net *net, unsigned int bearer_id)  { +	struct tipc_net *tn = net_generic(net, tipc_net_id);  	struct tipc_link *l_ptr;  	struct tipc_node *n_ptr;  	rcu_read_lock(); -	list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { +	list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {  		tipc_node_lock(n_ptr);  		l_ptr = n_ptr->links[bearer_id];  		if (l_ptr) @@ -464,11 +494,14 @@ void tipc_link_reset_list(unsigned int bearer_id)  	rcu_read_unlock();  } -static void link_activate(struct tipc_link *l_ptr) +static void link_activate(struct tipc_link *link)  { -	l_ptr->next_in_no = l_ptr->stats.recv_info = 1; -	tipc_node_link_up(l_ptr->owner, l_ptr); -	tipc_bearer_add_dest(l_ptr->bearer_id, l_ptr->addr); +	struct tipc_node *node = link->owner; + +	link->next_in_no = 1; +	link->stats.recv_info = 1; +	tipc_node_link_up(node, link); +	tipc_bearer_add_dest(node->net, link->bearer_id, link->addr);  }  /** @@ -479,7 +512,7 @@ static void link_activate(struct tipc_link *l_ptr)  static void link_state_event(struct tipc_link *l_ptr, unsigned int event)  {  	struct tipc_link *other; -	u32 cont_intv = l_ptr->continuity_interval; +	unsigned long cont_intv = l_ptr->cont_intv;  	if (l_ptr->flags & LINK_STOPPED)  		return; @@ -522,8 +555,8 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)  			link_set_timer(l_ptr, cont_intv / 4);  			break;  		case RESET_MSG: -			pr_info("%s<%s>, requested by peer\n", link_rst_msg, -				l_ptr->name); +			pr_debug("%s<%s>, requested by peer\n", +				 link_rst_msg, l_ptr->name);  			tipc_link_reset(l_ptr);  			l_ptr->state = RESET_RESET;  			l_ptr->fsm_msg_cnt = 0; @@ -533,7 +566,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)  			link_set_timer(l_ptr, cont_intv);  			break;  		default: -			pr_err("%s%u in WW state\n", link_unk_evt, event); +			pr_debug("%s%u in WW state\n", link_unk_evt, event);  		}  		break;  	case WORKING_UNKNOWN: @@ -545,8 +578,8 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)  			link_set_timer(l_ptr, cont_intv);  			break;  		case RESET_MSG: -			pr_info("%s<%s>, requested by peer while probing\n", -				link_rst_msg, l_ptr->name); +			pr_debug("%s<%s>, requested by peer while probing\n", +				 link_rst_msg, l_ptr->name);  			tipc_link_reset(l_ptr);  			l_ptr->state = RESET_RESET;  			l_ptr->fsm_msg_cnt = 0; @@ -572,8 +605,8 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)  				l_ptr->fsm_msg_cnt++;  				link_set_timer(l_ptr, cont_intv / 4);  			} else {	/* Link has failed */ -				pr_warn("%s<%s>, peer not responding\n", -					link_rst_msg, l_ptr->name); +				pr_debug("%s<%s>, peer not responding\n", +					 link_rst_msg, l_ptr->name);  				tipc_link_reset(l_ptr);  				l_ptr->state = RESET_UNKNOWN;  				l_ptr->fsm_msg_cnt = 0; @@ -614,7 +647,9 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)  			break;  		case STARTING_EVT:  			l_ptr->flags |= LINK_STARTED; -			/* fall through */ +			l_ptr->fsm_msg_cnt++; +			link_set_timer(l_ptr, cont_intv); +			break;  		case TIMEOUT_EVT:  			tipc_link_proto_xmit(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);  			l_ptr->fsm_msg_cnt++; @@ -700,7 +735,8 @@ drop:   * Only the socket functions tipc_send_stream() and tipc_send_packet() need   * to act on the return value, since they may need to do more send attempts.   */ -int __tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list) +int __tipc_link_xmit(struct net *net, struct tipc_link *link, +		     struct sk_buff_head *list)  {  	struct tipc_msg *msg = buf_msg(skb_peek(list));  	uint psz = msg_size(msg); @@ -733,7 +769,8 @@ int __tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list)  		if (skb_queue_len(outqueue) < sndlim) {  			__skb_queue_tail(outqueue, skb); -			tipc_bearer_send(link->bearer_id, skb, addr); +			tipc_bearer_send(net, link->bearer_id, +					 skb, addr);  			link->next_out = NULL;  			link->unacked_window = 0;  		} else if (tipc_msg_bundle(outqueue, skb, mtu)) { @@ -758,7 +795,7 @@ int __tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list)  static void skb2list(struct sk_buff *skb, struct sk_buff_head *list)  { -	__skb_queue_head_init(list); +	skb_queue_head_init(list);  	__skb_queue_tail(list, skb);  } @@ -767,19 +804,21 @@ static int __tipc_link_xmit_skb(struct tipc_link *link, struct sk_buff *skb)  	struct sk_buff_head head;  	skb2list(skb, &head); -	return __tipc_link_xmit(link, &head); +	return __tipc_link_xmit(link->owner->net, link, &head);  } -int tipc_link_xmit_skb(struct sk_buff *skb, u32 dnode, u32 selector) +int tipc_link_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, +		       u32 selector)  {  	struct sk_buff_head head;  	skb2list(skb, &head); -	return tipc_link_xmit(&head, dnode, selector); +	return tipc_link_xmit(net, &head, dnode, selector);  }  /**   * tipc_link_xmit() is the general link level function for message sending + * @net: the applicable net namespace   * @list: chain of buffers containing message   * @dsz: amount of user data to be sent   * @dnode: address of destination node @@ -787,33 +826,28 @@ int tipc_link_xmit_skb(struct sk_buff *skb, u32 dnode, u32 selector)   * Consumes the buffer chain, except when returning -ELINKCONG   * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE   */ -int tipc_link_xmit(struct sk_buff_head *list, u32 dnode, u32 selector) +int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dnode, +		   u32 selector)  {  	struct tipc_link *link = NULL;  	struct tipc_node *node;  	int rc = -EHOSTUNREACH; -	node = tipc_node_find(dnode); +	node = tipc_node_find(net, dnode);  	if (node) {  		tipc_node_lock(node);  		link = node->active_links[selector & 1];  		if (link) -			rc = __tipc_link_xmit(link, list); +			rc = __tipc_link_xmit(net, link, list);  		tipc_node_unlock(node);  	} -  	if (link)  		return rc; -	if (likely(in_own_node(dnode))) { -		/* As a node local message chain never contains more than one -		 * buffer, we just need to dequeue one SKB buffer from the -		 * head list. -		 */ -		return tipc_sk_rcv(__skb_dequeue(list)); -	} -	__skb_queue_purge(list); +	if (likely(in_own_node(net, dnode))) +		return tipc_sk_rcv(net, list); +	__skb_queue_purge(list);  	return rc;  } @@ -835,7 +869,8 @@ static void tipc_link_sync_xmit(struct tipc_link *link)  		return;  	msg = buf_msg(skb); -	tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, link->addr); +	tipc_msg_init(link_own_addr(link), msg, BCAST_PROTOCOL, STATE_MSG, +		      INT_H_SIZE, link->addr);  	msg_set_last_bcast(msg, link->owner->bclink.acked);  	__tipc_link_xmit_skb(link, skb);  } @@ -890,7 +925,8 @@ void tipc_link_push_packets(struct tipc_link *l_ptr)  			msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);  			if (msg_user(msg) == MSG_BUNDLER)  				TIPC_SKB_CB(skb)->bundling = false; -			tipc_bearer_send(l_ptr->bearer_id, skb, +			tipc_bearer_send(l_ptr->owner->net, +					 l_ptr->bearer_id, skb,  					 &l_ptr->media_addr);  			l_ptr->next_out = tipc_skb_queue_next(outqueue, skb);  		} else { @@ -923,6 +959,7 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,  				    struct sk_buff *buf)  {  	struct tipc_msg *msg = buf_msg(buf); +	struct net *net = l_ptr->owner->net;  	pr_warn("Retransmission failure on link <%s>\n", l_ptr->name); @@ -940,7 +977,7 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,  		pr_cont("Outstanding acks: %lu\n",  			(unsigned long) TIPC_SKB_CB(buf)->handle); -		n_ptr = tipc_bclink_retransmit_to(); +		n_ptr = tipc_bclink_retransmit_to(net);  		tipc_node_lock(n_ptr);  		tipc_addr_string_fill(addr_string, n_ptr->addr); @@ -955,7 +992,7 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,  		tipc_node_unlock(n_ptr); -		tipc_bclink_set_flags(TIPC_BCLINK_RESET); +		tipc_bclink_set_flags(net, TIPC_BCLINK_RESET);  		l_ptr->stale_count = 0;  	}  } @@ -987,7 +1024,8 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *skb,  		msg = buf_msg(skb);  		msg_set_ack(msg, mod(l_ptr->next_in_no - 1));  		msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); -		tipc_bearer_send(l_ptr->bearer_id, skb, &l_ptr->media_addr); +		tipc_bearer_send(l_ptr->owner->net, l_ptr->bearer_id, skb, +				 &l_ptr->media_addr);  		retransmits--;  		l_ptr->stats.retransmitted++;  	} @@ -1063,14 +1101,16 @@ static int link_recv_buf_validate(struct sk_buff *buf)  /**   * tipc_rcv - process TIPC packets/messages arriving from off-node + * @net: the applicable net namespace   * @skb: TIPC packet   * @b_ptr: pointer to bearer message arrived on   *   * Invoked with no locks held.  Bearer pointer must point to a valid bearer   * structure (i.e. cannot be NULL), but bearer can be inactive.   */ -void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr) +void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr)  { +	struct tipc_net *tn = net_generic(net, tipc_net_id);  	struct sk_buff_head head;  	struct tipc_node *n_ptr;  	struct tipc_link *l_ptr; @@ -1096,19 +1136,19 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)  		if (unlikely(msg_non_seq(msg))) {  			if (msg_user(msg) ==  LINK_CONFIG) -				tipc_disc_rcv(skb, b_ptr); +				tipc_disc_rcv(net, skb, b_ptr);  			else -				tipc_bclink_rcv(skb); +				tipc_bclink_rcv(net, skb);  			continue;  		}  		/* Discard unicast link messages destined for another node */  		if (unlikely(!msg_short(msg) && -			     (msg_destnode(msg) != tipc_own_addr))) +			     (msg_destnode(msg) != tn->own_addr)))  			goto discard;  		/* Locate neighboring node that sent message */ -		n_ptr = tipc_node_find(msg_prevnode(msg)); +		n_ptr = tipc_node_find(net, msg_prevnode(msg));  		if (unlikely(!n_ptr))  			goto discard;  		tipc_node_lock(n_ptr); @@ -1116,7 +1156,7 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)  		/* Locate unicast link endpoint that should handle message */  		l_ptr = n_ptr->links[b_ptr->identity];  		if (unlikely(!l_ptr)) -			goto unlock_discard; +			goto unlock;  		/* Verify that communication with node is currently allowed */  		if ((n_ptr->action_flags & TIPC_WAIT_PEER_LINKS_DOWN) && @@ -1127,7 +1167,7 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)  			n_ptr->action_flags &= ~TIPC_WAIT_PEER_LINKS_DOWN;  		if (tipc_node_blocked(n_ptr)) -			goto unlock_discard; +			goto unlock;  		/* Validate message sequence number info */  		seq_no = msg_seqno(msg); @@ -1151,18 +1191,16 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)  		if (unlikely(l_ptr->next_out))  			tipc_link_push_packets(l_ptr); -		if (released && !skb_queue_empty(&l_ptr->waiting_sks)) { +		if (released && !skb_queue_empty(&l_ptr->wakeupq))  			link_prepare_wakeup(l_ptr); -			l_ptr->owner->action_flags |= TIPC_WAKEUP_USERS; -		}  		/* Process the incoming packet */  		if (unlikely(!link_working_working(l_ptr))) {  			if (msg_user(msg) == LINK_PROTOCOL) {  				tipc_link_proto_rcv(l_ptr, skb);  				link_retrieve_defq(l_ptr, &head); -				tipc_node_unlock(n_ptr); -				continue; +				skb = NULL; +				goto unlock;  			}  			/* Traffic message. Conditionally activate link */ @@ -1171,18 +1209,18 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)  			if (link_working_working(l_ptr)) {  				/* Re-insert buffer in front of queue */  				__skb_queue_head(&head, skb); -				tipc_node_unlock(n_ptr); -				continue; +				skb = NULL; +				goto unlock;  			} -			goto unlock_discard; +			goto unlock;  		}  		/* Link is now in state WORKING_WORKING */  		if (unlikely(seq_no != mod(l_ptr->next_in_no))) {  			link_handle_out_of_seq_msg(l_ptr, skb);  			link_retrieve_defq(l_ptr, &head); -			tipc_node_unlock(n_ptr); -			continue; +			skb = NULL; +			goto unlock;  		}  		l_ptr->next_in_no++;  		if (unlikely(!skb_queue_empty(&l_ptr->deferred_queue))) @@ -1192,95 +1230,102 @@ void tipc_rcv(struct sk_buff *skb, struct tipc_bearer *b_ptr)  			l_ptr->stats.sent_acks++;  			tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);  		} - -		if (tipc_link_prepare_input(l_ptr, &skb)) { -			tipc_node_unlock(n_ptr); -			continue; -		} -		tipc_node_unlock(n_ptr); - -		if (tipc_link_input(l_ptr, skb) != 0) -			goto discard; -		continue; -unlock_discard: +		tipc_link_input(l_ptr, skb); +		skb = NULL; +unlock:  		tipc_node_unlock(n_ptr);  discard: -		kfree_skb(skb); +		if (unlikely(skb)) +			kfree_skb(skb);  	}  } -/** - * tipc_link_prepare_input - process TIPC link messages - * - * returns nonzero if the message was consumed +/* tipc_data_input - deliver data and name distr msgs to upper layer   * + * Consumes buffer if message is of right type   * Node lock must be held   */ -static int tipc_link_prepare_input(struct tipc_link *l, struct sk_buff **buf) +static bool tipc_data_input(struct tipc_link *link, struct sk_buff *skb)  { -	struct tipc_node *n; -	struct tipc_msg *msg; -	int res = -EINVAL; +	struct tipc_node *node = link->owner; +	struct tipc_msg *msg = buf_msg(skb); +	u32 dport = msg_destport(msg); -	n = l->owner; -	msg = buf_msg(*buf);  	switch (msg_user(msg)) { -	case CHANGEOVER_PROTOCOL: -		if (tipc_link_tunnel_rcv(n, buf)) -			res = 0; -		break; -	case MSG_FRAGMENTER: -		l->stats.recv_fragments++; -		if (tipc_buf_append(&l->reasm_buf, buf)) { -			l->stats.recv_fragmented++; -			res = 0; -		} else if (!l->reasm_buf) { -			tipc_link_reset(l); +	case TIPC_LOW_IMPORTANCE: +	case TIPC_MEDIUM_IMPORTANCE: +	case TIPC_HIGH_IMPORTANCE: +	case TIPC_CRITICAL_IMPORTANCE: +	case CONN_MANAGER: +		if (tipc_skb_queue_tail(&link->inputq, skb, dport)) { +			node->inputq = &link->inputq; +			node->action_flags |= TIPC_MSG_EVT;  		} -		break; -	case MSG_BUNDLER: -		l->stats.recv_bundles++; -		l->stats.recv_bundled += msg_msgcnt(msg); -		res = 0; -		break; +		return true;  	case NAME_DISTRIBUTOR: -		n->bclink.recv_permitted = true; -		res = 0; -		break; +		node->bclink.recv_permitted = true; +		node->namedq = &link->namedq; +		skb_queue_tail(&link->namedq, skb); +		if (skb_queue_len(&link->namedq) == 1) +			node->action_flags |= TIPC_NAMED_MSG_EVT; +		return true; +	case MSG_BUNDLER: +	case CHANGEOVER_PROTOCOL: +	case MSG_FRAGMENTER:  	case BCAST_PROTOCOL: -		tipc_link_sync_rcv(n, *buf); -		break; +		return false;  	default: -		res = 0; -	} -	return res; +		pr_warn("Dropping received illegal msg type\n"); +		kfree_skb(skb); +		return false; +	};  } -/** - * tipc_link_input - Deliver message too higher layers + +/* tipc_link_input - process packet that has passed link protocol check + * + * Consumes buffer + * Node lock must be held   */ -static int tipc_link_input(struct tipc_link *l, struct sk_buff *buf) +static void tipc_link_input(struct tipc_link *link, struct sk_buff *skb)  { -	struct tipc_msg *msg = buf_msg(buf); -	int res = 0; +	struct tipc_node *node = link->owner; +	struct tipc_msg *msg = buf_msg(skb); +	struct sk_buff *iskb; +	int pos = 0; + +	if (likely(tipc_data_input(link, skb))) +		return;  	switch (msg_user(msg)) { -	case TIPC_LOW_IMPORTANCE: -	case TIPC_MEDIUM_IMPORTANCE: -	case TIPC_HIGH_IMPORTANCE: -	case TIPC_CRITICAL_IMPORTANCE: -	case CONN_MANAGER: -		tipc_sk_rcv(buf); +	case CHANGEOVER_PROTOCOL: +		if (!tipc_link_tunnel_rcv(node, &skb)) +			break; +		if (msg_user(buf_msg(skb)) != MSG_BUNDLER) { +			tipc_data_input(link, skb); +			break; +		} +	case MSG_BUNDLER: +		link->stats.recv_bundles++; +		link->stats.recv_bundled += msg_msgcnt(msg); + +		while (tipc_msg_extract(skb, &iskb, &pos)) +			tipc_data_input(link, iskb);  		break; -	case NAME_DISTRIBUTOR: -		tipc_named_rcv(buf); +	case MSG_FRAGMENTER: +		link->stats.recv_fragments++; +		if (tipc_buf_append(&link->reasm_buf, &skb)) { +			link->stats.recv_fragmented++; +			tipc_data_input(link, skb); +		} else if (!link->reasm_buf) { +			tipc_link_reset(link); +		}  		break; -	case MSG_BUNDLER: -		tipc_link_bundle_rcv(buf); +	case BCAST_PROTOCOL: +		tipc_link_sync_rcv(node, skb);  		break;  	default: -		res = -EINVAL; -	} -	return res; +		break; +	};  }  /** @@ -1381,7 +1426,7 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,  	msg_set_type(msg, msg_typ);  	msg_set_net_plane(msg, l_ptr->net_plane);  	msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); -	msg_set_last_bcast(msg, tipc_bclink_get_last_sent()); +	msg_set_last_bcast(msg, tipc_bclink_get_last_sent(l_ptr->owner->net));  	if (msg_typ == STATE_MSG) {  		u32 next_sent = mod(l_ptr->next_out_no); @@ -1445,7 +1490,8 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,  	skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));  	buf->priority = TC_PRIO_CONTROL; -	tipc_bearer_send(l_ptr->bearer_id, buf, &l_ptr->media_addr); +	tipc_bearer_send(l_ptr->owner->net, l_ptr->bearer_id, buf, +			 &l_ptr->media_addr);  	l_ptr->unacked_window = 0;  	kfree_skb(buf);  } @@ -1455,7 +1501,8 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,   * Note that network plane id propagates through the network, and may   * change at any time. The node with lowest address rules   */ -static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf) +static void tipc_link_proto_rcv(struct tipc_link *l_ptr, +				struct sk_buff *buf)  {  	u32 rec_gap = 0;  	u32 max_pkt_info; @@ -1468,7 +1515,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)  		goto exit;  	if (l_ptr->net_plane != msg_net_plane(msg)) -		if (tipc_own_addr > msg_prevnode(msg)) +		if (link_own_addr(l_ptr) > msg_prevnode(msg))  			l_ptr->net_plane = msg_net_plane(msg);  	switch (msg_type(msg)) { @@ -1535,9 +1582,9 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)  		if (msg_linkprio(msg) &&  		    (msg_linkprio(msg) != l_ptr->priority)) { -			pr_warn("%s<%s>, priority change %u->%u\n", -				link_rst_msg, l_ptr->name, l_ptr->priority, -				msg_linkprio(msg)); +			pr_debug("%s<%s>, priority change %u->%u\n", +				 link_rst_msg, l_ptr->name, +				 l_ptr->priority, msg_linkprio(msg));  			l_ptr->priority = msg_linkprio(msg);  			tipc_link_reset(l_ptr); /* Enforce change to take effect */  			break; @@ -1636,8 +1683,8 @@ void tipc_link_failover_send_queue(struct tipc_link *l_ptr)  	if (!tunnel)  		return; -	tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, -		 ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr); +	tipc_msg_init(link_own_addr(l_ptr), &tunnel_hdr, CHANGEOVER_PROTOCOL, +		      ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);  	msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);  	msg_set_msgcnt(&tunnel_hdr, msgcount); @@ -1694,8 +1741,8 @@ void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr,  	struct sk_buff *skb;  	struct tipc_msg tunnel_hdr; -	tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL, -		 DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr); +	tipc_msg_init(link_own_addr(l_ptr), &tunnel_hdr, CHANGEOVER_PROTOCOL, +		      DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);  	msg_set_msgcnt(&tunnel_hdr, skb_queue_len(&l_ptr->outqueue));  	msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);  	skb_queue_walk(&l_ptr->outqueue, skb) { @@ -1729,7 +1776,7 @@ void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr,   * @from_pos: offset to extract from   *   * Returns a new message buffer containing an embedded message.  The - * encapsulating message itself is left unchanged. + * encapsulating buffer is left unchanged.   */  static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)  { @@ -1743,8 +1790,6 @@ static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)  	return eb;  } - -  /* tipc_link_dup_rcv(): Receive a tunnelled DUPLICATE_MSG packet.   * Owner node is locked.   */ @@ -1804,10 +1849,8 @@ static struct sk_buff *tipc_link_failover_rcv(struct tipc_link *l_ptr,  		}  	}  exit: -	if ((l_ptr->exp_msg_count == 0) && (l_ptr->flags & LINK_STOPPED)) { -		tipc_node_detach_link(l_ptr->owner, l_ptr); -		kfree(l_ptr); -	} +	if ((!l_ptr->exp_msg_count) && (l_ptr->flags & LINK_STOPPED)) +		tipc_link_delete(l_ptr);  	return buf;  } @@ -1845,50 +1888,16 @@ exit:  	return *buf != NULL;  } -/* - *  Bundler functionality: - */ -void tipc_link_bundle_rcv(struct sk_buff *buf) +static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol)  { -	u32 msgcount = msg_msgcnt(buf_msg(buf)); -	u32 pos = INT_H_SIZE; -	struct sk_buff *obuf; -	struct tipc_msg *omsg; - -	while (msgcount--) { -		obuf = buf_extract(buf, pos); -		if (obuf == NULL) { -			pr_warn("Link unable to unbundle message(s)\n"); -			break; -		} -		omsg = buf_msg(obuf); -		pos += align(msg_size(omsg)); -		if (msg_isdata(omsg)) { -			if (unlikely(msg_type(omsg) == TIPC_MCAST_MSG)) -				tipc_sk_mcast_rcv(obuf); -			else -				tipc_sk_rcv(obuf); -		} else if (msg_user(omsg) == CONN_MANAGER) { -			tipc_sk_rcv(obuf); -		} else if (msg_user(omsg) == NAME_DISTRIBUTOR) { -			tipc_named_rcv(obuf); -		} else { -			pr_warn("Illegal bundled msg: %u\n", msg_user(omsg)); -			kfree_skb(obuf); -		} -	} -	kfree_skb(buf); -} +	unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4; -static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance) -{ -	if ((tolerance < TIPC_MIN_LINK_TOL) || (tolerance > TIPC_MAX_LINK_TOL)) +	if ((tol < TIPC_MIN_LINK_TOL) || (tol > TIPC_MAX_LINK_TOL))  		return; -	l_ptr->tolerance = tolerance; -	l_ptr->continuity_interval = -		((tolerance / 4) > 500) ? 500 : tolerance / 4; -	l_ptr->abort_limit = tolerance / (l_ptr->continuity_interval / 4); +	l_ptr->tolerance = tol; +	l_ptr->cont_intv = msecs_to_jiffies(intv); +	l_ptr->abort_limit = tol / (jiffies_to_msecs(l_ptr->cont_intv) / 4);  }  void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window) @@ -1911,22 +1920,25 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window)  }  /* tipc_link_find_owner - locate owner node of link by link's name + * @net: the applicable net namespace   * @name: pointer to link name string   * @bearer_id: pointer to index in 'node->links' array where the link was found.   *   * Returns pointer to node owning the link, or 0 if no matching link is found.   */ -static struct tipc_node *tipc_link_find_owner(const char *link_name, +static struct tipc_node *tipc_link_find_owner(struct net *net, +					      const char *link_name,  					      unsigned int *bearer_id)  { +	struct tipc_net *tn = net_generic(net, tipc_net_id);  	struct tipc_link *l_ptr;  	struct tipc_node *n_ptr; -	struct tipc_node *found_node = 0; +	struct tipc_node *found_node = NULL;  	int i;  	*bearer_id = 0;  	rcu_read_lock(); -	list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) { +	list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {  		tipc_node_lock(n_ptr);  		for (i = 0; i < MAX_BEARERS; i++) {  			l_ptr = n_ptr->links[i]; @@ -1946,148 +1958,6 @@ static struct tipc_node *tipc_link_find_owner(const char *link_name,  }  /** - * link_value_is_valid -- validate proposed link tolerance/priority/window - * - * @cmd: value type (TIPC_CMD_SET_LINK_*) - * @new_value: the new value - * - * Returns 1 if value is within range, 0 if not. - */ -static int link_value_is_valid(u16 cmd, u32 new_value) -{ -	switch (cmd) { -	case TIPC_CMD_SET_LINK_TOL: -		return (new_value >= TIPC_MIN_LINK_TOL) && -			(new_value <= TIPC_MAX_LINK_TOL); -	case TIPC_CMD_SET_LINK_PRI: -		return (new_value <= TIPC_MAX_LINK_PRI); -	case TIPC_CMD_SET_LINK_WINDOW: -		return (new_value >= TIPC_MIN_LINK_WIN) && -			(new_value <= TIPC_MAX_LINK_WIN); -	} -	return 0; -} - -/** - * link_cmd_set_value - change priority/tolerance/window for link/bearer/media - * @name: ptr to link, bearer, or media name - * @new_value: new value of link, bearer, or media setting - * @cmd: which link, bearer, or media attribute to set (TIPC_CMD_SET_LINK_*) - * - * Caller must hold RTNL lock to ensure link/bearer/media is not deleted. - * - * Returns 0 if value updated and negative value on error. - */ -static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd) -{ -	struct tipc_node *node; -	struct tipc_link *l_ptr; -	struct tipc_bearer *b_ptr; -	struct tipc_media *m_ptr; -	int bearer_id; -	int res = 0; - -	node = tipc_link_find_owner(name, &bearer_id); -	if (node) { -		tipc_node_lock(node); -		l_ptr = node->links[bearer_id]; - -		if (l_ptr) { -			switch (cmd) { -			case TIPC_CMD_SET_LINK_TOL: -				link_set_supervision_props(l_ptr, new_value); -				tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, -						     new_value, 0, 0); -				break; -			case TIPC_CMD_SET_LINK_PRI: -				l_ptr->priority = new_value; -				tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, -						     0, new_value, 0); -				break; -			case TIPC_CMD_SET_LINK_WINDOW: -				tipc_link_set_queue_limits(l_ptr, new_value); -				break; -			default: -				res = -EINVAL; -				break; -			} -		} -		tipc_node_unlock(node); -		return res; -	} - -	b_ptr = tipc_bearer_find(name); -	if (b_ptr) { -		switch (cmd) { -		case TIPC_CMD_SET_LINK_TOL: -			b_ptr->tolerance = new_value; -			break; -		case TIPC_CMD_SET_LINK_PRI: -			b_ptr->priority = new_value; -			break; -		case TIPC_CMD_SET_LINK_WINDOW: -			b_ptr->window = new_value; -			break; -		default: -			res = -EINVAL; -			break; -		} -		return res; -	} - -	m_ptr = tipc_media_find(name); -	if (!m_ptr) -		return -ENODEV; -	switch (cmd) { -	case TIPC_CMD_SET_LINK_TOL: -		m_ptr->tolerance = new_value; -		break; -	case TIPC_CMD_SET_LINK_PRI: -		m_ptr->priority = new_value; -		break; -	case TIPC_CMD_SET_LINK_WINDOW: -		m_ptr->window = new_value; -		break; -	default: -		res = -EINVAL; -		break; -	} -	return res; -} - -struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, -				     u16 cmd) -{ -	struct tipc_link_config *args; -	u32 new_value; -	int res; - -	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG)) -		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - -	args = (struct tipc_link_config *)TLV_DATA(req_tlv_area); -	new_value = ntohl(args->value); - -	if (!link_value_is_valid(cmd, new_value)) -		return tipc_cfg_reply_error_string( -			"cannot change, value invalid"); - -	if (!strcmp(args->name, tipc_bclink_name)) { -		if ((cmd == TIPC_CMD_SET_LINK_WINDOW) && -		    (tipc_bclink_set_queue_limits(new_value) == 0)) -			return tipc_cfg_reply_none(); -		return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED -						   " (cannot change setting on broadcast link)"); -	} - -	res = link_cmd_set_value(args->name, new_value, cmd); -	if (res) -		return tipc_cfg_reply_error_string("cannot change link setting"); - -	return tipc_cfg_reply_none(); -} - -/**   * link_reset_statistics - reset link statistics   * @l_ptr: pointer to link   */ @@ -2098,207 +1968,13 @@ static void link_reset_statistics(struct tipc_link *l_ptr)  	l_ptr->stats.recv_info = l_ptr->next_in_no;  } -struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space) -{ -	char *link_name; -	struct tipc_link *l_ptr; -	struct tipc_node *node; -	unsigned int bearer_id; - -	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME)) -		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - -	link_name = (char *)TLV_DATA(req_tlv_area); -	if (!strcmp(link_name, tipc_bclink_name)) { -		if (tipc_bclink_reset_stats()) -			return tipc_cfg_reply_error_string("link not found"); -		return tipc_cfg_reply_none(); -	} -	node = tipc_link_find_owner(link_name, &bearer_id); -	if (!node) -		return tipc_cfg_reply_error_string("link not found"); - -	tipc_node_lock(node); -	l_ptr = node->links[bearer_id]; -	if (!l_ptr) { -		tipc_node_unlock(node); -		return tipc_cfg_reply_error_string("link not found"); -	} -	link_reset_statistics(l_ptr); -	tipc_node_unlock(node); -	return tipc_cfg_reply_none(); -} - -/** - * percent - convert count to a percentage of total (rounding up or down) - */ -static u32 percent(u32 count, u32 total) -{ -	return (count * 100 + (total / 2)) / total; -} - -/** - * tipc_link_stats - print link statistics - * @name: link name - * @buf: print buffer area - * @buf_size: size of print buffer area - * - * Returns length of print buffer data string (or 0 if error) - */ -static int tipc_link_stats(const char *name, char *buf, const u32 buf_size) -{ -	struct tipc_link *l; -	struct tipc_stats *s; -	struct tipc_node *node; -	char *status; -	u32 profile_total = 0; -	unsigned int bearer_id; -	int ret; - -	if (!strcmp(name, tipc_bclink_name)) -		return tipc_bclink_stats(buf, buf_size); - -	node = tipc_link_find_owner(name, &bearer_id); -	if (!node) -		return 0; - -	tipc_node_lock(node); - -	l = node->links[bearer_id]; -	if (!l) { -		tipc_node_unlock(node); -		return 0; -	} - -	s = &l->stats; - -	if (tipc_link_is_active(l)) -		status = "ACTIVE"; -	else if (tipc_link_is_up(l)) -		status = "STANDBY"; -	else -		status = "DEFUNCT"; - -	ret = tipc_snprintf(buf, buf_size, "Link <%s>\n" -			    "  %s  MTU:%u  Priority:%u  Tolerance:%u ms" -			    "  Window:%u packets\n", -			    l->name, status, l->max_pkt, l->priority, -			    l->tolerance, l->queue_limit[0]); - -	ret += tipc_snprintf(buf + ret, buf_size - ret, -			     "  RX packets:%u fragments:%u/%u bundles:%u/%u\n", -			     l->next_in_no - s->recv_info, s->recv_fragments, -			     s->recv_fragmented, s->recv_bundles, -			     s->recv_bundled); - -	ret += tipc_snprintf(buf + ret, buf_size - ret, -			     "  TX packets:%u fragments:%u/%u bundles:%u/%u\n", -			     l->next_out_no - s->sent_info, s->sent_fragments, -			     s->sent_fragmented, s->sent_bundles, -			     s->sent_bundled); - -	profile_total = s->msg_length_counts; -	if (!profile_total) -		profile_total = 1; - -	ret += tipc_snprintf(buf + ret, buf_size - ret, -			     "  TX profile sample:%u packets  average:%u octets\n" -			     "  0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% " -			     "-16384:%u%% -32768:%u%% -66000:%u%%\n", -			     s->msg_length_counts, -			     s->msg_lengths_total / profile_total, -			     percent(s->msg_length_profile[0], profile_total), -			     percent(s->msg_length_profile[1], profile_total), -			     percent(s->msg_length_profile[2], profile_total), -			     percent(s->msg_length_profile[3], profile_total), -			     percent(s->msg_length_profile[4], profile_total), -			     percent(s->msg_length_profile[5], profile_total), -			     percent(s->msg_length_profile[6], profile_total)); - -	ret += tipc_snprintf(buf + ret, buf_size - ret, -			     "  RX states:%u probes:%u naks:%u defs:%u" -			     " dups:%u\n", s->recv_states, s->recv_probes, -			     s->recv_nacks, s->deferred_recv, s->duplicates); - -	ret += tipc_snprintf(buf + ret, buf_size - ret, -			     "  TX states:%u probes:%u naks:%u acks:%u" -			     " dups:%u\n", s->sent_states, s->sent_probes, -			     s->sent_nacks, s->sent_acks, s->retransmitted); - -	ret += tipc_snprintf(buf + ret, buf_size - ret, -			     "  Congestion link:%u  Send queue" -			     " max:%u avg:%u\n", s->link_congs, -			     s->max_queue_sz, s->queue_sz_counts ? -			     (s->accu_queue_sz / s->queue_sz_counts) : 0); - -	tipc_node_unlock(node); -	return ret; -} - -struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space) -{ -	struct sk_buff *buf; -	struct tlv_desc *rep_tlv; -	int str_len; -	int pb_len; -	char *pb; - -	if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME)) -		return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - -	buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN)); -	if (!buf) -		return NULL; - -	rep_tlv = (struct tlv_desc *)buf->data; -	pb = TLV_DATA(rep_tlv); -	pb_len = ULTRA_STRING_MAX_LEN; -	str_len = tipc_link_stats((char *)TLV_DATA(req_tlv_area), -				  pb, pb_len); -	if (!str_len) { -		kfree_skb(buf); -		return tipc_cfg_reply_error_string("link not found"); -	} -	str_len += 1;	/* for "\0" */ -	skb_put(buf, TLV_SPACE(str_len)); -	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); - -	return buf; -} - -/** - * tipc_link_get_max_pkt - get maximum packet size to use when sending to destination - * @dest: network address of destination node - * @selector: used to select from set of active links - * - * If no active link can be found, uses default maximum packet size. - */ -u32 tipc_link_get_max_pkt(u32 dest, u32 selector) -{ -	struct tipc_node *n_ptr; -	struct tipc_link *l_ptr; -	u32 res = MAX_PKT_DEFAULT; - -	if (dest == tipc_own_addr) -		return MAX_MSG_SIZE; - -	n_ptr = tipc_node_find(dest); -	if (n_ptr) { -		tipc_node_lock(n_ptr); -		l_ptr = n_ptr->active_links[selector & 1]; -		if (l_ptr) -			res = l_ptr->max_pkt; -		tipc_node_unlock(n_ptr); -	} -	return res; -} -  static void link_print(struct tipc_link *l_ptr, const char *str)  { +	struct tipc_net *tn = net_generic(l_ptr->owner->net, tipc_net_id);  	struct tipc_bearer *b_ptr;  	rcu_read_lock(); -	b_ptr = rcu_dereference_rtnl(bearer_list[l_ptr->bearer_id]); +	b_ptr = rcu_dereference_rtnl(tn->bearer_list[l_ptr->bearer_id]);  	if (b_ptr)  		pr_info("%s Link %x<%s>:", str, l_ptr->addr, b_ptr->name);  	rcu_read_unlock(); @@ -2362,6 +2038,7 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info)  	struct tipc_link *link;  	struct tipc_node *node;  	struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; +	struct net *net = sock_net(skb->sk);  	if (!info->attrs[TIPC_NLA_LINK])  		return -EINVAL; @@ -2377,7 +2054,7 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info)  	name = nla_data(attrs[TIPC_NLA_LINK_NAME]); -	node = tipc_link_find_owner(name, &bearer_id); +	node = tipc_link_find_owner(net, name, &bearer_id);  	if (!node)  		return -EINVAL; @@ -2493,14 +2170,16 @@ msg_full:  }  /* Caller should hold appropriate locks to protect the link */ -static int __tipc_nl_add_link(struct tipc_nl_msg *msg, struct tipc_link *link) +static int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg, +			      struct tipc_link *link)  {  	int err;  	void *hdr;  	struct nlattr *attrs;  	struct nlattr *prop; +	struct tipc_net *tn = net_generic(net, tipc_net_id); -	hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, +	hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,  			  NLM_F_MULTI, TIPC_NL_LINK_GET);  	if (!hdr)  		return -EMSGSIZE; @@ -2512,7 +2191,7 @@ static int __tipc_nl_add_link(struct tipc_nl_msg *msg, struct tipc_link *link)  	if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, link->name))  		goto attr_msg_full;  	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_DEST, -			tipc_cluster_mask(tipc_own_addr))) +			tipc_cluster_mask(tn->own_addr)))  		goto attr_msg_full;  	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_MTU, link->max_pkt))  		goto attr_msg_full; @@ -2562,9 +2241,8 @@ msg_full:  }  /* Caller should hold node lock  */ -static int __tipc_nl_add_node_links(struct tipc_nl_msg *msg, -				    struct tipc_node *node, -				    u32 *prev_link) +static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg, +				    struct tipc_node *node, u32 *prev_link)  {  	u32 i;  	int err; @@ -2575,7 +2253,7 @@ static int __tipc_nl_add_node_links(struct tipc_nl_msg *msg,  		if (!node->links[i])  			continue; -		err = __tipc_nl_add_link(msg, node->links[i]); +		err = __tipc_nl_add_link(net, msg, node->links[i]);  		if (err)  			return err;  	} @@ -2586,6 +2264,8 @@ static int __tipc_nl_add_node_links(struct tipc_nl_msg *msg,  int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)  { +	struct net *net = sock_net(skb->sk); +	struct tipc_net *tn = net_generic(net, tipc_net_id);  	struct tipc_node *node;  	struct tipc_nl_msg msg;  	u32 prev_node = cb->args[0]; @@ -2603,7 +2283,7 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)  	rcu_read_lock();  	if (prev_node) { -		node = tipc_node_find(prev_node); +		node = tipc_node_find(net, prev_node);  		if (!node) {  			/* We never set seq or call nl_dump_check_consistent()  			 * this means that setting prev_seq here will cause the @@ -2615,9 +2295,11 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)  			goto out;  		} -		list_for_each_entry_continue_rcu(node, &tipc_node_list, list) { +		list_for_each_entry_continue_rcu(node, &tn->node_list, +						 list) {  			tipc_node_lock(node); -			err = __tipc_nl_add_node_links(&msg, node, &prev_link); +			err = __tipc_nl_add_node_links(net, &msg, node, +						       &prev_link);  			tipc_node_unlock(node);  			if (err)  				goto out; @@ -2625,13 +2307,14 @@ int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)  			prev_node = node->addr;  		}  	} else { -		err = tipc_nl_add_bc_link(&msg); +		err = tipc_nl_add_bc_link(net, &msg);  		if (err)  			goto out; -		list_for_each_entry_rcu(node, &tipc_node_list, list) { +		list_for_each_entry_rcu(node, &tn->node_list, list) {  			tipc_node_lock(node); -			err = __tipc_nl_add_node_links(&msg, node, &prev_link); +			err = __tipc_nl_add_node_links(net, &msg, node, +						       &prev_link);  			tipc_node_unlock(node);  			if (err)  				goto out; @@ -2652,6 +2335,7 @@ out:  int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info)  { +	struct net *net = genl_info_net(info);  	struct sk_buff *ans_skb;  	struct tipc_nl_msg msg;  	struct tipc_link *link; @@ -2664,7 +2348,7 @@ int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info)  		return -EINVAL;  	name = nla_data(info->attrs[TIPC_NLA_LINK_NAME]); -	node = tipc_link_find_owner(name, &bearer_id); +	node = tipc_link_find_owner(net, name, &bearer_id);  	if (!node)  		return -EINVAL; @@ -2683,7 +2367,7 @@ int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info)  		goto err_out;  	} -	err = __tipc_nl_add_link(&msg, link); +	err = __tipc_nl_add_link(net, &msg, link);  	if (err)  		goto err_out; @@ -2706,6 +2390,7 @@ int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info)  	struct tipc_link *link;  	struct tipc_node *node;  	struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; +	struct net *net = sock_net(skb->sk);  	if (!info->attrs[TIPC_NLA_LINK])  		return -EINVAL; @@ -2722,13 +2407,13 @@ int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info)  	link_name = nla_data(attrs[TIPC_NLA_LINK_NAME]);  	if (strcmp(link_name, tipc_bclink_name) == 0) { -		err = tipc_bclink_reset_stats(); +		err = tipc_bclink_reset_stats(net);  		if (err)  			return err;  		return 0;  	} -	node = tipc_link_find_owner(link_name, &bearer_id); +	node = tipc_link_find_owner(net, link_name, &bearer_id);  	if (!node)  		return -EINVAL; |