patch-2.4.0-test6 linux/drivers/isdn/isdn_common.c

Next file: linux/drivers/isdn/isdn_common.h
Previous file: linux/drivers/isdn/isdn_cards.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test5/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.101 2000/04/07 14:50:34 calle Exp $
+/* $Id: isdn_common.c,v 1.108 2000/06/24 15:52:47 keil Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -20,417 +20,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Log: isdn_common.c,v $
- * Revision 1.101  2000/04/07 14:50:34  calle
- * Bugfix: on my system 2.3.99-pre3 Dual PII 350, unload of module isdn.o
- *         hangs if vfree is called with interrupt disabled. After moving
- * 	restore_flags in front of vfree it doesn't hang.
- *
- * Revision 1.100  2000/03/03 16:37:11  kai
- * incorporated some cosmetic changes from the official kernel tree back
- * into CVS
- *
- * Revision 1.99  2000/02/26 01:00:52  keil
- * changes from 2.3.47
- *
- * Revision 1.98  2000/02/16 14:56:27  paul
- * translated ISDN_MODEM_ANZREG to ISDN_MODEM_NUMREG for english speakers
- *
- * Revision 1.97  2000/01/23 18:45:37  keil
- * Change EAZ mapping to forbit the use of cards (insert a "-" for the MSN)
- *
- * Revision 1.96  2000/01/20 19:55:33  keil
- * Add FAX Class 1 support
- *
- * Revision 1.95  2000/01/09 20:43:13  detabc
- * exand logical bind-group's for both call's (in and out).
- * add first part of kernel-config-help for abc-extension.
- *
- * Revision 1.94  1999/11/20 22:14:13  detabc
- * added channel dial-skip in case of external use
- * (isdn phone or another isdn device) on the same NTBA.
- * usefull with two or more card's connected the different NTBA's.
- * global switchable in kernel-config and also per netinterface.
- *
- * add auto disable of netinterface's in case of:
- * 	to many connection's in short time.
- * 	config mistakes (wrong encapsulation, B2-protokoll or so on) on local
- * 	or remote side.
- * 	wrong password's or something else to a ISP (syncppp).
- *
- * possible encapsulations for this future are:
- * ISDN_NET_ENCAP_SYNCPPP, ISDN_NET_ENCAP_UIHDLC, ISDN_NET_ENCAP_RAWIP,
- * and ISDN_NET_ENCAP_CISCOHDLCK.
- *
- * Revision 1.93  1999/11/04 13:11:36  keil
- * Reinit of v110 structs
- *
- * Revision 1.92  1999/10/31 15:59:50  he
- * more skb headroom checks
- *
- * Revision 1.91  1999/10/28 22:48:45  armin
- * Bugfix: isdn_free_channel() now frees the channel,
- * even when the usage of the ttyI has changed.
- *
- * Revision 1.90  1999/10/27 21:21:17  detabc
- * Added support for building logically-bind-group's per interface.
- * usefull for outgoing call's with more then one isdn-card.
- *
- * Switchable support to dont reset the hangup-timeout for
- * receive frames. Most part's of the timru-rules for receiving frames
- * are now obsolete. If the input- or forwarding-firewall deny
- * the frame, the line will be not hold open.
- *
- * Revision 1.89  1999/10/16 14:46:47  keil
- * replace kmalloc with vmalloc for the big dev struct
- *
- * Revision 1.88  1999/10/02 00:39:26  he
- * Fixed a 2.3.x wait queue initialization (was causing panics)
- *
- * Revision 1.87  1999/09/12 16:19:39  detabc
- * added abc features
- * low cost routing for net-interfaces (only the HL side).
- * need more implementation in the isdnlog-utility
- * udp info support (first part).
- * different EAZ on outgoing call's.
- * more checks on D-Channel callbacks (double use of channels).
- * tested and running with kernel 2.3.17
- *
- * Revision 1.86  1999/07/31 12:59:42  armin
- * Added tty fax capabilities.
- *
- * Revision 1.85  1999/07/29 16:58:35  armin
- * Bugfix: DLE handling in isdn_readbchan()
- *
- * Revision 1.84  1999/07/25 16:21:10  keil
- * fix number matching
- *
- * Revision 1.83  1999/07/13 21:02:05  werner
- * Added limit possibilty of driver b_channel resources (ISDN_STAT_DISCH)
- *
- * Revision 1.82  1999/07/12 21:06:50  werner
- * Fixed problem when loading more than one driver temporary
- *
- * Revision 1.81  1999/07/11 17:14:09  armin
- * Added new layer 2 and 3 protocols for Fax and DSP functions.
- * Moved "Add CPN to RING message" to new register S23,
- * "Display message" is now correct on register S13 bit 7.
- * New audio command AT+VDD implemented (deactivate DTMF decoder and
- * activate possible existing hardware/DSP decoder).
- * Moved some tty defines to .h file.
- * Made whitespace possible in AT command line.
- * Some AT-emulator output bugfixes.
- * First Fax G3 implementations.
- *
- * Revision 1.80  1999/07/07 10:14:00  detabc
- * remove unused messages
- *
- * Revision 1.79  1999/07/05 23:51:30  werner
- * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl
- * hisaxctrl id 10 <nr. of chans 0-2>
- *
- * Revision 1.78  1999/07/05 20:21:15  werner
- * changes to use diversion sources for all kernel versions.
- * removed static device, only proc filesystem used
- *
- * Revision 1.77  1999/07/01 08:29:50  keil
- * compatibility to 2.3 kernel
- *
- * Revision 1.76  1999/06/29 16:16:44  calle
- * Let ISDN_CMD_UNLOAD work with open isdn devices without crash again.
- * Also right unlocking (ISDN_CMD_UNLOCK) is done now.
- * isdnlog should check returncode of read(2) calls.
- *
- * Revision 1.75  1999/04/18 14:06:47  fritz
- * Removed TIMRU stuff.
- *
- * Revision 1.74  1999/04/12 13:16:45  fritz
- * Changes from 2.0 tree.
- *
- * Revision 1.73  1999/04/12 12:33:15  fritz
- * Changes from 2.0 tree.
- *
- * Revision 1.72  1999/03/02 12:04:44  armin
- * -added ISDN_STAT_ADDCH to increase supported channels after
- *  register_isdn().
- * -ttyI now goes on-hook on ATZ when B-Ch is connected.
- * -added timer-function for register S7 (Wait for Carrier).
- * -analog modem (ISDN_PROTO_L2_MODEM) implementations.
- * -on L2_MODEM a string will be appended to the CONNECT-Message,
- *  which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN.
- * -variable "dialing" used for ATA also, for interrupting call
- *  establishment and register S7.
- *
- * Revision 1.71  1999/01/28 09:10:43  armin
- * Fixed bad while-loop in isdn_readbch().
- *
- * Revision 1.70  1999/01/15 19:58:54  he
- * removed compatibiltity macro
- *
- * Revision 1.69  1998/09/07 21:59:58  he
- * flush method for 2.1.118 and above
- * updated IIOCTLNETGPN
- *
- * Revision 1.68  1998/08/31 21:09:45  he
- * new ioctl IIOCNETGPN for /dev/isdninfo (get network interface'
- *     peer phone number)
- *
- * Revision 1.67  1998/06/26 15:12:21  fritz
- * Added handling of STAT_ICALL with incomplete CPN.
- * Added AT&L for ttyI emulator.
- * Added more locking stuff in tty_write.
- *
- * Revision 1.66  1998/06/17 19:50:41  he
- * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
- * brute force fix to avoid Ugh's in isdn_tty_write()
- * cleaned up some dead code
- *
- *
- * Revision 1.62  1998/04/14 16:28:43  he
- * Fixed user space access with interrupts off and remaining
- * copy_{to,from}_user() -> -EFAULT return codes
- *
- * Revision 1.61  1998/03/22 18:50:46  hipp
- * Added BSD Compression for syncPPP .. UNTESTED at the moment
- *
- * Revision 1.60  1998/03/19 13:18:18  keil
- * Start of a CAPI like interface for supplementary Service
- * first service: SUSPEND
- *
- * Revision 1.59  1998/03/09 17:46:23  he
- * merged in 2.1.89 changes
- *
- * Revision 1.58  1998/03/07 22:35:24  fritz
- * Starting generic module support (Nothing usable yet).
- *
- * Revision 1.57  1998/03/07 18:21:01  cal
- * Dynamic Timeout-Rule-Handling vs. 971110 included
- *
- * Revision 1.56  1998/02/25 17:49:38  he
- * Changed return codes caused be failing copy_{to,from}_user to -EFAULT
- *
- * Revision 1.55  1998/02/23 23:35:32  fritz
- * Eliminated some compiler warnings.
- *
- * Revision 1.54  1998/02/22 19:44:19  fritz
- * Bugfixes and improvements regarding V.110, V.110 now running.
- *
- * Revision 1.53  1998/02/20 17:18:05  fritz
- * Changes for recent kernels.
- * Added common stub for sending commands to lowlevel.
- * Added V.110.
- *
- * Revision 1.52  1998/01/31 22:05:57  keil
- * Lots of changes for X.25 support:
- * Added generic support for connection-controlling encapsulation protocols
- * Added support of BHUP status message
- * Added support for additional p_encap X25IFACE
- * Added support for kernels >= 2.1.72
- *
- * Revision 1.51  1998/01/31 19:17:29  calle
- * merged changes from and for 2.1.82
- *
- * Revision 1.50  1997/12/12 06:12:11  calle
- * moved EXPORT_SYMBOL(register_isdn) from isdn_syms.c to isdn_common.c
- *
- * Revision 1.49  1997/11/06 17:16:52  keil
- * Sync to 2.1.62 changes
- *
- * Revision 1.48  1997/11/02 23:55:50  keil
- * Andi Kleen's changes for 2.1.60
- * without it the isdninfo and isdnctrl devices won't work
- *
- * Revision 1.47  1997/10/09 21:28:46  fritz
- * New HL<->LL interface:
- *   New BSENT callback with nr. of bytes included.
- *   Sending without ACK.
- *   New L1 error status (not yet in use).
- *   Cleaned up obsolete structures.
- * Implemented Cisco-SLARP.
- * Changed local net-interface data to be dynamically allocated.
- * Removed old 2.0 compatibility stuff.
- *
- * Revision 1.46  1997/10/01 09:20:27  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.45  1997/08/21 23:11:41  fritz
- * Added changes for kernels >= 2.1.45
- *
- * Revision 1.44  1997/05/27 15:17:23  fritz
- * Added changes for recent 2.1.x kernels:
- *   changed return type of isdn_close
- *   queue_task_* -> queue_task
- *   clear/set_bit -> test_and_... where apropriate.
- *   changed type of hard_header_cache parameter.
- *
- * Revision 1.43  1997/03/31 14:09:43  fritz
- * Fixed memory leak in isdn_close().
- *
- * Revision 1.42  1997/03/30 16:51:08  calle
- * changed calls to copy_from_user/copy_to_user and removed verify_area
- * were possible.
- *
- * Revision 1.41  1997/03/24 22:54:41  fritz
- * Some small fixes in debug code.
- *
- * Revision 1.40  1997/03/08 08:13:51  fritz
- * Bugfix: IIOCSETMAP (Set mapping) was broken.
- *
- * Revision 1.39  1997/03/07 01:32:54  fritz
- * Added proper ifdef's for CONFIG_ISDN_AUDIO
- *
- * Revision 1.38  1997/03/05 21:15:02  fritz
- * Fix: reduced stack usage of isdn_ioctl() and isdn_set_allcfg()
- *
- * Revision 1.37  1997/03/02 14:29:18  fritz
- * More ttyI related cleanup.
- *
- * Revision 1.36  1997/02/28 02:32:40  fritz
- * Cleanup: Moved some tty related stuff from isdn_common.c
- *          to isdn_tty.c
- * Bugfix:  Bisync protocol did not behave like documented.
- *
- * Revision 1.35  1997/02/21 13:01:19  fritz
- * Changes CAUSE message output in kernel log.
- *
- * Revision 1.34  1997/02/10 20:12:43  fritz
- * Changed interface for reporting incoming calls.
- *
- * Revision 1.33  1997/02/10 10:05:42  fritz
- * More changes for Kernel 2.1.X
- * Symbol information moved to isdn_syms.c
- *
- * Revision 1.32  1997/02/03 22:55:26  fritz
- * Reformatted according CodingStyle.
- * Changed isdn_writebuf_stub static.
- * Slow down tty-RING counter.
- * skb->free stuff replaced by macro.
- * Bugfix in audio-skb locking.
- * Bugfix in HL-driver locking.
- *
- * Revision 1.31  1997/01/17 01:19:18  fritz
- * Applied chargeint patch.
- *
- * Revision 1.30  1997/01/14 01:27:47  fritz
- * Changed audio receive not to rely on skb->users and skb->lock.
- * Added ATI2 and related variables.
- * Started adding full-duplex audio capability.
- *
- * Revision 1.29  1997/01/12 23:33:03  fritz
- * Made isdn_all_eaz foolproof.
- *
- * Revision 1.28  1996/11/13 02:33:19  fritz
- * Fixed a race condition.
- *
- * Revision 1.27  1996/10/27 22:02:41  keil
- * return codes for ISDN_STAT_ICALL
- *
- * Revision 1.26  1996/10/23 11:59:40  fritz
- * More compatibility changes.
- *
- * Revision 1.25  1996/10/22 23:13:54  fritz
- * Changes for compatibility to 2.0.X and 2.1.X kernels.
- *
- * Revision 1.24  1996/10/11 14:02:03  fritz
- * Bugfix: call to isdn_ppp_timer_timeout() never compiled, because of
- *         typo in #ifdef.
- *
- * Revision 1.23  1996/06/25 18:35:38  fritz
- * Fixed bogus memory access in isdn_set_allcfg().
- *
- * Revision 1.22  1996/06/24 17:37:37  fritz
- * Bugfix: isdn_timer_ctrl() did restart timer, even if it
- *         was already running.
- *         lowlevel driver locking did use wrong parameters.
- *
- * Revision 1.21  1996/06/15 14:58:20  fritz
- * Added version signatures for data structures used
- * by userlevel programs.
- *
- * Revision 1.20  1996/06/12 16:01:49  fritz
- * Bugfix: Remote B-channel hangup sometimes did not result
- *         in a NO CARRIER on tty.
- *
- * Revision 1.19  1996/06/11 14:52:04  hipp
- * minor bugfix in isdn_writebuf_skb_stub()
- *
- * Revision 1.18  1996/06/06 14:51:51  fritz
- * Changed to support DTMF decoding on audio playback also.
- *
- * Revision 1.17  1996/06/05 02:24:10  fritz
- * Added DTMF decoder for audio mode.
- *
- * Revision 1.16  1996/06/03 20:09:05  fritz
- * Bugfix: called wrong function pointer for locking in
- *         isdn_get_free_channel().
- *
- * Revision 1.15  1996/05/31 01:10:54  fritz
- * Bugfixes:
- *   Lowlevel modules did not get locked correctly.
- *   Did show wrong revision when initializing.
- *   Minor fixes in ioctl code.
- *   sk_buff did not get freed, if error in writebuf_stub.
- *
- * Revision 1.14  1996/05/18 01:36:55  fritz
- * Added spelling corrections and some minor changes
- * to stay in sync with kernel.
- *
- * Revision 1.13  1996/05/17 15:43:30  fritz
- * Bugfix: decrement of rcvcount in readbchan() corrected.
- *
- * Revision 1.12  1996/05/17 03:55:43  fritz
- * Changed DLE handling for audio receive.
- * Some cleanup.
- * Added display of isdn_audio_revision.
- *
- * Revision 1.11  1996/05/11 21:51:32  fritz
- * Changed queue management to use sk_buffs.
- *
- * Revision 1.10  1996/05/10 08:49:16  fritz
- * Checkin before major changes of tty-code.
- *
- * Revision 1.9  1996/05/07 09:19:41  fritz
- * Adapted to changes in isdn_tty.c
- *
- * Revision 1.8  1996/05/06 11:34:51  hipp
- * fixed a few bugs
- *
- * Revision 1.7  1996/05/02 03:55:17  fritz
- * Bugfixes:
- *  - B-channel connect message for modem devices
- *    sometimes did not result in a CONNECT-message.
- *  - register_isdn did not check for driverId-conflicts.
- *
- * Revision 1.6  1996/04/30 20:57:21  fritz
- * Commit test
- *
- * Revision 1.5  1996/04/20 16:19:07  fritz
- * Changed slow timer handlers to increase accuracy.
- * Added statistic information for usage by xisdnload.
- * Fixed behaviour of isdnctrl-device on non-blocked io.
- * Fixed all io to go through generic writebuf-function without
- * bypassing. Same for incoming data.
- * Fixed bug: Last channel had been unusable.
- * Fixed kfree of tty xmit_buf on ppp initialization failure.
- *
- * Revision 1.4  1996/02/11 02:33:26  fritz
- * Fixed bug in main timer-dispatcher.
- * Bugfix: Lot of tty-callbacks got called regardless of the events already
- * been handled by network-devices.
- * Changed ioctl-names.
- *
- * Revision 1.3  1996/01/22 05:16:11  fritz
- * Changed ioctl-names.
- * Fixed bugs in isdn_open and isdn_close regarding PPP_MINOR.
- *
- * Revision 1.2  1996/01/21 16:52:40  fritz
- * Support for sk_buffs added, changed header-stuffing.
- *
- * Revision 1.1  1996/01/09 04:12:52  fritz
- * Initial revision
- *
  */
 
 #include <linux/config.h>
