diff options
Diffstat (limited to 'net/tipc/port.c')
| -rw-r--r-- | net/tipc/port.c | 101 | 
1 files changed, 57 insertions, 44 deletions
diff --git a/net/tipc/port.c b/net/tipc/port.c index 94d2904cce6..0f40b105530 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -59,16 +59,38 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);  static void port_timeout(unsigned long ref); -static u32 port_peernode(struct tipc_port *p_ptr) +static inline u32 port_peernode(struct tipc_port *p_ptr)  {  	return msg_destnode(&p_ptr->phdr);  } -static u32 port_peerport(struct tipc_port *p_ptr) +static inline u32 port_peerport(struct tipc_port *p_ptr)  {  	return msg_destport(&p_ptr->phdr);  } +/* + * tipc_port_peer_msg - verify message was sent by connected port's peer + * + * Handles cases where the node's network address has changed from + * the default of <0.0.0> to its configured setting. + */ + +int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg) +{ +	u32 peernode; +	u32 orignode; + +	if (msg_origport(msg) != port_peerport(p_ptr)) +		return 0; + +	orignode = msg_orignode(msg); +	peernode = port_peernode(p_ptr); +	return (orignode == peernode) || +		(!orignode && (peernode == tipc_own_addr)) || +		(!peernode && (orignode == tipc_own_addr)); +} +  /**   * tipc_multicast - send a multicast message to local and remote destinations   */ @@ -221,18 +243,25 @@ struct tipc_port *tipc_createport_raw(void *usr_handle,  	p_ptr->usr_handle = usr_handle;  	p_ptr->max_pkt = MAX_PKT_DEFAULT;  	p_ptr->ref = ref; -	msg = &p_ptr->phdr; -	tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0); -	msg_set_origport(msg, ref);  	INIT_LIST_HEAD(&p_ptr->wait_list);  	INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);  	p_ptr->dispatcher = dispatcher;  	p_ptr->wakeup = wakeup;  	p_ptr->user_port = NULL;  	k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref); -	spin_lock_bh(&tipc_port_list_lock);  	INIT_LIST_HEAD(&p_ptr->publications);  	INIT_LIST_HEAD(&p_ptr->port_list); + +	/* +	 * Must hold port list lock while initializing message header template +	 * to ensure a change to node's own network address doesn't result +	 * in template containing out-dated network address information +	 */ + +	spin_lock_bh(&tipc_port_list_lock); +	msg = &p_ptr->phdr; +	tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0); +	msg_set_origport(msg, ref);  	list_add_tail(&p_ptr->port_list, &ports);  	spin_unlock_bh(&tipc_port_list_lock);  	return p_ptr; @@ -415,7 +444,7 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)  	/* send returned message & dispose of rejected message */  	src_node = msg_prevnode(msg); -	if (src_node == tipc_own_addr) +	if (in_own_node(src_node))  		tipc_port_recv_msg(rbuf);  	else  		tipc_link_send(rbuf, src_node, msg_link_selector(rmsg)); @@ -519,25 +548,21 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf)  	struct tipc_msg *msg = buf_msg(buf);  	struct tipc_port *p_ptr;  	struct sk_buff *r_buf = NULL; -	u32 orignode = msg_orignode(msg); -	u32 origport = msg_origport(msg);  	u32 destport = msg_destport(msg);  	int wakeable;  	/* Validate connection */  	p_ptr = tipc_port_lock(destport); -	if (!p_ptr || !p_ptr->connected || -	    (port_peernode(p_ptr) != orignode) || -	    (port_peerport(p_ptr) != origport)) { +	if (!p_ptr || !p_ptr->connected || !tipc_port_peer_msg(p_ptr, msg)) {  		r_buf = tipc_buf_acquire(BASIC_H_SIZE);  		if (r_buf) {  			msg = buf_msg(r_buf);  			tipc_msg_init(msg, TIPC_HIGH_IMPORTANCE, TIPC_CONN_MSG, -				      BASIC_H_SIZE, orignode); +				      BASIC_H_SIZE, msg_orignode(msg));  			msg_set_errcode(msg, TIPC_ERR_NO_PORT);  			msg_set_origport(msg, destport); -			msg_set_destport(msg, origport); +			msg_set_destport(msg, msg_origport(msg));  		}  		if (p_ptr)  			tipc_port_unlock(p_ptr); @@ -646,8 +671,6 @@ void tipc_port_reinit(void)  	spin_lock_bh(&tipc_port_list_lock);  	list_for_each_entry(p_ptr, &ports, port_list) {  		msg = &p_ptr->phdr; -		if (msg_orignode(msg) == tipc_own_addr) -			break;  		msg_set_prevnode(msg, tipc_own_addr);  		msg_set_orignode(msg, tipc_own_addr);  	} @@ -676,6 +699,7 @@ static void port_dispatcher_sigh(void *dummy)  		struct tipc_name_seq dseq;  		void *usr_handle;  		int connected; +		int peer_invalid;  		int published;  		u32 message_type; @@ -696,6 +720,7 @@ static void port_dispatcher_sigh(void *dummy)  		up_ptr = p_ptr->user_port;  		usr_handle = up_ptr->usr_handle;  		connected = p_ptr->connected; +		peer_invalid = connected && !tipc_port_peer_msg(p_ptr, msg);  		published = p_ptr->published;  		if (unlikely(msg_errcode(msg))) @@ -705,8 +730,6 @@ static void port_dispatcher_sigh(void *dummy)  		case TIPC_CONN_MSG:{  				tipc_conn_msg_event cb = up_ptr->conn_msg_cb; -				u32 peer_port = port_peerport(p_ptr); -				u32 peer_node = port_peernode(p_ptr);  				u32 dsz;  				tipc_port_unlock(p_ptr); @@ -715,8 +738,7 @@ static void port_dispatcher_sigh(void *dummy)  				if (unlikely(!connected)) {  					if (tipc_connect2port(dref, &orig))  						goto reject; -				} else if ((msg_origport(msg) != peer_port) || -					   (msg_orignode(msg) != peer_node)) +				} else if (peer_invalid)  					goto reject;  				dsz = msg_data_sz(msg);  				if (unlikely(dsz && @@ -768,14 +790,9 @@ err:  		case TIPC_CONN_MSG:{  				tipc_conn_shutdown_event cb =  					up_ptr->conn_err_cb; -				u32 peer_port = port_peerport(p_ptr); -				u32 peer_node = port_peernode(p_ptr);  				tipc_port_unlock(p_ptr); -				if (!cb || !connected) -					break; -				if ((msg_origport(msg) != peer_port) || -				    (msg_orignode(msg) != peer_node)) +				if (!cb || !connected || peer_invalid)  					break;  				tipc_disconnect(dref);  				skb_pull(buf, msg_hdr_sz(msg)); @@ -1152,17 +1169,6 @@ int tipc_port_recv_msg(struct sk_buff *buf)  	/* validate destination & pass to port, otherwise reject message */  	p_ptr = tipc_port_lock(destport);  	if (likely(p_ptr)) { -		if (likely(p_ptr->connected)) { -			if ((unlikely(msg_origport(msg) != -				      tipc_peer_port(p_ptr))) || -			    (unlikely(msg_orignode(msg) != -				      tipc_peer_node(p_ptr))) || -			    (unlikely(!msg_connected(msg)))) { -				err = TIPC_ERR_NO_PORT; -				tipc_port_unlock(p_ptr); -				goto reject; -			} -		}  		err = p_ptr->dispatcher(p_ptr, buf);  		tipc_port_unlock(p_ptr);  		if (likely(!err)) @@ -1170,7 +1176,7 @@ int tipc_port_recv_msg(struct sk_buff *buf)  	} else {  		err = TIPC_ERR_NO_PORT;  	} -reject: +  	return tipc_reject_msg(buf, err);  } @@ -1211,7 +1217,7 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect,  	p_ptr->congested = 1;  	if (!tipc_port_congested(p_ptr)) {  		destnode = port_peernode(p_ptr); -		if (likely(destnode != tipc_own_addr)) +		if (likely(!in_own_node(destnode)))  			res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,  							   total_len, destnode);  		else @@ -1261,13 +1267,17 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,  	msg_set_destport(msg, destport);  	if (likely(destport || destnode)) { -		if (likely(destnode == tipc_own_addr)) +		if (likely(in_own_node(destnode)))  			res = tipc_port_recv_sections(p_ptr, num_sect,  						      msg_sect, total_len); -		else +		else if (tipc_own_addr)  			res = tipc_link_send_sections_fast(p_ptr, msg_sect,  							   num_sect, total_len,  							   destnode); +		else +			res = tipc_port_reject_sections(p_ptr, msg, msg_sect, +							num_sect, total_len, +							TIPC_ERR_NO_NODE);  		if (likely(res != -ELINKCONG)) {  			if (res > 0)  				p_ptr->sent++; @@ -1305,12 +1315,15 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest,  	msg_set_destport(msg, dest->ref);  	msg_set_hdr_sz(msg, BASIC_H_SIZE); -	if (dest->node == tipc_own_addr) +	if (in_own_node(dest->node))  		res =  tipc_port_recv_sections(p_ptr, num_sect, msg_sect,  					       total_len); -	else +	else if (tipc_own_addr)  		res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,  						   total_len, dest->node); +	else +		res = tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect, +						total_len, TIPC_ERR_NO_NODE);  	if (likely(res != -ELINKCONG)) {  		if (res > 0)  			p_ptr->sent++; @@ -1349,7 +1362,7 @@ int tipc_send_buf2port(u32 ref, struct tipc_portid const *dest,  	skb_push(buf, BASIC_H_SIZE);  	skb_copy_to_linear_data(buf, msg, BASIC_H_SIZE); -	if (dest->node == tipc_own_addr) +	if (in_own_node(dest->node))  		res = tipc_port_recv_msg(buf);  	else  		res = tipc_send_buf_fast(buf, dest->node);  |