diff options
Diffstat (limited to 'net/tipc/socket.c')
| -rw-r--r-- | net/tipc/socket.c | 102 | 
1 files changed, 96 insertions, 6 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 7e6240e41e69..ea33eab4fb9d 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -57,6 +57,10 @@ static int tipc_release(struct socket *sock);  static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);  static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p);  static void tipc_sk_timeout(unsigned long ref); +static int tipc_sk_publish(struct tipc_port *port, uint scope, +			   struct tipc_name_seq const *seq); +static int tipc_sk_withdraw(struct tipc_port *port, uint scope, +			    struct tipc_name_seq const *seq);  static const struct proto_ops packet_ops;  static const struct proto_ops stream_ops; @@ -138,6 +142,38 @@ static void reject_rx_queue(struct sock *sk)  	}  } +/* tipc_sk_peer_msg - verify if 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. + */ +static bool tipc_sk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg) +{ +	u32 peer_port = tipc_port_peerport(&tsk->port); +	u32 orig_node; +	u32 peer_node; + +	if (unlikely(!tsk->port.connected)) +		return false; + +	if (unlikely(msg_origport(msg) != peer_port)) +		return false; + +	orig_node = msg_orignode(msg); +	peer_node = tipc_port_peernode(&tsk->port); + +	if (likely(orig_node == peer_node)) +		return true; + +	if (!orig_node && (peer_node == tipc_own_addr)) +		return true; + +	if (!peer_node && (orig_node == tipc_own_addr)) +		return true; + +	return false; +} +  /**   * tipc_sk_create - create a TIPC socket   * @net: network namespace (must be default network) @@ -356,7 +392,7 @@ static int tipc_release(struct socket *sock)  		}  	} -	tipc_withdraw(port, 0, NULL); +	tipc_sk_withdraw(port, 0, NULL);  	tipc_ref_discard(port->ref);  	k_cancel_timer(&port->timer);  	if (port->connected) { @@ -407,7 +443,7 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,  	lock_sock(sk);  	if (unlikely(!uaddr_len)) { -		res = tipc_withdraw(&tsk->port, 0, NULL); +		res = tipc_sk_withdraw(&tsk->port, 0, NULL);  		goto exit;  	} @@ -435,8 +471,8 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,  	}  	res = (addr->scope > 0) ? -		tipc_publish(&tsk->port, addr->scope, &addr->addr.nameseq) : -		tipc_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq); +		tipc_sk_publish(&tsk->port, addr->scope, &addr->addr.nameseq) : +		tipc_sk_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq);  exit:  	release_sock(sk);  	return res; @@ -663,7 +699,7 @@ static int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode,  	int conn_cong;  	/* Ignore if connection cannot be validated: */ -	if (!port->connected || !tipc_port_peer_msg(port, msg)) +	if (!tipc_sk_peer_msg(tsk, msg))  		goto exit;  	port->probing_state = TIPC_CONN_OK; @@ -1444,7 +1480,7 @@ static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)  	switch ((int)sock->state) {  	case SS_CONNECTED:  		/* Accept only connection-based messages sent by peer */ -		if (msg_connected(msg) && tipc_port_peer_msg(port, msg)) { +		if (tipc_sk_peer_msg(tsk, msg)) {  			if (unlikely(msg_errcode(msg))) {  				sock->state = SS_DISCONNECTING;  				port->connected = 0; @@ -2027,6 +2063,60 @@ exit:  	tipc_sk_put(tsk);  } +static int tipc_sk_publish(struct tipc_port *port, uint scope, +			   struct tipc_name_seq const *seq) +{ +	struct publication *publ; +	u32 key; + +	if (port->connected) +		return -EINVAL; +	key = port->ref + port->pub_count + 1; +	if (key == port->ref) +		return -EADDRINUSE; + +	publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper, +				    scope, port->ref, key); +	if (unlikely(!publ)) +		return -EINVAL; + +	list_add(&publ->pport_list, &port->publications); +	port->pub_count++; +	port->published = 1; +	return 0; +} + +static int tipc_sk_withdraw(struct tipc_port *port, uint scope, +			    struct tipc_name_seq const *seq) +{ +	struct publication *publ; +	struct publication *safe; +	int rc = -EINVAL; + +	list_for_each_entry_safe(publ, safe, &port->publications, pport_list) { +		if (seq) { +			if (publ->scope != scope) +				continue; +			if (publ->type != seq->type) +				continue; +			if (publ->lower != seq->lower) +				continue; +			if (publ->upper != seq->upper) +				break; +			tipc_nametbl_withdraw(publ->type, publ->lower, +					      publ->ref, publ->key); +			rc = 0; +			break; +		} +		tipc_nametbl_withdraw(publ->type, publ->lower, +				      publ->ref, publ->key); +		rc = 0; +	} +	if (list_empty(&port->publications)) +		port->published = 0; +	return rc; +} +  static int tipc_sk_show(struct tipc_port *port, char *buf,  			int len, int full_id)  {  | 