@@ -459,7 +48,7 @@
 
 isdn_dev *dev = (isdn_dev *) 0;
 
-static char *isdn_revision = "$Revision: 1.101 $";
+static char *isdn_revision = "$Revision: 1.108 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -484,6 +73,7 @@
 static void set_global_features(void);
 static void isdn_register_devfs(int);
 static void isdn_unregister_devfs(int);
+static int isdn_wildmat(char *s, char *p);
 
 void
 isdn_lock_drivers(void)
@@ -577,7 +167,7 @@
  * [^xyz]  matches any single character not in the set of characters
  */
 
-int
+static int
 isdn_wildmat(char *s, char *p)
 {
 	register int last;
@@ -623,6 +213,23 @@
 	return (*s == '\0')?0:nostar;
 }
 
+int isdn_msncmp( const char * msn1, const char * msn2 )
+{
+	char TmpMsn1[ ISDN_MSNLEN ];
+	char TmpMsn2[ ISDN_MSNLEN ];
+	char *p;
+
+	for ( p = TmpMsn1; *msn1 && *msn1 != ':'; )  // Strip off a SPID
+		*p++ = *msn1++;
+	*p = '\0';
+
+	for ( p = TmpMsn2; *msn2 && *msn2 != ':'; )  // Strip off a SPID
+		*p++ = *msn2++;
+	*p = '\0';
+
+	return isdn_wildmat( TmpMsn1, TmpMsn2 );
+}
+
 static void
 isdn_free_queue(struct sk_buff_head *queue)
 {
@@ -686,10 +293,6 @@
 			}
 			if (tf & ISDN_TIMER_CARRIER)
 				isdn_tty_carrier_timeout();
