Esempio n. 1
0
/*
 * 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 int
isdnloop_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;
	spin_lock_irqsave(&card->isdnloop_lock, flags);
	switch (sdef.ptype) {
	case ISDN_PTYPE_EURO:
		if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96",
				  -1)) {
			spin_unlock_irqrestore(&card->isdnloop_lock, flags);
			return -ENOMEM;
		}
		card->sil[0] = card->sil[1] = 4;
		if (isdnloop_fake(card, "TEI OK", 0)) {
			spin_unlock_irqrestore(&card->isdnloop_lock, flags);
			return -ENOMEM;
		}
		for (i = 0; i < 3; i++) {
			strlcpy(card->s0num[i], sdef.num[i],
				sizeof(card->s0num[0]));
		}
		break;
	case ISDN_PTYPE_1TR6:
		if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
				  -1)) {
			spin_unlock_irqrestore(&card->isdnloop_lock, flags);
			return -ENOMEM;
		}
		card->sil[0] = card->sil[1] = 4;
		if (isdnloop_fake(card, "TEI OK", 0)) {
			spin_unlock_irqrestore(&card->isdnloop_lock, flags);
			return -ENOMEM;
		}
		strlcpy(card->s0num[0], sdef.num[0], sizeof(card->s0num[0]));
		card->s0num[1][0] = '\0';
		card->s0num[2][0] = '\0';
		break;
	default:
		spin_unlock_irqrestore(&card->isdnloop_lock, 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;
	spin_unlock_irqrestore(&card->isdnloop_lock, flags);
	return 0;
}
/*
 * 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 void
isdnloop_atimeout(isdnloop_card *card, int ch)
{
	unsigned long flags;
	char buf[60];

	spin_lock_irqsave(&card->isdnloop_lock, flags);
	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);
	
	sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3));
	isdnloop_fake(card, buf, ch + 1);
	spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
/*
 * 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);
}
/*
 * Parse an ICN-type command string sent to the 'card'.
 * Perform misc. actions depending on the command.
 *
 * Parameter:
 *   card = pointer to card struct.
 */
