diff options
Diffstat (limited to 'net/decnet/dn_dev.c')
| -rw-r--r-- | net/decnet/dn_dev.c | 172 | 
1 files changed, 84 insertions, 88 deletions
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 0ba15633c41..3b726f31c64 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -42,7 +42,6 @@  #include <linux/notifier.h>  #include <linux/slab.h>  #include <asm/uaccess.h> -#include <asm/system.h>  #include <net/net_namespace.h>  #include <net/neighbour.h>  #include <net/dst.h> @@ -159,11 +158,11 @@ static int max_t3[] = { 8191 }; /* Must fit in 16 bits when multiplied by BCT3MU  static int min_priority[1];  static int max_priority[] = { 127 }; /* From DECnet spec */ -static int dn_forwarding_proc(ctl_table *, int, +static int dn_forwarding_proc(struct ctl_table *, int,  			void __user *, size_t *, loff_t *);  static struct dn_dev_sysctl_table {  	struct ctl_table_header *sysctl_header; -	ctl_table dn_dev_vars[5]; +	struct ctl_table dn_dev_vars[5];  } dn_dev_sysctl = {  	NULL,  	{ @@ -210,15 +209,7 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *  	struct dn_dev_sysctl_table *t;  	int i; -#define DN_CTL_PATH_DEV	3 - -	struct ctl_path dn_ctl_path[] = { -		{ .procname = "net",  }, -		{ .procname = "decnet",  }, -		{ .procname = "conf",  }, -		{ /* to be set */ }, -		{ }, -	}; +	char path[sizeof("net/decnet/conf/") + IFNAMSIZ];  	t = kmemdup(&dn_dev_sysctl, sizeof(*t), GFP_KERNEL);  	if (t == NULL) @@ -229,15 +220,12 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *  		t->dn_dev_vars[i].data = ((char *)parms) + offset;  	} -	if (dev) { -		dn_ctl_path[DN_CTL_PATH_DEV].procname = dev->name; -	} else { -		dn_ctl_path[DN_CTL_PATH_DEV].procname = parms->name; -	} +	snprintf(path, sizeof(path), "net/decnet/conf/%s", +		dev? dev->name : parms->name);  	t->dn_dev_vars[0].extra1 = (void *)dev; -	t->sysctl_header = register_sysctl_paths(dn_ctl_path, t->dn_dev_vars); +	t->sysctl_header = register_net_sysctl(&init_net, path, t->dn_dev_vars);  	if (t->sysctl_header == NULL)  		kfree(t);  	else @@ -249,12 +237,12 @@ static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)  	if (parms->sysctl) {  		struct dn_dev_sysctl_table *t = parms->sysctl;  		parms->sysctl = NULL; -		unregister_sysctl_table(t->sysctl_header); +		unregister_net_sysctl_table(t->sysctl_header);  		kfree(t);  	}  } -static int dn_forwarding_proc(ctl_table *table, int write, +static int dn_forwarding_proc(struct ctl_table *table, int write,  				void __user *buffer,  				size_t *lenp, loff_t *ppos)  { @@ -332,14 +320,9 @@ static struct dn_ifaddr *dn_dev_alloc_ifa(void)  	return ifa;  } -static void dn_dev_free_ifa_rcu(struct rcu_head *head) -{ -	kfree(container_of(head, struct dn_ifaddr, rcu)); -} -  static void dn_dev_free_ifa(struct dn_ifaddr *ifa)  { -	call_rcu(&ifa->rcu, dn_dev_free_ifa_rcu); +	kfree_rcu(ifa, rcu);  }  static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy) @@ -442,17 +425,17 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg)  	dev_load(&init_net, ifr->ifr_name); -	switch(cmd) { -		case SIOCGIFADDR: -			break; -		case SIOCSIFADDR: -			if (!capable(CAP_NET_ADMIN)) -				return -EACCES; -			if (sdn->sdn_family != AF_DECnet) -				return -EINVAL; -			break; -		default: +	switch (cmd) { +	case SIOCGIFADDR: +		break; +	case SIOCSIFADDR: +		if (!capable(CAP_NET_ADMIN)) +			return -EACCES; +		if (sdn->sdn_family != AF_DECnet)  			return -EINVAL; +		break; +	default: +		return -EINVAL;  	}  	rtnl_lock(); @@ -475,27 +458,27 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg)  		goto done;  	} -	switch(cmd) { -		case SIOCGIFADDR: -			*((__le16 *)sdn->sdn_nodeaddr) = ifa->ifa_local; -			goto rarok; - -		case SIOCSIFADDR: -			if (!ifa) { -				if ((ifa = dn_dev_alloc_ifa()) == NULL) { -					ret = -ENOBUFS; -					break; -				} -				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); -			} else { -				if (ifa->ifa_local == dn_saddr2dn(sdn)) -					break; -				dn_dev_del_ifa(dn_db, ifap, 0); +	switch (cmd) { +	case SIOCGIFADDR: +		*((__le16 *)sdn->sdn_nodeaddr) = ifa->ifa_local; +		goto rarok; + +	case SIOCSIFADDR: +		if (!ifa) { +			if ((ifa = dn_dev_alloc_ifa()) == NULL) { +				ret = -ENOBUFS; +				break;  			} +			memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); +		} else { +			if (ifa->ifa_local == dn_saddr2dn(sdn)) +				break; +			dn_dev_del_ifa(dn_db, ifap, 0); +		} -			ifa->ifa_local = ifa->ifa_address = dn_saddr2dn(sdn); +		ifa->ifa_local = ifa->ifa_address = dn_saddr2dn(sdn); -			ret = dn_dev_set_ifa(dev, ifa); +		ret = dn_dev_set_ifa(dev, ifa);  	}  done:  	rtnl_unlock(); @@ -578,9 +561,10 @@ static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = {  	[IFA_LOCAL]		= { .type = NLA_U16 },  	[IFA_LABEL]		= { .type = NLA_STRING,  				    .len = IFNAMSIZ - 1 }, +	[IFA_FLAGS]		= { .type = NLA_U32 },  }; -static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct nlattr *tb[IFA_MAX+1]; @@ -590,6 +574,9 @@ static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)  	struct dn_ifaddr __rcu **ifap;  	int err = -EINVAL; +	if (!netlink_capable(skb, CAP_NET_ADMIN)) +		return -EPERM; +  	if (!net_eq(net, &init_net))  		goto errout; @@ -621,7 +608,7 @@ errout:  	return err;  } -static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)  {  	struct net *net = sock_net(skb->sk);  	struct nlattr *tb[IFA_MAX+1]; @@ -631,6 +618,9 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)  	struct dn_ifaddr *ifa;  	int err; +	if (!netlink_capable(skb, CAP_NET_ADMIN)) +		return -EPERM; +  	if (!net_eq(net, &init_net))  		return -EINVAL; @@ -659,7 +649,8 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)  	ifa->ifa_local = nla_get_le16(tb[IFA_LOCAL]);  	ifa->ifa_address = nla_get_le16(tb[IFA_ADDRESS]); -	ifa->ifa_flags = ifm->ifa_flags; +	ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : +					 ifm->ifa_flags;  	ifa->ifa_scope = ifm->ifa_scope;  	ifa->ifa_dev = dn_db; @@ -680,33 +671,36 @@ static inline size_t dn_ifaddr_nlmsg_size(void)  	return NLMSG_ALIGN(sizeof(struct ifaddrmsg))  	       + nla_total_size(IFNAMSIZ) /* IFA_LABEL */  	       + nla_total_size(2) /* IFA_ADDRESS */ -	       + nla_total_size(2); /* IFA_LOCAL */ +	       + nla_total_size(2) /* IFA_LOCAL */ +	       + nla_total_size(4); /* IFA_FLAGS */  }  static int dn_nl_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa, -			     u32 pid, u32 seq, int event, unsigned int flags) +			     u32 portid, u32 seq, int event, unsigned int flags)  {  	struct ifaddrmsg *ifm;  	struct nlmsghdr *nlh; +	u32 ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; -	nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), flags); +	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags);  	if (nlh == NULL)  		return -EMSGSIZE;  	ifm = nlmsg_data(nlh);  	ifm->ifa_family = AF_DECnet;  	ifm->ifa_prefixlen = 16; -	ifm->ifa_flags = ifa->ifa_flags | IFA_F_PERMANENT; +	ifm->ifa_flags = ifa_flags;  	ifm->ifa_scope = ifa->ifa_scope;  	ifm->ifa_index = ifa->ifa_dev->dev->ifindex; -	if (ifa->ifa_address) -		NLA_PUT_LE16(skb, IFA_ADDRESS, ifa->ifa_address); -	if (ifa->ifa_local) -		NLA_PUT_LE16(skb, IFA_LOCAL, ifa->ifa_local); -	if (ifa->ifa_label[0]) -		NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label); - +	if ((ifa->ifa_address && +	     nla_put_le16(skb, IFA_ADDRESS, ifa->ifa_address)) || +	    (ifa->ifa_local && +	     nla_put_le16(skb, IFA_LOCAL, ifa->ifa_local)) || +	    (ifa->ifa_label[0] && +	     nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || +	     nla_put_u32(skb, IFA_FLAGS, ifa_flags)) +		goto nla_put_failure;  	return nlmsg_end(skb, nlh);  nla_put_failure: @@ -752,7 +746,8 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)  	skip_naddr = cb->args[1];  	idx = 0; -	for_each_netdev(&init_net, dev) { +	rcu_read_lock(); +	for_each_netdev_rcu(&init_net, dev) {  		if (idx < skip_ndevs)  			goto cont;  		else if (idx > skip_ndevs) { @@ -761,15 +756,15 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)  			skip_naddr = 0;  		} -		if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) +		if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL)  			goto cont; -		for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa; -		     ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) { +		for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa; +		     ifa = rcu_dereference(ifa->ifa_next), dn_idx++) {  			if (dn_idx < skip_naddr)  				continue; -			if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, +			if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).portid,  					      cb->nlh->nlmsg_seq, RTM_NEWADDR,  					      NLM_F_MULTI) < 0)  				goto done; @@ -778,6 +773,7 @@ cont:  		idx++;  	}  done: +	rcu_read_unlock();  	cb->args[0] = idx;  	cb->args[1] = dn_idx; @@ -1104,7 +1100,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)  	dn_db->neigh_parms = neigh_parms_alloc(dev, &dn_neigh_table);  	if (!dn_db->neigh_parms) { -		rcu_assign_pointer(dev->dn_ptr, NULL); +		RCU_INIT_POINTER(dev->dn_ptr, NULL);  		kfree(dn_db);  		return NULL;  	} @@ -1130,7 +1126,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)  /*   * This processes a device up event. We only start up   * the loopback device & ethernet devices with correct - * MAC addreses automatically. Others must be started + * MAC addresses automatically. Others must be started   * specifically.   *   * FIXME: How should we configure the loopback address ? If we could dispense @@ -1316,7 +1312,7 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)  	++*pos; -	dev = (struct net_device *)v; +	dev = v;  	if (v == SEQ_START_TOKEN)  		dev = net_device_entry(&init_net.dev_base_head); @@ -1338,13 +1334,13 @@ static void dn_dev_seq_stop(struct seq_file *seq, void *v)  static char *dn_type2asc(char type)  { -	switch(type) { -		case DN_DEV_BCAST: -			return "B"; -		case DN_DEV_UCAST: -			return "U"; -		case DN_DEV_MPOINT: -			return "M"; +	switch (type) { +	case DN_DEV_BCAST: +		return "B"; +	case DN_DEV_UCAST: +		return "U"; +	case DN_DEV_MPOINT: +		return "M";  	}  	return "?"; @@ -1417,11 +1413,11 @@ void __init dn_dev_init(void)  	dn_dev_devices_on(); -	rtnl_register(PF_DECnet, RTM_NEWADDR, dn_nl_newaddr, NULL); -	rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL); -	rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr); +	rtnl_register(PF_DECnet, RTM_NEWADDR, dn_nl_newaddr, NULL, NULL); +	rtnl_register(PF_DECnet, RTM_DELADDR, dn_nl_deladdr, NULL, NULL); +	rtnl_register(PF_DECnet, RTM_GETADDR, NULL, dn_nl_dump_ifaddr, NULL); -	proc_net_fops_create(&init_net, "decnet_dev", S_IRUGO, &dn_dev_seq_fops); +	proc_create("decnet_dev", S_IRUGO, init_net.proc_net, &dn_dev_seq_fops);  #ifdef CONFIG_SYSCTL  	{ @@ -1442,7 +1438,7 @@ void __exit dn_dev_cleanup(void)  	}  #endif /* CONFIG_SYSCTL */ -	proc_net_remove(&init_net, "decnet_dev"); +	remove_proc_entry("decnet_dev", init_net.proc_net);  	dn_dev_devices_off();  }  | 