-#if (defined CONFIG_ISDN_PPP) && (defined CONFIG_ISDN_MPP)
-			if (tf & ISDN_TIMER_IPPP)
-				isdn_ppp_timer_timeout();
-#endif
 		}
 	}
 	if (tf) 
@@ -850,6 +453,7 @@
 	int r;
 	int retval = 0;
 	isdn_ctrl cmd;
+	isdn_net_dev *p;
 
 	di = c->driver;
 	i = isdn_dc2minor(di, c->arg);
@@ -898,7 +502,7 @@
 				return 0;
 			}
 			/* Try to find a network-interface which will accept incoming call */
-			r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, c->parm.setup));
+			r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup));
 			switch (r) {
 				case 0:
 					/* No network-device replies.
@@ -907,7 +511,7 @@
 					 * 3 on eventually match, if CID is longer.
 					 */
                                         if (c->command == ISDN_STAT_ICALL)
-					  if ((retval = isdn_tty_find_icall(di, c->arg, c->parm.setup))) return(retval);
+					  if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return(retval);
 #ifdef CONFIG_ISDN_DIVERSION 
                                          if (divert_if)
                  	                  if ((retval = divert_if->stat_callback(c))) 
@@ -928,9 +532,16 @@
 					cmd.driver = di;
 					cmd.arg = c->arg;
 					cmd.command = ISDN_CMD_ACCEPTD;
-					isdn_command(&cmd);
-					retval = 1;
+					for ( p = dev->netdev; p; p = p->next )
+						if ( p->local->isdn_channel == cmd.arg )
+						{
+							strcpy( cmd.parm.setup.eazmsn, p->local->msn );
+							isdn_command(&cmd);
+							retval = 1;
+							break;
+						}
 					break;
+
 				case 2:	/* For calling back, first reject incoming call ... */
 				case 3:	/* Interface found, but down, reject call actively  */
 					retval = 2;
@@ -1379,54 +990,78 @@
 	ulong flags;
 	int drvidx;
 	int chidx;
+	int retval;
 	char *p;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
 
+	lock_kernel();
 	if (minor == ISDN_MINOR_STATUS) {
 		if (!file->private_data) {
-			if (file->f_flags & O_NONBLOCK)
-				return -EAGAIN;
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				goto out;
+			}
 			interruptible_sleep_on(&(dev->info_waitq));
 		}
 		p = isdn_statstr();
 		file->private_data = 0;
 		if ((len = strlen(p)) <= count) {
-			if (copy_to_user(buf, p, len))
-				return -EFAULT;
+			if (copy_to_user(buf, p, len)) {
+				retval = -EFAULT;
+				goto out;
+			}
 			*off += len;
-			return len;
+			retval = len;
+			goto out;
 		}
-		return 0;
+		retval = 0;
+		goto out;
+	}
+	if (!dev->drivers) {
+		retval = -ENODEV;
+		goto out;
 	}