static void
isdnloop_parse_cmd(isdnloop_card * card)
{
	char *p = card->omsg;
	isdn_ctrl cmd;
	char buf[60];
	isdnloop_stat *s = isdnloop_cmd_table;
	int action = -1;
	int i;
	int ch;

	if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) {
		isdnloop_fake_err(card);
		return;
	}
	ch = card->omsg[1] - '0';
	if ((ch < 0) || (ch > 2)) {
		isdnloop_fake_err(card);
		return;
	}
	p += 3;
	while (s->statstr) {
		if (!strncmp(p, s->statstr, strlen(s->statstr))) {
			action = s->action;
			if (s->command && (ch != 0)) {
				isdnloop_fake_err(card);
				return;
			}
			break;
		}
		s++;
	}
	if (action == -1)
		return;
	switch (action) {
		case 1:
			/* 0x;BCON_R */
			if (card->rcard[ch - 1]) {
				isdnloop_fake(card->rcard[ch - 1], "BCON_I",
					      card->rch[ch - 1] + 1);
				isdnloop_fake(card, "BCON_C", ch);
			}
			break;
		case 17:
			/* 0x;BCON_I */
			if (card->rcard[ch - 1]) {
				isdnloop_fake(card->rcard[ch - 1], "BCON_C",
					      card->rch[ch - 1] + 1);
			}
			break;
		case 2:
			/* 0x;BDIS_R */
			isdnloop_fake(card, "BDIS_C", ch);
			if (card->rcard[ch - 1]) {
				isdnloop_fake(card->rcard[ch - 1], "BDIS_I",
					      card->rch[ch - 1] + 1);
			}
			break;
		case 16:
			/* 0x;DCON_R */
			isdnloop_kill_ctimer(card, ch - 1);
			if (card->rcard[ch - 1]) {
				isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
				isdnloop_fake(card->rcard[ch - 1], "DCON_C",
					      card->rch[ch - 1] + 1);
				isdnloop_fake(card, "DCON_C", ch);
			}
			break;
		case 3:
			/* 0x;DDIS_R */
			isdnloop_kill_ctimer(card, ch - 1);
			if (card->rcard[ch - 1]) {
				isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
				isdnloop_fake(card->rcard[ch - 1], "DDIS_I",
					      card->rch[ch - 1] + 1);
				card->rcard[ch - 1] = NULL;
			}
			isdnloop_fake(card, "DDIS_C", ch);
			break;
		case 4:
			/* 0x;DSCA_Rdd,yy,zz,oo */
			if (card->ptype != ISDN_PTYPE_1TR6) {
				isdnloop_fake_err(card);
				return;
			}
			/* Fall through */
		case 5:
			/* 0x;DCAL_Rdd,yy,zz,oo */
			p += 6;
			switch (isdnloop_try_call(card, p, ch - 1, &cmd)) {
				case 0:
					/* Alerting */
					sprintf(buf, "D%s_I%s,%02d,%02d,%s",
					   (action == 4) ? "SCA" : "CAL",
						isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1),
						cmd.parm.setup.si1,
						cmd.parm.setup.si2,
					isdnloop_vstphone(card->rcard[ch - 1],
					       cmd.parm.setup.phone, 0));
					isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1);
					/* Fall through */
				case 3:
					/* si1 does not match, don't alert but start timer */
					isdnloop_start_ctimer(card, ch - 1);
					break;
				case 1:
					/* Remote busy */
					isdnloop_fake(card, "DDIS_I", ch);
					sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1));
					isdnloop_fake(card, buf, ch);
					break;
				case 2:
					/* No such user */
					isdnloop_fake(card, "DDIS_I", ch);
					sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2));
					isdnloop_fake(card, buf, ch);
					break;
			}
			break;
		case 6:
			/* 0x;EAZC */
			card->eazlist[ch - 1][0] = '\0';
			break;
		case 7:
			/* 0x;EAZ */
			p += 3;
			strcpy(card->eazlist[ch - 1], p);
			break;
		case 8:
			/* 0x;SEEAZ */
			sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]);
			isdnloop_fake(card, buf, ch + 1);
			break;
		case 9:
			/* 0x;MSN */
			break;
		case 10:
			/* 0x;MSNALL */
			break;
		case 11:
			/* 0x;SETSIL */
			p += 6;
			i = 0;
			while (strchr("0157", *p)) {
				if (i)
					card->sil[ch - 1] |= si2bit[*p - '0'];
				i = (*p++ == '0');
			}
			if (*p)
				isdnloop_fake_err(card);
			break;
		case 12:
			/* 0x;SEESIL */
			sprintf(buf, "SIN-LIST: ");
			p = buf + 10;
			for (i = 0; i < 3; i++)
				if (card->sil[ch - 1] & (1 << i))
					p += sprintf(p, "%02d", bit2si[i]);
			isdnloop_fake(card, buf, ch + 1);
			break;
		case 13:
			/* 0x;SILC */
			card->sil[ch - 1] = 0;
			break;
		case 14:
			/* 00;FV2ON */
			break;
		case 15:
			/* 00;FV2OFF */
			break;
	}
}
static void
isdnloop_parse_cmd(isdnloop_card *card)
{
	char *p = card->omsg;
	isdn_ctrl cmd;
	char buf[60];
	isdnloop_stat *s = isdnloop_cmd_table;
	int action = -1;
	int i;
	int ch;

	if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) {
		isdnloop_fake_err(card);
		return;
	}
	ch = card->omsg[1] - '0';
	if ((ch < 0) || (ch > 2)) {
		isdnloop_fake_err(card);
		return;
	}
	p += 3;
	while (s->statstr) {
		if (!strncmp(p, s->statstr, strlen(s->statstr))) {
			action = s->action;
			if (s->command && (ch != 0)) {
				isdnloop_fake_err(card);
				return;
			}
			break;
		}
		s++;
	}
	if (action == -1)
		return;
	switch (action) {
	case 1:
		
		if (card->rcard[ch - 1]) {
			isdnloop_fake(card->rcard[ch - 1], "BCON_I",
				      card->rch[ch - 1] + 1);
			isdnloop_fake(card, "BCON_C", ch);
		}
		break;
	case 17:
		
		if (card->rcard[ch - 1]) {
			isdnloop_fake(card->rcard[ch - 1], "BCON_C",
				      card->rch[ch - 1] + 1);
		}
		break;
	case 2:
		
		isdnloop_fake(card, "BDIS_C", ch);
		if (card->rcard[ch - 1]) {
			isdnloop_fake(card->rcard[ch - 1], "BDIS_I",
				      card->rch[ch - 1] + 1);
		}
		break;
	case 16:
		
		isdnloop_kill_ctimer(card, ch - 1);
		if (card->rcard[ch - 1]) {
			isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
			isdnloop_fake(card->rcard[ch - 1], "DCON_C",
				      card->rch[ch - 1] + 1);
			isdnloop_fake(card, "DCON_C", ch);
		}
		break;
	case 3:
		
		isdnloop_kill_ctimer(card, ch - 1);
		if (card->rcard[ch - 1]) {
			isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]);
			isdnloop_fake(card->rcard[ch - 1], "DDIS_I",
				      card->rch[ch - 1] + 1);
			card->rcard[ch - 1] = NULL;
		}
		isdnloop_fake(card, "DDIS_C", ch);
		break;
	case 4:
		
		if (card->ptype != ISDN_PTYPE_1TR6) {
			isdnloop_fake_err(card);
			return;
		}
		
	case 5:
		
		p += 6;
		switch (isdnloop_try_call(card, p, ch - 1, &cmd)) {
		case 0:
			
			sprintf(buf, "D%s_I%s,%02d,%02d,%s",
				(action == 4) ? "SCA" : "CAL",
				isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1),
				cmd.parm.setup.si1,
				cmd.parm.setup.si2,
				isdnloop_vstphone(card->rcard[ch - 1],
						  cmd.parm.setup.phone, 0));
			isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1);
			
		case 3:
			
			isdnloop_start_ctimer(card, ch - 1);
			break;
		case 1:
			
			isdnloop_fake(card, "DDIS_I", ch);
			sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1));
			isdnloop_fake(card, buf, ch);
			break;
		case 2:
			
			isdnloop_fake(card, "DDIS_I", ch);
			sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2));
			isdnloop_fake(card, buf, ch);
			break;
		}
		break;
	case 6:
		
		card->eazlist[ch - 1][0] = '\0';
		break;
	case 7:
		
		p += 3;
		strcpy(card->eazlist[ch - 1], p);
		break;
	case 8:
		
		sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]);
		isdnloop_fake(card, buf, ch + 1);
		break;
	case 9:
		
		break;
	case 10:
		
		break;
	case 11:
		
		p += 6;
		i = 0;
		while (strchr("0157", *p)) {
			if (i)
				card->sil[ch - 1] |= si2bit[*p - '0'];
			i = (*p++ == '0');
		}
		if (*p)
			isdnloop_fake_err(card);
		break;
	case 12:
		
		sprintf(buf, "SIN-LIST: ");
		p = buf + 10;
		for (i = 0; i < 3; i++)
			if (card->sil[ch - 1] & (1 << i))
				p += sprintf(p, "%02d", bit2si[i]);
		isdnloop_fake(card, buf, ch + 1);
		break;
	case 13:
		
		card->sil[ch - 1] = 0;
		break;
	case 14:
		
		break;
	case 15:
		
		break;
	}
}