patch-2.4.0-prerelease linux/net/atm/common.c

Next file: linux/net/atm/lec.c
Previous file: linux/net/atm/addr.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test12/linux/net/atm/common.c linux/net/atm/common.c
@@ -72,6 +72,7 @@
 #define DPRINTK(format,args...)
 #endif
 
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
@@ -139,13 +140,19 @@
 				vcc->dev->ops->free_rx_skb(vcc,skb);
 			else kfree_skb(skb);
 		}
+		spin_lock (&atm_dev_lock);	
+		fops_put (vcc->dev->ops);
 		if (atomic_read(&vcc->rx_inuse))
 			printk(KERN_WARNING "atm_release_vcc: strange ... "
 			    "rx_inuse == %d after closing\n",
 			    atomic_read(&vcc->rx_inuse));
 		bind_vcc(vcc,NULL);
-	}
+	} else
+		spin_lock (&atm_dev_lock);	
+
 	if (free_sk) free_atm_vcc_sk(sk);
+
+	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -238,9 +245,11 @@
 	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
 	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
 	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
+	fops_get (dev->ops);
 	if (dev->ops->open) {
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
+			fops_put (dev->ops);
 			bind_vcc(vcc,NULL);
 			return error;
 		}
@@ -252,10 +261,18 @@
 static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
 {
 	struct atm_dev *dev;
+	int return_val;
 
+	spin_lock (&atm_dev_lock);
 	dev = atm_find_dev(itf);
-	if (!dev) return -ENODEV;
-	return atm_do_connect_dev(vcc,dev,vpi,vci);
+	if (!dev)
+		return_val =  -ENODEV;
+	else
+		return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
+
+	spin_unlock (&atm_dev_lock);
+
+	return return_val;
 }
 
 
@@ -285,8 +302,10 @@
 	else {
 		struct atm_dev *dev;
 
+		spin_lock (&atm_dev_lock);
 		for (dev = atm_devs; dev; dev = dev->next)
 			if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+		spin_unlock (&atm_dev_lock);
 		if (!dev) return -ENODEV;
 	}
 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
@@ -523,57 +542,86 @@
 	struct atm_vcc *vcc;
 	int *tmp_buf;
 	void *buf;
-	int error,len,size,number;
+	int error,len,size,number, ret_val;
 
+	ret_val = 0;
+	spin_lock (&atm_dev_lock);
 	vcc = ATM_SD(sock);
 	switch (cmd) {
 		case SIOCOUTQ:
 			if (sock->state != SS_CONNECTED ||
-			    !test_bit(ATM_VF_READY,&vcc->flags))
-				return -EINVAL;
-			return put_user(vcc->sk->sndbuf-
+			    !test_bit(ATM_VF_READY,&vcc->flags)) {
+				ret_val =  -EINVAL;
+				goto done;
+			}
+			ret_val =  put_user(vcc->sk->sndbuf-
 			    atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
 			    (int *) arg) ? -EFAULT : 0;
+			goto done;
 		case SIOCINQ:
 			{
 				struct sk_buff *skb;
 
-				if (sock->state != SS_CONNECTED)
-					return -EINVAL;
+				if (sock->state != SS_CONNECTED) {
+					ret_val = -EINVAL;
+					goto done;
+				}
 				skb = skb_peek(&vcc->recvq);
-				return put_user(skb ? skb->len : 0,(int *) arg)
+				ret_val = put_user(skb ? skb->len : 0,(int *) arg)
 				    ? -EFAULT : 0;
+				goto done;
 			}
 		case ATM_GETNAMES:
 			if (get_user(buf,
-			    &((struct atm_iobuf *) arg)->buffer))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->buffer)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			if (get_user(len,
-			    &((struct atm_iobuf *) arg)->length))
-				return -EFAULT;
+				     &((struct atm_iobuf *) arg)->length)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			size = 0;
 			for (dev = atm_devs; dev; dev = dev->next)
 				size += sizeof(int);
-			if (size > len) return -E2BIG;
+			if (size > len) {
+				ret_val = -E2BIG;
+				goto done;
+			}
 			tmp_buf = kmalloc(size,GFP_KERNEL);
-			if (!tmp_buf) return -ENOMEM;
+			if (!tmp_buf) {
+				ret_val = -ENOMEM;
+				goto done;
+			}
 			for (dev = atm_devs; dev; dev = dev->next)
 				*tmp_buf++ = dev->number;