-	if (!dev->drivers)
-		return -ENODEV;
 	if (minor < ISDN_MINOR_CTRL) {
+		printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			return -ENODEV;
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			return -ENODEV;
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
+		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
+			retval = -ENODEV;
+			goto out;
+		}
 		chidx = isdn_minor2chan(minor);
-		if(  ! (p = kmalloc(count,GFP_KERNEL))  ) return -ENOMEM;
+		if (!(p = kmalloc(count, GFP_KERNEL))) {
+			retval = -ENOMEM;
+			goto out;
+		}
 		save_flags(flags);
 		cli();
 		len = isdn_readbchan(drvidx, chidx, p, 0, count,
 				     &dev->drv[drvidx]->rcv_waitq[chidx]);
 		*off += len;
 		restore_flags(flags);
-		if( copy_to_user(buf,p,len) ) len = -EFAULT;
+		if (copy_to_user(buf,p,len)) 
+			len = -EFAULT;
 		kfree(p);
-		return len;
+		retval = len;
+		goto out;
 	}
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0)
-			return -ENODEV;
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
 		if (!dev->drv[drvidx]->stavail) {
-			if (file->f_flags & O_NONBLOCK)
-				return -EAGAIN;
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				goto out;
+			}
 			interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
 		}
 		if (dev->drv[drvidx]->interface->readstat)
