📄 capidrv.c
字号:
* data of skb used in s_cmsg, * free data when s_cmsg is not used again * thanks to Lars Heete <hel@admin.de> */ kfree_skb(skb);}/* ------------------------------------------------------------------- */#define PUTBYTE_TO_STATUS(card, byte) \ do { \ *(card)->q931_write++ = (byte); \ if ((card)->q931_write > (card)->q931_end) \ (card)->q931_write = (card)->q931_buf; \ } while (0)static void handle_dtrace_data(capidrv_contr *card, int send, int level2, u8 *data, u16 len){ u8 *p, *end; isdn_ctrl cmd; if (!len) { printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", card->contrnr, len); return; } if (level2) { PUTBYTE_TO_STATUS(card, 'D'); PUTBYTE_TO_STATUS(card, '2'); PUTBYTE_TO_STATUS(card, send ? '>' : '<'); PUTBYTE_TO_STATUS(card, ':'); } else { PUTBYTE_TO_STATUS(card, 'D'); PUTBYTE_TO_STATUS(card, '3'); PUTBYTE_TO_STATUS(card, send ? '>' : '<'); PUTBYTE_TO_STATUS(card, ':'); } for (p = data, end = data+len; p < end; p++) { u8 w; PUTBYTE_TO_STATUS(card, ' '); w = (*p >> 4) & 0xf; PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); w = *p & 0xf; PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w); } PUTBYTE_TO_STATUS(card, '\n'); cmd.command = ISDN_STAT_STAVAIL; cmd.driver = card->myid; cmd.arg = len*3+5; card->interface.statcallb(&cmd);}/* ------------------------------------------------------------------- */static _cmsg cmdcmsg;static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card){ switch (c->arg) { case 1: debugmode = (int)(*((unsigned int *)c->parm.num)); printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n", card->contrnr, debugmode); return 0; default: printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n", card->contrnr, c->arg); return -EINVAL; } return -EINVAL;}/* * Handle leased lines (CAPI-Bundling) */struct internal_bchannelinfo { unsigned short channelalloc; unsigned short operation; unsigned char cmask[31];};static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep){ unsigned long bmask = 0; int active = !0; char *s; int i; if (strncmp(teln, "FV:", 3) != 0) return 1; s = teln + 3; while (*s && *s == ' ') s++; if (!*s) return -2; if (*s == 'p' || *s == 'P') { active = 0; s++; } if (*s == 'a' || *s == 'A') { active = !0; s++; } while (*s) { int digit1 = 0; int digit2 = 0; if (!isdigit(*s)) return -3; while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; } if (digit1 <= 0 && digit1 > 30) return -4; if (*s == 0 || *s == ',' || *s == ' ') { bmask |= (1 << digit1); digit1 = 0; if (*s) s++; continue; } if (*s != '-') return -5; s++; if (!isdigit(*s)) return -3; while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; } if (digit2 <= 0 && digit2 > 30) return -4; if (*s == 0 || *s == ',' || *s == ' ') { if (digit1 > digit2) for (i = digit2; i <= digit1 ; i++) bmask |= (1 << i); else for (i = digit1; i <= digit2 ; i++) bmask |= (1 << i); digit1 = digit2 = 0; if (*s) s++; continue; } return -6; } if (activep) *activep = active; if (bmaskp) *bmaskp = bmask; return 0;}static int FVteln2capi20(char *teln, u8 AdditionalInfo[1+2+2+31]){ unsigned long bmask; int active; int rc, i; rc = decodeFVteln(teln, &bmask, &active); if (rc) return rc; /* Length */ AdditionalInfo[0] = 2+2+31; /* Channel: 3 => use channel allocation */ AdditionalInfo[1] = 3; AdditionalInfo[2] = 0; /* Operation: 0 => DTE mode, 1 => DCE mode */ if (active) { AdditionalInfo[3] = 0; AdditionalInfo[4] = 0; } else { AdditionalInfo[3] = 1; AdditionalInfo[4] = 0; } /* Channel mask array */ AdditionalInfo[5] = 0; /* no D-Channel */ for (i=1; i <= 30; i++) AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0; return 0;}static int capidrv_command(isdn_ctrl * c, capidrv_contr * card){ isdn_ctrl cmd; struct capidrv_bchan *bchan; struct capidrv_plci *plcip; u8 AdditionalInfo[1+2+2+31]; int rc, isleasedline = 0; if (c->command == ISDN_CMD_IOCTL) return capidrv_ioctl(c, card); switch (c->command) { case ISDN_CMD_DIAL:{ u8 calling[ISDN_MSNLEN + 3]; u8 called[ISDN_MSNLEN + 2]; if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", card->contrnr, c->arg, c->parm.setup.phone, c->parm.setup.si1, c->parm.setup.si2, c->parm.setup.eazmsn); bchan = &card->bchans[c->arg % card->nbchan]; if (bchan->plcip) { printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", card->contrnr, c->arg, c->parm.setup.phone, c->parm.setup.si1, c->parm.setup.si2, c->parm.setup.eazmsn, bchan->plcip->plci); return 0; } bchan->si1 = c->parm.setup.si1; bchan->si2 = c->parm.setup.si2; strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num)); strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum)); rc = FVteln2capi20(bchan->num, AdditionalInfo); isleasedline = (rc == 0); if (rc < 0) printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num); if (isleasedline) { calling[0] = 0; called[0] = 0; if (debugmode) printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr); } else { calling[0] = strlen(bchan->mynum) + 2; calling[1] = 0; calling[2] = 0x80; strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN); called[0] = strlen(bchan->num) + 1; called[1] = 0x80; strncpy(called + 2, bchan->num, ISDN_MSNLEN); } capi_fill_CONNECT_REQ(&cmdcmsg, global.ap.applid, card->msgid++, card->contrnr, /* adr */ si2cip(bchan->si1, bchan->si2), /* cipvalue */ called, /* CalledPartyNumber */ calling, /* CallingPartyNumber */ NULL, /* CalledPartySubaddress */ NULL, /* CallingPartySubaddress */ b1prot(bchan->l2, bchan->l3), /* B1protocol */ b2prot(bchan->l2, bchan->l3), /* B2protocol */ b3prot(bchan->l2, bchan->l3), /* B3protocol */ b1config(bchan->l2, bchan->l3), /* B1configuration */ NULL, /* B2configuration */ NULL, /* B3configuration */ NULL, /* BC */ NULL, /* LLC */ NULL, /* HLC */ /* BChannelinformation */ isleasedline ? AdditionalInfo : NULL, NULL, /* Keypadfacility */ NULL, /* Useruserdata */ NULL /* Facilitydataarray */ ); if ((plcip = new_plci(card, (c->arg % card->nbchan))) == 0) { cmd.command = ISDN_STAT_DHUP; cmd.driver = card->myid; cmd.arg = (c->arg % card->nbchan); card->interface.statcallb(&cmd); return -1; } plcip->msgid = cmdcmsg.Messagenumber; plcip->leasedline = isleasedline; plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ); send_message(card, &cmdcmsg); return 0; } case ISDN_CMD_ACCEPTD: bchan = &card->bchans[c->arg % card->nbchan]; if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n", card->contrnr, c->arg, bchan->l2, bchan->l3); capi_fill_CONNECT_RESP(&cmdcmsg, global.ap.applid, card->msgid++, bchan->plcip->plci, /* adr */ 0, /* Reject */ b1prot(bchan->l2, bchan->l3), /* B1protocol */ b2prot(bchan->l2, bchan->l3), /* B2protocol */ b3prot(bchan->l2, bchan->l3), /* B3protocol */ b1config(bchan->l2, bchan->l3), /* B1configuration */ NULL, /* B2configuration */ NULL, /* B3configuration */ NULL, /* ConnectedNumber */ NULL, /* ConnectedSubaddress */ NULL, /* LLC */ NULL, /* BChannelinformation */ NULL, /* Keypadfacility */ NULL, /* Useruserdata */ NULL /* Facilitydataarray */ ); capi_cmsg2message(&cmdcmsg, cmdcmsg.buf); plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP); send_message(card, &cmdcmsg); return 0; case ISDN_CMD_ACCEPTB: if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n", card->contrnr, c->arg); return -ENOSYS; case ISDN_CMD_HANGUP: if (debugmode) printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n", card->contrnr, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; if (bchan->disconnecting) { if (debugmode) printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n", card->contrnr, c->arg); return 0; } if (bchan->nccip) { bchan->disconnecting = 1; capi_fill_DISCONNECT_B3_REQ(&cmdcmsg, global.ap.applid, card->msgid++, bchan->nccip->ncci, NULL /* NCPI */ ); ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ); send_message(card, &cmdcmsg); return 0; } else if (bchan->plcip) { if (bchan->plcip->state == ST_PLCI_INCOMING) { /* * just ignore, we a called from * isdn_status_callback(), * which will return 0 or 2, this is handled * by the CONNECT_IND handler */ bchan->disconnecting = 1; return 0; } else if (bchan->plcip->plci) { bchan->disconnecting = 1; capi_fill_DISCONNECT_REQ(&cmdcmsg, global.ap.applid, card->msgid++, bchan->plcip->plci, NULL, /* BChannelinformation */ NULL, /* Keypadfacility */ NULL, /* Useruserdata */ NULL /* Facilitydataarray */ ); plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ); send_message(card, &cmdcmsg); return 0; } else { printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n", card->contrnr, c->arg); return -EINVAL; } } printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n", card->contrnr, c->arg); return -EINVAL;/* ready */ case ISDN_CMD_SETL2: if (debugmode) printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n", card->contrnr, (c->arg & 0xff), (c->arg >> 8)); bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; bchan->l2 = (c->arg >> 8); return 0; case ISDN_CMD_SETL3: if (debugmode) printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n", card->contrnr, (c->arg & 0xff), (c->arg >> 8)); bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; bchan->l3 = (c->arg >> 8); return 0; case ISDN_CMD_SETEAZ: if (debugmode) printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n", card->contrnr, c->parm.num, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN); return 0; case ISDN_CMD_CLREAZ: if (debugmode) printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n", card->contrnr, c->arg); bchan = &card->bchans[c->arg % card->nbchan]; bchan->msn[0] = 0; return 0; default: printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n", card->contrnr, c->command); return -EINVAL; } return 0;}static int if_command(isdn_ctrl * c){ capidrv_contr *card = findcontrbydriverid(c->driver); if (card) return capidrv_command(c, card); printk(KERN_ERR "capidrv: if_command %d called with invalid driverId %d!\n", c->command, c->driver); return -ENODEV;}static _cmsg sendcmsg;static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb){ capidrv_contr *card = findcontrbydriverid(id); capidrv_bchan *bchan; capidrv_ncci *nccip; int len = skb->len; int msglen; u16 errcode; u16 datahandle; if (!card) { printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n", id); return 0; } if (debugmode > 4) printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n", card->contrnr, len, skb, doack); bchan = &card->bchans[channel % card->nbchan]; nccip = bchan->nccip; if (!nccip || nccip->state != ST_NCCI_ACTIVE) { printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n", card->contrnr, card->name, channel); return 0; } datahandle = nccip->datahandle; capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++, nccip->ncci, /* adr */ (u32) skb->data, /* Data */ skb->len, /* DataLength */ datahandle, /* DataHandle */ 0 /* Flags */ ); if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0) return 0; capi_cmsg2message(&sendcmsg, sendcmsg.buf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -