diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/bearer.c | 11 | ||||
| -rw-r--r-- | net/tipc/bearer.h | 13 | ||||
| -rw-r--r-- | net/tipc/core.c | 2 | ||||
| -rw-r--r-- | net/tipc/core.h | 2 | ||||
| -rw-r--r-- | net/tipc/link.c | 40 | ||||
| -rw-r--r-- | net/tipc/monitor.c | 10 | ||||
| -rw-r--r-- | net/tipc/msg.h | 2 | ||||
| -rw-r--r-- | net/tipc/netlink.c | 27 | ||||
| -rw-r--r-- | net/tipc/netlink_compat.c | 25 | ||||
| -rw-r--r-- | net/tipc/socket.c | 500 | ||||
| -rw-r--r-- | net/tipc/udp_media.c | 5 | 
11 files changed, 336 insertions, 301 deletions
| diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 975dbeb60ab0..52d74760fb68 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -421,6 +421,10 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,  	dev = dev_get_by_name(net, driver_name);  	if (!dev)  		return -ENODEV; +	if (tipc_mtu_bad(dev, 0)) { +		dev_put(dev); +		return -EINVAL; +	}  	/* Associate TIPC bearer with L2 bearer */  	rcu_assign_pointer(b->media_ptr, dev); @@ -610,8 +614,6 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,  	if (!b)  		return NOTIFY_DONE; -	b->mtu = dev->mtu; -  	switch (evt) {  	case NETDEV_CHANGE:  		if (netif_carrier_ok(dev)) @@ -624,6 +626,11 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,  		tipc_reset_bearer(net, b);  		break;  	case NETDEV_CHANGEMTU: +		if (tipc_mtu_bad(dev, 0)) { +			bearer_disable(net, b); +			break; +		} +		b->mtu = dev->mtu;  		tipc_reset_bearer(net, b);  		break;  	case NETDEV_CHANGEADDR: diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 78892e2f53e3..278ff7f616f9 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -39,6 +39,7 @@  #include "netlink.h"  #include "core.h" +#include "msg.h"  #include <net/genetlink.h>  #define MAX_MEDIA	3 @@ -59,6 +60,9 @@  #define TIPC_MEDIA_TYPE_IB	2  #define TIPC_MEDIA_TYPE_UDP	3 +/* minimum bearer MTU */ +#define TIPC_MIN_BEARER_MTU	(MAX_H_SIZE + INT_H_SIZE) +  /**   * struct tipc_media_addr - destination address used by TIPC bearers   * @value: address info (format defined by media) @@ -215,4 +219,13 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,  void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,  			 struct sk_buff_head *xmitq); +/* check if device MTU is too low for tipc headers */ +static inline bool tipc_mtu_bad(struct net_device *dev, unsigned int reserve) +{ +	if (dev->mtu >= TIPC_MIN_BEARER_MTU + reserve) +		return false; +	netdev_warn(dev, "MTU too low for tipc bearer\n"); +	return true; +} +  #endif	/* _TIPC_BEARER_H */ diff --git a/net/tipc/core.c b/net/tipc/core.c index 236b043a4156..0b982d048fb9 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -47,7 +47,7 @@  #include <linux/module.h>  /* configurable TIPC parameters */ -int tipc_net_id __read_mostly; +unsigned int tipc_net_id __read_mostly;  int sysctl_tipc_rmem[3] __read_mostly;	/* min/default/max */  static int __net_init tipc_init_net(struct net *net) diff --git a/net/tipc/core.h b/net/tipc/core.h index a1845fb27d80..5cc5398be722 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -74,7 +74,7 @@ struct tipc_monitor;  #define MAX_BEARERS	         3  #define TIPC_DEF_MON_THRESHOLD  32 -extern int tipc_net_id __read_mostly; +extern unsigned int tipc_net_id __read_mostly;  extern int sysctl_tipc_rmem[3] __read_mostly;  extern int sysctl_tipc_named_timeout __read_mostly; diff --git a/net/tipc/link.c b/net/tipc/link.c index 1055164c6232..bda89bf9f4ff 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -47,8 +47,8 @@  #include <linux/pkt_sched.h>  struct tipc_stats { -	u32 sent_info;		/* used in counting # sent packets */ -	u32 recv_info;		/* used in counting # recv'd packets */ +	u32 sent_pkts; +	u32 recv_pkts;  	u32 sent_states;  	u32 recv_states;  	u32 sent_probes; @@ -857,7 +857,6 @@ void tipc_link_reset(struct tipc_link *l)  	l->acked = 0;  	l->silent_intv_cnt = 0;  	l->rst_cnt = 0; -	l->stats.recv_info = 0;  	l->stale_count = 0;  	l->bc_peer_is_up = false;  	memset(&l->mon_state, 0, sizeof(l->mon_state)); @@ -888,6 +887,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,  	struct sk_buff_head *transmq = &l->transmq;  	struct sk_buff_head *backlogq = &l->backlogq;  	struct sk_buff *skb, *_skb, *bskb; +	int pkt_cnt = skb_queue_len(list);  	/* Match msg importance against this and all higher backlog limits: */  	if (!skb_queue_empty(backlogq)) { @@ -901,6 +901,11 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,  		return -EMSGSIZE;  	} +	if (pkt_cnt > 1) { +		l->stats.sent_fragmented++; +		l->stats.sent_fragments += pkt_cnt; +	} +  	/* Prepare each packet for sending, and add to relevant queue: */  	while (skb_queue_len(list)) {  		skb = skb_peek(list); @@ -920,6 +925,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,  			__skb_queue_tail(xmitq, _skb);  			TIPC_SKB_CB(skb)->ackers = l->ackers;  			l->rcv_unacked = 0; +			l->stats.sent_pkts++;  			seqno++;  			continue;  		} @@ -968,6 +974,7 @@ void tipc_link_advance_backlog(struct tipc_link *l, struct sk_buff_head *xmitq)  		msg_set_ack(hdr, ack);  		msg_set_bcast_ack(hdr, bc_ack);  		l->rcv_unacked = 0; +		l->stats.sent_pkts++;  		seqno++;  	}  	l->snd_nxt = seqno; @@ -1260,7 +1267,7 @@ int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb,  		/* Deliver packet */  		l->rcv_nxt++; -		l->stats.recv_info++; +		l->stats.recv_pkts++;  		if (!tipc_data_input(l, skb, l->inputq))  			rc |= tipc_link_input(l, skb, l->inputq);  		if (unlikely(++l->rcv_unacked >= TIPC_MIN_LINK_WIN)) @@ -1492,8 +1499,9 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,  		if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL))  			l->tolerance = peers_tol; -		if (peers_prio && in_range(peers_prio, TIPC_MIN_LINK_PRI, -					   TIPC_MAX_LINK_PRI)) { +		/* Update own prio if peer indicates a different value */ +		if ((peers_prio != l->priority) && +		    in_range(peers_prio, 1, TIPC_MAX_LINK_PRI)) {  			l->priority = peers_prio;  			rc = tipc_link_fsm_evt(l, LINK_FAILURE_EVT);  		} @@ -1799,10 +1807,6 @@ void tipc_link_set_queue_limits(struct tipc_link *l, u32 win)  void tipc_link_reset_stats(struct tipc_link *l)  {  	memset(&l->stats, 0, sizeof(l->stats)); -	if (!link_is_bc_sndlink(l)) { -		l->stats.sent_info = l->snd_nxt; -		l->stats.recv_info = l->rcv_nxt; -	}  }  static void link_print(struct tipc_link *l, const char *str) @@ -1866,12 +1870,12 @@ static int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s)  	};  	struct nla_map map[] = { -		{TIPC_NLA_STATS_RX_INFO, s->recv_info}, +		{TIPC_NLA_STATS_RX_INFO, 0},  		{TIPC_NLA_STATS_RX_FRAGMENTS, s->recv_fragments},  		{TIPC_NLA_STATS_RX_FRAGMENTED, s->recv_fragmented},  		{TIPC_NLA_STATS_RX_BUNDLES, s->recv_bundles},  		{TIPC_NLA_STATS_RX_BUNDLED, s->recv_bundled}, -		{TIPC_NLA_STATS_TX_INFO, s->sent_info}, +		{TIPC_NLA_STATS_TX_INFO, 0},  		{TIPC_NLA_STATS_TX_FRAGMENTS, s->sent_fragments},  		{TIPC_NLA_STATS_TX_FRAGMENTED, s->sent_fragmented},  		{TIPC_NLA_STATS_TX_BUNDLES, s->sent_bundles}, @@ -1946,9 +1950,9 @@ int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg,  		goto attr_msg_full;  	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_MTU, link->mtu))  		goto attr_msg_full; -	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, link->rcv_nxt)) +	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, link->stats.recv_pkts))  		goto attr_msg_full; -	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, link->snd_nxt)) +	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, link->stats.sent_pkts))  		goto attr_msg_full;  	if (tipc_link_is_up(link)) @@ -2003,12 +2007,12 @@ static int __tipc_nl_add_bc_link_stat(struct sk_buff *skb,  	};  	struct nla_map map[] = { -		{TIPC_NLA_STATS_RX_INFO, stats->recv_info}, +		{TIPC_NLA_STATS_RX_INFO, stats->recv_pkts},  		{TIPC_NLA_STATS_RX_FRAGMENTS, stats->recv_fragments},  		{TIPC_NLA_STATS_RX_FRAGMENTED, stats->recv_fragmented},  		{TIPC_NLA_STATS_RX_BUNDLES, stats->recv_bundles},  		{TIPC_NLA_STATS_RX_BUNDLED, stats->recv_bundled}, -		{TIPC_NLA_STATS_TX_INFO, stats->sent_info}, +		{TIPC_NLA_STATS_TX_INFO, stats->sent_pkts},  		{TIPC_NLA_STATS_TX_FRAGMENTS, stats->sent_fragments},  		{TIPC_NLA_STATS_TX_FRAGMENTED, stats->sent_fragmented},  		{TIPC_NLA_STATS_TX_BUNDLES, stats->sent_bundles}, @@ -2075,9 +2079,9 @@ int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg)  		goto attr_msg_full;  	if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, bcl->name))  		goto attr_msg_full; -	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, bcl->rcv_nxt)) +	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, 0))  		goto attr_msg_full; -	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, bcl->snd_nxt)) +	if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, 0))  		goto attr_msg_full;  	prop = nla_nest_start(msg->skb, TIPC_NLA_LINK_PROP); diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c index ed97a5876ebe..9e109bb1a207 100644 --- a/net/tipc/monitor.c +++ b/net/tipc/monitor.c @@ -455,14 +455,14 @@ void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,  	int i, applied_bef;  	state->probing = false; -	if (!dlen) -		return;  	/* Sanity check received domain record */ -	if ((dlen < new_dlen) || ntohs(arrv_dom->len) != new_dlen) { -		pr_warn_ratelimited("Received illegal domain record\n"); +	if (dlen < dom_rec_len(arrv_dom, 0)) +		return; +	if (dlen != dom_rec_len(arrv_dom, new_member_cnt)) +		return; +	if ((dlen < new_dlen) || ntohs(arrv_dom->len) != new_dlen)  		return; -	}  	/* Synch generation numbers with peer if link just came up */  	if (!state->synched) { diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 50a739860d37..8d408612ffa4 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -95,7 +95,7 @@ struct plist;  #define TIPC_MEDIA_INFO_OFFSET	5  struct tipc_skb_cb { -	void *handle; +	u32 bytes_read;  	struct sk_buff *tail;  	bool validated;  	bool wakeup_pending; diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 3200059d14b2..26ca8dd64ded 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -135,15 +135,6 @@ const struct nla_policy tipc_nl_udp_policy[TIPC_NLA_UDP_MAX + 1] = {  /* Users of the legacy API (tipc-config) can't handle that we add operations,   * so we have a separate genl handling for the new API.   */ -struct genl_family tipc_genl_family = { -	.id		= GENL_ID_GENERATE, -	.name		= TIPC_GENL_V2_NAME, -	.version	= TIPC_GENL_V2_VERSION, -	.hdrsize	= 0, -	.maxattr	= TIPC_NLA_MAX, -	.netnsok	= true, -}; -  static const struct genl_ops tipc_genl_v2_ops[] = {  	{  		.cmd	= TIPC_NL_BEARER_DISABLE, @@ -258,23 +249,33 @@ static const struct genl_ops tipc_genl_v2_ops[] = {  #endif  }; +struct genl_family tipc_genl_family __ro_after_init = { +	.name		= TIPC_GENL_V2_NAME, +	.version	= TIPC_GENL_V2_VERSION, +	.hdrsize	= 0, +	.maxattr	= TIPC_NLA_MAX, +	.netnsok	= true, +	.module		= THIS_MODULE, +	.ops		= tipc_genl_v2_ops, +	.n_ops		= ARRAY_SIZE(tipc_genl_v2_ops), +}; +  int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr)  {  	u32 maxattr = tipc_genl_family.maxattr; -	*attr = tipc_genl_family.attrbuf; +	*attr = genl_family_attrbuf(&tipc_genl_family);  	if (!*attr)  		return -EOPNOTSUPP;  	return nlmsg_parse(nlh, GENL_HDRLEN, *attr, maxattr, tipc_nl_policy);  } -int tipc_netlink_start(void) +int __init tipc_netlink_start(void)  {  	int res; -	res = genl_register_family_with_ops(&tipc_genl_family, -					    tipc_genl_v2_ops); +	res = genl_register_family(&tipc_genl_family);  	if (res) {  		pr_err("Failed to register netlink interface\n");  		return res; diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 1fd464764765..e1ae8a8a2b8e 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -1215,15 +1215,6 @@ send:  	return err;  } -static struct genl_family tipc_genl_compat_family = { -	.id		= GENL_ID_GENERATE, -	.name		= TIPC_GENL_NAME, -	.version	= TIPC_GENL_VERSION, -	.hdrsize	= TIPC_GENL_HDRLEN, -	.maxattr	= 0, -	.netnsok	= true, -}; -  static struct genl_ops tipc_genl_compat_ops[] = {  	{  		.cmd		= TIPC_GENL_CMD, @@ -1231,12 +1222,22 @@ static struct genl_ops tipc_genl_compat_ops[] = {  	},  }; -int tipc_netlink_compat_start(void) +static struct genl_family tipc_genl_compat_family __ro_after_init = { +	.name		= TIPC_GENL_NAME, +	.version	= TIPC_GENL_VERSION, +	.hdrsize	= TIPC_GENL_HDRLEN, +	.maxattr	= 0, +	.netnsok	= true, +	.module		= THIS_MODULE, +	.ops		= tipc_genl_compat_ops, +	.n_ops		= ARRAY_SIZE(tipc_genl_compat_ops), +}; + +int __init tipc_netlink_compat_start(void)  {  	int res; -	res = genl_register_family_with_ops(&tipc_genl_compat_family, -					    tipc_genl_compat_ops); +	res = genl_register_family(&tipc_genl_compat_family);  	if (res) {  		pr_err("Failed to register legacy compat interface\n");  		return res; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index db32777ab591..333c5dae0072 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -44,44 +44,43 @@  #include "bcast.h"  #include "netlink.h" -#define SS_LISTENING		-1	/* socket is listening */ -#define SS_READY		-2	/* socket is connectionless */ -  #define CONN_TIMEOUT_DEFAULT	8000	/* default connect timeout = 8s */  #define CONN_PROBING_INTERVAL	msecs_to_jiffies(3600000)  /* [ms] => 1 h */  #define TIPC_FWD_MSG		1 -#define TIPC_CONN_OK		0 -#define TIPC_CONN_PROBING	1  #define TIPC_MAX_PORT		0xffffffff  #define TIPC_MIN_PORT		1 +enum { +	TIPC_LISTEN = TCP_LISTEN, +	TIPC_ESTABLISHED = TCP_ESTABLISHED, +	TIPC_OPEN = TCP_CLOSE, +	TIPC_DISCONNECTING = TCP_CLOSE_WAIT, +	TIPC_CONNECTING = TCP_SYN_SENT, +}; +  /**   * struct tipc_sock - TIPC socket structure   * @sk: socket - interacts with 'port' and with user via the socket API - * @connected: non-zero if port is currently connected to a peer port   * @conn_type: TIPC type used when connection was established   * @conn_instance: TIPC instance used when connection was established   * @published: non-zero if port has one or more associated names   * @max_pkt: maximum packet size "hint" used when building messages sent by port   * @portid: unique port identity in TIPC socket hash table   * @phdr: preformatted message header used when sending messages - * @port_list: adjacent ports in TIPC's global list of ports   * @publications: list of publications for port   * @pub_count: total # of publications port has made during its lifetime   * @probing_state: - * @probing_intv:   * @conn_timeout: the time we can wait for an unresponded setup request   * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue   * @link_cong: non-zero if owner must sleep because of link congestion   * @sent_unacked: # messages sent by socket, and not yet acked by peer   * @rcv_unacked: # messages read by user, but not yet acked back to peer - * @remote: 'connected' peer for dgram/rdm + * @peer: 'connected' peer for dgram/rdm   * @node: hash table node   * @rcu: rcu struct for tipc_sock   */  struct tipc_sock {  	struct sock sk; -	int connected;  	u32 conn_type;  	u32 conn_instance;  	int published; @@ -91,17 +90,16 @@ struct tipc_sock {  	struct list_head sock_list;  	struct list_head publications;  	u32 pub_count; -	u32 probing_state; -	unsigned long probing_intv;  	uint conn_timeout;  	atomic_t dupl_rcvcnt; +	bool probe_unacked;  	bool link_cong;  	u16 snt_unacked;  	u16 snd_win;  	u16 peer_caps;  	u16 rcv_unacked;  	u16 rcv_win; -	struct sockaddr_tipc remote; +	struct sockaddr_tipc peer;  	struct rhash_head node;  	struct rcu_head rcu;  }; @@ -186,7 +184,7 @@ static struct tipc_sock *tipc_sk(const struct sock *sk)  static bool tsk_conn_cong(struct tipc_sock *tsk)  { -	return tsk->snt_unacked >= tsk->snd_win; +	return tsk->snt_unacked > tsk->snd_win;  }  /* tsk_blocks(): translate a buffer size in bytes to number of @@ -248,6 +246,21 @@ static void tsk_rej_rx_queue(struct sock *sk)  		tipc_sk_respond(sk, skb, TIPC_ERR_NO_PORT);  } +static bool tipc_sk_connected(struct sock *sk) +{ +	return sk->sk_state == TIPC_ESTABLISHED; +} + +/* tipc_sk_type_connectionless - check if the socket is datagram socket + * @sk: socket + * + * Returns true if connection less, false otherwise + */ +static bool tipc_sk_type_connectionless(struct sock *sk) +{ +	return sk->sk_type == SOCK_RDM || sk->sk_type == SOCK_DGRAM; +} +  /* tsk_peer_msg - verify if message was sent by connected port's peer   *   * Handles cases where the node's network address has changed from @@ -255,12 +268,13 @@ static void tsk_rej_rx_queue(struct sock *sk)   */  static bool tsk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg)  { -	struct tipc_net *tn = net_generic(sock_net(&tsk->sk), tipc_net_id); +	struct sock *sk = &tsk->sk; +	struct tipc_net *tn = net_generic(sock_net(sk), tipc_net_id);  	u32 peer_port = tsk_peer_port(tsk);  	u32 orig_node;  	u32 peer_node; -	if (unlikely(!tsk->connected)) +	if (unlikely(!tipc_sk_connected(sk)))  		return false;  	if (unlikely(msg_origport(msg) != peer_port)) @@ -281,6 +295,45 @@ static bool tsk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg)  	return false;  } +/* tipc_set_sk_state - set the sk_state of the socket + * @sk: socket + * + * Caller must hold socket lock + * + * Returns 0 on success, errno otherwise + */ +static int tipc_set_sk_state(struct sock *sk, int state) +{ +	int oldsk_state = sk->sk_state; +	int res = -EINVAL; + +	switch (state) { +	case TIPC_OPEN: +		res = 0; +		break; +	case TIPC_LISTEN: +	case TIPC_CONNECTING: +		if (oldsk_state == TIPC_OPEN) +			res = 0; +		break; +	case TIPC_ESTABLISHED: +		if (oldsk_state == TIPC_CONNECTING || +		    oldsk_state == TIPC_OPEN) +			res = 0; +		break; +	case TIPC_DISCONNECTING: +		if (oldsk_state == TIPC_CONNECTING || +		    oldsk_state == TIPC_ESTABLISHED) +			res = 0; +		break; +	} + +	if (!res) +		sk->sk_state = state; + +	return res; +} +  /**   * tipc_sk_create - create a TIPC socket   * @net: network namespace (must be default network) @@ -298,7 +351,6 @@ static int tipc_sk_create(struct net *net, struct socket *sock,  {  	struct tipc_net *tn;  	const struct proto_ops *ops; -	socket_state state;  	struct sock *sk;  	struct tipc_sock *tsk;  	struct tipc_msg *msg; @@ -310,16 +362,13 @@ static int tipc_sk_create(struct net *net, struct socket *sock,  	switch (sock->type) {  	case SOCK_STREAM:  		ops = &stream_ops; -		state = SS_UNCONNECTED;  		break;  	case SOCK_SEQPACKET:  		ops = &packet_ops; -		state = SS_UNCONNECTED;  		break;  	case SOCK_DGRAM:  	case SOCK_RDM:  		ops = &msg_ops; -		state = SS_READY;  		break;  	default:  		return -EPROTOTYPE; @@ -340,14 +389,15 @@ static int tipc_sk_create(struct net *net, struct socket *sock,  	/* Finish initializing socket data structures */  	sock->ops = ops; -	sock->state = state;  	sock_init_data(sock, sk); +	tipc_set_sk_state(sk, TIPC_OPEN);  	if (tipc_sk_insert(tsk)) {  		pr_warn("Socket create failed; port number exhausted\n");  		return -EINVAL;  	}  	msg_set_origport(msg, tsk->portid);  	setup_timer(&sk->sk_timer, tipc_sk_timeout, (unsigned long)tsk); +	sk->sk_shutdown = 0;  	sk->sk_backlog_rcv = tipc_backlog_rcv;  	sk->sk_rcvbuf = sysctl_tipc_rmem[1];  	sk->sk_data_ready = tipc_data_ready; @@ -360,11 +410,12 @@ static int tipc_sk_create(struct net *net, struct socket *sock,  	tsk->snd_win = tsk_adv_blocks(RCVBUF_MIN);  	tsk->rcv_win = tsk->snd_win; -	if (sock->state == SS_READY) { +	if (tipc_sk_type_connectionless(sk)) {  		tsk_set_unreturnable(tsk, true);  		if (sock->type == SOCK_DGRAM)  			tsk_set_unreliable(tsk, true);  	} +  	return 0;  } @@ -375,6 +426,44 @@ static void tipc_sk_callback(struct rcu_head *head)  	sock_put(&tsk->sk);  } +/* Caller should hold socket lock for the socket. */ +static void __tipc_shutdown(struct socket *sock, int error) +{ +	struct sock *sk = sock->sk; +	struct tipc_sock *tsk = tipc_sk(sk); +	struct net *net = sock_net(sk); +	u32 dnode = tsk_peer_node(tsk); +	struct sk_buff *skb; + +	/* Reject all unreceived messages, except on an active connection +	 * (which disconnects locally & sends a 'FIN+' to peer). +	 */ +	while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { +		if (TIPC_SKB_CB(skb)->bytes_read) { +			kfree_skb(skb); +		} else { +			if (!tipc_sk_type_connectionless(sk) && +			    sk->sk_state != TIPC_DISCONNECTING) { +				tipc_set_sk_state(sk, TIPC_DISCONNECTING); +				tipc_node_remove_conn(net, dnode, tsk->portid); +			} +			tipc_sk_respond(sk, skb, error); +		} +	} +	if (sk->sk_state != TIPC_DISCONNECTING) { +		skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, +				      TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode, +				      tsk_own_node(tsk), tsk_peer_port(tsk), +				      tsk->portid, error); +		if (skb) +			tipc_node_xmit_skb(net, skb, dnode, tsk->portid); +		if (!tipc_sk_type_connectionless(sk)) { +			tipc_node_remove_conn(net, dnode, tsk->portid); +			tipc_set_sk_state(sk, TIPC_DISCONNECTING); +		} +	} +} +  /**   * tipc_release - destroy a TIPC socket   * @sock: socket to destroy @@ -394,10 +483,7 @@ static void tipc_sk_callback(struct rcu_head *head)  static int tipc_release(struct socket *sock)  {  	struct sock *sk = sock->sk; -	struct net *net;  	struct tipc_sock *tsk; -	struct sk_buff *skb; -	u32 dnode;  	/*  	 * Exit if socket isn't fully initialized (occurs when a failed accept() @@ -406,47 +492,16 @@ static int tipc_release(struct socket *sock)  	if (sk == NULL)  		return 0; -	net = sock_net(sk);  	tsk = tipc_sk(sk);  	lock_sock(sk); -	/* -	 * Reject all unreceived messages, except on an active connection -	 * (which disconnects locally & sends a 'FIN+' to peer) -	 */ -	dnode = tsk_peer_node(tsk); -	while (sock->state != SS_DISCONNECTING) { -		skb = __skb_dequeue(&sk->sk_receive_queue); -		if (skb == NULL) -			break; -		if (TIPC_SKB_CB(skb)->handle != NULL) -			kfree_skb(skb); -		else { -			if ((sock->state == SS_CONNECTING) || -			    (sock->state == SS_CONNECTED)) { -				sock->state = SS_DISCONNECTING; -				tsk->connected = 0; -				tipc_node_remove_conn(net, dnode, tsk->portid); -			} -			tipc_sk_respond(sk, skb, TIPC_ERR_NO_PORT); -		} -	} - +	__tipc_shutdown(sock, TIPC_ERR_NO_PORT); +	sk->sk_shutdown = SHUTDOWN_MASK;  	tipc_sk_withdraw(tsk, 0, NULL);  	sk_stop_timer(sk, &sk->sk_timer);  	tipc_sk_remove(tsk); -	if (tsk->connected) { -		skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, -				      TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode, -				      tsk_own_node(tsk), tsk_peer_port(tsk), -				      tsk->portid, TIPC_ERR_NO_PORT); -		if (skb) -			tipc_node_xmit_skb(net, skb, dnode, tsk->portid); -		tipc_node_remove_conn(net, dnode, tsk->portid); -	}  	/* Reject any messages that accumulated in backlog queue */ -	sock->state = SS_DISCONNECTING;  	release_sock(sk);  	call_rcu(&tsk->rcu, tipc_sk_callback); @@ -532,13 +587,14 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,  			int *uaddr_len, int peer)  {  	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; -	struct tipc_sock *tsk = tipc_sk(sock->sk); +	struct sock *sk = sock->sk; +	struct tipc_sock *tsk = tipc_sk(sk);  	struct tipc_net *tn = net_generic(sock_net(sock->sk), tipc_net_id);  	memset(addr, 0, sizeof(*addr));  	if (peer) { -		if ((sock->state != SS_CONNECTED) && -			((peer != 2) || (sock->state != SS_DISCONNECTING))) +		if ((!tipc_sk_connected(sk)) && +		    ((peer != 2) || (sk->sk_state != TIPC_DISCONNECTING)))  			return -ENOTCONN;  		addr->addr.id.ref = tsk_peer_port(tsk);  		addr->addr.id.node = tsk_peer_node(tsk); @@ -570,28 +626,6 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,   * exits.  TCP and other protocols seem to rely on higher level poll routines   * to handle any preventable race conditions, so TIPC will do the same ...   * - * TIPC sets the returned events as follows: - * - * socket state		flags set - * ------------		--------- - * unconnected		no read flags - *			POLLOUT if port is not congested - * - * connecting		POLLIN/POLLRDNORM if ACK/NACK in rx queue - *			no write flags - * - * connected		POLLIN/POLLRDNORM if data in rx queue - *			POLLOUT if port is not congested - * - * disconnecting	POLLIN/POLLRDNORM/POLLHUP - *			no write flags - * - * listening		POLLIN if SYN in rx queue - *			no write flags - * - * ready		POLLIN/POLLRDNORM if data in rx queue - * [connectionless]	POLLOUT (since port cannot be congested) - *   * IMPORTANT: The fact that a read or write operation is indicated does NOT   * imply that the operation will succeed, merely that it should be performed   * and will not block. @@ -605,22 +639,29 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,  	sock_poll_wait(file, sk_sleep(sk), wait); -	switch ((int)sock->state) { -	case SS_UNCONNECTED: -		if (!tsk->link_cong) -			mask |= POLLOUT; -		break; -	case SS_READY: -	case SS_CONNECTED: +	if (sk->sk_shutdown & RCV_SHUTDOWN) +		mask |= POLLRDHUP | POLLIN | POLLRDNORM; +	if (sk->sk_shutdown == SHUTDOWN_MASK) +		mask |= POLLHUP; + +	switch (sk->sk_state) { +	case TIPC_ESTABLISHED:  		if (!tsk->link_cong && !tsk_conn_cong(tsk))  			mask |= POLLOUT;  		/* fall thru' */ -	case SS_CONNECTING: -	case SS_LISTENING: +	case TIPC_LISTEN: +	case TIPC_CONNECTING:  		if (!skb_queue_empty(&sk->sk_receive_queue))  			mask |= (POLLIN | POLLRDNORM);  		break; -	case SS_DISCONNECTING: +	case TIPC_OPEN: +		if (!tsk->link_cong) +			mask |= POLLOUT; +		if (tipc_sk_type_connectionless(sk) && +		    (!skb_queue_empty(&sk->sk_receive_queue))) +			mask |= (POLLIN | POLLRDNORM); +		break; +	case TIPC_DISCONNECTING:  		mask = (POLLIN | POLLRDNORM | POLLHUP);  		break;  	} @@ -651,6 +692,9 @@ static int tipc_sendmcast(struct  socket *sock, struct tipc_name_seq *seq,  	uint mtu;  	int rc; +	if (!timeo && tsk->link_cong) +		return -ELINKCONG; +  	msg_set_type(mhdr, TIPC_MCAST_MSG);  	msg_set_lookup_scope(mhdr, TIPC_CLUSTER_SCOPE);  	msg_set_destport(mhdr, 0); @@ -763,7 +807,7 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,  	if (!tsk_peer_msg(tsk, hdr))  		goto exit; -	tsk->probing_state = TIPC_CONN_OK; +	tsk->probe_unacked = false;  	if (mtyp == CONN_PROBE) {  		msg_set_type(hdr, CONN_PROBE_REPLY); @@ -786,25 +830,25 @@ exit:  static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)  { +	DEFINE_WAIT_FUNC(wait, woken_wake_function);  	struct sock *sk = sock->sk;  	struct tipc_sock *tsk = tipc_sk(sk); -	DEFINE_WAIT(wait);  	int done;  	do {  		int err = sock_error(sk);  		if (err)  			return err; -		if (sock->state == SS_DISCONNECTING) +		if (sk->sk_shutdown & SEND_SHUTDOWN)  			return -EPIPE;  		if (!*timeo_p)  			return -EAGAIN;  		if (signal_pending(current))  			return sock_intr_errno(*timeo_p); -		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); -		done = sk_wait_event(sk, timeo_p, !tsk->link_cong); -		finish_wait(sk_sleep(sk), &wait); +		add_wait_queue(sk_sleep(sk), &wait); +		done = sk_wait_event(sk, timeo_p, !tsk->link_cong, &wait); +		remove_wait_queue(sk_sleep(sk), &wait);  	} while (!done);  	return 0;  } @@ -844,6 +888,7 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)  	struct tipc_msg *mhdr = &tsk->phdr;  	u32 dnode, dport;  	struct sk_buff_head pktchain; +	bool is_connectionless = tipc_sk_type_connectionless(sk);  	struct sk_buff *skb;  	struct tipc_name_seq *seq;  	struct iov_iter save; @@ -854,18 +899,18 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz)  	if (dsz > TIPC_MAX_USER_MSG_SIZE)  		return -EMSGSIZE;  	if (unlikely(!dest)) { -		if (tsk->connected && sock->state == SS_READY) -			dest = &tsk->remote; +		if (is_connectionless && tsk->peer.family == AF_TIPC) +			dest = &tsk->peer;  		else  			return -EDESTADDRREQ;  	} else if (unlikely(m->msg_namelen < sizeof(*dest)) ||  		   dest->family != AF_TIPC) {  		return -EINVAL;  	} -	if (unlikely(sock->state != SS_READY)) { -		if (sock->state == SS_LISTENING) +	if (!is_connectionless) { +		if (sk->sk_state == TIPC_LISTEN)  			return -EPIPE; -		if (sock->state != SS_UNCONNECTED) +		if (sk->sk_state != TIPC_OPEN)  			return -EISCONN;  		if (tsk->published)  			return -EOPNOTSUPP; @@ -917,8 +962,8 @@ new_mtu:  		TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong;  		rc = tipc_node_xmit(net, &pktchain, dnode, tsk->portid);  		if (likely(!rc)) { -			if (sock->state != SS_READY) -				sock->state = SS_CONNECTING; +			if (!is_connectionless) +				tipc_set_sk_state(sk, TIPC_CONNECTING);  			return dsz;  		}  		if (rc == -ELINKCONG) { @@ -940,30 +985,30 @@ new_mtu:  static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p)  { +	DEFINE_WAIT_FUNC(wait, woken_wake_function);  	struct sock *sk = sock->sk;  	struct tipc_sock *tsk = tipc_sk(sk); -	DEFINE_WAIT(wait);  	int done;  	do {  		int err = sock_error(sk);  		if (err)  			return err; -		if (sock->state == SS_DISCONNECTING) +		if (sk->sk_state == TIPC_DISCONNECTING)  			return -EPIPE; -		else if (sock->state != SS_CONNECTED) +		else if (!tipc_sk_connected(sk))  			return -ENOTCONN;  		if (!*timeo_p)  			return -EAGAIN;  		if (signal_pending(current))  			return sock_intr_errno(*timeo_p); -		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); +		add_wait_queue(sk_sleep(sk), &wait);  		done = sk_wait_event(sk, timeo_p,  				     (!tsk->link_cong &&  				      !tsk_conn_cong(tsk)) || -				     !tsk->connected); -		finish_wait(sk_sleep(sk), &wait); +				      !tipc_sk_connected(sk), &wait); +		remove_wait_queue(sk_sleep(sk), &wait);  	} while (!done);  	return 0;  } @@ -1018,14 +1063,17 @@ static int __tipc_send_stream(struct socket *sock, struct msghdr *m, size_t dsz)  	if (dsz > (uint)INT_MAX)  		return -EMSGSIZE; -	if (unlikely(sock->state != SS_CONNECTED)) { -		if (sock->state == SS_DISCONNECTING) +	if (unlikely(!tipc_sk_connected(sk))) { +		if (sk->sk_state == TIPC_DISCONNECTING)  			return -EPIPE;  		else  			return -ENOTCONN;  	}  	timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); +	if (!timeo && tsk->link_cong) +		return -ELINKCONG; +  	dnode = tsk_peer_node(tsk);  	skb_queue_head_init(&pktchain); @@ -1099,10 +1147,8 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,  	msg_set_lookup_scope(msg, 0);  	msg_set_hdr_sz(msg, SHORT_H_SIZE); -	tsk->probing_intv = CONN_PROBING_INTERVAL; -	tsk->probing_state = TIPC_CONN_OK; -	tsk->connected = 1; -	sk_reset_timer(sk, &sk->sk_timer, jiffies + tsk->probing_intv); +	sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTERVAL); +	tipc_set_sk_state(sk, TIPC_ESTABLISHED);  	tipc_node_add_conn(net, peer_node, tsk->portid, peer_port);  	tsk->max_pkt = tipc_node_get_mtu(net, peer_node, tsk->portid);  	tsk->peer_caps = tipc_node_get_capabilities(net, peer_node); @@ -1210,13 +1256,14 @@ static int tipc_sk_anc_data_recv(struct msghdr *m, struct tipc_msg *msg,  static void tipc_sk_send_ack(struct tipc_sock *tsk)  { -	struct net *net = sock_net(&tsk->sk); +	struct sock *sk = &tsk->sk; +	struct net *net = sock_net(sk);  	struct sk_buff *skb = NULL;  	struct tipc_msg *msg;  	u32 peer_port = tsk_peer_port(tsk);  	u32 dnode = tsk_peer_node(tsk); -	if (!tsk->connected) +	if (!tipc_sk_connected(sk))  		return;  	skb = tipc_msg_create(CONN_MANAGER, CONN_ACK, INT_H_SIZE, 0,  			      dnode, tsk_own_node(tsk), peer_port, @@ -1245,7 +1292,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)  	for (;;) {  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);  		if (timeo && skb_queue_empty(&sk->sk_receive_queue)) { -			if (sock->state == SS_DISCONNECTING) { +			if (sk->sk_shutdown & RCV_SHUTDOWN) {  				err = -ENOTCONN;  				break;  			} @@ -1286,6 +1333,7 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m, size_t buf_len,  	struct tipc_sock *tsk = tipc_sk(sk);  	struct sk_buff *buf;  	struct tipc_msg *msg; +	bool is_connectionless = tipc_sk_type_connectionless(sk);  	long timeo;  	unsigned int sz;  	u32 err; @@ -1297,7 +1345,7 @@ static int tipc_recvmsg(struct socket *sock, struct msghdr *m, size_t buf_len,  	lock_sock(sk); -	if (unlikely(sock->state == SS_UNCONNECTED)) { +	if (!is_connectionless && unlikely(sk->sk_state == TIPC_OPEN)) {  		res = -ENOTCONN;  		goto exit;  	} @@ -1342,8 +1390,8 @@ restart:  			goto exit;  		res = sz;  	} else { -		if ((sock->state == SS_READY) || -		    ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)) +		if (is_connectionless || err == TIPC_CONN_SHUTDOWN || +		    m->msg_control)  			res = 0;  		else  			res = -ECONNRESET; @@ -1352,7 +1400,7 @@ restart:  	if (unlikely(flags & MSG_PEEK))  		goto exit; -	if (likely(sock->state != SS_READY)) { +	if (likely(!is_connectionless)) {  		tsk->rcv_unacked += tsk_inc(tsk, hlen + sz);  		if (unlikely(tsk->rcv_unacked >= (tsk->rcv_win / 4)))  			tipc_sk_send_ack(tsk); @@ -1383,7 +1431,7 @@ static int tipc_recv_stream(struct socket *sock, struct msghdr *m,  	struct tipc_msg *msg;  	long timeo;  	unsigned int sz; -	int sz_to_copy, target, needed; +	int target;  	int sz_copied = 0;  	u32 err;  	int res = 0, hlen; @@ -1394,7 +1442,7 @@ static int tipc_recv_stream(struct socket *sock, struct msghdr *m,  	lock_sock(sk); -	if (unlikely(sock->state == SS_UNCONNECTED)) { +	if (unlikely(sk->sk_state == TIPC_OPEN)) {  		res = -ENOTCONN;  		goto exit;  	} @@ -1431,11 +1479,13 @@ restart:  	/* Capture message data (if valid) & compute return value (always) */  	if (!err) { -		u32 offset = (u32)(unsigned long)(TIPC_SKB_CB(buf)->handle); +		u32 offset = TIPC_SKB_CB(buf)->bytes_read; +		u32 needed; +		int sz_to_copy;  		sz -= offset;  		needed = (buf_len - sz_copied); -		sz_to_copy = (sz <= needed) ? sz : needed; +		sz_to_copy = min(sz, needed);  		res = skb_copy_datagram_msg(buf, hlen + offset, m, sz_to_copy);  		if (res) @@ -1445,8 +1495,8 @@ restart:  		if (sz_to_copy < sz) {  			if (!(flags & MSG_PEEK)) -				TIPC_SKB_CB(buf)->handle = -				(void *)(unsigned long)(offset + sz_to_copy); +				TIPC_SKB_CB(buf)->bytes_read = +					offset + sz_to_copy;  			goto exit;  		}  	} else { @@ -1528,49 +1578,31 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)  {  	struct sock *sk = &tsk->sk;  	struct net *net = sock_net(sk); -	struct socket *sock = sk->sk_socket;  	struct tipc_msg *hdr = buf_msg(skb);  	if (unlikely(msg_mcast(hdr)))  		return false; -	switch ((int)sock->state) { -	case SS_CONNECTED: - -		/* Accept only connection-based messages sent by peer */ -		if (unlikely(!tsk_peer_msg(tsk, hdr))) -			return false; - -		if (unlikely(msg_errcode(hdr))) { -			sock->state = SS_DISCONNECTING; -			tsk->connected = 0; -			/* Let timer expire on it's own */ -			tipc_node_remove_conn(net, tsk_peer_node(tsk), -					      tsk->portid); -		} -		return true; - -	case SS_CONNECTING: - +	switch (sk->sk_state) { +	case TIPC_CONNECTING:  		/* Accept only ACK or NACK message */  		if (unlikely(!msg_connected(hdr)))  			return false;  		if (unlikely(msg_errcode(hdr))) { -			sock->state = SS_DISCONNECTING; +			tipc_set_sk_state(sk, TIPC_DISCONNECTING);  			sk->sk_err = ECONNREFUSED;  			return true;  		}  		if (unlikely(!msg_isdata(hdr))) { -			sock->state = SS_DISCONNECTING; +			tipc_set_sk_state(sk, TIPC_DISCONNECTING);  			sk->sk_err = EINVAL;  			return true;  		}  		tipc_sk_finish_conn(tsk, msg_origport(hdr), msg_orignode(hdr));  		msg_set_importance(&tsk->phdr, msg_importance(hdr)); -		sock->state = SS_CONNECTED;  		/* If 'ACK+' message, add to socket receive queue */  		if (msg_data_sz(hdr)) @@ -1584,18 +1616,31 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)  		msg_set_dest_droppable(hdr, 1);  		return false; -	case SS_LISTENING: -	case SS_UNCONNECTED: - +	case TIPC_OPEN: +	case TIPC_DISCONNECTING: +		break; +	case TIPC_LISTEN:  		/* Accept only SYN message */  		if (!msg_connected(hdr) && !(msg_errcode(hdr)))  			return true;  		break; -	case SS_DISCONNECTING: -		break; +	case TIPC_ESTABLISHED: +		/* Accept only connection-based messages sent by peer */ +		if (unlikely(!tsk_peer_msg(tsk, hdr))) +			return false; + +		if (unlikely(msg_errcode(hdr))) { +			tipc_set_sk_state(sk, TIPC_DISCONNECTING); +			/* Let timer expire on it's own */ +			tipc_node_remove_conn(net, tsk_peer_node(tsk), +					      tsk->portid); +			sk->sk_state_change(sk); +		} +		return true;  	default: -		pr_err("Unknown socket state %u\n", sock->state); +		pr_err("Unknown sk_state %u\n", sk->sk_state);  	} +  	return false;  } @@ -1646,7 +1691,6 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *skb)  static bool filter_rcv(struct sock *sk, struct sk_buff *skb,  		       struct sk_buff_head *xmitq)  { -	struct socket *sock = sk->sk_socket;  	struct tipc_sock *tsk = tipc_sk(sk);  	struct tipc_msg *hdr = buf_msg(skb);  	unsigned int limit = rcvbuf_limit(sk, skb); @@ -1672,7 +1716,7 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb,  	}  	/* Reject if wrong message type for current socket state */ -	if (unlikely(sock->state == SS_READY)) { +	if (tipc_sk_type_connectionless(sk)) {  		if (msg_connected(hdr)) {  			err = TIPC_ERR_NO_PORT;  			goto reject; @@ -1689,7 +1733,7 @@ static bool filter_rcv(struct sock *sk, struct sk_buff *skb,  	}  	/* Enqueue message */ -	TIPC_SKB_CB(skb)->handle = NULL; +	TIPC_SKB_CB(skb)->bytes_read = 0;  	__skb_queue_tail(&sk->sk_receive_queue, skb);  	skb_set_owner_r(skb, sk); @@ -1839,8 +1883,8 @@ xmit:  static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)  { +	DEFINE_WAIT_FUNC(wait, woken_wake_function);  	struct sock *sk = sock->sk; -	DEFINE_WAIT(wait);  	int done;  	do { @@ -1852,9 +1896,10 @@ static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)  		if (signal_pending(current))  			return sock_intr_errno(*timeo_p); -		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); -		done = sk_wait_event(sk, timeo_p, sock->state != SS_CONNECTING); -		finish_wait(sk_sleep(sk), &wait); +		add_wait_queue(sk_sleep(sk), &wait); +		done = sk_wait_event(sk, timeo_p, +				     sk->sk_state != TIPC_CONNECTING, &wait); +		remove_wait_queue(sk_sleep(sk), &wait);  	} while (!done);  	return 0;  } @@ -1876,21 +1921,19 @@ static int tipc_connect(struct socket *sock, struct sockaddr *dest,  	struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;  	struct msghdr m = {NULL,};  	long timeout = (flags & O_NONBLOCK) ? 0 : tsk->conn_timeout; -	socket_state previous; +	int previous;  	int res = 0;  	lock_sock(sk);  	/* DGRAM/RDM connect(), just save the destaddr */ -	if (sock->state == SS_READY) { +	if (tipc_sk_type_connectionless(sk)) {  		if (dst->family == AF_UNSPEC) { -			memset(&tsk->remote, 0, sizeof(struct sockaddr_tipc)); -			tsk->connected = 0; +			memset(&tsk->peer, 0, sizeof(struct sockaddr_tipc));  		} else if (destlen != sizeof(struct sockaddr_tipc)) {  			res = -EINVAL;  		} else { -			memcpy(&tsk->remote, dest, destlen); -			tsk->connected = 1; +			memcpy(&tsk->peer, dest, destlen);  		}  		goto exit;  	} @@ -1906,9 +1949,10 @@ static int tipc_connect(struct socket *sock, struct sockaddr *dest,  		goto exit;  	} -	previous = sock->state; -	switch (sock->state) { -	case SS_UNCONNECTED: +	previous = sk->sk_state; + +	switch (sk->sk_state) { +	case TIPC_OPEN:  		/* Send a 'SYN-' to destination */  		m.msg_name = dest;  		m.msg_namelen = destlen; @@ -1923,27 +1967,29 @@ static int tipc_connect(struct socket *sock, struct sockaddr *dest,  		if ((res < 0) && (res != -EWOULDBLOCK))  			goto exit; -		/* Just entered SS_CONNECTING state; the only +		/* Just entered TIPC_CONNECTING state; the only  		 * difference is that return value in non-blocking  		 * case is EINPROGRESS, rather than EALREADY.  		 */  		res = -EINPROGRESS; -	case SS_CONNECTING: -		if (previous == SS_CONNECTING) -			res = -EALREADY; -		if (!timeout) +		/* fall thru' */ +	case TIPC_CONNECTING: +		if (!timeout) { +			if (previous == TIPC_CONNECTING) +				res = -EALREADY;  			goto exit; +		}  		timeout = msecs_to_jiffies(timeout);  		/* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */  		res = tipc_wait_for_connect(sock, &timeout);  		break; -	case SS_CONNECTED: +	case TIPC_ESTABLISHED:  		res = -EISCONN;  		break;  	default:  		res = -EINVAL; -		break;  	} +  exit:  	release_sock(sk);  	return res; @@ -1962,15 +2008,9 @@ static int tipc_listen(struct socket *sock, int len)  	int res;  	lock_sock(sk); - -	if (sock->state != SS_UNCONNECTED) -		res = -EINVAL; -	else { -		sock->state = SS_LISTENING; -		res = 0; -	} - +	res = tipc_set_sk_state(sk, TIPC_LISTEN);  	release_sock(sk); +  	return res;  } @@ -1996,9 +2036,6 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)  		err = 0;  		if (!skb_queue_empty(&sk->sk_receive_queue))  			break; -		err = -EINVAL; -		if (sock->state != SS_LISTENING) -			break;  		err = -EAGAIN;  		if (!timeo)  			break; @@ -2029,7 +2066,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)  	lock_sock(sk); -	if (sock->state != SS_LISTENING) { +	if (sk->sk_state != TIPC_LISTEN) {  		res = -EINVAL;  		goto exit;  	} @@ -2040,7 +2077,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)  	buf = skb_peek(&sk->sk_receive_queue); -	res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, 1); +	res = tipc_sk_create(sock_net(sock->sk), new_sock, 0, 0);  	if (res)  		goto exit;  	security_sk_clone(sock->sk, new_sock->sk); @@ -2060,7 +2097,6 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)  	/* Connect new socket to it's peer */  	tipc_sk_finish_conn(new_tsock, msg_origport(msg), msg_orignode(msg)); -	new_sock->state = SS_CONNECTED;  	tsk_set_importance(new_tsock, msg_importance(msg));  	if (msg_named(msg)) { @@ -2100,13 +2136,6 @@ exit:  static int tipc_shutdown(struct socket *sock, int how)  {  	struct sock *sk = sock->sk; -	struct net *net = sock_net(sk); -	struct tipc_sock *tsk = tipc_sk(sk); -	struct sk_buff *skb; -	u32 dnode = tsk_peer_node(tsk); -	u32 dport = tsk_peer_port(tsk); -	u32 onode = tipc_own_addr(net); -	u32 oport = tsk->portid;  	int res;  	if (how != SHUT_RDWR) @@ -2114,45 +2143,17 @@ static int tipc_shutdown(struct socket *sock, int how)  	lock_sock(sk); -	switch (sock->state) { -	case SS_CONNECTING: -	case SS_CONNECTED: - -restart: -		dnode = tsk_peer_node(tsk); - -		/* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ -		skb = __skb_dequeue(&sk->sk_receive_queue); -		if (skb) { -			if (TIPC_SKB_CB(skb)->handle != NULL) { -				kfree_skb(skb); -				goto restart; -			} -			tipc_sk_respond(sk, skb, TIPC_CONN_SHUTDOWN); -		} else { -			skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, -					      TIPC_CONN_MSG, SHORT_H_SIZE, -					      0, dnode, onode, dport, oport, -					      TIPC_CONN_SHUTDOWN); -			if (skb) -				tipc_node_xmit_skb(net, skb, dnode, tsk->portid); -		} -		tsk->connected = 0; -		sock->state = SS_DISCONNECTING; -		tipc_node_remove_conn(net, dnode, tsk->portid); -		/* fall through */ - -	case SS_DISCONNECTING: +	__tipc_shutdown(sock, TIPC_CONN_SHUTDOWN); +	sk->sk_shutdown = SEND_SHUTDOWN; +	if (sk->sk_state == TIPC_DISCONNECTING) {  		/* Discard any unreceived messages */  		__skb_queue_purge(&sk->sk_receive_queue);  		/* Wake up anyone sleeping in poll */  		sk->sk_state_change(sk);  		res = 0; -		break; - -	default: +	} else {  		res = -ENOTCONN;  	} @@ -2169,17 +2170,16 @@ static void tipc_sk_timeout(unsigned long data)  	u32 own_node = tsk_own_node(tsk);  	bh_lock_sock(sk); -	if (!tsk->connected) { +	if (!tipc_sk_connected(sk)) {  		bh_unlock_sock(sk);  		goto exit;  	}  	peer_port = tsk_peer_port(tsk);  	peer_node = tsk_peer_node(tsk); -	if (tsk->probing_state == TIPC_CONN_PROBING) { +	if (tsk->probe_unacked) {  		if (!sock_owned_by_user(sk)) { -			sk->sk_socket->state = SS_DISCONNECTING; -			tsk->connected = 0; +			tipc_set_sk_state(sk, TIPC_DISCONNECTING);  			tipc_node_remove_conn(sock_net(sk), tsk_peer_node(tsk),  					      tsk_peer_port(tsk));  			sk->sk_state_change(sk); @@ -2188,13 +2188,15 @@ static void tipc_sk_timeout(unsigned long data)  			sk_reset_timer(sk, &sk->sk_timer, (HZ / 20));  		} -	} else { -		skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE, -				      INT_H_SIZE, 0, peer_node, own_node, -				      peer_port, tsk->portid, TIPC_OK); -		tsk->probing_state = TIPC_CONN_PROBING; -		sk_reset_timer(sk, &sk->sk_timer, jiffies + tsk->probing_intv); +		bh_unlock_sock(sk); +		goto exit;  	} + +	skb = tipc_msg_create(CONN_MANAGER, CONN_PROBE, +			      INT_H_SIZE, 0, peer_node, own_node, +			      peer_port, tsk->portid, TIPC_OK); +	tsk->probe_unacked = true; +	sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTERVAL);  	bh_unlock_sock(sk);  	if (skb)  		tipc_node_xmit_skb(sock_net(sk), skb, peer_node, tsk->portid); @@ -2205,11 +2207,12 @@ exit:  static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,  			   struct tipc_name_seq const *seq)  { -	struct net *net = sock_net(&tsk->sk); +	struct sock *sk = &tsk->sk; +	struct net *net = sock_net(sk);  	struct publication *publ;  	u32 key; -	if (tsk->connected) +	if (tipc_sk_connected(sk))  		return -EINVAL;  	key = tsk->portid + tsk->pub_count + 1;  	if (key == tsk->portid) @@ -2667,6 +2670,7 @@ static int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,  	struct nlattr *attrs;  	struct net *net = sock_net(skb->sk);  	struct tipc_net *tn = net_generic(net, tipc_net_id); +	struct sock *sk = &tsk->sk;  	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,  			  &tipc_genl_family, NLM_F_MULTI, TIPC_NL_SOCK_GET); @@ -2681,7 +2685,7 @@ static int __tipc_nl_add_sk(struct sk_buff *skb, struct netlink_callback *cb,  	if (nla_put_u32(skb, TIPC_NLA_SOCK_ADDR, tn->own_addr))  		goto attr_msg_cancel; -	if (tsk->connected) { +	if (tipc_sk_connected(sk)) {  		err = __tipc_nl_add_sk_con(skb, tsk);  		if (err)  			goto attr_msg_cancel; diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 78cab9c5a445..b58dc95f3d35 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -697,6 +697,11 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  		udp_conf.local_ip.s_addr = htonl(INADDR_ANY);  		udp_conf.use_udp_checksums = false;  		ub->ifindex = dev->ifindex; +		if (tipc_mtu_bad(dev, sizeof(struct iphdr) + +				      sizeof(struct udphdr))) { +			err = -EINVAL; +			goto err; +		}  		b->mtu = dev->mtu - sizeof(struct iphdr)  			- sizeof(struct udphdr);  #if IS_ENABLED(CONFIG_IPV6) |