@@ -1443,17 +1078,23 @@
 			dev->drv[drvidx]->stavail = 0;
 		restore_flags(flags);
 		*off += len;
-		return len;
+		retval = len;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		return (isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count));
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
+		goto out;
+	}
 #endif
-	return -ENODEV;
+	retval = -ENODEV;
+ out:
+	unlock_kernel();
+	return retval;
 }
 
 static loff_t
-isdn_lseek(struct file *file, loff_t offset, int orig)
+isdn_llseek(struct file *file, loff_t offset, int orig)
 {
 	return -ESPIPE;
 }
@@ -1464,6 +1105,7 @@
 	uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
 	int drvidx;
 	int chidx;
+	int retval;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
@@ -1472,21 +1114,31 @@
 		return -EPERM;
 	if (!dev->drivers)
 		return -ENODEV;
+
+	lock_kernel();
 	if (minor < ISDN_MINOR_CTRL) {
+		printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			return -ENODEV;
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			return -ENODEV;
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
+		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
+			retval = -ENODEV;
+			goto out;
+		}
 		chidx = isdn_minor2chan(minor);
 		while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
 			interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
-		return count;
+		retval = count;
+		goto out;
 	}
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0)
-			return -ENODEV;
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
 		/*
 		 * We want to use the isdnctrl device to load the firmware
 		 *
@@ -1494,16 +1146,22 @@
 		 return -ENODEV;
 		 */
 		if (dev->drv[drvidx]->interface->writecmd)
