isdnloop.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:39k
- /* $Id: isdnloop.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
- *
- * ISDN low-level module implementing a dummy loop driver.
- *
- * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.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 "isdnloop.h"
- static char *revision = "$Revision: 1.1.4.1 $";
- static char *isdnloop_id;
- MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
- MODULE_AUTHOR("Fritz Elfert");
- MODULE_LICENSE("GPL");
- MODULE_PARM(isdnloop_id, "s");
- MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
- static int isdnloop_addcard(char *);
- /*
- * Free queue completely.
- *
- * Parameter:
- * card = pointer to card struct
- * channel = channel number
- */
- static void
- isdnloop_free_queue(isdnloop_card * card, int channel)
- {
- struct sk_buff_head *queue = &card->bqueue[channel];
- skb_queue_purge(queue);
- card->sndcount[channel] = 0;
- }
- /*
- * Send B-Channel data to another virtual card.
- * This routine is called via timer-callback from isdnloop_pollbchan().
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel number (0-based)
- */
- static void
- isdnloop_bchan_send(isdnloop_card * card, int ch)
- {
- isdnloop_card *rcard = card->rcard[ch];
- int rch = card->rch[ch], len, ack;
- struct sk_buff *skb;
- isdn_ctrl cmd;
- while (card->sndcount[ch]) {
- if ((skb = skb_dequeue(&card->bqueue[ch]))) {
- len = skb->len;
- card->sndcount[ch] -= len;
- ack = *(skb->head); /* used as scratch area */
- cmd.driver = card->myid;
- cmd.arg = ch;
- if (rcard){
- rcard->interface.rcvcallb_skb(rcard->myid, rch, skb);
- } else {
- printk(KERN_WARNING "isdnloop: no rcard, skb droppedn");
- dev_kfree_skb(skb);
- cmd.command = ISDN_STAT_L1ERR;
- cmd.parm.errcode = ISDN_STAT_L1ERR_SEND;
- card->interface.statcallb(&cmd);
- };
- cmd.command = ISDN_STAT_BSENT;
- cmd.parm.length = len;
- if ( ack ) card->interface.statcallb(&cmd);
- } else
- card->sndcount[ch] = 0;
- }
- }
- /*
- * Send/Receive Data to/from the B-Channel.
- * This routine is called via timer-callback.
- * It schedules itself while any B-Channel is open.
- *
- * Parameter:
- * data = pointer to card struct, set by kernel timer.data
- */
- static void
- isdnloop_pollbchan(unsigned long data)
- {
- isdnloop_card *card = (isdnloop_card *) data;
- unsigned long flags;
- if (card->flags & ISDNLOOP_FLAGS_B1ACTIVE)
- isdnloop_bchan_send(card, 0);
- if (card->flags & ISDNLOOP_FLAGS_B2ACTIVE)
- isdnloop_bchan_send(card, 1);
- if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) {
- /* schedule b-channel polling again */
- save_flags(flags);
- cli();
- card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
- add_timer(&card->rb_timer);
- card->flags |= ISDNLOOP_FLAGS_RBTIMER;
- restore_flags(flags);
- } else
- card->flags &= ~ISDNLOOP_FLAGS_RBTIMER;
- }
- /*
- * Parse ICN-type setup string and fill fields of setup-struct
- * with parsed data.
- *
- * Parameter:
- * setup = setup string, format: [caller-id],si1,si2,[called-id]
- * cmd = pointer to struct to be filled.
- */
- static void
- isdnloop_parse_setup(char *setup, isdn_ctrl * cmd)
- {
- char *t = setup;
- char *s = strpbrk(t, ",");
- *s++ = ' ';
- strncpy(cmd->parm.setup.phone, t, sizeof(cmd->parm.setup.phone));
- s = strpbrk(t = s, ",");
- *s++ = ' ';
- if (!strlen(t))
- cmd->parm.setup.si1 = 0;
- else
- cmd->parm.setup.si1 = simple_strtoul(t, NULL, 10);
- s = strpbrk(t = s, ",");
- *s++ = ' ';
- if (!strlen(t))
- cmd->parm.setup.si2 = 0;
- else
- cmd->parm.setup.si2 =
- simple_strtoul(t, NULL, 10);
- strncpy(cmd->parm.setup.eazmsn, s, sizeof(cmd->parm.setup.eazmsn));
- cmd->parm.setup.plan = 0;
- cmd->parm.setup.screen = 0;
- }
- typedef struct isdnloop_stat {
- char *statstr;
- int command;
- int action;
- } isdnloop_stat;
- /* *INDENT-OFF* */
- static isdnloop_stat isdnloop_stat_table[] =
- {
- {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
- {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
- {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */
- {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */
- {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
- {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
- {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
- {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
- {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
- {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
- {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
- {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */
- {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
- {"E_L1: ACTIVATION FAILED",
- ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {NULL, 0, -1}
- };
- /* *INDENT-ON* */
- /*
- * Parse Status message-strings from virtual card.
- * Depending on status, call statcallb for sending messages to upper
- * levels. Also set/reset B-Channel active-flags.
- *
- * Parameter:
- * status = status string to parse.
- * channel = channel where message comes from.
- * card = card where message comes from.
- */
- static void
- isdnloop_parse_status(u_char * status, int channel, isdnloop_card * card)
- {
- isdnloop_stat *s = isdnloop_stat_table;
- int action = -1;
- isdn_ctrl cmd;
- while (s->statstr) {
- if (!strncmp(status, s->statstr, strlen(s->statstr))) {
- cmd.command = s->command;
- action = s->action;
- break;
- }
- s++;
- }
- if (action == -1)
- return;
- cmd.driver = card->myid;
- cmd.arg = channel;
- switch (action) {
- case 1:
- /* BCON_x */
- card->flags |= (channel) ?
- ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE;
- break;
- case 2:
- /* BDIS_x */
- card->flags &= ~((channel) ?
- ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE);
- isdnloop_free_queue(card, channel);
- break;
- case 3:
- /* DCAL_I and DSCA_I */
- isdnloop_parse_setup(status + 6, &cmd);
- break;
- case 4:
- /* FCALL */
- sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
- sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
- cmd.parm.setup.si1 = 7;
- cmd.parm.setup.si2 = 0;
- cmd.parm.setup.plan = 0;
- cmd.parm.setup.screen = 0;
- break;
- case 5:
- /* CIF */
- strncpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num) - 1);
- break;
- case 6:
- /* AOC */
- sprintf(cmd.parm.num, "%d",
- (int) simple_strtoul(status + 7, NULL, 16));
- break;
- case 7:
- /* CAU */
- status += 3;
- if (strlen(status) == 4)
- sprintf(cmd.parm.num, "%s%c%c",
- status + 2, *status, *(status + 1));
- else
- strncpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num) - 1);
- break;
- case 8:
- /* Misc Errors on L1 and L2 */
- card->flags &= ~ISDNLOOP_FLAGS_B1ACTIVE;
- isdnloop_free_queue(card, 0);
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_BHUP;
- card->flags &= ~ISDNLOOP_FLAGS_B2ACTIVE;
- isdnloop_free_queue(card, 1);
- cmd.arg = 1;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 1;
- cmd.driver = card->myid;
- break;
- }
- card->interface.statcallb(&cmd);
- }
- /*
- * Store a cwcharacter into ringbuffer for reading from /dev/isdnctrl
- *
- * Parameter:
- * card = pointer to card struct.
- * c = char to store.
- */
- static void
- isdnloop_putmsg(isdnloop_card * card, unsigned char c)
- {
- ulong flags;
- save_flags(flags);
- cli();
- *card->msg_buf_write++ = (c == 0xff) ? 'n' : c;
- if (card->msg_buf_write == card->msg_buf_read) {
- if (++card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- if (card->msg_buf_write > card->msg_buf_end)
- card->msg_buf_write = card->msg_buf;
- restore_flags(flags);
- }
- /*
- * Poll a virtual cards message queue.
- * If there are new status-replies from the card, copy them to
- * ringbuffer for reading on /dev/isdnctrl and call
- * isdnloop_parse_status() for processing them. Watch for special
- * Firmware bootmessage and parse it, to get the D-Channel protocol.
- * If there are B-Channels open, initiate a timer-callback to
- * isdnloop_pollbchan().
- * This routine is called periodically via timer interrupt.
- *
- * Parameter:
- * data = pointer to card struct
- */
- static void
- isdnloop_polldchan(unsigned long data)
- {
- isdnloop_card *card = (isdnloop_card *) data;
- struct sk_buff *skb;
- int avail;
- int left;
- u_char c;
- int ch;
- unsigned long flags;
- u_char *p;
- isdn_ctrl cmd;
- if ((skb = skb_dequeue(&card->dqueue)))
- avail = skb->len;
- else
- avail = 0;
- for (left = avail; left > 0; left--) {
- c = *skb->data;
- skb_pull(skb, 1);
- isdnloop_putmsg(card, c);
- card->imsg[card->iptr] = c;
- if (card->iptr < 59)
- card->iptr++;
- if (!skb->len) {
- avail++;
- isdnloop_putmsg(card, 'n');
- card->imsg[card->iptr] = 0;
- card->iptr = 0;
- if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
- card->imsg[1] <= '2' && card->imsg[2] == ';') {
- ch = (card->imsg[1] - '0') - 1;
- p = &card->imsg[3];
- isdnloop_parse_status(p, ch, card);
- } else {
- p = card->imsg;
- if (!strncmp(p, "DRV1.", 5)) {
- printk(KERN_INFO "isdnloop: (%s) %sn", CID, p);
- if (!strncmp(p + 7, "TC", 2)) {
- card->ptype = ISDN_PTYPE_1TR6;
- card->interface.features |= ISDN_FEATURE_P_1TR6;
- printk(KERN_INFO
- "isdnloop: (%s) 1TR6-Protocol loaded and runningn", CID);
- }
- if (!strncmp(p + 7, "EC", 2)) {
- card->ptype = ISDN_PTYPE_EURO;
- card->interface.features |= ISDN_FEATURE_P_EURO;
- printk(KERN_INFO
- "isdnloop: (%s) Euro-Protocol loaded and runningn", CID);
- }
- continue;
- }
- }
- }
- }
- if (avail) {
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = avail;
- card->interface.statcallb(&cmd);
- }
- if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE))
- if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) {
- /* schedule b-channel polling */
- card->flags |= ISDNLOOP_FLAGS_RBTIMER;
- save_flags(flags);
- cli();
- del_timer(&card->rb_timer);
- card->rb_timer.function = isdnloop_pollbchan;
- card->rb_timer.data = (unsigned long) card;
- card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
- add_timer(&card->rb_timer);
- restore_flags(flags);
- }
- /* schedule again */
- save_flags(flags);
- cli();
- card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
- add_timer(&card->st_timer);
- restore_flags(flags);
- }
- /*
- * Append a packet to the transmit buffer-queue.
- *
- * Parameter:
- * channel = Number of B-channel
- * skb = packet to send.
- * card = pointer to card-struct
- * Return:
- * Number of bytes transferred, -E??? on error
- */
- static int
- isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card)
- {
- int len = skb->len;
- unsigned long flags;
- struct sk_buff *nskb;
- if (len > 4000) {
- printk(KERN_WARNING
- "isdnloop: Send packet too largen");
- return -EINVAL;
- }
- if (len) {
- if (!(card->flags & (channel) ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE))
- return 0;
- if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
- return 0;
- save_flags(flags);
- cli();
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (nskb) {
- skb_queue_tail(&card->bqueue[channel], nskb);
- dev_kfree_skb(skb);
- } else
- len = 0;
- card->sndcount[channel] += len;
- restore_flags(flags);
- }
- return len;
- }
- /*
- * Read the messages from the card's ringbuffer
- *
- * Parameter:
- * buf = pointer to buffer.
- * len = number of bytes to read.
- * user = flag, 1: called from userlevel 0: called from kernel.
- * card = pointer to card struct.
- * Return:
- * number of bytes actually transferred.
- */
- static int
- isdnloop_readstatus(u_char * buf, int len, int user, isdnloop_card * card)
- {
- int count;
- u_char *p;
- for (p = buf, count = 0; count < len; p++, count++) {
- if (card->msg_buf_read == card->msg_buf_write)
- return count;
- if (user)
- put_user(*card->msg_buf_read++, p);
- else
- *p = *card->msg_buf_read++;
- if (card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- return count;
- }
- /*
- * Simulate a card's response by appending it to the cards
- * message queue.
- *
- * Parameter:
- * card = pointer to card struct.
- * s = pointer to message-string.
- * ch = channel: 0 = generic messages, 1 and 2 = D-channel messages.
- * Return:
- * 0 on success, 1 on memory squeeze.
- */
- static int
- isdnloop_fake(isdnloop_card * card, char *s, int ch)
- {
- struct sk_buff *skb;
- int len = strlen(s) + ((ch >= 0) ? 3 : 0);
- if (!(skb = dev_alloc_skb(len))) {
- printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_faken");
- return 1;
- }
- if (ch >= 0)
- sprintf(skb_put(skb, 3), "%02d;", ch);
- memcpy(skb_put(skb, strlen(s)), s, strlen(s));
- skb_queue_tail(&card->dqueue, skb);
- return 0;
- }
- /* *INDENT-OFF* */
- static isdnloop_stat isdnloop_cmd_table[] =
- {
- {"BCON_R", 0, 1}, /* B-Channel connect */
- {"BCON_I", 0, 17}, /* B-Channel connect ind */
- {"BDIS_R", 0, 2}, /* B-Channel disconnect */
- {"DDIS_R", 0, 3}, /* D-Channel disconnect */
- {"DCON_R", 0, 16}, /* D-Channel connect */
- {"DSCA_R", 0, 4}, /* Dial 1TR6-SPV */
- {"DCAL_R", 0, 5}, /* Dial */
- {"EAZC", 0, 6}, /* Clear EAZ listener */
- {"EAZ", 0, 7}, /* Set EAZ listener */
- {"SEEAZ", 0, 8}, /* Get EAZ listener */
- {"MSN", 0, 9}, /* Set/Clear MSN listener */
- {"MSALL", 0, 10}, /* Set multi MSN listeners */
- {"SETSIL", 0, 11}, /* Set SI list */
- {"SEESIL", 0, 12}, /* Get SI list */
- {"SILC", 0, 13}, /* Clear SI list */
- {"LOCK", 0, -1}, /* LOCK channel */
- {"UNLOCK", 0, -1}, /* UNLOCK channel */
- {"FV2ON", 1, 14}, /* Leased mode on */
- {"FV2OFF", 1, 15}, /* Leased mode off */
- {NULL, 0, -1}
- };
- /* *INDENT-ON* */
- /*
- * Simulate an error-response from a card.
- *
- * Parameter:
- * card = pointer to card struct.
- */
- static void
- isdnloop_fake_err(isdnloop_card * card)
- {
- char buf[60];
- sprintf(buf, "E%s", card->omsg);
- isdnloop_fake(card, buf, -1);
- isdnloop_fake(card, "NAK", -1);
- }
- static u_char ctable_eu[] =
- {0x00, 0x11, 0x01, 0x12};
- static u_char ctable_1t[] =
- {0x00, 0x3b, 0x01, 0x3a};
- /*
- * Assemble a simplified cause message depending on the
- * D-channel protocol used.
- *
- * Parameter:
- * card = pointer to card struct.
- * loc = location: 0 = local, 1 = remote.
- * cau = cause: 1 = busy, 2 = nonexistent callerid, 3 = no user responding.
- * Return:
- * Pointer to buffer containing the assembled message.
- */
- static char *
- isdnloop_unicause(isdnloop_card * card, int loc, int cau)
- {
- static char buf[6];
- switch (card->ptype) {
- case ISDN_PTYPE_EURO:
- sprintf(buf, "E%02X%02X", (loc) ? 4 : 2, ctable_eu[cau]);
- break;
- case ISDN_PTYPE_1TR6:
- sprintf(buf, "%02X44", ctable_1t[cau]);
- break;
- default:
- return ("0000");
- }
- return (buf);
- }
- /*
- * Release a virtual connection. Called from timer interrupt, when
- * called party did not respond.
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel (0-based)
- */
- static void
- isdnloop_atimeout(isdnloop_card * card, int ch)
- {
- unsigned long flags;
- char buf[60];
- save_flags(flags);
- cli();
- if (card->rcard) {
- isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1);
- card->rcard[ch]->rcard[card->rch[ch]] = NULL;
- card->rcard[ch] = NULL;
- }
- isdnloop_fake(card, "DDIS_I", ch + 1);
- /* No user responding */
- sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3));
- isdnloop_fake(card, buf, ch + 1);
- restore_flags(flags);
- }
- /*
- * Wrapper for isdnloop_atimeout().
- */
- static void
- isdnloop_atimeout0(unsigned long data)
- {
- isdnloop_card *card = (isdnloop_card *) data;
- isdnloop_atimeout(card, 0);
- }
- /*
- * Wrapper for isdnloop_atimeout().
- */
- static void
- isdnloop_atimeout1(unsigned long data)
- {
- isdnloop_card *card = (isdnloop_card *) data;
- isdnloop_atimeout(card, 1);
- }
- /*
- * Install a watchdog for a user, not responding.
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel to watch for.
- */
- static void
- isdnloop_start_ctimer(isdnloop_card * card, int ch)
- {
- unsigned long flags;
- save_flags(flags);
- cli();
- init_timer(&card->c_timer[ch]);
- card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT;
- if (ch)
- card->c_timer[ch].function = isdnloop_atimeout1;
- else
- card->c_timer[ch].function = isdnloop_atimeout0;
- card->c_timer[ch].data = (unsigned long) card;
- add_timer(&card->c_timer[ch]);
- restore_flags(flags);
- }
- /*
- * Kill a pending channel watchdog.
- *
- * Parameter:
- * card = pointer to card struct.
- * ch = channel (0-based).
- */
- static void
- isdnloop_kill_ctimer(isdnloop_card * card, int ch)
- {
- unsigned long flags;
- save_flags(flags);
- cli();
- del_timer(&card->c_timer[ch]);
- restore_flags(flags);
- }
- static u_char si2bit[] =
- {0, 1, 0, 0, 0, 2, 0, 4, 0, 0};
- static u_char bit2si[] =
- {1, 5, 7};
- /*
- * Try finding a listener for an outgoing call.
- *
- * Parameter:
- * card = pointer to calling card.
- * p = pointer to ICN-type setup-string.
- * lch = channel of calling card.
- * cmd = pointer to struct to be filled when parsing setup.
- * Return:
- * 0 = found match, alerting should happen.
- * 1 = found matching number but it is busy.
- * 2 = no matching listener.
- * 3 = found matching number but SI does not match.
- */
- static int
- isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd)
- {
- isdnloop_card *cc = cards;
- unsigned long flags;
- int ch;
- int num_match;
- int i;
- char *e;
- char nbuf[32];
- isdnloop_parse_setup(p, cmd);
- while (cc) {
- for (ch = 0; ch < 2; ch++) {
- /* Exclude ourself */
- if ((cc == card) && (ch == lch))
- continue;
- num_match = 0;
- switch (cc->ptype) {
- case ISDN_PTYPE_EURO:
- for (i = 0; i < 3; i++)
- if (!(strcmp(cc->s0num[i], cmd->parm.setup.phone)))
- num_match = 1;
- break;
- case ISDN_PTYPE_1TR6:
- e = cc->eazlist[ch];
- while (*e) {
- sprintf(nbuf, "%s%c", cc->s0num[0], *e);
- if (!(strcmp(nbuf, cmd->parm.setup.phone)))
- num_match = 1;
- e++;
- }
- }
- if (num_match) {
- save_flags(flags);
- cli();
- /* channel idle? */
- if (!(cc->rcard[ch])) {
- /* Check SI */
- if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) {
- restore_flags(flags);
- return 3;
- }
- /* ch is idle, si and number matches */
- cc->rcard[ch] = card;
- cc->rch[ch] = lch;
- card->rcard[lch] = cc;
- card->rch[lch] = ch;
- restore_flags(flags);
- return 0;
- } else {
- restore_flags(flags);
- /* num matches, but busy */
- if (ch == 1)
- return 1;
- }
- }
- }
- cc = cc->next;
- }
- return 2;
- }
- /*
- * Depending on D-channel protocol and caller/called, modify
- * phone number.
- *
- * Parameter:
- * card = pointer to card struct.
- * phone = pointer phone number.
- * caller = flag: 1 = caller, 0 = called.
- * Return:
- * pointer to new phone number.
- */
- static char *
- isdnloop_vstphone(isdnloop_card * card, char *phone, int caller)
- {
- int i;
- static char nphone[30];
- switch (card->ptype) {
- case ISDN_PTYPE_EURO:
- if (caller) {
- for (i = 0; i < 2; i++)
- if (!(strcmp(card->s0num[i], phone)))
- return (phone);
- return (card->s0num[0]);
- }
- return (phone);
- break;
- case ISDN_PTYPE_1TR6:
- if (caller) {
- sprintf(nphone, "%s%c", card->s0num[0], phone[0]);
- return (nphone);
- } else
- return (&phone[strlen(phone) - 1]);
- break;
- }
- return ("