diff options
Diffstat (limited to 'net/tipc/port.c')
| -rw-r--r-- | net/tipc/port.c | 284 | 
1 files changed, 129 insertions, 155 deletions
| diff --git a/net/tipc/port.c b/net/tipc/port.c index c68dc956a42..54d812a5a4d 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -222,7 +222,7 @@ struct tipc_port *tipc_createport_raw(void *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, LONG_H_SIZE, 0); +	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); @@ -327,26 +327,23 @@ int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable)  }  /* - * port_build_proto_msg(): build a port level protocol - * or a connection abortion message. Called with - * tipc_port lock on. + * port_build_proto_msg(): create connection protocol message for port + * + * On entry the port must be locked and connected.   */ -static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode, -					    u32 origport, u32 orignode, -					    u32 usr, u32 type, u32 err, -					    u32 ack) +static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr, +					    u32 type, u32 ack)  {  	struct sk_buff *buf;  	struct tipc_msg *msg; -	buf = tipc_buf_acquire(LONG_H_SIZE); +	buf = tipc_buf_acquire(INT_H_SIZE);  	if (buf) {  		msg = buf_msg(buf); -		tipc_msg_init(msg, usr, type, LONG_H_SIZE, destnode); -		msg_set_errcode(msg, err); -		msg_set_destport(msg, destport); -		msg_set_origport(msg, origport); -		msg_set_orignode(msg, orignode); +		tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE, +			      port_peernode(p_ptr)); +		msg_set_destport(msg, port_peerport(p_ptr)); +		msg_set_origport(msg, p_ptr->ref);  		msg_set_msgcnt(msg, ack);  	}  	return buf; @@ -358,45 +355,48 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)  	struct sk_buff *rbuf;  	struct tipc_msg *rmsg;  	int hdr_sz; -	u32 imp = msg_importance(msg); +	u32 imp;  	u32 data_sz = msg_data_sz(msg); - -	if (data_sz > MAX_REJECT_SIZE) -		data_sz = MAX_REJECT_SIZE; -	if (msg_connected(msg) && (imp < TIPC_CRITICAL_IMPORTANCE)) -		imp++; +	u32 src_node; +	u32 rmsg_sz;  	/* discard rejected message if it shouldn't be returned to sender */ -	if (msg_errcode(msg) || msg_dest_droppable(msg)) { -		buf_discard(buf); -		return data_sz; -	} -	/* construct rejected message */ -	if (msg_mcast(msg)) -		hdr_sz = MCAST_H_SIZE; -	else -		hdr_sz = LONG_H_SIZE; -	rbuf = tipc_buf_acquire(data_sz + hdr_sz); -	if (rbuf == NULL) { -		buf_discard(buf); -		return data_sz; +	if (WARN(!msg_isdata(msg), +		 "attempt to reject message with user=%u", msg_user(msg))) { +		dump_stack(); +		goto exit;  	} +	if (msg_errcode(msg) || msg_dest_droppable(msg)) +		goto exit; + +	/* +	 * construct returned message by copying rejected message header and +	 * data (or subset), then updating header fields that need adjusting +	 */ + +	hdr_sz = msg_hdr_sz(msg); +	rmsg_sz = hdr_sz + min_t(u32, data_sz, MAX_REJECT_SIZE); + +	rbuf = tipc_buf_acquire(rmsg_sz); +	if (rbuf == NULL) +		goto exit; +  	rmsg = buf_msg(rbuf); -	tipc_msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg)); -	msg_set_errcode(rmsg, err); -	msg_set_destport(rmsg, msg_origport(msg)); -	msg_set_origport(rmsg, msg_destport(msg)); -	if (msg_short(msg)) { -		msg_set_orignode(rmsg, tipc_own_addr); -		/* leave name type & instance as zeroes */ -	} else { -		msg_set_orignode(rmsg, msg_destnode(msg)); -		msg_set_nametype(rmsg, msg_nametype(msg)); -		msg_set_nameinst(rmsg, msg_nameinst(msg)); +	skb_copy_to_linear_data(rbuf, msg, rmsg_sz); + +	if (msg_connected(rmsg)) { +		imp = msg_importance(rmsg); +		if (imp < TIPC_CRITICAL_IMPORTANCE) +			msg_set_importance(rmsg, ++imp);  	} -	msg_set_size(rmsg, data_sz + hdr_sz); -	skb_copy_to_linear_data_offset(rbuf, hdr_sz, msg_data(msg), data_sz); +	msg_set_non_seq(rmsg, 0); +	msg_set_size(rmsg, rmsg_sz); +	msg_set_errcode(rmsg, err); +	msg_set_prevnode(rmsg, tipc_own_addr); +	msg_swap_words(rmsg, 4, 5); +	if (!msg_short(rmsg)) +		msg_swap_words(rmsg, 6, 7);  	/* send self-abort message when rejecting on a connected port */  	if (msg_connected(msg)) { @@ -411,9 +411,15 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)  		tipc_net_route_msg(abuf);  	} -	/* send rejected message */ +	/* send returned message & dispose of rejected message */ + +	src_node = msg_prevnode(msg); +	if (src_node == tipc_own_addr) +		tipc_port_recv_msg(rbuf); +	else +		tipc_link_send(rbuf, src_node, msg_link_selector(rmsg)); +exit:  	buf_discard(buf); -	tipc_net_route_msg(rbuf);  	return data_sz;  } @@ -449,14 +455,7 @@ static void port_timeout(unsigned long ref)  	if (p_ptr->probing_state == PROBING) {  		buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);  	} else { -		buf = port_build_proto_msg(port_peerport(p_ptr), -					   port_peernode(p_ptr), -					   p_ptr->ref, -					   tipc_own_addr, -					   CONN_MANAGER, -					   CONN_PROBE, -					   TIPC_OK, -					   0); +		buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0);  		p_ptr->probing_state = PROBING;  		k_start_timer(&p_ptr->timer, p_ptr->probing_interval);  	} @@ -480,100 +479,94 @@ static void port_handle_node_down(unsigned long ref)  static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err)  { -	u32 imp = msg_importance(&p_ptr->phdr); +	struct sk_buff *buf = port_build_peer_abort_msg(p_ptr, err); -	if (!p_ptr->connected) -		return NULL; -	if (imp < TIPC_CRITICAL_IMPORTANCE) -		imp++; -	return port_build_proto_msg(p_ptr->ref, -				    tipc_own_addr, -				    port_peerport(p_ptr), -				    port_peernode(p_ptr), -				    imp, -				    TIPC_CONN_MSG, -				    err, -				    0); +	if (buf) { +		struct tipc_msg *msg = buf_msg(buf); +		msg_swap_words(msg, 4, 5); +		msg_swap_words(msg, 6, 7); +	} +	return buf;  }  static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err)  { -	u32 imp = msg_importance(&p_ptr->phdr); +	struct sk_buff *buf; +	struct tipc_msg *msg; +	u32 imp;  	if (!p_ptr->connected)  		return NULL; -	if (imp < TIPC_CRITICAL_IMPORTANCE) -		imp++; -	return port_build_proto_msg(port_peerport(p_ptr), -				    port_peernode(p_ptr), -				    p_ptr->ref, -				    tipc_own_addr, -				    imp, -				    TIPC_CONN_MSG, -				    err, -				    0); + +	buf = tipc_buf_acquire(BASIC_H_SIZE); +	if (buf) { +		msg = buf_msg(buf); +		memcpy(msg, &p_ptr->phdr, BASIC_H_SIZE); +		msg_set_hdr_sz(msg, BASIC_H_SIZE); +		msg_set_size(msg, BASIC_H_SIZE); +		imp = msg_importance(msg); +		if (imp < TIPC_CRITICAL_IMPORTANCE) +			msg_set_importance(msg, ++imp); +		msg_set_errcode(msg, err); +	} +	return buf;  }  void tipc_port_recv_proto_msg(struct sk_buff *buf)  {  	struct tipc_msg *msg = buf_msg(buf); -	struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg)); -	u32 err = TIPC_OK; +	struct tipc_port *p_ptr;  	struct sk_buff *r_buf = NULL; -	struct sk_buff *abort_buf = NULL; - -	if (!p_ptr) { -		err = TIPC_ERR_NO_PORT; -	} else if (p_ptr->connected) { -		if ((port_peernode(p_ptr) != msg_orignode(msg)) || -		    (port_peerport(p_ptr) != msg_origport(msg))) { -			err = TIPC_ERR_NO_PORT; -		} else if (msg_type(msg) == CONN_ACK) { -			int wakeup = tipc_port_congested(p_ptr) && -				     p_ptr->congested && -				     p_ptr->wakeup; -			p_ptr->acked += msg_msgcnt(msg); -			if (tipc_port_congested(p_ptr)) -				goto exit; -			p_ptr->congested = 0; -			if (!wakeup) -				goto exit; -			p_ptr->wakeup(p_ptr); -			goto exit; +	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)) { +		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); +			msg_set_errcode(msg, TIPC_ERR_NO_PORT); +			msg_set_origport(msg, destport); +			msg_set_destport(msg, origport);  		} -	} else if (p_ptr->published) { -		err = TIPC_ERR_NO_PORT; -	} -	if (err) { -		r_buf = port_build_proto_msg(msg_origport(msg), -					     msg_orignode(msg), -					     msg_destport(msg), -					     tipc_own_addr, -					     TIPC_HIGH_IMPORTANCE, -					     TIPC_CONN_MSG, -					     err, -					     0); +		if (p_ptr) +			tipc_port_unlock(p_ptr);  		goto exit;  	} -	/* All is fine */ -	if (msg_type(msg) == CONN_PROBE) { -		r_buf = port_build_proto_msg(msg_origport(msg), -					     msg_orignode(msg), -					     msg_destport(msg), -					     tipc_own_addr, -					     CONN_MANAGER, -					     CONN_PROBE_REPLY, -					     TIPC_OK, -					     0); +	/* Process protocol message sent by peer */ + +	switch (msg_type(msg)) { +	case CONN_ACK: +		wakeable = tipc_port_congested(p_ptr) && p_ptr->congested && +			p_ptr->wakeup; +		p_ptr->acked += msg_msgcnt(msg); +		if (!tipc_port_congested(p_ptr)) { +			p_ptr->congested = 0; +			if (wakeable) +				p_ptr->wakeup(p_ptr); +		} +		break; +	case CONN_PROBE: +		r_buf = port_build_proto_msg(p_ptr, CONN_PROBE_REPLY, 0); +		break; +	default: +		/* CONN_PROBE_REPLY or unrecognized - no action required */ +		break;  	}  	p_ptr->probing_state = CONFIRMED; +	tipc_port_unlock(p_ptr);  exit: -	if (p_ptr) -		tipc_port_unlock(p_ptr);  	tipc_net_route_msg(r_buf); -	tipc_net_route_msg(abort_buf);  	buf_discard(buf);  } @@ -889,14 +882,7 @@ void tipc_acknowledge(u32 ref, u32 ack)  		return;  	if (p_ptr->connected) {  		p_ptr->conn_unacked -= ack; -		buf = port_build_proto_msg(port_peerport(p_ptr), -					   port_peernode(p_ptr), -					   ref, -					   tipc_own_addr, -					   CONN_MANAGER, -					   CONN_ACK, -					   TIPC_OK, -					   ack); +		buf = port_build_proto_msg(p_ptr, CONN_ACK, ack);  	}  	tipc_port_unlock(p_ptr);  	tipc_net_route_msg(buf); @@ -1140,19 +1126,7 @@ int tipc_shutdown(u32 ref)  	if (!p_ptr)  		return -EINVAL; -	if (p_ptr->connected) { -		u32 imp = msg_importance(&p_ptr->phdr); -		if (imp < TIPC_CRITICAL_IMPORTANCE) -			imp++; -		buf = port_build_proto_msg(port_peerport(p_ptr), -					   port_peernode(p_ptr), -					   ref, -					   tipc_own_addr, -					   imp, -					   TIPC_CONN_MSG, -					   TIPC_CONN_SHUTDOWN, -					   0); -	} +	buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN);  	tipc_port_unlock(p_ptr);  	tipc_net_route_msg(buf);  	return tipc_disconnect(ref); @@ -1238,7 +1212,7 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,  	msg_set_type(msg, TIPC_NAMED_MSG);  	msg_set_orignode(msg, tipc_own_addr);  	msg_set_origport(msg, ref); -	msg_set_hdr_sz(msg, LONG_H_SIZE); +	msg_set_hdr_sz(msg, NAMED_H_SIZE);  	msg_set_nametype(msg, name->type);  	msg_set_nameinst(msg, name->instance);  	msg_set_lookup_scope(msg, tipc_addr_scope(domain)); @@ -1291,7 +1265,7 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest,  	msg_set_origport(msg, ref);  	msg_set_destnode(msg, dest->node);  	msg_set_destport(msg, dest->ref); -	msg_set_hdr_sz(msg, DIR_MSG_H_SIZE); +	msg_set_hdr_sz(msg, BASIC_H_SIZE);  	if (dest->node == tipc_own_addr)  		res =  tipc_port_recv_sections(p_ptr, num_sect, msg_sect, @@ -1331,13 +1305,13 @@ int tipc_send_buf2port(u32 ref, struct tipc_portid const *dest,  	msg_set_origport(msg, ref);  	msg_set_destnode(msg, dest->node);  	msg_set_destport(msg, dest->ref); -	msg_set_hdr_sz(msg, DIR_MSG_H_SIZE); -	msg_set_size(msg, DIR_MSG_H_SIZE + dsz); -	if (skb_cow(buf, DIR_MSG_H_SIZE)) +	msg_set_hdr_sz(msg, BASIC_H_SIZE); +	msg_set_size(msg, BASIC_H_SIZE + dsz); +	if (skb_cow(buf, BASIC_H_SIZE))  		return -ENOMEM; -	skb_push(buf, DIR_MSG_H_SIZE); -	skb_copy_to_linear_data(buf, msg, DIR_MSG_H_SIZE); +	skb_push(buf, BASIC_H_SIZE); +	skb_copy_to_linear_data(buf, msg, BASIC_H_SIZE);  	if (dest->node == tipc_own_addr)  		res = tipc_port_recv_msg(buf); | 