-			return (dev->drv[drvidx]->interface->
-				writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)));
+			retval = dev->drv[drvidx]->interface->
+				writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor));
 		else
-			return count;
+			retval = count;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		return (isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count));
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
+		goto out;
+	}
 #endif
-	return -ENODEV;
+	retval = -ENODEV;
+ out:
+	unlock_kernel();
+	return retval;
 }
 
 static unsigned int
@@ -1513,32 +1171,38 @@
 	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
 	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 
+	lock_kernel();
 	if (minor == ISDN_MINOR_STATUS) {
 		poll_wait(file, &(dev->info_waitq), wait);
 		/* mask = POLLOUT | POLLWRNORM; */
 		if (file->private_data) {
 			mask |= POLLIN | POLLRDNORM;
 		}
-		return mask;
+		goto out;
 	}
 	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
 		if (drvidx < 0) {
 			/* driver deregistered while file open */
-		        return POLLHUP;
+			mask = POLLHUP;
+			goto out;
 		}
 		poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
 		mask = POLLOUT | POLLWRNORM;
 		if (dev->drv[drvidx]->stavail) {
 			mask |= POLLIN | POLLRDNORM;
 		}
-		return mask;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		return (isdn_ppp_poll(file, wait));
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		mask = isdn_ppp_poll(file, wait);
+		goto out;
+	}
 #endif
