📄 isdnloop.c
字号:
* 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; copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef)); 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 ((i = verify_area(VERIFY_READ, (void *) a, sizeof(isdnloop_sdef)))) return i; return (isdnloop_start(card, (isdnloop_sdef *) a)); break; case ISDNLOOP_IOCTL_ADDCARD: if ((i = verify_area(VERIFY_READ, (void *) a, sizeof(isdnloop_cdef)))) return i; copy_from_user((char *) &cdef, (char *) a, sizeof(cdef)); 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(10); } schedule_timeout(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; default: return -EINVAL; } i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); card->l2_proto[a & 255] = (a >> 8); } break; case ISDN_CMD_GETL2: if (!card->flags & ISDNLOOP_FLAGS_RUNNING) return -ENODEV; if ((c->arg & 255) < ISDNLOOP_BCH) return card->l2_proto[c->arg & 255]; else return -ENODEV; case ISDN_CMD_SETL3: if (!card->flags & ISDNLOOP_FLAGS_RUNNING) return -ENODEV; return 0; case ISDN_CMD_GETL3: if (!card->flags & ISDNLOOP_FLAGS_RUNNING) return -ENODEV; if ((c->arg & 255) < ISDNLOOP_BCH) return ISDN_PROTO_L3_TRANS; else return -ENODEV; case ISDN_CMD_GETEAZ: if (!card->flags & ISDNLOOP_FLAGS_RUNNING) return -ENODEV; break; case ISDN_CMD_SETSIL: if (!card->flags & ISDNLOOP_FLAGS_RUNNING) return -ENODEV; break; case ISDN_CMD_GETSIL: if (!card->flags & ISDNLOOP_FLAGS_RUNNING) return -ENODEV; break; case ISDN_CMD_LOCK: MOD_INC_USE_COUNT; break; case ISDN_CMD_UNLOCK: MOD_DEC_USE_COUNT; break; 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 * buf, int len, int user, 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, user, card)); } printk(KERN_ERR "isdnloop: if_writecmd called with invalid driverId!\n"); return -ENODEV;}static intif_readstatus(u_char * buf, int len, int user, 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, user, 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.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; strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); 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){ ulong flags; isdnloop_card *card; save_flags(flags); cli(); if (!(card = isdnloop_initcard(id1))) { restore_flags(flags); return -EIO; } restore_flags(flags); printk(KERN_INFO "isdnloop: (%s) virtual card added\n", card->interface.id); return 0;}#ifdef MODULE#define isdnloop_init init_module#elsevoidisdnloop_setup(char *str, int *ints){ static char sid[20]; if (strlen(str)) { strcpy(sid, str); isdnloop_id = sid; }}#endifintisdnloop_init(void){ char *p; char rev[10]; /* No symbols to export, hide all symbols */ EXPORT_NO_SYMBOLS; 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); return (isdnloop_addcard(isdnloop_id));}#ifdef MODULEvoidcleanup_module(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) { struct sk_buff *skb; last = card; while ((skb = skb_dequeue(&card->dqueue))) dev_kfree_skb(skb); card = card->next; kfree(last); } printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -