⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isdn_common.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ * * Linux ISDN subsystem, common used functions (linklevel). * * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1995,96    Thinking Objects Software GmbH Wuerzburg * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/vmalloc.h>#include <linux/isdn.h>#include <linux/smp_lock.h>#include "isdn_common.h"#include "isdn_tty.h"#include "isdn_net.h"#include "isdn_ppp.h"#ifdef CONFIG_ISDN_AUDIO#include "isdn_audio.h"#endif#ifdef CONFIG_ISDN_DIVERSION_MODULE#define CONFIG_ISDN_DIVERSION#endif#ifdef CONFIG_ISDN_DIVERSION#include <linux/isdn_divertif.h>#endif /* CONFIG_ISDN_DIVERSION */#include "isdn_v110.h"/* Debugflags */#undef ISDN_DEBUG_STATCALLBMODULE_DESCRIPTION("ISDN4Linux: link layer");MODULE_AUTHOR("Fritz Elfert");MODULE_LICENSE("GPL");isdn_dev *dev;static char *isdn_revision = "$Revision: 1.1.2.3 $";extern char *isdn_net_revision;extern char *isdn_tty_revision;#ifdef CONFIG_ISDN_PPPextern char *isdn_ppp_revision;#elsestatic char *isdn_ppp_revision = ": none $";#endif#ifdef CONFIG_ISDN_AUDIOextern char *isdn_audio_revision;#elsestatic char *isdn_audio_revision = ": none $";#endifextern char *isdn_v110_revision;#ifdef CONFIG_ISDN_DIVERSIONstatic isdn_divert_if *divert_if; /* = NULL */#endif /* CONFIG_ISDN_DIVERSION */static int isdn_writebuf_stub(int, int, const u_char __user *, int);static void set_global_features(void);static int isdn_wildmat(char *s, char *p);static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding);static inline voidisdn_lock_driver(isdn_driver_t *drv){	try_module_get(drv->interface->owner);	drv->locks++;}voidisdn_lock_drivers(void){	int i;	for (i = 0; i < ISDN_MAX_DRIVERS; i++) {		if (!dev->drv[i])			continue;		isdn_lock_driver(dev->drv[i]);	}}static inline voidisdn_unlock_driver(isdn_driver_t *drv){	if (drv->locks > 0) {		drv->locks--;		module_put(drv->interface->owner);	}}voidisdn_unlock_drivers(void){	int i;	for (i = 0; i < ISDN_MAX_DRIVERS; i++) {		if (!dev->drv[i])			continue;		isdn_unlock_driver(dev->drv[i]);	}}#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)voidisdn_dumppkt(char *s, u_char * p, int len, int dumplen){	int dumpc;	printk(KERN_DEBUG "%s(%d) ", s, len);	for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++)		printk(" %02x", *p++);	printk("\n");}#endif/* * I picked the pattern-matching-functions from an old GNU-tar version (1.10) * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz) */static intisdn_star(char *s, char *p){	while (isdn_wildmat(s, p)) {		if (*++s == '\0')			return (2);	}	return (0);}/* * Shell-type Pattern-matching for incoming caller-Ids * This function gets a string in s and checks, if it matches the pattern * given in p. * * Return: *   0 = match. *   1 = no match. *   2 = no match. Would eventually match, if s would be longer. * * Possible Patterns: * * '?'     matches one character * '*'     matches zero or more characters * [xyz]   matches the set of characters in brackets. * [^xyz]  matches any single character not in the set of characters */static intisdn_wildmat(char *s, char *p){	register int last;	register int matched;	register int reverse;	register int nostar = 1;	if (!(*s) && !(*p))		return(1);	for (; *p; s++, p++)		switch (*p) {			case '\\':				/*				 * Literal match with following character,				 * fall through.				 */				p++;			default:				if (*s != *p)					return (*s == '\0')?2:1;				continue;			case '?':				/* Match anything. */				if (*s == '\0')					return (2);				continue;			case '*':				nostar = 0;					/* Trailing star matches everything. */				return (*++p ? isdn_star(s, p) : 0);			case '[':				/* [^....] means inverse character class. */				if ((reverse = (p[1] == '^')))					p++;				for (last = 0, matched = 0; *++p && (*p != ']'); last = *p)					/* This next line requires a good C compiler. */					if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)						matched = 1;				if (matched == reverse)					return (1);				continue;		}	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 );}intisdn_dc2minor(int di, int ch){	int i;	for (i = 0; i < ISDN_MAX_CHANNELS; i++)		if (dev->chanmap[i] == ch && dev->drvmap[i] == di)			return i;	return -1;}static int isdn_timer_cnt1 = 0;static int isdn_timer_cnt2 = 0;static int isdn_timer_cnt3 = 0;static voidisdn_timer_funct(ulong dummy){	int tf = dev->tflags;	if (tf & ISDN_TIMER_FAST) {		if (tf & ISDN_TIMER_MODEMREAD)			isdn_tty_readmodem();		if (tf & ISDN_TIMER_MODEMPLUS)			isdn_tty_modem_escape();		if (tf & ISDN_TIMER_MODEMXMIT)			isdn_tty_modem_xmit();	}	if (tf & ISDN_TIMER_SLOW) {		if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) {			isdn_timer_cnt1 = 0;			if (tf & ISDN_TIMER_NETDIAL)				isdn_net_dial();		}		if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {			isdn_timer_cnt2 = 0;			if (tf & ISDN_TIMER_NETHANGUP)				isdn_net_autohup();			if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) {				isdn_timer_cnt3 = 0;				if (tf & ISDN_TIMER_MODEMRING)					isdn_tty_modem_ring();			}			if (tf & ISDN_TIMER_CARRIER)				isdn_tty_carrier_timeout();		}	}	if (tf) 		mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);}voidisdn_timer_ctrl(int tf, int onoff){	unsigned long flags;	int old_tflags;	spin_lock_irqsave(&dev->timerlock, flags);	if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {		/* If the slow-timer wasn't activated until now */		isdn_timer_cnt1 = 0;		isdn_timer_cnt2 = 0;	}	old_tflags = dev->tflags;	if (onoff)		dev->tflags |= tf;	else		dev->tflags &= ~tf;	if (dev->tflags && !old_tflags)		mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);	spin_unlock_irqrestore(&dev->timerlock, flags);}/* * Receive a packet from B-Channel. (Called from low-level-module) */static voidisdn_receive_skb_callback(int di, int channel, struct sk_buff *skb){	int i;	if ((i = isdn_dc2minor(di, channel)) == -1) {		dev_kfree_skb(skb);		return;	}	/* Update statistics */	dev->ibytes[i] += skb->len;		/* First, try to deliver data to network-device */	if (isdn_net_rcv_skb(i, skb))		return;	/* V.110 handling	 * makes sense for async streams only, so it is	 * called after possible net-device delivery.	 */	if (dev->v110[i]) {		atomic_inc(&dev->v110use[i]);		skb = isdn_v110_decode(dev->v110[i], skb);		atomic_dec(&dev->v110use[i]);		if (!skb)			return;	}	/* No network-device found, deliver to tty or raw-channel */	if (skb->len) {		if (isdn_tty_rcv_skb(i, di, channel, skb))			return;		wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);	} else		dev_kfree_skb(skb);}/* * Intercept command from Linklevel to Lowlevel. * If layer 2 protocol is V.110 and this is not supported by current * lowlevel-driver, use driver's transparent mode and handle V.110 in * linklevel instead. */intisdn_command(isdn_ctrl *cmd){	if (cmd->driver == -1) {		printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);		return(1);	}	if (cmd->command == ISDN_CMD_SETL2) {		int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);		unsigned long l2prot = (cmd->arg >> 8) & 255;		unsigned long features = (dev->drv[cmd->driver]->interface->features						>> ISDN_FEATURE_L2_SHIFT) &						ISDN_FEATURE_L2_MASK;		unsigned long l2_feature = (1 << l2prot);		switch (l2prot) {			case ISDN_PROTO_L2_V11096:			case ISDN_PROTO_L2_V11019:			case ISDN_PROTO_L2_V11038:			/* If V.110 requested, but not supported by			 * HL-driver, set emulator-flag and change			 * Layer-2 to transparent			 */				if (!(features & l2_feature)) {					dev->v110emu[idx] = l2prot;					cmd->arg = (cmd->arg & 255) |						(ISDN_PROTO_L2_TRANS << 8);				} else					dev->v110emu[idx] = 0;		}	}	return dev->drv[cmd->driver]->interface->command(cmd);}voidisdn_all_eaz(int di, int ch){	isdn_ctrl cmd;	if (di < 0)		return;	cmd.driver = di;	cmd.arg = ch;	cmd.command = ISDN_CMD_SETEAZ;	cmd.parm.num[0] = '\0';	isdn_command(&cmd);}/* * Begin of a CAPI like LL<->HL interface, currently used only for  * supplementary service (CAPI 2.0 part III) */#include <linux/isdn/capicmd.h>static intisdn_capi_rec_hl_msg(capi_msg *cm) {		int di;	int ch;		di = (cm->adr.Controller & 0x7f) -1;	ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f);	switch(cm->Command) {		case CAPI_FACILITY:			/* in the moment only handled in tty */			return(isdn_tty_capi_facility(cm));		default:			return(-1);	}}static intisdn_status_callback(isdn_ctrl * c){	int di;	u_long flags;	int i;	int r;	int retval = 0;	isdn_ctrl cmd;	isdn_net_dev *p;	di = c->driver;	i = isdn_dc2minor(di, c->arg);	switch (c->command) {		case ISDN_STAT_BSENT:			if (i < 0)				return -1;			if (dev->global_flags & ISDN_GLOBAL_STOPPED)				return 0;			if (isdn_net_stat_callback(i, c))				return 0;			if (isdn_v110_stat_callback(i, c))				return 0;			if (isdn_tty_stat_callback(i, c))				return 0;			wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);			break;		case ISDN_STAT_STAVAIL:			dev->drv[di]->stavail += c->arg;			wake_up_interruptible(&dev->drv[di]->st_waitq);			break;		case ISDN_STAT_RUN:			dev->drv[di]->flags |= DRV_FLAG_RUNNING;			for (i = 0; i < ISDN_MAX_CHANNELS; i++)				if (dev->drvmap[i] == di)					isdn_all_eaz(di, dev->chanmap[i]);			set_global_features();			break;		case ISDN_STAT_STOP:			dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;			break;		case ISDN_STAT_ICALL:			if (i < 0)				return -1;#ifdef ISDN_DEBUG_STATCALLB			printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num);#endif			if (dev->global_flags & ISDN_GLOBAL_STOPPED) {				cmd.driver = di;				cmd.arg = c->arg;				cmd.command = ISDN_CMD_HANGUP;				isdn_command(&cmd);				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));			switch (r) {				case 0:					/* No network-device replies.					 * Try ttyI's.					 * These return 0 on no match, 1 on match and					 * 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);#ifdef CONFIG_ISDN_DIVERSION                                          if (divert_if)                 	                  if ((retval = divert_if->stat_callback(c))) 					    return(retval); /* processed */#endif /* CONFIG_ISDN_DIVERSION */                       					if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {						/* No tty responding */						cmd.driver = di;						cmd.arg = c->arg;						cmd.command = ISDN_CMD_HANGUP;						isdn_command(&cmd);						retval = 2;					}					break;				case 1:					/* Schedule connection-setup */					isdn_net_dial();					cmd.driver = di;					cmd.arg = c->arg;					cmd.command = ISDN_CMD_ACCEPTD;					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;					printk(KERN_INFO "isdn: Rejecting Call\n");					cmd.driver = di;					cmd.arg = c->arg;					cmd.command = ISDN_CMD_HANGUP;					isdn_command(&cmd);					if (r == 3)						break;					/* Fall through */				case 4:					/* ... then start callback. */					isdn_net_dial();					break;				case 5:					/* Number would eventually match, if longer */					retval = 3;					break;			}#ifdef ISDN_DEBUG_STATCALLB			printk(KERN_DEBUG "ICALL: ret=%d\n", retval);#endif			return retval;			break;		case ISDN_STAT_CINF:			if (i < 0)				return -1;#ifdef ISDN_DEBUG_STATCALLB			printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num);#endif			if (dev->global_flags & ISDN_GLOBAL_STOPPED)				return 0;			if (strcmp(c->parm.num, "0"))				isdn_net_stat_callback(i, c);			isdn_tty_stat_callback(i, c);			break;		case ISDN_STAT_CAUSE:#ifdef ISDN_DEBUG_STATCALLB			printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num);#endif			printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",			       dev->drvid[di], c->arg, c->parm.num);			isdn_tty_stat_callback(i, c);#ifdef CONFIG_ISDN_DIVERSION                        if (divert_if)                         divert_if->stat_callback(c); #endif /* CONFIG_ISDN_DIVERSION */			break;		case ISDN_STAT_DISPLAY:#ifdef ISDN_DEBUG_STATCALLB			printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display);#endif			isdn_tty_stat_callback(i, c);#ifdef CONFIG_ISDN_DIVERSION                        if (divert_if)                         divert_if->stat_callback(c); #endif /* CONFIG_ISDN_DIVERSION */			break;		case ISDN_STAT_DCONN:			if (i < 0)				return -1;#ifdef ISDN_DEBUG_STATCALLB

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -