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

📄 isdnloop.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
		del_timer(&card->c_timer[0]);		del_timer(&card->c_timer[1]);		cmd.command = ISDN_STAT_STOP;		cmd.driver = card->myid;		card->interface.statcallb(&cmd);	}	restore_flags(flags);}/* * Stop all cards before unload. */static voidisdnloop_stopallcards(void){	isdnloop_card *p = cards;	while (p) {		isdnloop_stopcard(p);		p = p->next;	}}/* * Start a 'card'. Simulate card's boot message and set the phone * number(s) of the virtual 'S0-Interface'. Install D-channel * poll timer. * * Parameter: *   card  = pointer to card struct. *   sdefp = pointer to struct holding ioctl parameters. * Return: *   0 on success, -E??? otherwise. */static intisdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp){	unsigned long flags;	isdnloop_sdef sdef;	int i;	if (card->flags & ISDNLOOP_FLAGS_RUNNING)		return -EBUSY;	if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef)))		return -EFAULT;	save_flags(flags);	cli();	switch (sdef.ptype) {		case ISDN_PTYPE_EURO:			if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96",					  -1)) {				restore_flags(flags);				return -ENOMEM;			}			card->sil[0] = card->sil[1] = 4;			if (isdnloop_fake(card, "TEI OK", 0)) {				restore_flags(flags);				return -ENOMEM;			}			for (i = 0; i < 3; i++)				strcpy(card->s0num[i], sdef.num[i]);			break;		case ISDN_PTYPE_1TR6:			if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",					  -1)) {				restore_flags(flags);				return -ENOMEM;			}			card->sil[0] = card->sil[1] = 4;			if (isdnloop_fake(card, "TEI OK", 0)) {				restore_flags(flags);				return -ENOMEM;			}			strcpy(card->s0num[0], sdef.num[0]);			card->s0num[1][0] = '\0';			card->s0num[2][0] = '\0';			break;		default:			restore_flags(flags);			printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n",			       sdef.ptype);			return -EINVAL;	}	init_timer(&card->st_timer);	card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;	card->st_timer.function = isdnloop_polldchan;	card->st_timer.data = (unsigned long) card;	add_timer(&card->st_timer);	card->flags |= ISDNLOOP_FLAGS_RUNNING;	restore_flags(flags);	return 0;}/* * Main handler for commands sent by linklevel. */static intisdnloop_command(isdn_ctrl * c, isdnloop_card * card){	ulong a;	int i;	char cbuf[60];	isdn_ctrl cmd;	isdnloop_cdef cdef;	switch (c->command) {		case ISDN_CMD_IOCTL:			memcpy(&a, c->parm.num, sizeof(ulong));			switch (c->arg) {				case ISDNLOOP_IOCTL_DEBUGVAR:					return (ulong) card;				case ISDNLOOP_IOCTL_STARTUP:					if (!access_ok(VERIFY_READ, (void *) a, sizeof(isdnloop_sdef)))						return -EFAULT;					return (isdnloop_start(card, (isdnloop_sdef *) a));					break;				case ISDNLOOP_IOCTL_ADDCARD:					if (copy_from_user((char *)&cdef,							   (char *)a,							   sizeof(cdef)))						return -EFAULT;					return (isdnloop_addcard(cdef.id1));					break;				case ISDNLOOP_IOCTL_LEASEDCFG:					if (a) {						if (!card->leased) {							card->leased = 1;							while (card->ptype == ISDN_PTYPE_UNKNOWN)								schedule_timeout_interruptible(10);							schedule_timeout_interruptible(10);							sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n");							i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);							printk(KERN_INFO							       "isdnloop: (%s) Leased-line mode enabled\n",							       CID);							cmd.command = ISDN_STAT_RUN;							cmd.driver = card->myid;							cmd.arg = 0;							card->interface.statcallb(&cmd);						}					} else {						if (card->leased) {							card->leased = 0;							sprintf(cbuf, "00;FV2OFF\n");							i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);							printk(KERN_INFO							       "isdnloop: (%s) Leased-line mode disabled\n",							       CID);							cmd.command = ISDN_STAT_RUN;							cmd.driver = card->myid;							cmd.arg = 0;							card->interface.statcallb(&cmd);						}					}					return 0;				default:					return -EINVAL;			}			break;		case ISDN_CMD_DIAL:			if (!card->flags & ISDNLOOP_FLAGS_RUNNING)				return -ENODEV;			if (card->leased)				break;			if ((c->arg & 255) < ISDNLOOP_BCH) {				char *p;				char dial[50];				char dcode[4];				a = c->arg;				p = c->parm.setup.phone;				if (*p == 's' || *p == 'S') {					/* Dial for SPV */					p++;					strcpy(dcode, "SCA");				} else					/* Normal Dial */					strcpy(dcode, "CAL");				strcpy(dial, p);				sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),					dcode, dial, c->parm.setup.si1,				c->parm.setup.si2, c->parm.setup.eazmsn);				i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);			}			break;		case ISDN_CMD_ACCEPTD:			if (!card->flags & ISDNLOOP_FLAGS_RUNNING)				return -ENODEV;			if (c->arg < ISDNLOOP_BCH) {				a = c->arg + 1;				cbuf[0] = 0;				switch (card->l2_proto[a - 1]) {					case ISDN_PROTO_L2_X75I:						sprintf(cbuf, "%02d;BX75\n", (int) a);						break;#ifdef CONFIG_ISDN_X25					case ISDN_PROTO_L2_X25DTE:						sprintf(cbuf, "%02d;BX2T\n", (int) a);						break;					case ISDN_PROTO_L2_X25DCE:						sprintf(cbuf, "%02d;BX2C\n", (int) a);						break;#endif					case ISDN_PROTO_L2_HDLC:						sprintf(cbuf, "%02d;BTRA\n", (int) a);						break;				}				if (strlen(cbuf))					i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);				sprintf(cbuf, "%02d;DCON_R\n", (int) a);				i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);			}			break;		case ISDN_CMD_ACCEPTB:			if (!card->flags & ISDNLOOP_FLAGS_RUNNING)				return -ENODEV;			if (c->arg < ISDNLOOP_BCH) {				a = c->arg + 1;				switch (card->l2_proto[a - 1]) {					case ISDN_PROTO_L2_X75I:						sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a);						break;#ifdef CONFIG_ISDN_X25					case ISDN_PROTO_L2_X25DTE:						sprintf(cbuf, "%02d;BCON_R,BX2T\n", (int) a);						break;					case ISDN_PROTO_L2_X25DCE:						sprintf(cbuf, "%02d;BCON_R,BX2C\n", (int) a);						break;#endif					case ISDN_PROTO_L2_HDLC:						sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a);						break;					default:						sprintf(cbuf, "%02d;BCON_R\n", (int) a);				}				printk(KERN_DEBUG "isdnloop writecmd '%s'\n", cbuf);				i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);				break;		case ISDN_CMD_HANGUP:				if (!card->flags & ISDNLOOP_FLAGS_RUNNING)					return -ENODEV;				if (c->arg < ISDNLOOP_BCH) {					a = c->arg + 1;					sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a);					i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);				}				break;		case ISDN_CMD_SETEAZ:				if (!card->flags & ISDNLOOP_FLAGS_RUNNING)					return -ENODEV;				if (card->leased)					break;				if (c->arg < ISDNLOOP_BCH) {					a = c->arg + 1;					if (card->ptype == ISDN_PTYPE_EURO) {						sprintf(cbuf, "%02d;MS%s%s\n", (int) a,							c->parm.num[0] ? "N" : "ALL", c->parm.num);					} else						sprintf(cbuf, "%02d;EAZ%s\n", (int) a,							c->parm.num[0] ? c->parm.num : (u_char *) "0123456789");					i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);				}				break;		case ISDN_CMD_CLREAZ:				if (!card->flags & ISDNLOOP_FLAGS_RUNNING)					return -ENODEV;				if (card->leased)					break;				if (c->arg < ISDNLOOP_BCH) {					a = c->arg + 1;					if (card->ptype == ISDN_PTYPE_EURO)						sprintf(cbuf, "%02d;MSNC\n", (int) a);					else						sprintf(cbuf, "%02d;EAZC\n", (int) a);					i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);				}				break;		case ISDN_CMD_SETL2:				if (!card->flags & ISDNLOOP_FLAGS_RUNNING)					return -ENODEV;				if ((c->arg & 255) < ISDNLOOP_BCH) {					a = c->arg;					switch (a >> 8) {						case ISDN_PROTO_L2_X75I:							sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1);							break;#ifdef CONFIG_ISDN_X25						case ISDN_PROTO_L2_X25DTE:							sprintf(cbuf, "%02d;BX2T\n", (int) (a & 255) + 1);							break;						case ISDN_PROTO_L2_X25DCE:							sprintf(cbuf, "%02d;BX2C\n", (int) (a & 255) + 1);							break;#endif						case ISDN_PROTO_L2_HDLC:							sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);							break;						case ISDN_PROTO_L2_TRANS:							sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);							break;						default:							return -EINVAL;					}					i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);					card->l2_proto[a & 255] = (a >> 8);				}				break;		case ISDN_CMD_SETL3:				if (!card->flags & ISDNLOOP_FLAGS_RUNNING)					return -ENODEV;				return 0;		default:				return -EINVAL;			}	}	return 0;}/* * Find card with given driverId */static inline isdnloop_card *isdnloop_findcard(int driverid){	isdnloop_card *p = cards;	while (p) {		if (p->myid == driverid)			return p;		p = p->next;	}	return (isdnloop_card *) 0;}/* * Wrapper functions for interface to linklevel */static intif_command(isdn_ctrl * c){	isdnloop_card *card = isdnloop_findcard(c->driver);	if (card)		return (isdnloop_command(c, card));	printk(KERN_ERR	       "isdnloop: if_command called with invalid driverId!\n");	return -ENODEV;}static intif_writecmd(const u_char __user *buf, int len, int id, int channel){	isdnloop_card *card = isdnloop_findcard(id);	if (card) {		if (!card->flags & ISDNLOOP_FLAGS_RUNNING)			return -ENODEV;		return (isdnloop_writecmd(buf, len, 1, card));	}	printk(KERN_ERR	       "isdnloop: if_writecmd called with invalid driverId!\n");	return -ENODEV;}static intif_readstatus(u_char __user *buf, int len, int id, int channel){	isdnloop_card *card = isdnloop_findcard(id);	if (card) {		if (!card->flags & ISDNLOOP_FLAGS_RUNNING)			return -ENODEV;		return (isdnloop_readstatus(buf, len, card));	}	printk(KERN_ERR	       "isdnloop: if_readstatus called with invalid driverId!\n");	return -ENODEV;}static intif_sendbuf(int id, int channel, int ack, struct sk_buff *skb){	isdnloop_card *card = isdnloop_findcard(id);	if (card) {		if (!card->flags & ISDNLOOP_FLAGS_RUNNING)			return -ENODEV;		/* ack request stored in skb scratch area */		*(skb->head) = ack;		return (isdnloop_sendbuf(channel, skb, card));	}	printk(KERN_ERR	       "isdnloop: if_sendbuf called with invalid driverId!\n");	return -ENODEV;}/* * Allocate a new card-struct, initialize it * link it into cards-list and register it at linklevel. */static isdnloop_card *isdnloop_initcard(char *id){	isdnloop_card *card;	int i;	if (!(card = (isdnloop_card *) kmalloc(sizeof(isdnloop_card), GFP_KERNEL))) {		printk(KERN_WARNING		 "isdnloop: (%s) Could not allocate card-struct.\n", id);		return (isdnloop_card *) 0;	}	memset((char *) card, 0, sizeof(isdnloop_card));	card->interface.owner = THIS_MODULE;	card->interface.channels = ISDNLOOP_BCH;	card->interface.hl_hdrlen  = 1; /* scratch area for storing ack flag*/ 	card->interface.maxbufsize = 4000;	card->interface.command = if_command;	card->interface.writebuf_skb = if_sendbuf;	card->interface.writecmd = if_writecmd;	card->interface.readstat = if_readstatus;	card->interface.features = ISDN_FEATURE_L2_X75I |#ifdef CONFIG_ISDN_X25	    ISDN_FEATURE_L2_X25DTE |	    ISDN_FEATURE_L2_X25DCE |#endif	    ISDN_FEATURE_L2_HDLC |	    ISDN_FEATURE_L3_TRANS |	    ISDN_FEATURE_P_UNKNOWN;	card->ptype = ISDN_PTYPE_UNKNOWN;	strlcpy(card->interface.id, id, sizeof(card->interface.id));	card->msg_buf_write = card->msg_buf;	card->msg_buf_read = card->msg_buf;	card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];	for (i = 0; i < ISDNLOOP_BCH; i++) {		card->l2_proto[i] = ISDN_PROTO_L2_X75I;		skb_queue_head_init(&card->bqueue[i]);	}	skb_queue_head_init(&card->dqueue);	card->next = cards;	cards = card;	if (!register_isdn(&card->interface)) {		cards = cards->next;		printk(KERN_WARNING		       "isdnloop: Unable to register %s\n", id);		kfree(card);		return (isdnloop_card *) 0;	}	card->myid = card->interface.channels;	return card;}static intisdnloop_addcard(char *id1){	isdnloop_card *card;	if (!(card = isdnloop_initcard(id1))) {		return -EIO;	}	printk(KERN_INFO	       "isdnloop: (%s) virtual card added\n",	       card->interface.id);	return 0;}static int __initisdnloop_init(void){	char *p;	char rev[10];	if ((p = strchr(revision, ':'))) {		strcpy(rev, p + 1);		p = strchr(rev, '$');		*p = 0;	} else		strcpy(rev, " ??? ");	printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev);	if (isdnloop_id)		return (isdnloop_addcard(isdnloop_id));	return 0;}static void __exitisdnloop_exit(void){	isdn_ctrl cmd;	isdnloop_card *card = cards;	isdnloop_card *last;	int i;	isdnloop_stopallcards();	while (card) {		cmd.command = ISDN_STAT_UNLOAD;		cmd.driver = card->myid;		card->interface.statcallb(&cmd);		for (i = 0; i < ISDNLOOP_BCH; i++)			isdnloop_free_queue(card, i);		card = card->next;	}	card = cards;	while (card) {		last = card;		skb_queue_purge(&card->dqueue);		card = card->next;		kfree(last);	}	printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n");}module_init(isdnloop_init);module_exit(isdnloop_exit);

⌨️ 快捷键说明

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