diff options
| -rw-r--r-- | net/tipc/node.c | 78 | ||||
| -rw-r--r-- | net/tipc/node.h | 3 | ||||
| -rw-r--r-- | net/tipc/port.c | 29 | 
3 files changed, 85 insertions, 25 deletions
diff --git a/net/tipc/node.c b/net/tipc/node.c index 6ea2c15cfc88..17e6378c4dfe 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -51,6 +51,13 @@ static u32 tipc_num_nodes;  static u32 tipc_num_links;  static DEFINE_SPINLOCK(node_list_lock); +struct tipc_sock_conn { +	u32 port; +	u32 peer_port; +	u32 peer_node; +	struct list_head list; +}; +  /*   * A trivial power-of-two bitmask technique is used for speed, since this   * operation is done for every incoming TIPC packet. The number of hash table @@ -101,6 +108,7 @@ struct tipc_node *tipc_node_create(u32 addr)  	INIT_HLIST_NODE(&n_ptr->hash);  	INIT_LIST_HEAD(&n_ptr->list);  	INIT_LIST_HEAD(&n_ptr->nsub); +	INIT_LIST_HEAD(&n_ptr->conn_sks);  	__skb_queue_head_init(&n_ptr->waiting_sks);  	hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]); @@ -138,6 +146,71 @@ void tipc_node_stop(void)  	spin_unlock_bh(&node_list_lock);  } +int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port) +{ +	struct tipc_node *node; +	struct tipc_sock_conn *conn; + +	if (in_own_node(dnode)) +		return 0; + +	node = tipc_node_find(dnode); +	if (!node) { +		pr_warn("Connecting sock to node 0x%x failed\n", dnode); +		return -EHOSTUNREACH; +	} +	conn = kmalloc(sizeof(*conn), GFP_ATOMIC); +	if (!conn) +		return -EHOSTUNREACH; +	conn->peer_node = dnode; +	conn->port = port; +	conn->peer_port = peer_port; + +	tipc_node_lock(node); +	list_add_tail(&conn->list, &node->conn_sks); +	tipc_node_unlock(node); +	return 0; +} + +void tipc_node_remove_conn(u32 dnode, u32 port) +{ +	struct tipc_node *node; +	struct tipc_sock_conn *conn, *safe; + +	if (in_own_node(dnode)) +		return; + +	node = tipc_node_find(dnode); +	if (!node) +		return; + +	tipc_node_lock(node); +	list_for_each_entry_safe(conn, safe, &node->conn_sks, list) { +		if (port != conn->port) +			continue; +		list_del(&conn->list); +		kfree(conn); +	} +	tipc_node_unlock(node); +} + +void tipc_node_abort_sock_conns(struct list_head *conns) +{ +	struct tipc_sock_conn *conn, *safe; +	struct sk_buff *buf; + +	list_for_each_entry_safe(conn, safe, conns, list) { +		buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG, +				      SHORT_H_SIZE, 0, tipc_own_addr, +				      conn->peer_node, conn->port, +				      conn->peer_port, TIPC_ERR_NO_NODE); +		if (likely(buf)) +			tipc_sk_rcv(buf); +		list_del(&conn->list); +		kfree(conn); +	} +} +  /**   * tipc_node_link_up - handle addition of link   * @@ -476,6 +549,7 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len)  void tipc_node_unlock(struct tipc_node *node)  {  	LIST_HEAD(nsub_list); +	LIST_HEAD(conn_sks);  	struct sk_buff_head waiting_sks;  	u32 addr = 0; @@ -491,6 +565,7 @@ void tipc_node_unlock(struct tipc_node *node)  	}  	if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) {  		list_replace_init(&node->nsub, &nsub_list); +		list_replace_init(&node->conn_sks, &conn_sks);  		node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN;  	}  	if (node->action_flags & TIPC_NOTIFY_NODE_UP) { @@ -502,6 +577,9 @@ void tipc_node_unlock(struct tipc_node *node)  	while (!skb_queue_empty(&waiting_sks))  		tipc_sk_rcv(__skb_dequeue(&waiting_sks)); +	if (!list_empty(&conn_sks)) +		tipc_node_abort_sock_conns(&conn_sks); +  	if (!list_empty(&nsub_list))  		tipc_nodesub_notify(&nsub_list); diff --git a/net/tipc/node.h b/net/tipc/node.h index 2ebf9e8b50fd..522d6f3157b3 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -117,6 +117,7 @@ struct tipc_node {  	u32 signature;  	struct list_head nsub;  	struct sk_buff_head waiting_sks; +	struct list_head conn_sks;  	struct rcu_head rcu;  }; @@ -135,6 +136,8 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)  struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space);  int tipc_node_get_linkname(u32 bearer_id, u32 node, char *linkname, size_t len);  void tipc_node_unlock(struct tipc_node *node); +int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port); +void tipc_node_remove_conn(u32 dnode, u32 port);  static inline void tipc_node_lock(struct tipc_node *node)  { diff --git a/net/tipc/port.c b/net/tipc/port.c index b58a777a4399..edbd83d223c5 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -48,7 +48,6 @@  DEFINE_SPINLOCK(tipc_port_list_lock);  static LIST_HEAD(ports); -static void port_handle_node_down(unsigned long ref);  static struct sk_buff *port_build_self_abort_msg(struct tipc_port *, u32 err);  static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);  static void port_timeout(unsigned long ref); @@ -126,10 +125,10 @@ void tipc_port_destroy(struct tipc_port *p_ptr)  	k_cancel_timer(&p_ptr->timer);  	if (p_ptr->connected) {  		buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT); -		tipc_nodesub_unsubscribe(&p_ptr->subscription);  		msg = buf_msg(buf);  		peer = msg_destnode(msg);  		tipc_link_xmit(buf, peer, msg_link_selector(msg)); +		tipc_node_remove_conn(peer, p_ptr->ref);  	}  	spin_lock_bh(&tipc_port_list_lock);  	list_del(&p_ptr->port_list); @@ -188,22 +187,6 @@ static void port_timeout(unsigned long ref)  	tipc_link_xmit(buf, msg_destnode(msg),	msg_link_selector(msg));  } - -static void port_handle_node_down(unsigned long ref) -{ -	struct tipc_port *p_ptr = tipc_port_lock(ref); -	struct sk_buff *buf = NULL; -	struct tipc_msg *msg = NULL; - -	if (!p_ptr) -		return; -	buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE); -	tipc_port_unlock(p_ptr); -	msg = buf_msg(buf); -	tipc_link_xmit(buf, msg_destnode(msg),	msg_link_selector(msg)); -} - -  static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err)  {  	struct sk_buff *buf = port_build_peer_abort_msg(p_ptr, err); @@ -217,7 +200,6 @@ static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 er  	return buf;  } -  static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err)  {  	struct sk_buff *buf; @@ -447,11 +429,8 @@ int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr,  	p_ptr->probing_state = TIPC_CONN_OK;  	p_ptr->connected = 1;  	k_start_timer(&p_ptr->timer, p_ptr->probing_interval); - -	tipc_nodesub_subscribe(&p_ptr->subscription, peer->node, -			  (void *)(unsigned long)ref, -			  (net_ev_handler)port_handle_node_down); -	res = 0; +	res = tipc_node_add_conn(tipc_port_peernode(p_ptr), p_ptr->ref, +				 tipc_port_peerport(p_ptr));  exit:  	p_ptr->max_pkt = tipc_node_get_mtu(peer->node, ref);  	return res; @@ -467,7 +446,7 @@ int __tipc_port_disconnect(struct tipc_port *tp_ptr)  	if (tp_ptr->connected) {  		tp_ptr->connected = 0;  		/* let timer expire on it's own to avoid deadlock! */ -		tipc_nodesub_unsubscribe(&tp_ptr->subscription); +		tipc_node_remove_conn(tipc_port_peernode(tp_ptr), tp_ptr->ref);  		return 0;  	}  | 
