diff options
| author | Mark Brown <broonie@kernel.org> | 2020-08-25 11:01:46 +0100 | 
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2020-08-25 11:01:46 +0100 | 
| commit | 3bec5b6aae830355e786e204b20a7cea38c3a8ed (patch) | |
| tree | fd597b87faf55ceb2a207ee94f4feca6276696db /net/tipc | |
| parent | a577f3456c0a2fac3dee037c483753e6e68f3e49 (diff) | |
| parent | d012a7190fc1fd72ed48911e77ca97ba4521bccd (diff) | |
Merge tag 'v5.9-rc2' into regulator-5.9
Linux 5.9-rc2
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/Kconfig | 1 | ||||
| -rw-r--r-- | net/tipc/bcast.c | 6 | ||||
| -rw-r--r-- | net/tipc/bcast.h | 4 | ||||
| -rw-r--r-- | net/tipc/bearer.c | 2 | ||||
| -rw-r--r-- | net/tipc/crypto.c | 12 | ||||
| -rw-r--r-- | net/tipc/discover.c | 5 | ||||
| -rw-r--r-- | net/tipc/eth_media.c | 4 | ||||
| -rw-r--r-- | net/tipc/link.c | 44 | ||||
| -rw-r--r-- | net/tipc/msg.c | 2 | ||||
| -rw-r--r-- | net/tipc/msg.h | 46 | ||||
| -rw-r--r-- | net/tipc/name_distr.c | 116 | ||||
| -rw-r--r-- | net/tipc/name_distr.h | 9 | ||||
| -rw-r--r-- | net/tipc/name_table.c | 9 | ||||
| -rw-r--r-- | net/tipc/name_table.h | 2 | ||||
| -rw-r--r-- | net/tipc/netlink_compat.c | 12 | ||||
| -rw-r--r-- | net/tipc/node.c | 33 | ||||
| -rw-r--r-- | net/tipc/node.h | 8 | ||||
| -rw-r--r-- | net/tipc/socket.c | 16 | ||||
| -rw-r--r-- | net/tipc/udp_media.c | 12 | 
19 files changed, 247 insertions, 96 deletions
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig index 9dd780215eef..be1c4003d67d 100644 --- a/net/tipc/Kconfig +++ b/net/tipc/Kconfig @@ -6,6 +6,7 @@  menuconfig TIPC  	tristate "The TIPC Protocol"  	depends on INET +	depends on IPV6 || IPV6=n  	help  	  The Transparent Inter Process Communication (TIPC) protocol is  	  specially designed for intra cluster communication. This protocol diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 383f87bc1061..940d176e0e87 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -250,8 +250,8 @@ static void tipc_bcast_select_xmit_method(struct net *net, int dests,   * Consumes the buffer chain.   * Returns 0 if success, otherwise errno: -EHOSTUNREACH,-EMSGSIZE   */ -static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts, -			   u16 *cong_link_cnt) +int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts, +		    u16 *cong_link_cnt)  {  	struct tipc_link *l = tipc_bc_sndlink(net);  	struct sk_buff_head xmitq; @@ -752,7 +752,7 @@ void tipc_nlist_purge(struct tipc_nlist *nl)  	nl->local = false;  } -u32 tipc_bcast_get_broadcast_mode(struct net *net) +u32 tipc_bcast_get_mode(struct net *net)  {  	struct tipc_bc_base *bb = tipc_bc_base(net); diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 4240c95188b1..2d9352dc7b0e 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -90,6 +90,8 @@ void tipc_bcast_toggle_rcast(struct net *net, bool supp);  int tipc_mcast_xmit(struct net *net, struct sk_buff_head *pkts,  		    struct tipc_mc_method *method, struct tipc_nlist *dests,  		    u16 *cong_link_cnt); +int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts, +		    u16 *cong_link_cnt);  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,  			struct tipc_msg *hdr); @@ -101,7 +103,7 @@ int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg,  int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]);  int tipc_bclink_reset_stats(struct net *net, struct tipc_link *l); -u32 tipc_bcast_get_broadcast_mode(struct net *net); +u32 tipc_bcast_get_mode(struct net *net);  u32 tipc_bcast_get_broadcast_ratio(struct net *net);  void tipc_mcast_filter_msg(struct net *net, struct sk_buff_head *defq, diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index e366ec9a7e4d..808b147df7d5 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -595,7 +595,7 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,  /**   * tipc_l2_rcv_msg - handle incoming TIPC message from an interface - * @buf: the received packet + * @skb: the received message   * @dev: the net device that the packet was received on   * @pt: the packet_type structure which was used to register this handler   * @orig_dev: the original receive net device in case the device is a bond diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c index c8c47fc72653..c38babaa4e57 100644 --- a/net/tipc/crypto.c +++ b/net/tipc/crypto.c @@ -441,7 +441,7 @@ static int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey,  	/* Allocate per-cpu TFM entry pointer */  	tmp->tfm_entry = alloc_percpu(struct tipc_tfm *);  	if (!tmp->tfm_entry) { -		kzfree(tmp); +		kfree_sensitive(tmp);  		return -ENOMEM;  	} @@ -491,7 +491,7 @@ static int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey,  	/* Not any TFM is allocated? */  	if (!tfm_cnt) {  		free_percpu(tmp->tfm_entry); -		kzfree(tmp); +		kfree_sensitive(tmp);  		return err;  	} @@ -545,7 +545,7 @@ static int tipc_aead_clone(struct tipc_aead **dst, struct tipc_aead *src)  	aead->tfm_entry = alloc_percpu_gfp(struct tipc_tfm *, GFP_ATOMIC);  	if (unlikely(!aead->tfm_entry)) { -		kzfree(aead); +		kfree_sensitive(aead);  		return -ENOMEM;  	} @@ -757,10 +757,12 @@ static void tipc_aead_encrypt_done(struct crypto_async_request *base, int err)  	switch (err) {  	case 0:  		this_cpu_inc(tx->stats->stat[STAT_ASYNC_OK]); +		rcu_read_lock();  		if (likely(test_bit(0, &b->up)))  			b->media->send_msg(net, skb, b, &tx_ctx->dst);  		else  			kfree_skb(skb); +		rcu_read_unlock();  		break;  	case -EINPROGRESS:  		return; @@ -1352,7 +1354,7 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net,  	/* Allocate statistic structure */  	c->stats = alloc_percpu_gfp(struct tipc_crypto_stats, GFP_ATOMIC);  	if (!c->stats) { -		kzfree(c); +		kfree_sensitive(c);  		return -ENOMEM;  	} @@ -1408,7 +1410,7 @@ void tipc_crypto_stop(struct tipc_crypto **crypto)  	free_percpu(c->stats);  	*crypto = NULL; -	kzfree(c); +	kfree_sensitive(c);  }  void tipc_crypto_timeout(struct tipc_crypto *rx) diff --git a/net/tipc/discover.c b/net/tipc/discover.c index bfe43da127c0..d4ecacddb40c 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -74,7 +74,7 @@ struct tipc_discoverer {  /**   * tipc_disc_init_msg - initialize a link setup message   * @net: the applicable net namespace - * @type: message type (request or response) + * @mtyp: message type (request or response)   * @b: ptr to bearer issuing message   */  static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb, @@ -339,7 +339,7 @@ exit:   * @net: the applicable net namespace   * @b: ptr to bearer issuing requests   * @dest: destination address for request messages - * @dest_domain: network domain to which links can be established + * @skb: pointer to created frame   *   * Returns 0 if successful, otherwise -errno.   */ @@ -393,7 +393,6 @@ void tipc_disc_delete(struct tipc_discoverer *d)   * tipc_disc_reset - reset object to send periodic link setup requests   * @net: the applicable net namespace   * @b: ptr to bearer issuing requests - * @dest_domain: network domain to which links can be established   */  void tipc_disc_reset(struct net *net, struct tipc_bearer *b)  { diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 8b0bb600602d..c68019697cfe 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -62,12 +62,10 @@ static int tipc_eth_raw2addr(struct tipc_bearer *b,  			     struct tipc_media_addr *addr,  			     char *msg)  { -	char bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -  	memset(addr, 0, sizeof(*addr));  	ether_addr_copy(addr->value, msg);  	addr->media_id = TIPC_MEDIA_TYPE_ETH; -	addr->broadcast = !memcmp(addr->value, bcast_mac, ETH_ALEN); +	addr->broadcast = is_broadcast_ether_addr(addr->value);  	return 0;  } diff --git a/net/tipc/link.c b/net/tipc/link.c index ee3b8d0576b8..107578122973 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -445,7 +445,7 @@ u32 tipc_link_state(struct tipc_link *l)  /**   * tipc_link_create - create a new link - * @n: pointer to associated node + * @net: pointer to associated network namespace   * @if_name: associated interface name   * @bearer_id: id (index) of associated bearer   * @tolerance: link tolerance to be used by link @@ -530,7 +530,7 @@ bool tipc_link_create(struct net *net, char *if_name, int bearer_id,  /**   * tipc_link_bc_create - create new link to be used for broadcast - * @n: pointer to associated node + * @net: pointer to associated network namespace   * @mtu: mtu to be used initially if no peers   * @window: send window to be used   * @inputq: queue to put messages ready for delivery @@ -827,11 +827,11 @@ int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq)  		state |= l->bc_rcvlink->rcv_unacked;  		state |= l->rcv_unacked;  		state |= !skb_queue_empty(&l->transmq); -		state |= !skb_queue_empty(&l->deferdq);  		probe = mstate->probing;  		probe |= l->silent_intv_cnt;  		if (probe || mstate->monitoring)  			l->silent_intv_cnt++; +		probe |= !skb_queue_empty(&l->deferdq);  		if (l->snd_nxt == l->checkpoint) {  			tipc_link_update_cwin(l, 0, 0);  			probe = true; @@ -921,6 +921,21 @@ static void link_prepare_wakeup(struct tipc_link *l)  } +/** + * tipc_link_set_skb_retransmit_time - set the time at which retransmission of + *                                     the given skb should be next attempted + * @skb: skb to set a future retransmission time for + * @l: link the skb will be transmitted on + */ +static void tipc_link_set_skb_retransmit_time(struct sk_buff *skb, +					      struct tipc_link *l) +{ +	if (link_is_bc_sndlink(l)) +		TIPC_SKB_CB(skb)->nxt_retr = TIPC_BC_RETR_LIM; +	else +		TIPC_SKB_CB(skb)->nxt_retr = TIPC_UC_RETR_TIME; +} +  void tipc_link_reset(struct tipc_link *l)  {  	struct sk_buff_head list; @@ -974,7 +989,7 @@ void tipc_link_reset(struct tipc_link *l)  /**   * tipc_link_xmit(): enqueue buffer list according to queue situation - * @link: link to use + * @l: link to use   * @list: chain of buffers containing message   * @xmitq: returned list of packets to be sent by caller   * @@ -1036,9 +1051,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,  				return -ENOBUFS;  			}  			__skb_queue_tail(transmq, skb); -			/* next retransmit attempt */ -			if (link_is_bc_sndlink(l)) -				TIPC_SKB_CB(skb)->nxt_retr = TIPC_BC_RETR_LIM; +			tipc_link_set_skb_retransmit_time(skb, l);  			__skb_queue_tail(xmitq, _skb);  			TIPC_SKB_CB(skb)->ackers = l->ackers;  			l->rcv_unacked = 0; @@ -1139,9 +1152,7 @@ static void tipc_link_advance_backlog(struct tipc_link *l,  		if (unlikely(skb == l->backlog[imp].target_bskb))  			l->backlog[imp].target_bskb = NULL;  		__skb_queue_tail(&l->transmq, skb); -		/* next retransmit attempt */ -		if (link_is_bc_sndlink(l)) -			TIPC_SKB_CB(skb)->nxt_retr = TIPC_BC_RETR_LIM; +		tipc_link_set_skb_retransmit_time(skb, l);  		__skb_queue_tail(xmitq, _skb);  		TIPC_SKB_CB(skb)->ackers = l->ackers; @@ -1385,12 +1396,12 @@ u16 tipc_get_gap_ack_blks(struct tipc_gap_ack_blks **ga, struct tipc_link *l,  		p = (struct tipc_gap_ack_blks *)msg_data(hdr);  		sz = ntohs(p->len);  		/* Sanity check */ -		if (sz == tipc_gap_ack_blks_sz(p->ugack_cnt + p->bgack_cnt)) { +		if (sz == struct_size(p, gacks, p->ugack_cnt + p->bgack_cnt)) {  			/* Good, check if the desired type exists */  			if ((uc && p->ugack_cnt) || (!uc && p->bgack_cnt))  				goto ok;  		/* Backward compatible: peer might not support bc, but uc? */ -		} else if (uc && sz == tipc_gap_ack_blks_sz(p->ugack_cnt)) { +		} else if (uc && sz == struct_size(p, gacks, p->ugack_cnt)) {  			if (p->ugack_cnt) {  				p->bgack_cnt = 0;  				goto ok; @@ -1472,7 +1483,7 @@ static u16 tipc_build_gap_ack_blks(struct tipc_link *l, struct tipc_msg *hdr)  			__tipc_build_gap_ack_blks(ga, l, ga->bgack_cnt) : 0;  	/* Total len */ -	len = tipc_gap_ack_blks_sz(ga->bgack_cnt + ga->ugack_cnt); +	len = struct_size(ga, gacks, ga->bgack_cnt + ga->ugack_cnt);  	ga->len = htons(len);  	return len;  } @@ -1521,7 +1532,7 @@ static int tipc_link_advance_transmq(struct tipc_link *l, struct tipc_link *r,  		gacks = &ga->gacks[ga->bgack_cnt];  	} else if (ga) {  		/* Copy the Gap ACKs, bc part, for later renewal if needed */ -		this_ga = kmemdup(ga, tipc_gap_ack_blks_sz(ga->bgack_cnt), +		this_ga = kmemdup(ga, struct_size(ga, gacks, ga->bgack_cnt),  				  GFP_ATOMIC);  		if (likely(this_ga)) {  			this_ga->start_index = 0; @@ -1584,8 +1595,7 @@ release:  			/* retransmit skb if unrestricted*/  			if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr))  				continue; -			TIPC_SKB_CB(skb)->nxt_retr = (is_uc) ? -					TIPC_UC_RETR_TIME : TIPC_BC_RETR_LIM; +			tipc_link_set_skb_retransmit_time(skb, l);  			_skb = pskb_copy(skb, GFP_ATOMIC);  			if (!_skb)  				continue; @@ -2745,7 +2755,7 @@ int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg,  	void *hdr;  	struct nlattr *attrs;  	struct nlattr *prop; -	u32 bc_mode = tipc_bcast_get_broadcast_mode(net); +	u32 bc_mode = tipc_bcast_get_mode(net);  	u32 bc_ratio = tipc_bcast_get_broadcast_ratio(net);  	if (!bcl) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 01b64869a173..848fae674532 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -202,7 +202,7 @@ err:  /**   * tipc_msg_append(): Append data to tail of an existing buffer queue - * @hdr: header to be used + * @_hdr: header to be used   * @m: the data to be appended   * @mss: max allowable size of buffer   * @dlen: size of data to be appended diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 58660d56bc83..1016e96db5c4 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -189,11 +189,9 @@ struct tipc_gap_ack_blks {  	struct tipc_gap_ack gacks[];  }; -#define tipc_gap_ack_blks_sz(n) (sizeof(struct tipc_gap_ack_blks) + \ -				 sizeof(struct tipc_gap_ack) * (n)) -  #define MAX_GAP_ACK_BLKS	128 -#define MAX_GAP_ACK_BLKS_SZ	tipc_gap_ack_blks_sz(MAX_GAP_ACK_BLKS) +#define MAX_GAP_ACK_BLKS_SZ	(sizeof(struct tipc_gap_ack_blks) + \ +				 sizeof(struct tipc_gap_ack) * MAX_GAP_ACK_BLKS)  static inline struct tipc_msg *buf_msg(struct sk_buff *skb)  { @@ -438,6 +436,36 @@ static inline void msg_set_errcode(struct tipc_msg *m, u32 err)  	msg_set_bits(m, 1, 25, 0xf, err);  } +static inline void msg_set_bulk(struct tipc_msg *m) +{ +	msg_set_bits(m, 1, 28, 0x1, 1); +} + +static inline u32 msg_is_bulk(struct tipc_msg *m) +{ +	return msg_bits(m, 1, 28, 0x1); +} + +static inline void msg_set_last_bulk(struct tipc_msg *m) +{ +	msg_set_bits(m, 1, 27, 0x1, 1); +} + +static inline u32 msg_is_last_bulk(struct tipc_msg *m) +{ +	return msg_bits(m, 1, 27, 0x1); +} + +static inline void msg_set_non_legacy(struct tipc_msg *m) +{ +	msg_set_bits(m, 1, 26, 0x1, 1); +} + +static inline u32 msg_is_legacy(struct tipc_msg *m) +{ +	return !msg_bits(m, 1, 26, 0x1); +} +  static inline u32 msg_reroute_cnt(struct tipc_msg *m)  {  	return msg_bits(m, 1, 21, 0xf); @@ -567,6 +595,16 @@ static inline void msg_set_origport(struct tipc_msg *m, u32 p)  	msg_set_word(m, 4, p);  } +static inline u16 msg_named_seqno(struct tipc_msg *m) +{ +	return msg_bits(m, 4, 0, 0xffff); +} + +static inline void msg_set_named_seqno(struct tipc_msg *m, u16 n) +{ +	msg_set_bits(m, 4, 0, 0xffff, n); +} +  static inline u32 msg_destport(struct tipc_msg *m)  {  	return msg_word(m, 5); diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 5feaf3b67380..2f9c148f17e2 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -102,7 +102,8 @@ struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ)  		pr_warn("Publication distribution failure\n");  		return NULL;  	} - +	msg_set_named_seqno(buf_msg(skb), nt->snd_nxt++); +	msg_set_non_legacy(buf_msg(skb));  	item = (struct distr_item *)msg_data(buf_msg(skb));  	publ_to_item(item, publ);  	return skb; @@ -114,8 +115,8 @@ struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ)  struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ)  {  	struct name_table *nt = tipc_name_table(net); -	struct sk_buff *buf;  	struct distr_item *item; +	struct sk_buff *skb;  	write_lock_bh(&nt->cluster_scope_lock);  	list_del(&publ->binding_node); @@ -123,15 +124,16 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ)  	if (publ->scope == TIPC_NODE_SCOPE)  		return NULL; -	buf = named_prepare_buf(net, WITHDRAWAL, ITEM_SIZE, 0); -	if (!buf) { +	skb = named_prepare_buf(net, WITHDRAWAL, ITEM_SIZE, 0); +	if (!skb) {  		pr_warn("Withdrawal distribution failure\n");  		return NULL;  	} - -	item = (struct distr_item *)msg_data(buf_msg(buf)); +	msg_set_named_seqno(buf_msg(skb), nt->snd_nxt++); +	msg_set_non_legacy(buf_msg(skb)); +	item = (struct distr_item *)msg_data(buf_msg(skb));  	publ_to_item(item, publ); -	return buf; +	return skb;  }  /** @@ -141,7 +143,7 @@ struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ)   * @pls: linked list of publication items to be packed into buffer chain   */  static void named_distribute(struct net *net, struct sk_buff_head *list, -			     u32 dnode, struct list_head *pls) +			     u32 dnode, struct list_head *pls, u16 seqno)  {  	struct publication *publ;  	struct sk_buff *skb = NULL; @@ -149,6 +151,7 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,  	u32 msg_dsz = ((tipc_node_get_mtu(net, dnode, 0, false) - INT_H_SIZE) /  			ITEM_SIZE) * ITEM_SIZE;  	u32 msg_rem = msg_dsz; +	struct tipc_msg *hdr;  	list_for_each_entry(publ, pls, binding_node) {  		/* Prepare next buffer: */ @@ -159,8 +162,11 @@ 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)); +			hdr = buf_msg(skb); +			msg_set_bc_ack_invalid(hdr, true); +			msg_set_bulk(hdr); +			msg_set_non_legacy(hdr); +			item = (struct distr_item *)msg_data(hdr);  		}  		/* Pack publication into message: */ @@ -176,24 +182,35 @@ static void named_distribute(struct net *net, struct sk_buff_head *list,  		}  	}  	if (skb) { -		msg_set_size(buf_msg(skb), INT_H_SIZE + (msg_dsz - msg_rem)); +		hdr = buf_msg(skb); +		msg_set_size(hdr, INT_H_SIZE + (msg_dsz - msg_rem));  		skb_trim(skb, INT_H_SIZE + (msg_dsz - msg_rem));  		__skb_queue_tail(list, skb);  	} +	hdr = buf_msg(skb_peek_tail(list)); +	msg_set_last_bulk(hdr); +	msg_set_named_seqno(hdr, seqno);  }  /**   * tipc_named_node_up - tell specified node about all publications by this node   */ -void tipc_named_node_up(struct net *net, u32 dnode) +void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)  {  	struct name_table *nt = tipc_name_table(net); +	struct tipc_net *tn = tipc_net(net);  	struct sk_buff_head head; +	u16 seqno;  	__skb_queue_head_init(&head); +	spin_lock_bh(&tn->nametbl_lock); +	if (!(capabilities & TIPC_NAMED_BCAST)) +		nt->rc_dests++; +	seqno = nt->snd_nxt; +	spin_unlock_bh(&tn->nametbl_lock);  	read_lock_bh(&nt->cluster_scope_lock); -	named_distribute(net, &head, dnode, &nt->cluster_scope); +	named_distribute(net, &head, dnode, &nt->cluster_scope, seqno);  	tipc_node_xmit(net, &head, dnode, 0);  	read_unlock_bh(&nt->cluster_scope_lock);  } @@ -245,13 +262,21 @@ static void tipc_dist_queue_purge(struct net *net, u32 addr)  	spin_unlock_bh(&tn->nametbl_lock);  } -void tipc_publ_notify(struct net *net, struct list_head *nsub_list, u32 addr) +void tipc_publ_notify(struct net *net, struct list_head *nsub_list, +		      u32 addr, u16 capabilities)  { +	struct name_table *nt = tipc_name_table(net); +	struct tipc_net *tn = tipc_net(net); +  	struct publication *publ, *tmp;  	list_for_each_entry_safe(publ, tmp, nsub_list, binding_node)  		tipc_publ_purge(net, publ, addr);  	tipc_dist_queue_purge(net, addr); +	spin_lock_bh(&tn->nametbl_lock); +	if (!(capabilities & TIPC_NAMED_BCAST)) +		nt->rc_dests--; +	spin_unlock_bh(&tn->nametbl_lock);  }  /** @@ -295,29 +320,62 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i,  	return false;  } +static struct sk_buff *tipc_named_dequeue(struct sk_buff_head *namedq, +					  u16 *rcv_nxt, bool *open) +{ +	struct sk_buff *skb, *tmp; +	struct tipc_msg *hdr; +	u16 seqno; + +	skb_queue_walk_safe(namedq, skb, tmp) { +		skb_linearize(skb); +		hdr = buf_msg(skb); +		seqno = msg_named_seqno(hdr); +		if (msg_is_last_bulk(hdr)) { +			*rcv_nxt = seqno; +			*open = true; +		} + +		if (msg_is_bulk(hdr) || msg_is_legacy(hdr)) { +			__skb_unlink(skb, namedq); +			return skb; +		} + +		if (*open && (*rcv_nxt == seqno)) { +			(*rcv_nxt)++; +			__skb_unlink(skb, namedq); +			return skb; +		} + +		if (less(seqno, *rcv_nxt)) { +			__skb_unlink(skb, namedq); +			kfree_skb(skb); +			continue; +		} +	} +	return NULL; +} +  /**   * tipc_named_rcv - process name table update messages sent by another node   */ -void tipc_named_rcv(struct net *net, struct sk_buff_head *inputq) +void tipc_named_rcv(struct net *net, struct sk_buff_head *namedq, +		    u16 *rcv_nxt, bool *open)  { -	struct tipc_net *tn = net_generic(net, tipc_net_id); -	struct tipc_msg *msg; +	struct tipc_net *tn = tipc_net(net);  	struct distr_item *item; -	uint count; -	u32 node; +	struct tipc_msg *hdr;  	struct sk_buff *skb; -	int mtype; +	u32 count, node;  	spin_lock_bh(&tn->nametbl_lock); -	for (skb = skb_dequeue(inputq); skb; skb = skb_dequeue(inputq)) { -		skb_linearize(skb); -		msg = buf_msg(skb); -		mtype = msg_type(msg); -		item = (struct distr_item *)msg_data(msg); -		count = msg_data_sz(msg) / ITEM_SIZE; -		node = msg_orignode(msg); +	while ((skb = tipc_named_dequeue(namedq, rcv_nxt, open))) { +		hdr = buf_msg(skb); +		node = msg_orignode(hdr); +		item = (struct distr_item *)msg_data(hdr); +		count = msg_data_sz(hdr) / ITEM_SIZE;  		while (count--) { -			tipc_update_nametbl(net, item, node, mtype); +			tipc_update_nametbl(net, item, node, msg_type(hdr));  			item++;  		}  		kfree_skb(skb); @@ -345,6 +403,6 @@ void tipc_named_reinit(struct net *net)  		publ->node = self;  	list_for_each_entry_rcu(publ, &nt->cluster_scope, binding_node)  		publ->node = self; - +	nt->rc_dests = 0;  	spin_unlock_bh(&tn->nametbl_lock);  } diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h index 63fc73e0fa6c..092323158f06 100644 --- a/net/tipc/name_distr.h +++ b/net/tipc/name_distr.h @@ -67,11 +67,14 @@ struct distr_item {  	__be32 key;  }; +void tipc_named_bcast(struct net *net, struct sk_buff *skb);  struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ);  struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ); -void tipc_named_node_up(struct net *net, u32 dnode); -void tipc_named_rcv(struct net *net, struct sk_buff_head *msg_queue); +void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities); +void tipc_named_rcv(struct net *net, struct sk_buff_head *namedq, +		    u16 *rcv_nxt, bool *open);  void tipc_named_reinit(struct net *net); -void tipc_publ_notify(struct net *net, struct list_head *nsub_list, u32 addr); +void tipc_publ_notify(struct net *net, struct list_head *nsub_list, +		      u32 addr, u16 capabilities);  #endif diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 359b2bc888cf..2ac33d32edc2 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -729,6 +729,7 @@ struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,  	struct tipc_net *tn = tipc_net(net);  	struct publication *p = NULL;  	struct sk_buff *skb = NULL; +	u32 rc_dests;  	spin_lock_bh(&tn->nametbl_lock); @@ -743,12 +744,14 @@ struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,  		nt->local_publ_count++;  		skb = tipc_named_publish(net, p);  	} +	rc_dests = nt->rc_dests;  exit:  	spin_unlock_bh(&tn->nametbl_lock);  	if (skb) -		tipc_node_broadcast(net, skb); +		tipc_node_broadcast(net, skb, rc_dests);  	return p; +  }  /** @@ -762,6 +765,7 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower,  	u32 self = tipc_own_addr(net);  	struct sk_buff *skb = NULL;  	struct publication *p; +	u32 rc_dests;  	spin_lock_bh(&tn->nametbl_lock); @@ -775,10 +779,11 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower,  		pr_err("Failed to remove local publication {%u,%u,%u}/%u\n",  		       type, lower, upper, key);  	} +	rc_dests = nt->rc_dests;  	spin_unlock_bh(&tn->nametbl_lock);  	if (skb) { -		tipc_node_broadcast(net, skb); +		tipc_node_broadcast(net, skb, rc_dests);  		return 1;  	}  	return 0; diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h index 728bc7016c38..8064e1986e2c 100644 --- a/net/tipc/name_table.h +++ b/net/tipc/name_table.h @@ -106,6 +106,8 @@ struct name_table {  	struct list_head cluster_scope;  	rwlock_t cluster_scope_lock;  	u32 local_publ_count; +	u32 rc_dests; +	u32 snd_nxt;  };  int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb); diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 217516357ef2..90e3c70a91ad 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -275,8 +275,9 @@ err_out:  static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,  				 struct tipc_nl_compat_msg *msg)  { -	int err; +	struct nlmsghdr *nlh;  	struct sk_buff *arg; +	int err;  	if (msg->req_type && (!msg->req_size ||  			      !TLV_CHECK_TYPE(msg->req, msg->req_type))) @@ -305,6 +306,15 @@ static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,  		return -ENOMEM;  	} +	nlh = nlmsg_put(arg, 0, 0, tipc_genl_family.id, 0, NLM_F_MULTI); +	if (!nlh) { +		kfree_skb(arg); +		kfree_skb(msg->rep); +		msg->rep = NULL; +		return -EMSGSIZE; +	} +	nlmsg_end(arg, nlh); +  	err = __tipc_nl_compat_dumpit(cmd, msg, arg);  	if (err) {  		kfree_skb(msg->rep); diff --git a/net/tipc/node.c b/net/tipc/node.c index a4c2816c3746..4edcee3088da 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -75,6 +75,8 @@ struct tipc_bclink_entry {  	struct sk_buff_head arrvq;  	struct sk_buff_head inputq2;  	struct sk_buff_head namedq; +	u16 named_rcv_nxt; +	bool named_open;  };  /** @@ -396,10 +398,10 @@ static void tipc_node_write_unlock(struct tipc_node *n)  	write_unlock_bh(&n->lock);  	if (flags & TIPC_NOTIFY_NODE_DOWN) -		tipc_publ_notify(net, publ_list, addr); +		tipc_publ_notify(net, publ_list, addr, n->capabilities);  	if (flags & TIPC_NOTIFY_NODE_UP) -		tipc_named_node_up(net, addr); +		tipc_named_node_up(net, addr, n->capabilities);  	if (flags & TIPC_NOTIFY_LINK_UP) {  		tipc_mon_peer_up(net, addr, bearer_id); @@ -1483,6 +1485,7 @@ static void node_lost_contact(struct tipc_node *n,  	/* Clean up broadcast state */  	tipc_bcast_remove_peer(n->net, n->bc_entry.link); +	__skb_queue_purge(&n->bc_entry.namedq);  	/* Abort any ongoing link failover */  	for (i = 0; i < MAX_BEARERS; i++) { @@ -1512,7 +1515,7 @@ static void node_lost_contact(struct tipc_node *n,   * tipc_node_get_linkname - get the name of a link   *   * @bearer_id: id of the bearer - * @node: peer node address + * @addr: peer node address   * @linkname: link name output buffer   *   * Returns 0 on success @@ -1729,12 +1732,23 @@ int tipc_node_distr_xmit(struct net *net, struct sk_buff_head *xmitq)  	return 0;  } -void tipc_node_broadcast(struct net *net, struct sk_buff *skb) +void tipc_node_broadcast(struct net *net, struct sk_buff *skb, int rc_dests)  { +	struct sk_buff_head xmitq;  	struct sk_buff *txskb;  	struct tipc_node *n; +	u16 dummy;  	u32 dst; +	/* Use broadcast if all nodes support it */ +	if (!rc_dests && tipc_bcast_get_mode(net) != BCLINK_MODE_RCAST) { +		__skb_queue_head_init(&xmitq); +		__skb_queue_tail(&xmitq, skb); +		tipc_bcast_xmit(net, &xmitq, &dummy); +		return; +	} + +	/* Otherwise use legacy replicast method */  	rcu_read_lock();  	list_for_each_entry_rcu(n, tipc_nodes(net), list) {  		dst = n->addr; @@ -1749,7 +1763,6 @@ void tipc_node_broadcast(struct net *net, struct sk_buff *skb)  		tipc_node_xmit_skb(net, txskb, dst, 0);  	}  	rcu_read_unlock(); -  	kfree_skb(skb);  } @@ -1844,7 +1857,9 @@ static void tipc_node_bc_rcv(struct net *net, struct sk_buff *skb, int bearer_id  	/* Handle NAME_DISTRIBUTOR messages sent from 1.7 nodes */  	if (!skb_queue_empty(&n->bc_entry.namedq)) -		tipc_named_rcv(net, &n->bc_entry.namedq); +		tipc_named_rcv(net, &n->bc_entry.namedq, +			       &n->bc_entry.named_rcv_nxt, +			       &n->bc_entry.named_open);  	/* If reassembly or retransmission failure => reset all links to peer */  	if (rc & TIPC_LINK_DOWN_EVT) @@ -2007,7 +2022,7 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,   * tipc_rcv - process TIPC packets/messages arriving from off-node   * @net: the applicable net namespace   * @skb: TIPC packet - * @bearer: pointer to bearer message arrived on + * @b: pointer to bearer message arrived on   *   * Invoked with no locks held. Bearer pointer must point to a valid bearer   * structure (i.e. cannot be NULL), but bearer can be inactive. @@ -2114,7 +2129,9 @@ rcv:  		tipc_node_link_down(n, bearer_id, false);  	if (unlikely(!skb_queue_empty(&n->bc_entry.namedq))) -		tipc_named_rcv(net, &n->bc_entry.namedq); +		tipc_named_rcv(net, &n->bc_entry.namedq, +			       &n->bc_entry.named_rcv_nxt, +			       &n->bc_entry.named_open);  	if (unlikely(!skb_queue_empty(&n->bc_entry.inputq1)))  		tipc_node_mcast_rcv(n); diff --git a/net/tipc/node.h b/net/tipc/node.h index a6803b449a2c..9f6f13f1604f 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -55,7 +55,8 @@ enum {  	TIPC_MCAST_RBCTL      = (1 << 7),  	TIPC_GAP_ACK_BLOCK    = (1 << 8),  	TIPC_TUNNEL_ENHANCED  = (1 << 9), -	TIPC_NAGLE            = (1 << 10) +	TIPC_NAGLE            = (1 << 10), +	TIPC_NAMED_BCAST      = (1 << 11)  };  #define TIPC_NODE_CAPABILITIES (TIPC_SYN_BIT           |  \ @@ -68,7 +69,8 @@ enum {  				TIPC_MCAST_RBCTL       |   \  				TIPC_GAP_ACK_BLOCK     |   \  				TIPC_TUNNEL_ENHANCED   |   \ -				TIPC_NAGLE) +				TIPC_NAGLE             |   \ +				TIPC_NAMED_BCAST)  #define INVALID_BEARER_ID -1 @@ -101,7 +103,7 @@ int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest,  		       u32 selector);  void tipc_node_subscribe(struct net *net, struct list_head *subscr, u32 addr);  void tipc_node_unsubscribe(struct net *net, struct list_head *subscr, u32 addr); -void tipc_node_broadcast(struct net *net, struct sk_buff *skb); +void tipc_node_broadcast(struct net *net, struct sk_buff *skb, int rc_dests);  int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port);  void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port);  int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel, bool connected); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index a94f38333698..07419f36116a 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -711,7 +711,6 @@ exit:   * tipc_getname - get port ID of socket or peer socket   * @sock: socket structure   * @uaddr: area for returned socket address - * @uaddr_len: area for returned length of socket address   * @peer: 0 = own ID, 1 = current peer ID, 2 = current/former peer ID   *   * Returns 0 on success, errno otherwise @@ -1053,7 +1052,7 @@ static int tipc_send_group_anycast(struct socket *sock, struct msghdr *m,  /**   * tipc_send_group_bcast - send message to all members in communication group - * @sk: socket structure + * @sock: socket structure   * @m: message to send   * @dlen: total length of message data   * @timeout: timeout to wait for wakeup @@ -1673,7 +1672,7 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,  /**   * tipc_sk_set_orig_addr - capture sender's address for received message   * @m: descriptor for message info - * @hdr: received message header + * @skb: received message   *   * Note: Address is not captured if not requested by receiver.   */ @@ -2095,7 +2094,6 @@ static void tipc_write_space(struct sock *sk)  /**   * tipc_data_ready - wake up threads to indicate messages have been received   * @sk: socket - * @len: the length of messages   */  static void tipc_data_ready(struct sock *sk)  { @@ -2677,7 +2675,7 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)  /**   * tipc_accept - wait for connection request   * @sock: listening socket - * @newsock: new socket that is to be connected + * @new_sock: new socket that is to be connected   * @flags: file-related flags associated with socket   *   * Returns 0 on success, errno otherwise @@ -3105,7 +3103,7 @@ static int tipc_sk_leave(struct tipc_sock *tsk)   * Returns 0 on success, errno otherwise   */  static int tipc_setsockopt(struct socket *sock, int lvl, int opt, -			   char __user *ov, unsigned int ol) +			   sockptr_t ov, unsigned int ol)  {  	struct sock *sk = sock->sk;  	struct tipc_sock *tsk = tipc_sk(sk); @@ -3126,17 +3124,17 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt,  	case TIPC_NODELAY:  		if (ol < sizeof(value))  			return -EINVAL; -		if (get_user(value, (u32 __user *)ov)) +		if (copy_from_sockptr(&value, ov, sizeof(u32)))  			return -EFAULT;  		break;  	case TIPC_GROUP_JOIN:  		if (ol < sizeof(mreq))  			return -EINVAL; -		if (copy_from_user(&mreq, ov, sizeof(mreq))) +		if (copy_from_sockptr(&mreq, ov, sizeof(mreq)))  			return -EFAULT;  		break;  	default: -		if (ov || ol) +		if (!sockptr_is_null(ov) || ol)  			return -EINVAL;  	} diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 28a283f26a8d..911d13cd2e67 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -565,7 +565,7 @@ msg_full:  /**   * tipc_parse_udp_addr - build udp media address from netlink data - * @nlattr:	netlink attribute containing sockaddr storage aligned address + * @nla:	netlink attribute containing sockaddr storage aligned address   * @addr:	tipc media address to fill with address, port and protocol type   * @scope_id:	IPv6 scope id pointer, not NULL indicates it's required   */ @@ -660,6 +660,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  	struct udp_tunnel_sock_cfg tuncfg = {NULL};  	struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];  	u8 node_id[NODE_ID_LEN] = {0,}; +	struct net_device *dev;  	int rmcast = 0;  	ub = kzalloc(sizeof(*ub), GFP_ATOMIC); @@ -714,8 +715,6 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  	rcu_assign_pointer(ub->bearer, b);  	tipc_udp_media_addr_set(&b->addr, &local);  	if (local.proto == htons(ETH_P_IP)) { -		struct net_device *dev; -  		dev = __ip_dev_find(net, local.ipv4.s_addr, false);  		if (!dev) {  			err = -ENODEV; @@ -738,6 +737,12 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  		b->mtu = b->media->mtu;  #if IS_ENABLED(CONFIG_IPV6)  	} else if (local.proto == htons(ETH_P_IPV6)) { +		dev = ub->ifindex ? __dev_get_by_index(net, ub->ifindex) : NULL; +		dev = ipv6_dev_find(net, &local.ipv6, dev); +		if (!dev) { +			err = -ENODEV; +			goto err; +		}  		udp_conf.family = AF_INET6;  		udp_conf.use_udp6_tx_checksums = true;  		udp_conf.use_udp6_rx_checksums = true; @@ -745,6 +750,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  			udp_conf.local_ip6 = in6addr_any;  		else  			udp_conf.local_ip6 = local.ipv6; +		ub->ifindex = dev->ifindex;  		b->mtu = 1280;  #endif  	} else {  | 