-	printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
-	return POLLERR;
+	mask = POLLERR;
+ out:
+	unlock_kernel();
+	return mask;
 }
 
 
@@ -2013,6 +1677,7 @@
 	if (!dev->channels)
 		return -ENODEV;
 	if (minor < ISDN_MINOR_CTRL) {
+		printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
 		if (drvidx < 0)
 			return -ENODEV;
@@ -2091,7 +1756,7 @@
 static struct file_operations isdn_fops =
 {
 	owner:		THIS_MODULE,
-	llseek:		isdn_lseek,
+	llseek:		isdn_llseek,
 	read:		isdn_read,
 	write:		isdn_write,
 	poll:		isdn_poll,
@@ -2276,7 +1941,6 @@
 		skb_pull(nskb, sizeof(int));
 		if (!nskb->len) {
 			dev_kfree_skb(nskb);
-			dev_kfree_skb(skb);
 			return v110_ret;
 		}
 		/* V.110 must always be acknowledged */
@@ -2315,9 +1979,10 @@
 			atomic_inc(&dev->v110use[idx]);
 			dev->v110[idx]->skbuser++;
 			atomic_dec(&dev->v110use[idx]);
-			dev_kfree_skb(skb);
 			/* For V.110 return unencoded data length */
 			ret = v110_ret;
+			/* if the complete frame was send we free the skb;
+			   if not upper function will requeue the skb */ 
 			if (ret == skb->len)
 				dev_kfree_skb(skb);
 		}
@@ -2639,7 +2304,7 @@
 			    &isdn_fops, NULL);
 	dev->devfs_handle_isdnctrl =
 	    devfs_register (devfs_handle, "isdnctrl", DEVFS_FL_DEFAULT,
-			    ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR,
+			    ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, 
 			    &isdn_fops, NULL);
 }
 

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