diff options
Diffstat (limited to 'net/ipv4/ipmr.c')
| -rw-r--r-- | net/ipv4/ipmr.c | 63 | 
1 files changed, 39 insertions, 24 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index eec1f6df80d8..3f0c6d602fb7 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1547,6 +1547,28 @@ out:  	return ret;  } +/* Execute if this ioctl is a special mroute ioctl */ +int ipmr_sk_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) +{ +	switch (cmd) { +	/* These userspace buffers will be consumed by ipmr_ioctl() */ +	case SIOCGETVIFCNT: { +		struct sioc_vif_req buffer; + +		return sock_ioctl_inout(sk, cmd, arg, &buffer, +				      sizeof(buffer)); +		} +	case SIOCGETSGCNT: { +		struct sioc_sg_req buffer; + +		return sock_ioctl_inout(sk, cmd, arg, &buffer, +				      sizeof(buffer)); +		} +	} +	/* return code > 0 means that the ioctl was not executed */ +	return 1; +} +  /* Getsock opt support for the multicast routing system. */  int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,  			 sockptr_t optlen) @@ -1593,13 +1615,13 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, sockptr_t optval,  }  /* The IP multicast ioctl support routines. */ -int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) +int ipmr_ioctl(struct sock *sk, int cmd, void *arg)  { -	struct sioc_sg_req sr; -	struct sioc_vif_req vr;  	struct vif_device *vif;  	struct mfc_cache *c;  	struct net *net = sock_net(sk); +	struct sioc_vif_req *vr; +	struct sioc_sg_req *sr;  	struct mr_table *mrt;  	mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); @@ -1608,40 +1630,33 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)  	switch (cmd) {  	case SIOCGETVIFCNT: -		if (copy_from_user(&vr, arg, sizeof(vr))) -			return -EFAULT; -		if (vr.vifi >= mrt->maxvif) +		vr = (struct sioc_vif_req *)arg; +		if (vr->vifi >= mrt->maxvif)  			return -EINVAL; -		vr.vifi = array_index_nospec(vr.vifi, mrt->maxvif); +		vr->vifi = array_index_nospec(vr->vifi, mrt->maxvif);  		rcu_read_lock(); -		vif = &mrt->vif_table[vr.vifi]; -		if (VIF_EXISTS(mrt, vr.vifi)) { -			vr.icount = READ_ONCE(vif->pkt_in); -			vr.ocount = READ_ONCE(vif->pkt_out); -			vr.ibytes = READ_ONCE(vif->bytes_in); -			vr.obytes = READ_ONCE(vif->bytes_out); +		vif = &mrt->vif_table[vr->vifi]; +		if (VIF_EXISTS(mrt, vr->vifi)) { +			vr->icount = READ_ONCE(vif->pkt_in); +			vr->ocount = READ_ONCE(vif->pkt_out); +			vr->ibytes = READ_ONCE(vif->bytes_in); +			vr->obytes = READ_ONCE(vif->bytes_out);  			rcu_read_unlock(); -			if (copy_to_user(arg, &vr, sizeof(vr))) -				return -EFAULT;  			return 0;  		}  		rcu_read_unlock();  		return -EADDRNOTAVAIL;  	case SIOCGETSGCNT: -		if (copy_from_user(&sr, arg, sizeof(sr))) -			return -EFAULT; +		sr = (struct sioc_sg_req *)arg;  		rcu_read_lock(); -		c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr); +		c = ipmr_cache_find(mrt, sr->src.s_addr, sr->grp.s_addr);  		if (c) { -			sr.pktcnt = c->_c.mfc_un.res.pkt; -			sr.bytecnt = c->_c.mfc_un.res.bytes; -			sr.wrong_if = c->_c.mfc_un.res.wrong_if; +			sr->pktcnt = c->_c.mfc_un.res.pkt; +			sr->bytecnt = c->_c.mfc_un.res.bytes; +			sr->wrong_if = c->_c.mfc_un.res.wrong_if;  			rcu_read_unlock(); - -			if (copy_to_user(arg, &sr, sizeof(sr))) -				return -EFAULT;  			return 0;  		}  		rcu_read_unlock();  |