diff options
Diffstat (limited to 'net/can/raw.c')
| -rw-r--r-- | net/can/raw.c | 58 | 
1 files changed, 25 insertions, 33 deletions
diff --git a/net/can/raw.c b/net/can/raw.c index 15c79b079184..ba6b52b1d776 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -84,6 +84,7 @@ struct raw_sock {  	struct sock sk;  	int bound;  	int ifindex; +	struct net_device *dev;  	struct list_head notifier;  	int loopback;  	int recv_own_msgs; @@ -277,7 +278,7 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,  	if (!net_eq(dev_net(dev), sock_net(sk)))  		return; -	if (ro->ifindex != dev->ifindex) +	if (ro->dev != dev)  		return;  	switch (msg) { @@ -292,6 +293,7 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,  		ro->ifindex = 0;  		ro->bound = 0; +		ro->dev = NULL;  		ro->count = 0;  		release_sock(sk); @@ -337,6 +339,7 @@ static int raw_init(struct sock *sk)  	ro->bound            = 0;  	ro->ifindex          = 0; +	ro->dev              = NULL;  	/* set default filter to single entry dfilter */  	ro->dfilter.can_id   = 0; @@ -383,21 +386,15 @@ static int raw_release(struct socket *sock)  	list_del(&ro->notifier);  	spin_unlock(&raw_notifier_lock); +	rtnl_lock();  	lock_sock(sk);  	/* remove current filters & unregister */  	if (ro->bound) { -		if (ro->ifindex) { -			struct net_device *dev; - -			dev = dev_get_by_index(sock_net(sk), ro->ifindex); -			if (dev) { -				raw_disable_allfilters(dev_net(dev), dev, sk); -				dev_put(dev); -			} -		} else { +		if (ro->dev) +			raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk); +		else  			raw_disable_allfilters(sock_net(sk), NULL, sk); -		}  	}  	if (ro->count > 1) @@ -405,6 +402,7 @@ static int raw_release(struct socket *sock)  	ro->ifindex = 0;  	ro->bound = 0; +	ro->dev = NULL;  	ro->count = 0;  	free_percpu(ro->uniq); @@ -412,6 +410,8 @@ static int raw_release(struct socket *sock)  	sock->sk = NULL;  	release_sock(sk); +	rtnl_unlock(); +  	sock_put(sk);  	return 0; @@ -422,6 +422,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)  	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;  	struct sock *sk = sock->sk;  	struct raw_sock *ro = raw_sk(sk); +	struct net_device *dev = NULL;  	int ifindex;  	int err = 0;  	int notify_enetdown = 0; @@ -431,14 +432,13 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)  	if (addr->can_family != AF_CAN)  		return -EINVAL; +	rtnl_lock();  	lock_sock(sk);  	if (ro->bound && addr->can_ifindex == ro->ifindex)  		goto out;  	if (addr->can_ifindex) { -		struct net_device *dev; -  		dev = dev_get_by_index(sock_net(sk), addr->can_ifindex);  		if (!dev) {  			err = -ENODEV; @@ -467,26 +467,20 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)  	if (!err) {  		if (ro->bound) {  			/* unregister old filters */ -			if (ro->ifindex) { -				struct net_device *dev; - -				dev = dev_get_by_index(sock_net(sk), -						       ro->ifindex); -				if (dev) { -					raw_disable_allfilters(dev_net(dev), -							       dev, sk); -					dev_put(dev); -				} -			} else { +			if (ro->dev) +				raw_disable_allfilters(dev_net(ro->dev), +						       ro->dev, sk); +			else  				raw_disable_allfilters(sock_net(sk), NULL, sk); -			}  		}  		ro->ifindex = ifindex;  		ro->bound = 1; +		ro->dev = dev;  	}   out:  	release_sock(sk); +	rtnl_unlock();  	if (notify_enetdown) {  		sk->sk_err = ENETDOWN; @@ -553,9 +547,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,  		rtnl_lock();  		lock_sock(sk); -		if (ro->bound && ro->ifindex) { -			dev = dev_get_by_index(sock_net(sk), ro->ifindex); -			if (!dev) { +		dev = ro->dev; +		if (ro->bound && dev) { +			if (dev->reg_state != NETREG_REGISTERED) {  				if (count > 1)  					kfree(filter);  				err = -ENODEV; @@ -596,7 +590,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,  		ro->count  = count;   out_fil: -		dev_put(dev);  		release_sock(sk);  		rtnl_unlock(); @@ -614,9 +607,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,  		rtnl_lock();  		lock_sock(sk); -		if (ro->bound && ro->ifindex) { -			dev = dev_get_by_index(sock_net(sk), ro->ifindex); -			if (!dev) { +		dev = ro->dev; +		if (ro->bound && dev) { +			if (dev->reg_state != NETREG_REGISTERED) {  				err = -ENODEV;  				goto out_err;  			} @@ -640,7 +633,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,  		ro->err_mask = err_mask;   out_err: -		dev_put(dev);  		release_sock(sk);  		rtnl_unlock();  |