📄 isdnloop.c
字号:
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 + -