Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.2 1528 lines 39 kB view raw
1/* $Id: isdnloop.c,v 1.11.6.7 2001/11/11 19:54:31 kai Exp $ 2 * 3 * ISDN low-level module implementing a dummy loop driver. 4 * 5 * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de) 6 * 7 * This software may be used and distributed according to the terms 8 * of the GNU General Public License, incorporated herein by reference. 9 * 10 */ 11 12#include <linux/module.h> 13#include <linux/interrupt.h> 14#include <linux/slab.h> 15#include <linux/init.h> 16#include <linux/sched.h> 17#include "isdnloop.h" 18 19static char *isdnloop_id = "loop0"; 20 21MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card"); 22MODULE_AUTHOR("Fritz Elfert"); 23MODULE_LICENSE("GPL"); 24module_param(isdnloop_id, charp, 0); 25MODULE_PARM_DESC(isdnloop_id, "ID-String of first card"); 26 27static int isdnloop_addcard(char *); 28 29/* 30 * Free queue completely. 31 * 32 * Parameter: 33 * card = pointer to card struct 34 * channel = channel number 35 */ 36static void 37isdnloop_free_queue(isdnloop_card *card, int channel) 38{ 39 struct sk_buff_head *queue = &card->bqueue[channel]; 40 41 skb_queue_purge(queue); 42 card->sndcount[channel] = 0; 43} 44 45/* 46 * Send B-Channel data to another virtual card. 47 * This routine is called via timer-callback from isdnloop_pollbchan(). 48 * 49 * Parameter: 50 * card = pointer to card struct. 51 * ch = channel number (0-based) 52 */ 53static void 54isdnloop_bchan_send(isdnloop_card *card, int ch) 55{ 56 isdnloop_card *rcard = card->rcard[ch]; 57 int rch = card->rch[ch], len, ack; 58 struct sk_buff *skb; 59 isdn_ctrl cmd; 60 61 while (card->sndcount[ch]) { 62 skb = skb_dequeue(&card->bqueue[ch]); 63 if (skb) { 64 len = skb->len; 65 card->sndcount[ch] -= len; 66 ack = *(skb->head); /* used as scratch area */ 67 cmd.driver = card->myid; 68 cmd.arg = ch; 69 if (rcard) { 70 rcard->interface.rcvcallb_skb(rcard->myid, rch, skb); 71 } else { 72 printk(KERN_WARNING "isdnloop: no rcard, skb dropped\n"); 73 dev_kfree_skb(skb); 74 75 } 76 cmd.command = ISDN_STAT_BSENT; 77 cmd.parm.length = len; 78 card->interface.statcallb(&cmd); 79 } else 80 card->sndcount[ch] = 0; 81 } 82} 83 84/* 85 * Send/Receive Data to/from the B-Channel. 86 * This routine is called via timer-callback. 87 * It schedules itself while any B-Channel is open. 88 * 89 * Parameter: 90 * data = pointer to card struct, set by kernel timer.data 91 */ 92static void 93isdnloop_pollbchan(struct timer_list *t) 94{ 95 isdnloop_card *card = from_timer(card, t, rb_timer); 96 unsigned long flags; 97 98 if (card->flags & ISDNLOOP_FLAGS_B1ACTIVE) 99 isdnloop_bchan_send(card, 0); 100 if (card->flags & ISDNLOOP_FLAGS_B2ACTIVE) 101 isdnloop_bchan_send(card, 1); 102 if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) { 103 /* schedule b-channel polling again */ 104 spin_lock_irqsave(&card->isdnloop_lock, flags); 105 card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; 106 add_timer(&card->rb_timer); 107 card->flags |= ISDNLOOP_FLAGS_RBTIMER; 108 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 109 } else 110 card->flags &= ~ISDNLOOP_FLAGS_RBTIMER; 111} 112 113/* 114 * Parse ICN-type setup string and fill fields of setup-struct 115 * with parsed data. 116 * 117 * Parameter: 118 * setup = setup string, format: [caller-id],si1,si2,[called-id] 119 * cmd = pointer to struct to be filled. 120 */ 121static void 122isdnloop_parse_setup(char *setup, isdn_ctrl *cmd) 123{ 124 char *t = setup; 125 char *s = strchr(t, ','); 126 127 *s++ = '\0'; 128 strlcpy(cmd->parm.setup.phone, t, sizeof(cmd->parm.setup.phone)); 129 s = strchr(t = s, ','); 130 *s++ = '\0'; 131 if (!strlen(t)) 132 cmd->parm.setup.si1 = 0; 133 else 134 cmd->parm.setup.si1 = simple_strtoul(t, NULL, 10); 135 s = strchr(t = s, ','); 136 *s++ = '\0'; 137 if (!strlen(t)) 138 cmd->parm.setup.si2 = 0; 139 else 140 cmd->parm.setup.si2 = 141 simple_strtoul(t, NULL, 10); 142 strlcpy(cmd->parm.setup.eazmsn, s, sizeof(cmd->parm.setup.eazmsn)); 143 cmd->parm.setup.plan = 0; 144 cmd->parm.setup.screen = 0; 145} 146 147typedef struct isdnloop_stat { 148 char *statstr; 149 int command; 150 int action; 151} isdnloop_stat; 152/* *INDENT-OFF* */ 153static isdnloop_stat isdnloop_stat_table[] = { 154 {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */ 155 {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */ 156 {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */ 157 {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */ 158 {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */ 159 {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */ 160 {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */ 161 {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */ 162 {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */ 163 {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */ 164 {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */ 165 {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ 166 {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */ 167 {"E_L1: ACTIVATION FAILED", 168 ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ 169 {NULL, 0, -1} 170}; 171/* *INDENT-ON* */ 172 173 174/* 175 * Parse Status message-strings from virtual card. 176 * Depending on status, call statcallb for sending messages to upper 177 * levels. Also set/reset B-Channel active-flags. 178 * 179 * Parameter: 180 * status = status string to parse. 181 * channel = channel where message comes from. 182 * card = card where message comes from. 183 */ 184static void 185isdnloop_parse_status(u_char *status, int channel, isdnloop_card *card) 186{ 187 isdnloop_stat *s = isdnloop_stat_table; 188 int action = -1; 189 isdn_ctrl cmd; 190 191 while (s->statstr) { 192 if (!strncmp(status, s->statstr, strlen(s->statstr))) { 193 cmd.command = s->command; 194 action = s->action; 195 break; 196 } 197 s++; 198 } 199 if (action == -1) 200 return; 201 cmd.driver = card->myid; 202 cmd.arg = channel; 203 switch (action) { 204 case 1: 205 /* BCON_x */ 206 card->flags |= (channel) ? 207 ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE; 208 break; 209 case 2: 210 /* BDIS_x */ 211 card->flags &= ~((channel) ? 212 ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE); 213 isdnloop_free_queue(card, channel); 214 break; 215 case 3: 216 /* DCAL_I and DSCA_I */ 217 isdnloop_parse_setup(status + 6, &cmd); 218 break; 219 case 4: 220 /* FCALL */ 221 sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid); 222 sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1); 223 cmd.parm.setup.si1 = 7; 224 cmd.parm.setup.si2 = 0; 225 cmd.parm.setup.plan = 0; 226 cmd.parm.setup.screen = 0; 227 break; 228 case 5: 229 /* CIF */ 230 strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num)); 231 break; 232 case 6: 233 /* AOC */ 234 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d", 235 (int) simple_strtoul(status + 7, NULL, 16)); 236 break; 237 case 7: 238 /* CAU */ 239 status += 3; 240 if (strlen(status) == 4) 241 snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c", 242 status + 2, *status, *(status + 1)); 243 else 244 strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num)); 245 break; 246 case 8: 247 /* Misc Errors on L1 and L2 */ 248 card->flags &= ~ISDNLOOP_FLAGS_B1ACTIVE; 249 isdnloop_free_queue(card, 0); 250 cmd.arg = 0; 251 cmd.driver = card->myid; 252 card->interface.statcallb(&cmd); 253 cmd.command = ISDN_STAT_DHUP; 254 cmd.arg = 0; 255 cmd.driver = card->myid; 256 card->interface.statcallb(&cmd); 257 cmd.command = ISDN_STAT_BHUP; 258 card->flags &= ~ISDNLOOP_FLAGS_B2ACTIVE; 259 isdnloop_free_queue(card, 1); 260 cmd.arg = 1; 261 cmd.driver = card->myid; 262 card->interface.statcallb(&cmd); 263 cmd.command = ISDN_STAT_DHUP; 264 cmd.arg = 1; 265 cmd.driver = card->myid; 266 break; 267 } 268 card->interface.statcallb(&cmd); 269} 270 271/* 272 * Store a cwcharacter into ringbuffer for reading from /dev/isdnctrl 273 * 274 * Parameter: 275 * card = pointer to card struct. 276 * c = char to store. 277 */ 278static void 279isdnloop_putmsg(isdnloop_card *card, unsigned char c) 280{ 281 ulong flags; 282 283 spin_lock_irqsave(&card->isdnloop_lock, flags); 284 *card->msg_buf_write++ = (c == 0xff) ? '\n' : c; 285 if (card->msg_buf_write == card->msg_buf_read) { 286 if (++card->msg_buf_read > card->msg_buf_end) 287 card->msg_buf_read = card->msg_buf; 288 } 289 if (card->msg_buf_write > card->msg_buf_end) 290 card->msg_buf_write = card->msg_buf; 291 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 292} 293 294/* 295 * Poll a virtual cards message queue. 296 * If there are new status-replies from the card, copy them to 297 * ringbuffer for reading on /dev/isdnctrl and call 298 * isdnloop_parse_status() for processing them. Watch for special 299 * Firmware bootmessage and parse it, to get the D-Channel protocol. 300 * If there are B-Channels open, initiate a timer-callback to 301 * isdnloop_pollbchan(). 302 * This routine is called periodically via timer interrupt. 303 * 304 * Parameter: 305 * data = pointer to card struct 306 */ 307static void 308isdnloop_polldchan(struct timer_list *t) 309{ 310 isdnloop_card *card = from_timer(card, t, st_timer); 311 struct sk_buff *skb; 312 int avail; 313 int left; 314 u_char c; 315 int ch; 316 unsigned long flags; 317 u_char *p; 318 isdn_ctrl cmd; 319 320 skb = skb_dequeue(&card->dqueue); 321 if (skb) 322 avail = skb->len; 323 else 324 avail = 0; 325 for (left = avail; left > 0; left--) { 326 c = *skb->data; 327 skb_pull(skb, 1); 328 isdnloop_putmsg(card, c); 329 card->imsg[card->iptr] = c; 330 if (card->iptr < 59) 331 card->iptr++; 332 if (!skb->len) { 333 avail++; 334 isdnloop_putmsg(card, '\n'); 335 card->imsg[card->iptr] = 0; 336 card->iptr = 0; 337 if (card->imsg[0] == '0' && card->imsg[1] >= '0' && 338 card->imsg[1] <= '2' && card->imsg[2] == ';') { 339 ch = (card->imsg[1] - '0') - 1; 340 p = &card->imsg[3]; 341 isdnloop_parse_status(p, ch, card); 342 } else { 343 p = card->imsg; 344 if (!strncmp(p, "DRV1.", 5)) { 345 printk(KERN_INFO "isdnloop: (%s) %s\n", CID, p); 346 if (!strncmp(p + 7, "TC", 2)) { 347 card->ptype = ISDN_PTYPE_1TR6; 348 card->interface.features |= ISDN_FEATURE_P_1TR6; 349 printk(KERN_INFO 350 "isdnloop: (%s) 1TR6-Protocol loaded and running\n", CID); 351 } 352 if (!strncmp(p + 7, "EC", 2)) { 353 card->ptype = ISDN_PTYPE_EURO; 354 card->interface.features |= ISDN_FEATURE_P_EURO; 355 printk(KERN_INFO 356 "isdnloop: (%s) Euro-Protocol loaded and running\n", CID); 357 } 358 continue; 359 360 } 361 } 362 } 363 } 364 if (avail) { 365 cmd.command = ISDN_STAT_STAVAIL; 366 cmd.driver = card->myid; 367 cmd.arg = avail; 368 card->interface.statcallb(&cmd); 369 } 370 if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) 371 if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) { 372 /* schedule b-channel polling */ 373 card->flags |= ISDNLOOP_FLAGS_RBTIMER; 374 spin_lock_irqsave(&card->isdnloop_lock, flags); 375 del_timer(&card->rb_timer); 376 card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; 377 add_timer(&card->rb_timer); 378 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 379 } 380 /* schedule again */ 381 spin_lock_irqsave(&card->isdnloop_lock, flags); 382 card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD; 383 add_timer(&card->st_timer); 384 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 385} 386 387/* 388 * Append a packet to the transmit buffer-queue. 389 * 390 * Parameter: 391 * channel = Number of B-channel 392 * skb = packet to send. 393 * card = pointer to card-struct 394 * Return: 395 * Number of bytes transferred, -E??? on error 396 */ 397static int 398isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card *card) 399{ 400 int len = skb->len; 401 unsigned long flags; 402 struct sk_buff *nskb; 403 404 if (len > 4000) { 405 printk(KERN_WARNING 406 "isdnloop: Send packet too large\n"); 407 return -EINVAL; 408 } 409 if (len) { 410 if (!(card->flags & (channel ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE))) 411 return 0; 412 if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE) 413 return 0; 414 spin_lock_irqsave(&card->isdnloop_lock, flags); 415 nskb = dev_alloc_skb(skb->len); 416 if (nskb) { 417 skb_copy_from_linear_data(skb, 418 skb_put(nskb, len), len); 419 skb_queue_tail(&card->bqueue[channel], nskb); 420 dev_kfree_skb(skb); 421 } else 422 len = 0; 423 card->sndcount[channel] += len; 424 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 425 } 426 return len; 427} 428 429/* 430 * Read the messages from the card's ringbuffer 431 * 432 * Parameter: 433 * buf = pointer to buffer. 434 * len = number of bytes to read. 435 * user = flag, 1: called from userlevel 0: called from kernel. 436 * card = pointer to card struct. 437 * Return: 438 * number of bytes actually transferred. 439 */ 440static int 441isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card *card) 442{ 443 int count; 444 u_char __user *p; 445 446 for (p = buf, count = 0; count < len; p++, count++) { 447 if (card->msg_buf_read == card->msg_buf_write) 448 return count; 449 if (put_user(*card->msg_buf_read++, p)) 450 return -EFAULT; 451 if (card->msg_buf_read > card->msg_buf_end) 452 card->msg_buf_read = card->msg_buf; 453 } 454 return count; 455} 456 457/* 458 * Simulate a card's response by appending it to the cards 459 * message queue. 460 * 461 * Parameter: 462 * card = pointer to card struct. 463 * s = pointer to message-string. 464 * ch = channel: 0 = generic messages, 1 and 2 = D-channel messages. 465 * Return: 466 * 0 on success, 1 on memory squeeze. 467 */ 468static int 469isdnloop_fake(isdnloop_card *card, char *s, int ch) 470{ 471 struct sk_buff *skb; 472 int len = strlen(s) + ((ch >= 0) ? 3 : 0); 473 skb = dev_alloc_skb(len); 474 if (!skb) { 475 printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n"); 476 return 1; 477 } 478 if (ch >= 0) 479 sprintf(skb_put(skb, 3), "%02d;", ch); 480 skb_put_data(skb, s, strlen(s)); 481 skb_queue_tail(&card->dqueue, skb); 482 return 0; 483} 484/* *INDENT-OFF* */ 485static isdnloop_stat isdnloop_cmd_table[] = { 486 {"BCON_R", 0, 1}, /* B-Channel connect */ 487 {"BCON_I", 0, 17}, /* B-Channel connect ind */ 488 {"BDIS_R", 0, 2}, /* B-Channel disconnect */ 489 {"DDIS_R", 0, 3}, /* D-Channel disconnect */ 490 {"DCON_R", 0, 16}, /* D-Channel connect */ 491 {"DSCA_R", 0, 4}, /* Dial 1TR6-SPV */ 492 {"DCAL_R", 0, 5}, /* Dial */ 493 {"EAZC", 0, 6}, /* Clear EAZ listener */ 494 {"EAZ", 0, 7}, /* Set EAZ listener */ 495 {"SEEAZ", 0, 8}, /* Get EAZ listener */ 496 {"MSN", 0, 9}, /* Set/Clear MSN listener */ 497 {"MSALL", 0, 10}, /* Set multi MSN listeners */ 498 {"SETSIL", 0, 11}, /* Set SI list */ 499 {"SEESIL", 0, 12}, /* Get SI list */ 500 {"SILC", 0, 13}, /* Clear SI list */ 501 {"LOCK", 0, -1}, /* LOCK channel */ 502 {"UNLOCK", 0, -1}, /* UNLOCK channel */ 503 {"FV2ON", 1, 14}, /* Leased mode on */ 504 {"FV2OFF", 1, 15}, /* Leased mode off */ 505 {NULL, 0, -1} 506}; 507/* *INDENT-ON* */ 508 509 510/* 511 * Simulate an error-response from a card. 512 * 513 * Parameter: 514 * card = pointer to card struct. 515 */ 516static void 517isdnloop_fake_err(isdnloop_card *card) 518{ 519 char buf[64]; 520 521 snprintf(buf, sizeof(buf), "E%s", card->omsg); 522 isdnloop_fake(card, buf, -1); 523 isdnloop_fake(card, "NAK", -1); 524} 525 526static u_char ctable_eu[] = {0x00, 0x11, 0x01, 0x12}; 527static u_char ctable_1t[] = {0x00, 0x3b, 0x01, 0x3a}; 528 529/* 530 * Assemble a simplified cause message depending on the 531 * D-channel protocol used. 532 * 533 * Parameter: 534 * card = pointer to card struct. 535 * loc = location: 0 = local, 1 = remote. 536 * cau = cause: 1 = busy, 2 = nonexistent callerid, 3 = no user responding. 537 * Return: 538 * Pointer to buffer containing the assembled message. 539 */ 540static char * 541isdnloop_unicause(isdnloop_card *card, int loc, int cau) 542{ 543 static char buf[6]; 544 545 switch (card->ptype) { 546 case ISDN_PTYPE_EURO: 547 sprintf(buf, "E%02X%02X", (loc) ? 4 : 2, ctable_eu[cau]); 548 break; 549 case ISDN_PTYPE_1TR6: 550 sprintf(buf, "%02X44", ctable_1t[cau]); 551 break; 552 default: 553 return "0000"; 554 } 555 return buf; 556} 557 558/* 559 * Release a virtual connection. Called from timer interrupt, when 560 * called party did not respond. 561 * 562 * Parameter: 563 * card = pointer to card struct. 564 * ch = channel (0-based) 565 */ 566static void 567isdnloop_atimeout(isdnloop_card *card, int ch) 568{ 569 unsigned long flags; 570 char buf[60]; 571 572 spin_lock_irqsave(&card->isdnloop_lock, flags); 573 if (card->rcard[ch]) { 574 isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1); 575 card->rcard[ch]->rcard[card->rch[ch]] = NULL; 576 card->rcard[ch] = NULL; 577 } 578 isdnloop_fake(card, "DDIS_I", ch + 1); 579 /* No user responding */ 580 sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3)); 581 isdnloop_fake(card, buf, ch + 1); 582 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 583} 584 585/* 586 * Wrapper for isdnloop_atimeout(). 587 */ 588static void 589isdnloop_atimeout0(struct timer_list *t) 590{ 591 isdnloop_card *card = from_timer(card, t, c_timer[0]); 592 593 isdnloop_atimeout(card, 0); 594} 595 596/* 597 * Wrapper for isdnloop_atimeout(). 598 */ 599static void 600isdnloop_atimeout1(struct timer_list *t) 601{ 602 isdnloop_card *card = from_timer(card, t, c_timer[1]); 603 604 isdnloop_atimeout(card, 1); 605} 606 607/* 608 * Install a watchdog for a user, not responding. 609 * 610 * Parameter: 611 * card = pointer to card struct. 612 * ch = channel to watch for. 613 */ 614static void 615isdnloop_start_ctimer(isdnloop_card *card, int ch) 616{ 617 unsigned long flags; 618 619 spin_lock_irqsave(&card->isdnloop_lock, flags); 620 timer_setup(&card->c_timer[ch], ch ? isdnloop_atimeout1 621 : isdnloop_atimeout0, 0); 622 card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT; 623 add_timer(&card->c_timer[ch]); 624 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 625} 626 627/* 628 * Kill a pending channel watchdog. 629 * 630 * Parameter: 631 * card = pointer to card struct. 632 * ch = channel (0-based). 633 */ 634static void 635isdnloop_kill_ctimer(isdnloop_card *card, int ch) 636{ 637 unsigned long flags; 638 639 spin_lock_irqsave(&card->isdnloop_lock, flags); 640 del_timer(&card->c_timer[ch]); 641 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 642} 643 644static u_char si2bit[] = {0, 1, 0, 0, 0, 2, 0, 4, 0, 0}; 645static u_char bit2si[] = {1, 5, 7}; 646 647/* 648 * Try finding a listener for an outgoing call. 649 * 650 * Parameter: 651 * card = pointer to calling card. 652 * p = pointer to ICN-type setup-string. 653 * lch = channel of calling card. 654 * cmd = pointer to struct to be filled when parsing setup. 655 * Return: 656 * 0 = found match, alerting should happen. 657 * 1 = found matching number but it is busy. 658 * 2 = no matching listener. 659 * 3 = found matching number but SI does not match. 660 */ 661static int 662isdnloop_try_call(isdnloop_card *card, char *p, int lch, isdn_ctrl *cmd) 663{ 664 isdnloop_card *cc = cards; 665 unsigned long flags; 666 int ch; 667 int num_match; 668 int i; 669 char *e; 670 char nbuf[32]; 671 672 isdnloop_parse_setup(p, cmd); 673 while (cc) { 674 for (ch = 0; ch < 2; ch++) { 675 /* Exclude ourself */ 676 if ((cc == card) && (ch == lch)) 677 continue; 678 num_match = 0; 679 switch (cc->ptype) { 680 case ISDN_PTYPE_EURO: 681 for (i = 0; i < 3; i++) 682 if (!(strcmp(cc->s0num[i], cmd->parm.setup.phone))) 683 num_match = 1; 684 break; 685 case ISDN_PTYPE_1TR6: 686 e = cc->eazlist[ch]; 687 while (*e) { 688 sprintf(nbuf, "%s%c", cc->s0num[0], *e); 689 if (!(strcmp(nbuf, cmd->parm.setup.phone))) 690 num_match = 1; 691 e++; 692 } 693 } 694 if (num_match) { 695 spin_lock_irqsave(&card->isdnloop_lock, flags); 696 /* channel idle? */ 697 if (!(cc->rcard[ch])) { 698 /* Check SI */ 699 if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) { 700 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 701 return 3; 702 } 703 /* ch is idle, si and number matches */ 704 cc->rcard[ch] = card; 705 cc->rch[ch] = lch; 706 card->rcard[lch] = cc; 707 card->rch[lch] = ch; 708 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 709 return 0; 710 } else { 711 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 712 /* num matches, but busy */ 713 if (ch == 1) 714 return 1; 715 } 716 } 717 } 718 cc = cc->next; 719 } 720 return 2; 721} 722 723/* 724 * Depending on D-channel protocol and caller/called, modify 725 * phone number. 726 * 727 * Parameter: 728 * card = pointer to card struct. 729 * phone = pointer phone number. 730 * caller = flag: 1 = caller, 0 = called. 731 * Return: 732 * pointer to new phone number. 733 */ 734static char * 735isdnloop_vstphone(isdnloop_card *card, char *phone, int caller) 736{ 737 int i; 738 static char nphone[30]; 739 740 if (!card) { 741 printk("BUG!!!\n"); 742 return ""; 743 } 744 switch (card->ptype) { 745 case ISDN_PTYPE_EURO: 746 if (caller) { 747 for (i = 0; i < 2; i++) 748 if (!(strcmp(card->s0num[i], phone))) 749 return phone; 750 return card->s0num[0]; 751 } 752 return phone; 753 break; 754 case ISDN_PTYPE_1TR6: 755 if (caller) { 756 sprintf(nphone, "%s%c", card->s0num[0], phone[0]); 757 return nphone; 758 } else 759 return &phone[strlen(phone) - 1]; 760 break; 761 } 762 return ""; 763} 764 765/* 766 * Parse an ICN-type command string sent to the 'card'. 767 * Perform misc. actions depending on the command. 768 * 769 * Parameter: 770 * card = pointer to card struct. 771 */ 772static void 773isdnloop_parse_cmd(isdnloop_card *card) 774{ 775 char *p = card->omsg; 776 isdn_ctrl cmd; 777 char buf[60]; 778 isdnloop_stat *s = isdnloop_cmd_table; 779 int action = -1; 780 int i; 781 int ch; 782 783 if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) { 784 isdnloop_fake_err(card); 785 return; 786 } 787 ch = card->omsg[1] - '0'; 788 if ((ch < 0) || (ch > 2)) { 789 isdnloop_fake_err(card); 790 return; 791 } 792 p += 3; 793 while (s->statstr) { 794 if (!strncmp(p, s->statstr, strlen(s->statstr))) { 795 action = s->action; 796 if (s->command && (ch != 0)) { 797 isdnloop_fake_err(card); 798 return; 799 } 800 break; 801 } 802 s++; 803 } 804 if (action == -1) 805 return; 806 switch (action) { 807 case 1: 808 /* 0x;BCON_R */ 809 if (card->rcard[ch - 1]) { 810 isdnloop_fake(card->rcard[ch - 1], "BCON_I", 811 card->rch[ch - 1] + 1); 812 isdnloop_fake(card, "BCON_C", ch); 813 } 814 break; 815 case 17: 816 /* 0x;BCON_I */ 817 if (card->rcard[ch - 1]) { 818 isdnloop_fake(card->rcard[ch - 1], "BCON_C", 819 card->rch[ch - 1] + 1); 820 } 821 break; 822 case 2: 823 /* 0x;BDIS_R */ 824 isdnloop_fake(card, "BDIS_C", ch); 825 if (card->rcard[ch - 1]) { 826 isdnloop_fake(card->rcard[ch - 1], "BDIS_I", 827 card->rch[ch - 1] + 1); 828 } 829 break; 830 case 16: 831 /* 0x;DCON_R */ 832 isdnloop_kill_ctimer(card, ch - 1); 833 if (card->rcard[ch - 1]) { 834 isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]); 835 isdnloop_fake(card->rcard[ch - 1], "DCON_C", 836 card->rch[ch - 1] + 1); 837 isdnloop_fake(card, "DCON_C", ch); 838 } 839 break; 840 case 3: 841 /* 0x;DDIS_R */ 842 isdnloop_kill_ctimer(card, ch - 1); 843 if (card->rcard[ch - 1]) { 844 isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]); 845 isdnloop_fake(card->rcard[ch - 1], "DDIS_I", 846 card->rch[ch - 1] + 1); 847 card->rcard[ch - 1] = NULL; 848 } 849 isdnloop_fake(card, "DDIS_C", ch); 850 break; 851 case 4: 852 /* 0x;DSCA_Rdd,yy,zz,oo */ 853 if (card->ptype != ISDN_PTYPE_1TR6) { 854 isdnloop_fake_err(card); 855 return; 856 } 857 /* Fall through */ 858 case 5: 859 /* 0x;DCAL_Rdd,yy,zz,oo */ 860 p += 6; 861 switch (isdnloop_try_call(card, p, ch - 1, &cmd)) { 862 case 0: 863 /* Alerting */ 864 sprintf(buf, "D%s_I%s,%02d,%02d,%s", 865 (action == 4) ? "SCA" : "CAL", 866 isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1), 867 cmd.parm.setup.si1, 868 cmd.parm.setup.si2, 869 isdnloop_vstphone(card->rcard[ch - 1], 870 cmd.parm.setup.phone, 0)); 871 isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1); 872 /* Fall through */ 873 case 3: 874 /* si1 does not match, don't alert but start timer */ 875 isdnloop_start_ctimer(card, ch - 1); 876 break; 877 case 1: 878 /* Remote busy */ 879 isdnloop_fake(card, "DDIS_I", ch); 880 sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1)); 881 isdnloop_fake(card, buf, ch); 882 break; 883 case 2: 884 /* No such user */ 885 isdnloop_fake(card, "DDIS_I", ch); 886 sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2)); 887 isdnloop_fake(card, buf, ch); 888 break; 889 } 890 break; 891 case 6: 892 /* 0x;EAZC */ 893 card->eazlist[ch - 1][0] = '\0'; 894 break; 895 case 7: 896 /* 0x;EAZ */ 897 p += 3; 898 if (strlen(p) >= sizeof(card->eazlist[0])) 899 break; 900 strcpy(card->eazlist[ch - 1], p); 901 break; 902 case 8: 903 /* 0x;SEEAZ */ 904 sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]); 905 isdnloop_fake(card, buf, ch + 1); 906 break; 907 case 9: 908 /* 0x;MSN */ 909 break; 910 case 10: 911 /* 0x;MSNALL */ 912 break; 913 case 11: 914 /* 0x;SETSIL */ 915 p += 6; 916 i = 0; 917 while (strchr("0157", *p)) { 918 if (i) 919 card->sil[ch - 1] |= si2bit[*p - '0']; 920 i = (*p++ == '0'); 921 } 922 if (*p) 923 isdnloop_fake_err(card); 924 break; 925 case 12: 926 /* 0x;SEESIL */ 927 sprintf(buf, "SIN-LIST: "); 928 p = buf + 10; 929 for (i = 0; i < 3; i++) 930 if (card->sil[ch - 1] & (1 << i)) 931 p += sprintf(p, "%02d", bit2si[i]); 932 isdnloop_fake(card, buf, ch + 1); 933 break; 934 case 13: 935 /* 0x;SILC */ 936 card->sil[ch - 1] = 0; 937 break; 938 case 14: 939 /* 00;FV2ON */ 940 break; 941 case 15: 942 /* 00;FV2OFF */ 943 break; 944 } 945} 946 947/* 948 * Put command-strings into the of the 'card'. In reality, execute them 949 * right in place by calling isdnloop_parse_cmd(). Also copy every 950 * command to the read message ringbuffer, preceding it with a '>'. 951 * These mesagges can be read at /dev/isdnctrl. 952 * 953 * Parameter: 954 * buf = pointer to command buffer. 955 * len = length of buffer data. 956 * user = flag: 1 = called form userlevel, 0 called from kernel. 957 * card = pointer to card struct. 958 * Return: 959 * number of bytes transferred (currently always equals len). 960 */ 961static int 962isdnloop_writecmd(const u_char *buf, int len, int user, isdnloop_card *card) 963{ 964 int xcount = 0; 965 int ocount = 1; 966 isdn_ctrl cmd; 967 968 while (len) { 969 int count = len; 970 u_char *p; 971 u_char msg[0x100]; 972 973 if (count > 255) 974 count = 255; 975 if (user) { 976 if (copy_from_user(msg, buf, count)) 977 return -EFAULT; 978 } else 979 memcpy(msg, buf, count); 980 isdnloop_putmsg(card, '>'); 981 for (p = msg; count > 0; count--, p++) { 982 len--; 983 xcount++; 984 isdnloop_putmsg(card, *p); 985 card->omsg[card->optr] = *p; 986 if (*p == '\n') { 987 card->omsg[card->optr] = '\0'; 988 card->optr = 0; 989 isdnloop_parse_cmd(card); 990 if (len) { 991 isdnloop_putmsg(card, '>'); 992 ocount++; 993 } 994 } else { 995 if (card->optr < 59) 996 card->optr++; 997 } 998 ocount++; 999 } 1000 } 1001 cmd.command = ISDN_STAT_STAVAIL; 1002 cmd.driver = card->myid; 1003 cmd.arg = ocount; 1004 card->interface.statcallb(&cmd); 1005 return xcount; 1006} 1007 1008/* 1009 * Delete card's pending timers, send STOP to linklevel 1010 */ 1011static void 1012isdnloop_stopcard(isdnloop_card *card) 1013{ 1014 unsigned long flags; 1015 isdn_ctrl cmd; 1016 1017 spin_lock_irqsave(&card->isdnloop_lock, flags); 1018 if (card->flags & ISDNLOOP_FLAGS_RUNNING) { 1019 card->flags &= ~ISDNLOOP_FLAGS_RUNNING; 1020 del_timer(&card->st_timer); 1021 del_timer(&card->rb_timer); 1022 del_timer(&card->c_timer[0]); 1023 del_timer(&card->c_timer[1]); 1024 cmd.command = ISDN_STAT_STOP; 1025 cmd.driver = card->myid; 1026 card->interface.statcallb(&cmd); 1027 } 1028 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 1029} 1030 1031/* 1032 * Stop all cards before unload. 1033 */ 1034static void 1035isdnloop_stopallcards(void) 1036{ 1037 isdnloop_card *p = cards; 1038 1039 while (p) { 1040 isdnloop_stopcard(p); 1041 p = p->next; 1042 } 1043} 1044 1045/* 1046 * Start a 'card'. Simulate card's boot message and set the phone 1047 * number(s) of the virtual 'S0-Interface'. Install D-channel 1048 * poll timer. 1049 * 1050 * Parameter: 1051 * card = pointer to card struct. 1052 * sdefp = pointer to struct holding ioctl parameters. 1053 * Return: 1054 * 0 on success, -E??? otherwise. 1055 */ 1056static int 1057isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp) 1058{ 1059 unsigned long flags; 1060 isdnloop_sdef sdef; 1061 int i; 1062 1063 if (card->flags & ISDNLOOP_FLAGS_RUNNING) 1064 return -EBUSY; 1065 if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef))) 1066 return -EFAULT; 1067 1068 for (i = 0; i < 3; i++) { 1069 if (!memchr(sdef.num[i], 0, sizeof(sdef.num[i]))) 1070 return -EINVAL; 1071 } 1072 1073 spin_lock_irqsave(&card->isdnloop_lock, flags); 1074 switch (sdef.ptype) { 1075 case ISDN_PTYPE_EURO: 1076 if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96", 1077 -1)) { 1078 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 1079 return -ENOMEM; 1080 } 1081 card->sil[0] = card->sil[1] = 4; 1082 if (isdnloop_fake(card, "TEI OK", 0)) { 1083 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 1084 return -ENOMEM; 1085 } 1086 for (i = 0; i < 3; i++) { 1087 strlcpy(card->s0num[i], sdef.num[i], 1088 sizeof(card->s0num[0])); 1089 } 1090 break; 1091 case ISDN_PTYPE_1TR6: 1092 if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95", 1093 -1)) { 1094 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 1095 return -ENOMEM; 1096 } 1097 card->sil[0] = card->sil[1] = 4; 1098 if (isdnloop_fake(card, "TEI OK", 0)) { 1099 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 1100 return -ENOMEM; 1101 } 1102 strlcpy(card->s0num[0], sdef.num[0], sizeof(card->s0num[0])); 1103 card->s0num[1][0] = '\0'; 1104 card->s0num[2][0] = '\0'; 1105 break; 1106 default: 1107 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 1108 printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n", 1109 sdef.ptype); 1110 return -EINVAL; 1111 } 1112 timer_setup(&card->rb_timer, isdnloop_pollbchan, 0); 1113 timer_setup(&card->st_timer, isdnloop_polldchan, 0); 1114 card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD; 1115 add_timer(&card->st_timer); 1116 card->flags |= ISDNLOOP_FLAGS_RUNNING; 1117 spin_unlock_irqrestore(&card->isdnloop_lock, flags); 1118 return 0; 1119} 1120 1121/* 1122 * Main handler for commands sent by linklevel. 1123 */ 1124static int 1125isdnloop_command(isdn_ctrl *c, isdnloop_card *card) 1126{ 1127 ulong a; 1128 int i; 1129 char cbuf[80]; 1130 isdn_ctrl cmd; 1131 isdnloop_cdef cdef; 1132 1133 switch (c->command) { 1134 case ISDN_CMD_IOCTL: 1135 memcpy(&a, c->parm.num, sizeof(ulong)); 1136 switch (c->arg) { 1137 case ISDNLOOP_IOCTL_DEBUGVAR: 1138 return (ulong) card; 1139 case ISDNLOOP_IOCTL_STARTUP: 1140 return isdnloop_start(card, (isdnloop_sdef *) a); 1141 break; 1142 case ISDNLOOP_IOCTL_ADDCARD: 1143 if (copy_from_user((char *)&cdef, 1144 (char *)a, 1145 sizeof(cdef))) 1146 return -EFAULT; 1147 return isdnloop_addcard(cdef.id1); 1148 break; 1149 case ISDNLOOP_IOCTL_LEASEDCFG: 1150 if (a) { 1151 if (!card->leased) { 1152 card->leased = 1; 1153 while (card->ptype == ISDN_PTYPE_UNKNOWN) 1154 schedule_timeout_interruptible(10); 1155 schedule_timeout_interruptible(10); 1156 sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n"); 1157 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1158 printk(KERN_INFO 1159 "isdnloop: (%s) Leased-line mode enabled\n", 1160 CID); 1161 cmd.command = ISDN_STAT_RUN; 1162 cmd.driver = card->myid; 1163 cmd.arg = 0; 1164 card->interface.statcallb(&cmd); 1165 } 1166 } else { 1167 if (card->leased) { 1168 card->leased = 0; 1169 sprintf(cbuf, "00;FV2OFF\n"); 1170 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1171 printk(KERN_INFO 1172 "isdnloop: (%s) Leased-line mode disabled\n", 1173 CID); 1174 cmd.command = ISDN_STAT_RUN; 1175 cmd.driver = card->myid; 1176 cmd.arg = 0; 1177 card->interface.statcallb(&cmd); 1178 } 1179 } 1180 return 0; 1181 default: 1182 return -EINVAL; 1183 } 1184 break; 1185 case ISDN_CMD_DIAL: 1186 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1187 return -ENODEV; 1188 if (card->leased) 1189 break; 1190 if ((c->arg & 255) < ISDNLOOP_BCH) { 1191 char *p; 1192 char dcode[4]; 1193 1194 a = c->arg; 1195 p = c->parm.setup.phone; 1196 if (*p == 's' || *p == 'S') { 1197 /* Dial for SPV */ 1198 p++; 1199 strcpy(dcode, "SCA"); 1200 } else 1201 /* Normal Dial */ 1202 strcpy(dcode, "CAL"); 1203 snprintf(cbuf, sizeof(cbuf), 1204 "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), 1205 dcode, p, c->parm.setup.si1, 1206 c->parm.setup.si2, c->parm.setup.eazmsn); 1207 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1208 } 1209 break; 1210 case ISDN_CMD_ACCEPTD: 1211 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1212 return -ENODEV; 1213 if (c->arg < ISDNLOOP_BCH) { 1214 a = c->arg + 1; 1215 cbuf[0] = 0; 1216 switch (card->l2_proto[a - 1]) { 1217 case ISDN_PROTO_L2_X75I: 1218 sprintf(cbuf, "%02d;BX75\n", (int) a); 1219 break; 1220#ifdef CONFIG_ISDN_X25 1221 case ISDN_PROTO_L2_X25DTE: 1222 sprintf(cbuf, "%02d;BX2T\n", (int) a); 1223 break; 1224 case ISDN_PROTO_L2_X25DCE: 1225 sprintf(cbuf, "%02d;BX2C\n", (int) a); 1226 break; 1227#endif 1228 case ISDN_PROTO_L2_HDLC: 1229 sprintf(cbuf, "%02d;BTRA\n", (int) a); 1230 break; 1231 } 1232 if (strlen(cbuf)) 1233 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1234 sprintf(cbuf, "%02d;DCON_R\n", (int) a); 1235 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1236 } 1237 break; 1238 case ISDN_CMD_ACCEPTB: 1239 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1240 return -ENODEV; 1241 if (c->arg < ISDNLOOP_BCH) { 1242 a = c->arg + 1; 1243 switch (card->l2_proto[a - 1]) { 1244 case ISDN_PROTO_L2_X75I: 1245 sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a); 1246 break; 1247#ifdef CONFIG_ISDN_X25 1248 case ISDN_PROTO_L2_X25DTE: 1249 sprintf(cbuf, "%02d;BCON_R,BX2T\n", (int) a); 1250 break; 1251 case ISDN_PROTO_L2_X25DCE: 1252 sprintf(cbuf, "%02d;BCON_R,BX2C\n", (int) a); 1253 break; 1254#endif 1255 case ISDN_PROTO_L2_HDLC: 1256 sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a); 1257 break; 1258 default: 1259 sprintf(cbuf, "%02d;BCON_R\n", (int) a); 1260 } 1261 printk(KERN_DEBUG "isdnloop writecmd '%s'\n", cbuf); 1262 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1263 break; 1264 case ISDN_CMD_HANGUP: 1265 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1266 return -ENODEV; 1267 if (c->arg < ISDNLOOP_BCH) { 1268 a = c->arg + 1; 1269 sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a); 1270 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1271 } 1272 break; 1273 case ISDN_CMD_SETEAZ: 1274 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1275 return -ENODEV; 1276 if (card->leased) 1277 break; 1278 if (c->arg < ISDNLOOP_BCH) { 1279 a = c->arg + 1; 1280 if (card->ptype == ISDN_PTYPE_EURO) { 1281 sprintf(cbuf, "%02d;MS%s%s\n", (int) a, 1282 c->parm.num[0] ? "N" : "ALL", c->parm.num); 1283 } else 1284 sprintf(cbuf, "%02d;EAZ%s\n", (int) a, 1285 c->parm.num[0] ? c->parm.num : (u_char *) "0123456789"); 1286 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1287 } 1288 break; 1289 case ISDN_CMD_CLREAZ: 1290 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1291 return -ENODEV; 1292 if (card->leased) 1293 break; 1294 if (c->arg < ISDNLOOP_BCH) { 1295 a = c->arg + 1; 1296 if (card->ptype == ISDN_PTYPE_EURO) 1297 sprintf(cbuf, "%02d;MSNC\n", (int) a); 1298 else 1299 sprintf(cbuf, "%02d;EAZC\n", (int) a); 1300 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1301 } 1302 break; 1303 case ISDN_CMD_SETL2: 1304 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1305 return -ENODEV; 1306 if ((c->arg & 255) < ISDNLOOP_BCH) { 1307 a = c->arg; 1308 switch (a >> 8) { 1309 case ISDN_PROTO_L2_X75I: 1310 sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1); 1311 break; 1312#ifdef CONFIG_ISDN_X25 1313 case ISDN_PROTO_L2_X25DTE: 1314 sprintf(cbuf, "%02d;BX2T\n", (int) (a & 255) + 1); 1315 break; 1316 case ISDN_PROTO_L2_X25DCE: 1317 sprintf(cbuf, "%02d;BX2C\n", (int) (a & 255) + 1); 1318 break; 1319#endif 1320 case ISDN_PROTO_L2_HDLC: 1321 sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); 1322 break; 1323 case ISDN_PROTO_L2_TRANS: 1324 sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); 1325 break; 1326 default: 1327 return -EINVAL; 1328 } 1329 i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); 1330 card->l2_proto[a & 255] = (a >> 8); 1331 } 1332 break; 1333 case ISDN_CMD_SETL3: 1334 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1335 return -ENODEV; 1336 return 0; 1337 default: 1338 return -EINVAL; 1339 } 1340 } 1341 return 0; 1342} 1343 1344/* 1345 * Find card with given driverId 1346 */ 1347static inline isdnloop_card * 1348isdnloop_findcard(int driverid) 1349{ 1350 isdnloop_card *p = cards; 1351 1352 while (p) { 1353 if (p->myid == driverid) 1354 return p; 1355 p = p->next; 1356 } 1357 return (isdnloop_card *) 0; 1358} 1359 1360/* 1361 * Wrapper functions for interface to linklevel 1362 */ 1363static int 1364if_command(isdn_ctrl *c) 1365{ 1366 isdnloop_card *card = isdnloop_findcard(c->driver); 1367 1368 if (card) 1369 return isdnloop_command(c, card); 1370 printk(KERN_ERR 1371 "isdnloop: if_command called with invalid driverId!\n"); 1372 return -ENODEV; 1373} 1374 1375static int 1376if_writecmd(const u_char __user *buf, int len, int id, int channel) 1377{ 1378 isdnloop_card *card = isdnloop_findcard(id); 1379 1380 if (card) { 1381 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1382 return -ENODEV; 1383 return isdnloop_writecmd(buf, len, 1, card); 1384 } 1385 printk(KERN_ERR 1386 "isdnloop: if_writecmd called with invalid driverId!\n"); 1387 return -ENODEV; 1388} 1389 1390static int 1391if_readstatus(u_char __user *buf, int len, int id, int channel) 1392{ 1393 isdnloop_card *card = isdnloop_findcard(id); 1394 1395 if (card) { 1396 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1397 return -ENODEV; 1398 return isdnloop_readstatus(buf, len, card); 1399 } 1400 printk(KERN_ERR 1401 "isdnloop: if_readstatus called with invalid driverId!\n"); 1402 return -ENODEV; 1403} 1404 1405static int 1406if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) 1407{ 1408 isdnloop_card *card = isdnloop_findcard(id); 1409 1410 if (card) { 1411 if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) 1412 return -ENODEV; 1413 /* ack request stored in skb scratch area */ 1414 *(skb->head) = ack; 1415 return isdnloop_sendbuf(channel, skb, card); 1416 } 1417 printk(KERN_ERR 1418 "isdnloop: if_sendbuf called with invalid driverId!\n"); 1419 return -ENODEV; 1420} 1421 1422/* 1423 * Allocate a new card-struct, initialize it 1424 * link it into cards-list and register it at linklevel. 1425 */ 1426static isdnloop_card * 1427isdnloop_initcard(char *id) 1428{ 1429 isdnloop_card *card; 1430 int i; 1431 card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL); 1432 if (!card) { 1433 printk(KERN_WARNING 1434 "isdnloop: (%s) Could not allocate card-struct.\n", id); 1435 return (isdnloop_card *) 0; 1436 } 1437 card->interface.owner = THIS_MODULE; 1438 card->interface.channels = ISDNLOOP_BCH; 1439 card->interface.hl_hdrlen = 1; /* scratch area for storing ack flag*/ 1440 card->interface.maxbufsize = 4000; 1441 card->interface.command = if_command; 1442 card->interface.writebuf_skb = if_sendbuf; 1443 card->interface.writecmd = if_writecmd; 1444 card->interface.readstat = if_readstatus; 1445 card->interface.features = ISDN_FEATURE_L2_X75I | 1446#ifdef CONFIG_ISDN_X25 1447 ISDN_FEATURE_L2_X25DTE | 1448 ISDN_FEATURE_L2_X25DCE | 1449#endif 1450 ISDN_FEATURE_L2_HDLC | 1451 ISDN_FEATURE_L3_TRANS | 1452 ISDN_FEATURE_P_UNKNOWN; 1453 card->ptype = ISDN_PTYPE_UNKNOWN; 1454 strlcpy(card->interface.id, id, sizeof(card->interface.id)); 1455 card->msg_buf_write = card->msg_buf; 1456 card->msg_buf_read = card->msg_buf; 1457 card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1]; 1458 for (i = 0; i < ISDNLOOP_BCH; i++) { 1459 card->l2_proto[i] = ISDN_PROTO_L2_X75I; 1460 skb_queue_head_init(&card->bqueue[i]); 1461 } 1462 skb_queue_head_init(&card->dqueue); 1463 spin_lock_init(&card->isdnloop_lock); 1464 card->next = cards; 1465 cards = card; 1466 if (!register_isdn(&card->interface)) { 1467 cards = cards->next; 1468 printk(KERN_WARNING 1469 "isdnloop: Unable to register %s\n", id); 1470 kfree(card); 1471 return (isdnloop_card *) 0; 1472 } 1473 card->myid = card->interface.channels; 1474 return card; 1475} 1476 1477static int 1478isdnloop_addcard(char *id1) 1479{ 1480 isdnloop_card *card; 1481 card = isdnloop_initcard(id1); 1482 if (!card) { 1483 return -EIO; 1484 } 1485 printk(KERN_INFO 1486 "isdnloop: (%s) virtual card added\n", 1487 card->interface.id); 1488 return 0; 1489} 1490 1491static int __init 1492isdnloop_init(void) 1493{ 1494 if (isdnloop_id) 1495 return isdnloop_addcard(isdnloop_id); 1496 1497 return 0; 1498} 1499 1500static void __exit 1501isdnloop_exit(void) 1502{ 1503 isdn_ctrl cmd; 1504 isdnloop_card *card = cards; 1505 isdnloop_card *last; 1506 int i; 1507 1508 isdnloop_stopallcards(); 1509 while (card) { 1510 cmd.command = ISDN_STAT_UNLOAD; 1511 cmd.driver = card->myid; 1512 card->interface.statcallb(&cmd); 1513 for (i = 0; i < ISDNLOOP_BCH; i++) 1514 isdnloop_free_queue(card, i); 1515 card = card->next; 1516 } 1517 card = cards; 1518 while (card) { 1519 last = card; 1520 skb_queue_purge(&card->dqueue); 1521 card = card->next; 1522 kfree(last); 1523 } 1524 printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n"); 1525} 1526 1527module_init(isdnloop_init); 1528module_exit(isdnloop_exit);