diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/Makefile | 1 | ||||
| -rw-r--r-- | net/tipc/bcast.c | 4 | ||||
| -rw-r--r-- | net/tipc/bearer.c | 54 | ||||
| -rw-r--r-- | net/tipc/bearer.h | 3 | ||||
| -rw-r--r-- | net/tipc/link.c | 23 | ||||
| -rw-r--r-- | net/tipc/msg.c | 18 | ||||
| -rw-r--r-- | net/tipc/netlink_compat.c | 8 | ||||
| -rw-r--r-- | net/tipc/node.c | 22 | ||||
| -rw-r--r-- | net/tipc/socket.c | 6 | ||||
| -rw-r--r-- | net/tipc/subscr.c | 21 | 
10 files changed, 71 insertions, 89 deletions
| diff --git a/net/tipc/Makefile b/net/tipc/Makefile index 31b9f9c52974..2bfaa9d4b403 100644 --- a/net/tipc/Makefile +++ b/net/tipc/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0  #  # Makefile for the Linux TIPC layer  # diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 7d99029df342..a140dd4a84af 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -233,7 +233,7 @@ static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts,  	struct sk_buff_head xmitq;  	int rc = 0; -	__skb_queue_head_init(&xmitq); +	skb_queue_head_init(&xmitq);  	tipc_bcast_lock(net);  	if (tipc_link_bc_peers(l))  		rc = tipc_link_xmit(l, pkts, &xmitq); @@ -263,7 +263,7 @@ static int tipc_rcast_xmit(struct net *net, struct sk_buff_head *pkts,  	u32 dst, selector;  	selector = msg_link_selector(buf_msg(skb_peek(pkts))); -	__skb_queue_head_init(&_pkts); +	skb_queue_head_init(&_pkts);  	list_for_each_entry_safe(n, tmp, &dests->list, list) {  		dst = n->value; diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index d174ee3254ee..47ec121574ce 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -65,6 +65,8 @@ static struct tipc_bearer *bearer_get(struct net *net, int bearer_id)  }  static void bearer_disable(struct net *net, struct tipc_bearer *b); +static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev, +			   struct packet_type *pt, struct net_device *orig_dev);  /**   * tipc_media_find - locates specified media object by name @@ -365,30 +367,6 @@ static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b)  	return 0;  } -/* tipc_bearer_reset_all - reset all links on all bearers - */ -void tipc_bearer_reset_all(struct net *net) -{ -	struct tipc_bearer *b; -	int i; - -	for (i = 0; i < MAX_BEARERS; i++) { -		b = bearer_get(net, i); -		if (b) -			clear_bit_unlock(0, &b->up); -	} -	for (i = 0; i < MAX_BEARERS; i++) { -		b = bearer_get(net, i); -		if (b) -			tipc_reset_bearer(net, b); -	} -	for (i = 0; i < MAX_BEARERS; i++) { -		b = bearer_get(net, i); -		if (b) -			test_and_set_bit_lock(0, &b->up); -	} -} -  /**   * bearer_disable   * @@ -428,6 +406,10 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,  	/* Associate TIPC bearer with L2 bearer */  	rcu_assign_pointer(b->media_ptr, dev); +	b->pt.dev = dev; +	b->pt.type = htons(ETH_P_TIPC); +	b->pt.func = tipc_l2_rcv_msg; +	dev_add_pack(&b->pt);  	memset(&b->bcast_addr, 0, sizeof(b->bcast_addr));  	memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);  	b->bcast_addr.media_id = b->media->type_id; @@ -447,6 +429,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b)  	struct net_device *dev;  	dev = (struct net_device *)rtnl_dereference(b->media_ptr); +	dev_remove_pack(&b->pt);  	RCU_INIT_POINTER(dev->tipc_ptr, NULL);  	synchronize_net();  	dev_put(dev); @@ -594,11 +577,12 @@ static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev,  	struct tipc_bearer *b;  	rcu_read_lock(); -	b = rcu_dereference_rtnl(dev->tipc_ptr); +	b = rcu_dereference_rtnl(dev->tipc_ptr) ?: +		rcu_dereference_rtnl(orig_dev->tipc_ptr);  	if (likely(b && test_bit(0, &b->up) && -		   (skb->pkt_type <= PACKET_BROADCAST))) { +		   (skb->pkt_type <= PACKET_MULTICAST))) {  		skb->next = NULL; -		tipc_rcv(dev_net(dev), skb, b); +		tipc_rcv(dev_net(b->pt.dev), skb, b);  		rcu_read_unlock();  		return NET_RX_SUCCESS;  	} @@ -653,17 +637,12 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,  		break;  	case NETDEV_UNREGISTER:  	case NETDEV_CHANGENAME: -		bearer_disable(dev_net(dev), b); +		bearer_disable(net, b);  		break;  	}  	return NOTIFY_OK;  } -static struct packet_type tipc_packet_type __read_mostly = { -	.type = htons(ETH_P_TIPC), -	.func = tipc_l2_rcv_msg, -}; -  static struct notifier_block notifier = {  	.notifier_call  = tipc_l2_device_event,  	.priority	= 0, @@ -671,19 +650,12 @@ static struct notifier_block notifier = {  int tipc_bearer_setup(void)  { -	int err; - -	err = register_netdevice_notifier(¬ifier); -	if (err) -		return err; -	dev_add_pack(&tipc_packet_type); -	return 0; +	return register_netdevice_notifier(¬ifier);  }  void tipc_bearer_cleanup(void)  {  	unregister_netdevice_notifier(¬ifier); -	dev_remove_pack(&tipc_packet_type);  }  void tipc_bearer_stop(struct net *net) diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 635c9086e19a..42d6eeeb646d 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -131,6 +131,7 @@ struct tipc_media {   * @name: bearer name (format = media:interface)   * @media: ptr to media structure associated with bearer   * @bcast_addr: media address used in broadcasting + * @pt: packet type for bearer   * @rcu: rcu struct for tipc_bearer   * @priority: default link priority for bearer   * @window: default window size for bearer @@ -151,6 +152,7 @@ struct tipc_bearer {  	char name[TIPC_MAX_BEARER_NAME];  	struct tipc_media *media;  	struct tipc_media_addr bcast_addr; +	struct packet_type pt;  	struct rcu_head rcu;  	u32 priority;  	u32 window; @@ -210,7 +212,6 @@ void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest);  struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name);  int tipc_bearer_get_name(struct net *net, char *name, u32 bearer_id);  struct tipc_media *tipc_media_find(const char *name); -void tipc_bearer_reset_all(struct net *net);  int tipc_bearer_setup(void);  void tipc_bearer_cleanup(void);  void tipc_bearer_stop(struct net *net); diff --git a/net/tipc/link.c b/net/tipc/link.c index 60820dc35a08..ac0144f532aa 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -978,15 +978,15 @@ static void link_retransmit_failure(struct tipc_link *l, struct sk_buff *skb)  	struct tipc_msg *hdr = buf_msg(skb);  	pr_warn("Retransmission failure on link <%s>\n", l->name); -	link_print(l, "Resetting link "); +	link_print(l, "State of link ");  	pr_info("Failed msg: usr %u, typ %u, len %u, err %u\n",  		msg_user(hdr), msg_type(hdr), msg_size(hdr), msg_errcode(hdr));  	pr_info("sqno %u, prev: %x, src: %x\n",  		msg_seqno(hdr), msg_prevnode(hdr), msg_orignode(hdr));  } -int tipc_link_retrans(struct tipc_link *l, u16 from, u16 to, -		      struct sk_buff_head *xmitq) +int tipc_link_retrans(struct tipc_link *l, struct tipc_link *nacker, +		      u16 from, u16 to, struct sk_buff_head *xmitq)  {  	struct sk_buff *_skb, *skb = skb_peek(&l->transmq);  	struct tipc_msg *hdr; @@ -997,11 +997,14 @@ int tipc_link_retrans(struct tipc_link *l, u16 from, u16 to,  		return 0;  	/* Detect repeated retransmit failures on same packet */ -	if (likely(l->last_retransm != buf_seqno(skb))) { -		l->last_retransm = buf_seqno(skb); -		l->stale_count = 1; -	} else if (++l->stale_count > 100) { +	if (nacker->last_retransm != buf_seqno(skb)) { +		nacker->last_retransm = buf_seqno(skb); +		nacker->stale_count = 1; +	} else if (++nacker->stale_count > 100) {  		link_retransmit_failure(l, skb); +		nacker->stale_count = 0; +		if (link_is_bc_sndlink(l)) +			return TIPC_LINK_DOWN_EVT;  		return tipc_link_fsm_evt(l, LINK_FAILURE_EVT);  	} @@ -1528,7 +1531,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,  		/* If NACK, retransmit will now start at right position */  		if (gap) { -			rc = tipc_link_retrans(l, ack + 1, ack + gap, xmitq); +			rc = tipc_link_retrans(l, l, ack + 1, ack + gap, xmitq);  			l->stats.recv_nacks++;  		} @@ -1680,7 +1683,7 @@ int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr,  		return rc;  	if (link_bc_retr_eval(snd_l, &from, &to)) -		rc = tipc_link_retrans(snd_l, from, to, xmitq); +		rc = tipc_link_retrans(snd_l, l, from, to, xmitq);  	l->snd_nxt = peers_snd_nxt;  	if (link_bc_rcv_gap(l)) @@ -1775,7 +1778,7 @@ int tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb,  	if (dnode == tipc_own_addr(l->net)) {  		tipc_link_bc_ack_rcv(l, acked, xmitq); -		rc = tipc_link_retrans(l->bc_sndlink, from, to, xmitq); +		rc = tipc_link_retrans(l->bc_sndlink, l, from, to, xmitq);  		l->stats.recv_nacks++;  		return rc;  	} diff --git a/net/tipc/msg.c b/net/tipc/msg.c index ab3087687a32..17146c16ee2d 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -479,13 +479,14 @@ bool tipc_msg_make_bundle(struct sk_buff **skb,  struct tipc_msg *msg,  bool tipc_msg_reverse(u32 own_node,  struct sk_buff **skb, int err)  {  	struct sk_buff *_skb = *skb; -	struct tipc_msg *hdr = buf_msg(_skb); +	struct tipc_msg *hdr;  	struct tipc_msg ohdr; -	int dlen = min_t(uint, msg_data_sz(hdr), MAX_FORWARD_SIZE); +	int dlen;  	if (skb_linearize(_skb))  		goto exit;  	hdr = buf_msg(_skb); +	dlen = min_t(uint, msg_data_sz(hdr), MAX_FORWARD_SIZE);  	if (msg_dest_droppable(hdr))  		goto exit;  	if (msg_errcode(hdr)) @@ -511,8 +512,11 @@ bool tipc_msg_reverse(u32 own_node,  struct sk_buff **skb, int err)  	    pskb_expand_head(_skb, BUF_HEADROOM, BUF_TAILROOM, GFP_ATOMIC))  		goto exit; +	/* reassign after skb header modifications */ +	hdr = buf_msg(_skb);  	/* Now reverse the concerned fields */  	msg_set_errcode(hdr, err); +	msg_set_non_seq(hdr, 0);  	msg_set_origport(hdr, msg_destport(&ohdr));  	msg_set_destport(hdr, msg_origport(&ohdr));  	msg_set_destnode(hdr, msg_prevnode(&ohdr)); @@ -547,7 +551,7 @@ bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err)  		return false;  	if (msg_errcode(msg))  		return false; -	*err = -TIPC_ERR_NO_NAME; +	*err = TIPC_ERR_NO_NAME;  	if (skb_linearize(skb))  		return false;  	msg = buf_msg(skb); @@ -564,6 +568,14 @@ bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err)  	msg_set_destnode(msg, dnode);  	msg_set_destport(msg, dport);  	*err = TIPC_OK; + +	if (!skb_cloned(skb)) +		return true; + +	/* Unclone buffer in case it was bundled */ +	if (pskb_expand_head(skb, BUF_HEADROOM, BUF_TAILROOM, GFP_ATOMIC)) +		return false; +  	return true;  } diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 9bfe886ab330..e48f0b2c01b9 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -258,13 +258,15 @@ static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,  	arg = nlmsg_new(0, GFP_KERNEL);  	if (!arg) {  		kfree_skb(msg->rep); +		msg->rep = NULL;  		return -ENOMEM;  	}  	err = __tipc_nl_compat_dumpit(cmd, msg, arg); -	if (err) +	if (err) {  		kfree_skb(msg->rep); - +		msg->rep = NULL; +	}  	kfree_skb(arg);  	return err; @@ -1215,7 +1217,7 @@ send:  	return err;  } -static struct genl_ops tipc_genl_compat_ops[] = { +static const struct genl_ops tipc_genl_compat_ops[] = {  	{  		.cmd		= TIPC_GENL_CMD,  		.doit		= tipc_nl_compat_recv, diff --git a/net/tipc/node.c b/net/tipc/node.c index aeef8011ac7d..198dbc7adbe1 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1126,8 +1126,8 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr,  		strncpy(linkname, tipc_link_name(link), len);  		err = 0;  	} -exit:  	tipc_node_read_unlock(node); +exit:  	tipc_node_put(node);  	return err;  } @@ -1284,7 +1284,7 @@ static void tipc_node_bc_sync_rcv(struct tipc_node *n, struct tipc_msg *hdr,  	rc = tipc_bcast_sync_rcv(n->net, n->bc_entry.link, hdr);  	if (rc & TIPC_LINK_DOWN_EVT) { -		tipc_bearer_reset_all(n->net); +		tipc_node_reset_links(n);  		return;  	} @@ -1351,15 +1351,9 @@ static void tipc_node_bc_rcv(struct net *net, struct sk_buff *skb, int bearer_id  	if (!skb_queue_empty(&be->inputq1))  		tipc_node_mcast_rcv(n); -	if (rc & TIPC_LINK_DOWN_EVT) { -		/* Reception reassembly failure => reset all links to peer */ -		if (!tipc_link_is_up(be->link)) -			tipc_node_reset_links(n); - -		/* Retransmission failure => reset all links to all peers */ -		if (!tipc_link_is_up(tipc_bc_sndlink(net))) -			tipc_bearer_reset_all(net); -	} +	/* If reassembly or retransmission failure => reset all links to peer */ +	if (rc & TIPC_LINK_DOWN_EVT) +		tipc_node_reset_links(n);  	tipc_node_put(n);  } @@ -1455,10 +1449,8 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb,  	/* Initiate synch mode if applicable */  	if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG) && (oseqno == 1)) {  		syncpt = iseqno + exp_pkts - 1; -		if (!tipc_link_is_up(l)) { -			tipc_link_fsm_evt(l, LINK_ESTABLISH_EVT); +		if (!tipc_link_is_up(l))  			__tipc_node_link_up(n, bearer_id, xmitq); -		}  		if (n->state == SELF_UP_PEER_UP) {  			n->sync_point = syncpt;  			tipc_link_fsm_evt(l, LINK_SYNCH_BEGIN_EVT); @@ -1559,6 +1551,8 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b)  	/* Check/update node state before receiving */  	if (unlikely(skb)) { +		if (unlikely(skb_linearize(skb))) +			goto discard;  		tipc_node_write_lock(n);  		if (tipc_node_check_state(n, skb, bearer_id, &xmitq)) {  			if (le->link) { diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 101e3597338f..d50edd6e0019 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2255,8 +2255,8 @@ void tipc_sk_reinit(struct net *net)  	do {  		tsk = ERR_PTR(rhashtable_walk_start(&iter)); -		if (tsk) -			continue; +		if (IS_ERR(tsk)) +			goto walk_stop;  		while ((tsk = rhashtable_walk_next(&iter)) && !IS_ERR(tsk)) {  			spin_lock_bh(&tsk->sk.sk_lock.slock); @@ -2265,7 +2265,7 @@ void tipc_sk_reinit(struct net *net)  			msg_set_orignode(msg, tn->own_addr);  			spin_unlock_bh(&tsk->sk.sk_lock.slock);  		} - +walk_stop:  		rhashtable_walk_stop(&iter);  	} while (tsk == ERR_PTR(-EAGAIN));  } diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 0bf91cd3733c..be3d9e3183dc 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -52,7 +52,6 @@ struct tipc_subscriber {  	struct list_head subscrp_list;  }; -static void tipc_subscrp_delete(struct tipc_subscription *sub);  static void tipc_subscrb_put(struct tipc_subscriber *subscriber);  /** @@ -197,15 +196,19 @@ static void tipc_subscrb_subscrp_delete(struct tipc_subscriber *subscriber,  {  	struct list_head *subscription_list = &subscriber->subscrp_list;  	struct tipc_subscription *sub, *temp; +	u32 timeout;  	spin_lock_bh(&subscriber->lock);  	list_for_each_entry_safe(sub, temp, subscription_list,  subscrp_list) {  		if (s && memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr)))  			continue; -		tipc_nametbl_unsubscribe(sub); -		list_del(&sub->subscrp_list); -		tipc_subscrp_delete(sub); +		timeout = htohl(sub->evt.s.timeout, sub->swap); +		if (timeout == TIPC_WAIT_FOREVER || del_timer(&sub->timer)) { +			tipc_nametbl_unsubscribe(sub); +			list_del(&sub->subscrp_list); +			tipc_subscrp_put(sub); +		}  		if (s)  			break; @@ -236,18 +239,12 @@ static void tipc_subscrb_delete(struct tipc_subscriber *subscriber)  	tipc_subscrb_put(subscriber);  } -static void tipc_subscrp_delete(struct tipc_subscription *sub) -{ -	u32 timeout = htohl(sub->evt.s.timeout, sub->swap); - -	if (timeout == TIPC_WAIT_FOREVER || del_timer(&sub->timer)) -		tipc_subscrp_put(sub); -} -  static void tipc_subscrp_cancel(struct tipc_subscr *s,  				struct tipc_subscriber *subscriber)  { +	tipc_subscrb_get(subscriber);  	tipc_subscrb_subscrp_delete(subscriber, s); +	tipc_subscrb_put(subscriber);  }  static struct tipc_subscription *tipc_subscrp_create(struct net *net, |