diff options
Diffstat (limited to 'net/tipc')
| -rw-r--r-- | net/tipc/bearer.c | 29 | ||||
| -rw-r--r-- | net/tipc/bearer.h | 3 | ||||
| -rw-r--r-- | net/tipc/name_table.c | 103 | ||||
| -rw-r--r-- | net/tipc/netlink_compat.c | 5 | ||||
| -rw-r--r-- | net/tipc/node.c | 33 | ||||
| -rw-r--r-- | net/tipc/node.h | 3 | ||||
| -rw-r--r-- | net/tipc/socket.c | 13 | ||||
| -rw-r--r-- | net/tipc/udp_media.c | 4 | ||||
| -rw-r--r-- | net/tipc/udp_media.h | 14 | 
9 files changed, 146 insertions, 61 deletions
| diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index f7d47c89d658..2dfb492a7c94 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -697,6 +697,9 @@ static int __tipc_nl_add_bearer(struct tipc_nl_msg *msg,  		goto prop_msg_full;  	if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bearer->window))  		goto prop_msg_full; +	if (bearer->media->type_id == TIPC_MEDIA_TYPE_UDP) +		if (nla_put_u32(msg->skb, TIPC_NLA_PROP_MTU, bearer->mtu)) +			goto prop_msg_full;  	nla_nest_end(msg->skb, prop); @@ -979,12 +982,23 @@ int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)  		if (props[TIPC_NLA_PROP_TOL]) {  			b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]); -			tipc_node_apply_tolerance(net, b); +			tipc_node_apply_property(net, b, TIPC_NLA_PROP_TOL);  		}  		if (props[TIPC_NLA_PROP_PRIO])  			b->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);  		if (props[TIPC_NLA_PROP_WIN])  			b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); +		if (props[TIPC_NLA_PROP_MTU]) { +			if (b->media->type_id != TIPC_MEDIA_TYPE_UDP) +				return -EINVAL; +#ifdef CONFIG_TIPC_MEDIA_UDP +			if (tipc_udp_mtu_bad(nla_get_u32 +					     (props[TIPC_NLA_PROP_MTU]))) +				return -EINVAL; +			b->mtu = nla_get_u32(props[TIPC_NLA_PROP_MTU]); +			tipc_node_apply_property(net, b, TIPC_NLA_PROP_MTU); +#endif +		}  	}  	return 0; @@ -1029,6 +1043,9 @@ static int __tipc_nl_add_media(struct tipc_nl_msg *msg,  		goto prop_msg_full;  	if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, media->window))  		goto prop_msg_full; +	if (media->type_id == TIPC_MEDIA_TYPE_UDP) +		if (nla_put_u32(msg->skb, TIPC_NLA_PROP_MTU, media->mtu)) +			goto prop_msg_full;  	nla_nest_end(msg->skb, prop);  	nla_nest_end(msg->skb, attrs); @@ -1158,6 +1175,16 @@ int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)  			m->priority = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);  		if (props[TIPC_NLA_PROP_WIN])  			m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]); +		if (props[TIPC_NLA_PROP_MTU]) { +			if (m->type_id != TIPC_MEDIA_TYPE_UDP) +				return -EINVAL; +#ifdef CONFIG_TIPC_MEDIA_UDP +			if (tipc_udp_mtu_bad(nla_get_u32 +					     (props[TIPC_NLA_PROP_MTU]))) +				return -EINVAL; +			m->mtu = nla_get_u32(props[TIPC_NLA_PROP_MTU]); +#endif +		}  	}  	return 0; diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 6efcee63a381..394290cbbb1d 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -94,6 +94,8 @@ struct tipc_bearer;   * @priority: default link (and bearer) priority   * @tolerance: default time (in ms) before declaring link failure   * @window: default window (in packets) before declaring link congestion + * @mtu: max packet size bearer can support for media type not dependent on + * underlying device MTU   * @type_id: TIPC media identifier   * @hwaddr_len: TIPC media address len   * @name: media name @@ -118,6 +120,7 @@ struct tipc_media {  	u32 priority;  	u32 tolerance;  	u32 window; +	u32 mtu;  	u32 type_id;  	u32 hwaddr_len;  	char name[TIPC_MAX_MEDIA_NAME]; diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index dd1c4fa2eb78..bebe88cae07b 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -136,12 +136,12 @@ static struct tipc_service *tipc_service_create(u32 type, struct hlist_head *hd)  }  /** - * tipc_service_find_range - find service range matching a service instance + * tipc_service_first_range - find first service range in tree matching instance   *   * Very time-critical, so binary search through range rb tree   */ -static struct service_range *tipc_service_find_range(struct tipc_service *sc, -						     u32 instance) +static struct service_range *tipc_service_first_range(struct tipc_service *sc, +						      u32 instance)  {  	struct rb_node *n = sc->ranges.rb_node;  	struct service_range *sr; @@ -158,6 +158,30 @@ static struct service_range *tipc_service_find_range(struct tipc_service *sc,  	return NULL;  } +/*  tipc_service_find_range - find service range matching publication parameters + */ +static struct service_range *tipc_service_find_range(struct tipc_service *sc, +						     u32 lower, u32 upper) +{ +	struct rb_node *n = sc->ranges.rb_node; +	struct service_range *sr; + +	sr = tipc_service_first_range(sc, lower); +	if (!sr) +		return NULL; + +	/* Look for exact match */ +	for (n = &sr->tree_node; n; n = rb_next(n)) { +		sr = container_of(n, struct service_range, tree_node); +		if (sr->upper == upper) +			break; +	} +	if (!n || sr->lower != lower || sr->upper != upper) +		return NULL; + +	return sr; +} +  static struct service_range *tipc_service_create_range(struct tipc_service *sc,  						       u32 lower, u32 upper)  { @@ -238,54 +262,19 @@ err:  /**   * tipc_service_remove_publ - remove a publication from a service   */ -static struct publication *tipc_service_remove_publ(struct net *net, -						    struct tipc_service *sc, -						    u32 lower, u32 upper, -						    u32 node, u32 key, -						    struct service_range **rng) +static struct publication *tipc_service_remove_publ(struct service_range *sr, +						    u32 node, u32 key)  { -	struct tipc_subscription *sub, *tmp; -	struct service_range *sr;  	struct publication *p; -	bool found = false; -	bool last = false; -	struct rb_node *n; - -	sr = tipc_service_find_range(sc, lower); -	if (!sr) -		return NULL; -	/* Find exact matching service range */ -	for (n = &sr->tree_node; n; n = rb_next(n)) { -		sr = container_of(n, struct service_range, tree_node); -		if (sr->upper == upper) -			break; -	} -	if (!n || sr->lower != lower || sr->upper != upper) -		return NULL; - -	/* Find publication, if it exists */  	list_for_each_entry(p, &sr->all_publ, all_publ) {  		if (p->key != key || (node && node != p->node))  			continue; -		found = true; -		break; +		list_del(&p->all_publ); +		list_del(&p->local_publ); +		return p;  	} -	if (!found) -		return NULL; - -	list_del(&p->all_publ); -	list_del(&p->local_publ); -	if (list_empty(&sr->all_publ)) -		last = true; - -	/* Notify any waiting subscriptions */ -	list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) { -		tipc_sub_report_overlap(sub, p->lower, p->upper, TIPC_WITHDRAWN, -					p->port, p->node, p->scope, last); -	} -	*rng = sr; -	return p; +	return NULL;  }  /** @@ -376,17 +365,31 @@ struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,  					     u32 node, u32 key)  {  	struct tipc_service *sc = tipc_service_find(net, type); +	struct tipc_subscription *sub, *tmp;  	struct service_range *sr = NULL;  	struct publication *p = NULL; +	bool last;  	if (!sc)  		return NULL;  	spin_lock_bh(&sc->lock); -	p = tipc_service_remove_publ(net, sc, lower, upper, node, key, &sr); +	sr = tipc_service_find_range(sc, lower, upper); +	if (!sr) +		goto exit; +	p = tipc_service_remove_publ(sr, node, key); +	if (!p) +		goto exit; + +	/* Notify any waiting subscriptions */ +	last = list_empty(&sr->all_publ); +	list_for_each_entry_safe(sub, tmp, &sc->subscriptions, service_list) { +		tipc_sub_report_overlap(sub, lower, upper, TIPC_WITHDRAWN, +					p->port, node, p->scope, last); +	}  	/* Remove service range item if this was its last publication */ -	if (sr && list_empty(&sr->all_publ)) { +	if (list_empty(&sr->all_publ)) {  		rb_erase(&sr->tree_node, &sc->ranges);  		kfree(sr);  	} @@ -396,6 +399,7 @@ struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,  		hlist_del_init_rcu(&sc->service_list);  		kfree_rcu(sc, rcu);  	} +exit:  	spin_unlock_bh(&sc->lock);  	return p;  } @@ -437,7 +441,7 @@ u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *dnode)  		goto not_found;  	spin_lock_bh(&sc->lock); -	sr = tipc_service_find_range(sc, instance); +	sr = tipc_service_first_range(sc, instance);  	if (unlikely(!sr))  		goto no_match; @@ -484,7 +488,7 @@ bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 scope,  	spin_lock_bh(&sc->lock); -	sr = tipc_service_find_range(sc, instance); +	sr = tipc_service_first_range(sc, instance);  	if (!sr)  		goto no_match; @@ -756,8 +760,7 @@ static void tipc_service_delete(struct net *net, struct tipc_service *sc)  	spin_lock_bh(&sc->lock);  	rbtree_postorder_for_each_entry_safe(sr, tmpr, &sc->ranges, tree_node) {  		list_for_each_entry_safe(p, tmp, &sr->all_publ, all_publ) { -			tipc_service_remove_publ(net, sc, p->lower, p->upper, -						 p->node, p->key, &sr); +			tipc_service_remove_publ(sr, p->node, p->key);  			kfree_rcu(p, rcu);  		}  		rb_erase(&sr->tree_node, &sc->ranges); diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index 4492cda45566..a2f76743c73a 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c @@ -285,8 +285,9 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,  	if (!trans_buf)  		return -ENOMEM; -	attrbuf = kmalloc((tipc_genl_family.maxattr + 1) * -			sizeof(struct nlattr *), GFP_KERNEL); +	attrbuf = kmalloc_array(tipc_genl_family.maxattr + 1, +				sizeof(struct nlattr *), +				GFP_KERNEL);  	if (!attrbuf) {  		err = -ENOMEM;  		goto trans_out; diff --git a/net/tipc/node.c b/net/tipc/node.c index f29549de9245..6a44eb812baf 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -195,6 +195,27 @@ int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel)  	return mtu;  } +bool tipc_node_get_id(struct net *net, u32 addr, u8 *id) +{ +	u8 *own_id = tipc_own_id(net); +	struct tipc_node *n; + +	if (!own_id) +		return true; + +	if (addr == tipc_own_addr(net)) { +		memcpy(id, own_id, TIPC_NODEID_LEN); +		return true; +	} +	n = tipc_node_find(net, addr); +	if (!n) +		return false; + +	memcpy(id, &n->peer_id, TIPC_NODEID_LEN); +	tipc_node_put(n); +	return true; +} +  u16 tipc_node_get_capabilities(struct net *net, u32 addr)  {  	struct tipc_node *n; @@ -1681,7 +1702,8 @@ discard:  	kfree_skb(skb);  } -void tipc_node_apply_tolerance(struct net *net, struct tipc_bearer *b) +void tipc_node_apply_property(struct net *net, struct tipc_bearer *b, +			      int prop)  {  	struct tipc_net *tn = tipc_net(net);  	int bearer_id = b->identity; @@ -1696,8 +1718,13 @@ void tipc_node_apply_tolerance(struct net *net, struct tipc_bearer *b)  	list_for_each_entry_rcu(n, &tn->node_list, list) {  		tipc_node_write_lock(n);  		e = &n->links[bearer_id]; -		if (e->link) -			tipc_link_set_tolerance(e->link, b->tolerance, &xmitq); +		if (e->link) { +			if (prop == TIPC_NLA_PROP_TOL) +				tipc_link_set_tolerance(e->link, b->tolerance, +							&xmitq); +			else if (prop == TIPC_NLA_PROP_MTU) +				tipc_link_set_mtu(e->link, b->mtu); +		}  		tipc_node_write_unlock(n);  		tipc_bearer_xmit(net, bearer_id, &xmitq, &e->maddr);  	} diff --git a/net/tipc/node.h b/net/tipc/node.h index f24b83500df1..846c8f240872 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -60,6 +60,7 @@ enum {  #define INVALID_BEARER_ID -1  void tipc_node_stop(struct net *net); +bool tipc_node_get_id(struct net *net, u32 addr, u8 *id);  u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr);  void tipc_node_check_dest(struct net *net, u32 onode, u8 *peer_id128,  			  struct tipc_bearer *bearer, @@ -67,7 +68,7 @@ void tipc_node_check_dest(struct net *net, u32 onode, u8 *peer_id128,  			  struct tipc_media_addr *maddr,  			  bool *respond, bool *dupl_addr);  void tipc_node_delete_links(struct net *net, int bearer_id); -void tipc_node_apply_tolerance(struct net *net, struct tipc_bearer *b); +void tipc_node_apply_property(struct net *net, struct tipc_bearer *b, int prop);  int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node,  			   char *linkname, size_t len);  int tipc_node_xmit(struct net *net, struct sk_buff_head *list, u32 dnode, diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 6be21575503a..930852c54d7a 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2974,7 +2974,8 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt,  static int tipc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  { -	struct sock *sk = sock->sk; +	struct net *net = sock_net(sock->sk); +	struct tipc_sioc_nodeid_req nr = {0};  	struct tipc_sioc_ln_req lnr;  	void __user *argp = (void __user *)arg; @@ -2982,7 +2983,7 @@ static int tipc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  	case SIOCGETLINKNAME:  		if (copy_from_user(&lnr, argp, sizeof(lnr)))  			return -EFAULT; -		if (!tipc_node_get_linkname(sock_net(sk), +		if (!tipc_node_get_linkname(net,  					    lnr.bearer_id & 0xffff, lnr.peer,  					    lnr.linkname, TIPC_MAX_LINK_NAME)) {  			if (copy_to_user(argp, &lnr, sizeof(lnr))) @@ -2990,6 +2991,14 @@ static int tipc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  			return 0;  		}  		return -EADDRNOTAVAIL; +	case SIOCGETNODEID: +		if (copy_from_user(&nr, argp, sizeof(nr))) +			return -EFAULT; +		if (!tipc_node_get_id(net, nr.peer, nr.node_id)) +			return -EADDRNOTAVAIL; +		if (copy_to_user(argp, &nr, sizeof(nr))) +			return -EFAULT; +		return 0;  	default:  		return -ENOIOCTLCMD;  	} diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index e7d91f5d5cae..9783101bc4a9 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -713,8 +713,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,  			err = -EINVAL;  			goto err;  		} -		b->mtu = dev->mtu - sizeof(struct iphdr) -			- sizeof(struct udphdr); +		b->mtu = b->media->mtu;  #if IS_ENABLED(CONFIG_IPV6)  	} else if (local.proto == htons(ETH_P_IPV6)) {  		udp_conf.family = AF_INET6; @@ -803,6 +802,7 @@ struct tipc_media udp_media_info = {  	.priority	= TIPC_DEF_LINK_PRI,  	.tolerance	= TIPC_DEF_LINK_TOL,  	.window		= TIPC_DEF_LINK_WIN, +	.mtu		= TIPC_DEF_LINK_UDP_MTU,  	.type_id	= TIPC_MEDIA_TYPE_UDP,  	.hwaddr_len	= 0,  	.name		= "udp" diff --git a/net/tipc/udp_media.h b/net/tipc/udp_media.h index 281bbae87726..e7455cc73e16 100644 --- a/net/tipc/udp_media.h +++ b/net/tipc/udp_media.h @@ -38,9 +38,23 @@  #ifndef _TIPC_UDP_MEDIA_H  #define _TIPC_UDP_MEDIA_H +#include <linux/ip.h> +#include <linux/udp.h> +  int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr);  int tipc_udp_nl_add_bearer_data(struct tipc_nl_msg *msg, struct tipc_bearer *b);  int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb); +/* check if configured MTU is too low for tipc headers */ +static inline bool tipc_udp_mtu_bad(u32 mtu) +{ +	if (mtu >= (TIPC_MIN_BEARER_MTU + sizeof(struct iphdr) + +	    sizeof(struct udphdr))) +		return false; + +	pr_warn("MTU too low for tipc bearer\n"); +	return true; +} +  #endif  #endif | 
