diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/bcast.c | 14 | ||||
| -rw-r--r-- | net/tipc/bcast.h | 3 | ||||
| -rw-r--r-- | net/tipc/bearer.c | 11 | ||||
| -rw-r--r-- | net/tipc/bearer.h | 13 | ||||
| -rw-r--r-- | net/tipc/link.c | 42 | ||||
| -rw-r--r-- | net/tipc/monitor.c | 10 | ||||
| -rw-r--r-- | net/tipc/msg.h | 17 | ||||
| -rw-r--r-- | net/tipc/name_distr.c | 1 | ||||
| -rw-r--r-- | net/tipc/node.c | 2 | ||||
| -rw-r--r-- | net/tipc/socket.c | 50 | ||||
| -rw-r--r-- | net/tipc/udp_media.c | 5 | 
11 files changed, 89 insertions, 79 deletions
| diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 753f774cb46f..aa1babbea385 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -247,11 +247,17 @@ int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb)   *   * RCU is locked, no other locks set   */ -void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, u32 acked) +void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, +			struct tipc_msg *hdr)  {  	struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq; +	u16 acked = msg_bcast_ack(hdr);  	struct sk_buff_head xmitq; +	/* Ignore bc acks sent by peer before bcast synch point was received */ +	if (msg_bc_ack_invalid(hdr)) +		return; +  	__skb_queue_head_init(&xmitq);  	tipc_bcast_lock(net); @@ -279,11 +285,11 @@ int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,  	__skb_queue_head_init(&xmitq);  	tipc_bcast_lock(net); -	if (msg_type(hdr) == STATE_MSG) { +	if (msg_type(hdr) != STATE_MSG) { +		tipc_link_bc_init_rcv(l, hdr); +	} else if (!msg_bc_ack_invalid(hdr)) {  		tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), &xmitq);  		rc = tipc_link_bc_sync_rcv(l, hdr, &xmitq); -	} else { -		tipc_link_bc_init_rcv(l, hdr);  	}  	tipc_bcast_unlock(net); diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 5ffe34472ccd..855d53c64ab3 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -55,7 +55,8 @@ void tipc_bcast_dec_bearer_dst_cnt(struct net *net, int bearer_id);  int  tipc_bcast_get_mtu(struct net *net);  int tipc_bcast_xmit(struct net *net, struct sk_buff_head *list);  int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb); -void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, u32 acked); +void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, +			struct tipc_msg *hdr);  int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,  			struct tipc_msg *hdr);  int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg); 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/link.c b/net/tipc/link.c index b36e16cdc945..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)) @@ -1312,6 +1319,7 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,  	msg_set_next_sent(hdr, l->snd_nxt);  	msg_set_ack(hdr, l->rcv_nxt - 1);  	msg_set_bcast_ack(hdr, bcl->rcv_nxt - 1); +	msg_set_bc_ack_invalid(hdr, !node_up);  	msg_set_last_bcast(hdr, l->bc_sndlink->snd_nxt - 1);  	msg_set_link_tolerance(hdr, tolerance);  	msg_set_linkprio(hdr, priority); @@ -1491,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);  		} @@ -1574,6 +1583,7 @@ static void tipc_link_build_bc_init_msg(struct tipc_link *l,  	__skb_queue_head_init(&list);  	if (!tipc_link_build_bc_proto_msg(l->bc_rcvlink, false, 0, &list))  		return; +	msg_set_bc_ack_invalid(buf_msg(skb_peek(&list)), true);  	tipc_link_xmit(l, &list, xmitq);  } @@ -1797,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) @@ -1864,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}, @@ -1944,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)) @@ -2001,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}, @@ -2073,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 c3832cdf2278..50a739860d37 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -714,6 +714,23 @@ static inline void msg_set_peer_stopping(struct tipc_msg *m, u32 s)  	msg_set_bits(m, 5, 13, 0x1, s);  } +static inline bool msg_bc_ack_invalid(struct tipc_msg *m) +{ +	switch (msg_user(m)) { +	case BCAST_PROTOCOL: +	case NAME_DISTRIBUTOR: +	case LINK_PROTOCOL: +		return msg_bits(m, 5, 14, 0x1); +	default: +		return false; +	} +} + +static inline void msg_set_bc_ack_invalid(struct tipc_msg *m, bool invalid) +{ +	msg_set_bits(m, 5, 14, 0x1, invalid); +} +  static inline char *msg_media_addr(struct tipc_msg *m)  {  	return (char *)&m->hdr[TIPC_MEDIA_INFO_OFFSET]; diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index a04fe9be1c60..c1cfd92de17a 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -156,6 +156,7 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,  				pr_warn("Bulk publication failure\n");  				return;  			} +			msg_set_bc_ack_invalid(buf_msg(skb), true);  			item = (struct distr_item *)msg_data(buf_msg(skb));  		} diff --git a/net/tipc/node.c b/net/tipc/node.c index 7ef14e2d2356..9d2f4c2b08ab 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1535,7 +1535,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)  	if (unlikely(usr == LINK_PROTOCOL))  		tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq);  	else if (unlikely(tipc_link_acked(n->bc_entry.link) != bc_ack)) -		tipc_bcast_ack_rcv(net, n->bc_entry.link, bc_ack); +		tipc_bcast_ack_rcv(net, n->bc_entry.link, hdr);  	/* Receive packet directly if conditions permit */  	tipc_node_read_lock(n); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index f9f5f3c3dab5..41f013888f07 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1,7 +1,7 @@  /*   * net/tipc/socket.c: TIPC socket API   * - * Copyright (c) 2001-2007, 2012-2015, Ericsson AB + * Copyright (c) 2001-2007, 2012-2016, Ericsson AB   * Copyright (c) 2004-2008, 2010-2013, Wind River Systems   * All rights reserved.   * @@ -129,54 +129,8 @@ static const struct proto_ops packet_ops;  static const struct proto_ops stream_ops;  static const struct proto_ops msg_ops;  static struct proto tipc_proto; -  static const struct rhashtable_params tsk_rht_params; -/* - * Revised TIPC socket locking policy: - * - * Most socket operations take the standard socket lock when they start - * and hold it until they finish (or until they need to sleep).  Acquiring - * this lock grants the owner exclusive access to the fields of the socket - * data structures, with the exception of the backlog queue.  A few socket - * operations can be done without taking the socket lock because they only - * read socket information that never changes during the life of the socket. - * - * Socket operations may acquire the lock for the associated TIPC port if they - * need to perform an operation on the port.  If any routine needs to acquire - * both the socket lock and the port lock it must take the socket lock first - * to avoid the risk of deadlock. - * - * The dispatcher handling incoming messages cannot grab the socket lock in - * the standard fashion, since invoked it runs at the BH level and cannot block. - * Instead, it checks to see if the socket lock is currently owned by someone, - * and either handles the message itself or adds it to the socket's backlog - * queue; in the latter case the queued message is processed once the process - * owning the socket lock releases it. - * - * NOTE: Releasing the socket lock while an operation is sleeping overcomes - * the problem of a blocked socket operation preventing any other operations - * from occurring.  However, applications must be careful if they have - * multiple threads trying to send (or receive) on the same socket, as these - * operations might interfere with each other.  For example, doing a connect - * and a receive at the same time might allow the receive to consume the - * ACK message meant for the connect.  While additional work could be done - * to try and overcome this, it doesn't seem to be worthwhile at the present. - * - * NOTE: Releasing the socket lock while an operation is sleeping also ensures - * that another operation that must be performed in a non-blocking manner is - * not delayed for very long because the lock has already been taken. - * - * NOTE: This code assumes that certain fields of a port/socket pair are - * constant over its lifetime; such fields can be examined without taking - * the socket lock and/or port lock, and do not need to be re-read even - * after resuming processing after waiting.  These fields include: - *   - socket type - *   - pointer to socket sk structure (aka tipc_sock structure) - *   - pointer to port structure - *   - port reference - */ -  static u32 tsk_own_node(struct tipc_sock *tsk)  {  	return msg_prevnode(&tsk->phdr); @@ -232,7 +186,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 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) | 