-			if (copy_to_user(buf,(char *) tmp_buf-size,size))
-				return -EFAULT;
-			return put_user(size,
+			if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
+		        ret_val = put_user(size,
 			    &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case SIOCGSTAMP: /* borrowed from IP */
-			if (!vcc->timestamp.tv_sec) return -ENOENT;
+			if (!vcc->timestamp.tv_sec) {
+				ret_val = -ENOENT;
+				goto done;
+			}
 			vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
 			vcc->timestamp.tv_usec %= 1000000;
-			return copy_to_user((void *) arg,&vcc->timestamp,
+			ret_val = copy_to_user((void *) arg,&vcc->timestamp,
 			    sizeof(struct timeval)) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETSC:
 			printk(KERN_WARNING "ATM_SETSC is obsolete\n");
-			return 0;
+			ret_val = 0;
+			goto done;
 		case ATMSIGD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/*
 			 * The user/kernel protocol for exchanging signalling
 			 * info uses kernel pointers as opaque references,
@@ -581,175 +629,308 @@
 			 * on the kernel... so we should make sure that we
 			 * have the same privledges that /proc/kcore needs
 			 */
-			if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+			if (!capable(CAP_SYS_RAWIO)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = sigd_attach(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 #ifdef CONFIG_ATM_CLIP
 		case SIOCMKCLIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_create(arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_create(arg);
+			goto done;
 		case ATMARPD_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			error = atm_init_atmarp(vcc);
 			if (!error) sock->state = SS_CONNECTED;
-			return error;
+			ret_val = error;
+			goto done;
 		case ATMARP_MKIP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_mkip(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else 
+				ret_val = clip_mkip(vcc,arg);
+			goto done;
 		case ATMARP_SETENTRY:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_setentry(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_setentry(vcc,arg);
+			goto done;
 		case ATMARP_ENCAP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return clip_encap(vcc,arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = clip_encap(vcc,arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
                 case ATMLEC_CTRL:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
+                        if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
                         if (atm_lane_ops.lecd_attach == NULL)
                                 atm_lane_init();
-                        if (atm_lane_ops.lecd_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_lane_ops.lecd_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+                        if (atm_lane_ops.lecd_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_lane_ops.lecd_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val =  error;
+			goto done;
                 case ATMLEC_MCAST:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.mcast_attach(vcc, (int)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg);
+			goto done;
                 case ATMLEC_DATA:
-                        if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        return atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			if (!capable(CAP_NET_ADMIN))
+				ret_val = -EPERM;
+			else
+				ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
 		case ATMMPC_CTRL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-                        if (atm_mpoa_ops.mpoad_attach == NULL)
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (atm_mpoa_ops.mpoad_attach == NULL)
                                 atm_mpoa_init();
-                        if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */
-                                return -ENOSYS;
-                        error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
-                        if (error >= 0) sock->state = SS_CONNECTED;
-                        return error;
+			if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */
+				ret_val = -ENOSYS;
+				goto done;
+			}
+			error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
+			if (error >= 0) sock->state = SS_CONNECTED;
+			ret_val = error;
+			goto done;
 		case ATMMPC_DATA:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return atm_mpoa_ops.vcc_attach(vcc, arg);
+			if (!capable(CAP_NET_ADMIN)) 
+				ret_val = -EPERM;
+			else
+				ret_val = atm_mpoa_ops.vcc_attach(vcc, arg);
+			goto done;
 #endif
 #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
 		case SIOCSIFATMTCP:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.attach) return -ENOPKG;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.attach) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			fops_get (&atm_tcp_ops);
 			error = atm_tcp_ops.attach(vcc,(int) arg);
 			if (error >= 0) sock->state = SS_CONNECTED;
-			return error;
+			else            fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_CREATE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.create_persistent) return -ENOPKG;
-			return atm_tcp_ops.create_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.create_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.create_persistent((int) arg);
+			if (error < 0) fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 		case ATMTCP_REMOVE:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (!atm_tcp_ops.remove_persistent) return -ENOPKG;
-			return atm_tcp_ops.remove_persistent((int) arg);
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
+			if (!atm_tcp_ops.remove_persistent) {
+				ret_val = -ENOPKG;
+				goto done;
+			}
+			error = atm_tcp_ops.remove_persistent((int) arg);
+			fops_put (&atm_tcp_ops);
+			ret_val = error;
+			goto done;
 #endif
 		default:
 			break;
 	}
-	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) return -EFAULT;
-	if (get_user(len,&((struct atmif_sioc *) arg)->length)) return -EFAULT;
-	if (get_user(number,&((struct atmif_sioc *) arg)->number))
-		return -EFAULT;
-	if (!(dev = atm_find_dev(number))) return -ENODEV;
+	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(len,&((struct atmif_sioc *) arg)->length)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (get_user(number,&((struct atmif_sioc *) arg)->number)) {
+		ret_val = -EFAULT;
+		goto done;
+	}
+	if (!(dev = atm_find_dev(number))) {
+		ret_val = -ENODEV;
+		goto done;
+	}
+	
 	size = 0;
 	switch (cmd) {
 		case ATM_GETTYPE:
 			size = strlen(dev->type)+1;
-			if (copy_to_user(buf,dev->type,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->type,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETESI:
 			size = ESI_LEN;
-			if (copy_to_user(buf,dev->esi,size)) return -EFAULT;
+			if (copy_to_user(buf,dev->esi,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_SETESI:
 			{
 				int i;
 
 				for (i = 0; i < ESI_LEN; i++)
-					if (dev->esi[i]) return -EEXIST;
+					if (dev->esi[i]) {
+						ret_val = -EEXIST;
+						goto done;
+					}
 			}
 			/* fall through */
 		case ATM_SETESIF:
 			{
 				unsigned char esi[ESI_LEN];
 
-				if (!capable(CAP_NET_ADMIN)) return -EPERM;
-				if (copy_from_user(esi,buf,ESI_LEN))
-					return -EFAULT;
+				if (!capable(CAP_NET_ADMIN)) {
+					ret_val = -EPERM;
+					goto done;
+				}
+				if (copy_from_user(esi,buf,ESI_LEN)) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				memcpy(dev->esi,esi,ESI_LEN);
-				return ESI_LEN;
+				ret_val =  ESI_LEN;
+				goto done;
 			}
 		case ATM_GETSTATZ:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		case ATM_GETSTAT:
 			size = sizeof(struct atm_dev_stats);
 			error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
-			if (error) return error;
+			if (error) {
+				ret_val = error;
+				goto done;
+			}
 			break;
 		case ATM_GETCIRANGE:
 			size = sizeof(struct atm_cirange);
-			if (copy_to_user(buf,&dev->ci_range,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->ci_range,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_GETLINKRATE:
 			size = sizeof(int);
-			if (copy_to_user(buf,&dev->link_rate,size))
-				return -EFAULT;
+			if (copy_to_user(buf,&dev->link_rate,size)) {
+				ret_val = -EFAULT;
+				goto done;
+			}
 			break;
 		case ATM_RSTADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			reset_addr(dev);
 			break;
 		case ATM_ADDADDR:
 		case ATM_DELADDR:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			{
 				struct sockaddr_atmsvc addr;
 
-				if (copy_from_user(&addr,buf,sizeof(addr)))
-					return -EFAULT;
+				if (copy_from_user(&addr,buf,sizeof(addr))) {
+					ret_val = -EFAULT;
+					goto done;
+				}
 				if (cmd == ATM_ADDADDR)
-					return add_addr(dev,&addr);
-				else return del_addr(dev,&addr);
+					ret_val = add_addr(dev,&addr);
+				else
+					ret_val = del_addr(dev,&addr);
+				goto done;
 			}
 		case ATM_GETADDR:
 			size = get_addr(dev,buf,len);
-			if (size < 0) return size;
+			if (size < 0)
+				ret_val = size;
+			else
 			/* may return 0, but later on size == 0 means "don't
 			   write the length" */
-			return put_user(size,
-			    &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+				ret_val = put_user(size,
+						   &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+			goto done;
 		case ATM_SETLOOP:
 			if (__ATM_LM_XTRMT((int) (long) buf) &&
 			    __ATM_LM_XTLOC((int) (long) buf) >
-			    __ATM_LM_XTRMT((int) (long) buf))
-				return -EINVAL;
+			    __ATM_LM_XTRMT((int) (long) buf)) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			/* fall through */
 		case ATM_SETCIRANGE:
 		case SONET_GETSTATZ:
 		case SONET_SETDIAG:
 		case SONET_CLRDIAG:
 		case SONET_SETFRAMING:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			if (!capable(CAP_NET_ADMIN)) {
+				ret_val = -EPERM;
+				goto done;
+			}
 			/* fall through */
 		default:
-			if (!dev->ops->ioctl) return -EINVAL;
+			if (!dev->ops->ioctl) {
+				ret_val = -EINVAL;
+				goto done;
+			}
 			size = dev->ops->ioctl(dev,cmd,buf);
-			if (size < 0)
-				return size == -ENOIOCTLCMD ? -EINVAL : size;
+			if (size < 0) {
+				ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
+				goto done;
+			}
 	}
-	if (!size) return 0;
-	return put_user(size,&((struct atmif_sioc *) arg)->length) ?
-	    -EFAULT : 0;
+	
+	if (size)
+		ret_val =  put_user(size,&((struct atmif_sioc *) arg)->length) ?
+			-EFAULT : 0;
+
+ done:
+	spin_unlock (&atm_dev_lock); 
+	return ret_val;
 }
 
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)