1/* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $ 2 * 3 * DSS1 main diversion supplementary handling for i4l. 4 * 5 * Copyright 1999 by Werner Cornelius (werner@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/proc_fs.h> 13#include <linux/slab.h> 14#include <linux/timer.h> 15#include <linux/jiffies.h> 16 17#include "isdn_divert.h" 18 19/**********************************/ 20/* structure keeping calling info */ 21/**********************************/ 22struct call_struc { 23 isdn_ctrl ics; /* delivered setup + driver parameters */ 24 ulong divert_id; /* Id delivered to user */ 25 unsigned char akt_state; /* actual state */ 26 char deflect_dest[35]; /* deflection destination */ 27 struct timer_list timer; /* timer control structure */ 28 char info[90]; /* device info output */ 29 struct call_struc *next; /* pointer to next entry */ 30 struct call_struc *prev; 31}; 32 33 34/********************************************/ 35/* structure keeping deflection table entry */ 36/********************************************/ 37struct deflect_struc { 38 struct deflect_struc *next, *prev; 39 divert_rule rule; /* used rule */ 40}; 41 42 43/*****************************************/ 44/* variables for main diversion services */ 45/*****************************************/ 46/* diversion/deflection processes */ 47static struct call_struc *divert_head = NULL; /* head of remembered entrys */ 48static ulong next_id = 1; /* next info id */ 49static struct deflect_struc *table_head = NULL; 50static struct deflect_struc *table_tail = NULL; 51static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */ 52 53DEFINE_SPINLOCK(divert_lock); 54 55/***************************/ 56/* timer callback function */ 57/***************************/ 58static void deflect_timer_expire(ulong arg) 59{ 60 unsigned long flags; 61 struct call_struc *cs = (struct call_struc *) arg; 62 63 spin_lock_irqsave(&divert_lock, flags); 64 del_timer(&cs->timer); /* delete active timer */ 65 spin_unlock_irqrestore(&divert_lock, flags); 66 67 switch (cs->akt_state) { 68 case DEFLECT_PROCEED: 69 cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */ 70 divert_if.ll_cmd(&cs->ics); 71 spin_lock_irqsave(&divert_lock, flags); 72 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ 73 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); 74 add_timer(&cs->timer); 75 spin_unlock_irqrestore(&divert_lock, flags); 76 break; 77 78 case DEFLECT_ALERT: 79 cs->ics.command = ISDN_CMD_REDIR; /* protocol */ 80 strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone)); 81 strcpy(cs->ics.parm.setup.eazmsn, "Testtext delayed"); 82 divert_if.ll_cmd(&cs->ics); 83 spin_lock_irqsave(&divert_lock, flags); 84 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ 85 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); 86 add_timer(&cs->timer); 87 spin_unlock_irqrestore(&divert_lock, flags); 88 break; 89 90 case DEFLECT_AUTODEL: 91 default: 92 spin_lock_irqsave(&divert_lock, flags); 93 if (cs->prev) 94 cs->prev->next = cs->next; /* forward link */ 95 else 96 divert_head = cs->next; 97 if (cs->next) 98 cs->next->prev = cs->prev; /* back link */ 99 spin_unlock_irqrestore(&divert_lock, flags); 100 kfree(cs); 101 return; 102 103 } /* switch */ 104} /* deflect_timer_func */ 105 106 107/*****************************************/ 108/* handle call forwarding de/activations */ 109/* 0 = deact, 1 = act, 2 = interrogate */ 110/*****************************************/ 111int cf_command(int drvid, int mode, 112 u_char proc, char *msn, 113 u_char service, char *fwd_nr, ulong *procid) 114{ 115 unsigned long flags; 116 int retval, msnlen; 117 int fwd_len; 118 char *p, *ielenp, tmp[60]; 119 struct call_struc *cs; 120 121 if (strchr(msn, '.')) return (-EINVAL); /* subaddress not allowed in msn */ 122 if ((proc & 0x7F) > 2) return (-EINVAL); 123 proc &= 3; 124 p = tmp; 125 *p++ = 0x30; /* enumeration */ 126 ielenp = p++; /* remember total length position */ 127 *p++ = 0xa; /* proc tag */ 128 *p++ = 1; /* length */ 129 *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */ 130 *p++ = 0xa; /* service tag */ 131 *p++ = 1; /* length */ 132 *p++ = service; /* service to handle */ 133 134 if (mode == 1) { 135 if (!*fwd_nr) return (-EINVAL); /* destination missing */ 136 if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */ 137 fwd_len = strlen(fwd_nr); 138 *p++ = 0x30; /* number enumeration */ 139 *p++ = fwd_len + 2; /* complete forward to len */ 140 *p++ = 0x80; /* fwd to nr */ 141 *p++ = fwd_len; /* length of number */ 142 strcpy(p, fwd_nr); /* copy number */ 143 p += fwd_len; /* pointer beyond fwd */ 144 } /* activate */ 145 146 msnlen = strlen(msn); 147 *p++ = 0x80; /* msn number */ 148 if (msnlen > 1) { 149 *p++ = msnlen; /* length */ 150 strcpy(p, msn); 151 p += msnlen; 152 } else 153 *p++ = 0; 154 155 *ielenp = p - ielenp - 1; /* set total IE length */ 156 157 /* allocate mem for information struct */ 158 if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC))) 159 return (-ENOMEM); /* no memory */ 160 init_timer(&cs->timer); 161 cs->info[0] = '\0'; 162 cs->timer.function = deflect_timer_expire; 163 cs->timer.data = (ulong) cs; /* pointer to own structure */ 164 cs->ics.driver = drvid; 165 cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */ 166 cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */ 167 cs->ics.parm.dss1_io.proc = (mode == 1) ? 7 : (mode == 2) ? 11 : 8; /* operation */ 168 cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */ 169 cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */ 170 cs->ics.parm.dss1_io.data = tmp; /* start of buffer */ 171 172 spin_lock_irqsave(&divert_lock, flags); 173 cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */ 174 spin_unlock_irqrestore(&divert_lock, flags); 175 *procid = cs->ics.parm.dss1_io.ll_id; 176 177 sprintf(cs->info, "%d 0x%lx %s%s 0 %s %02x %d%s%s\n", 178 (!mode) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT, 179 cs->ics.parm.dss1_io.ll_id, 180 (mode != 2) ? "" : "0 ", 181 divert_if.drv_to_name(cs->ics.driver), 182 msn, 183 service & 0xFF, 184 proc, 185 (mode != 1) ? "" : " 0 ", 186 (mode != 1) ? "" : fwd_nr); 187 188 retval = divert_if.ll_cmd(&cs->ics); /* execute command */ 189 190 if (!retval) { 191 cs->prev = NULL; 192 spin_lock_irqsave(&divert_lock, flags); 193 cs->next = divert_head; 194 divert_head = cs; 195 spin_unlock_irqrestore(&divert_lock, flags); 196 } else 197 kfree(cs); 198 return (retval); 199} /* cf_command */ 200 201 202/****************************************/ 203/* handle a external deflection command */ 204/****************************************/ 205int deflect_extern_action(u_char cmd, ulong callid, char *to_nr) 206{ 207 struct call_struc *cs; 208 isdn_ctrl ic; 209 unsigned long flags; 210 int i; 211 212 if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */ 213 cs = divert_head; /* start of parameter list */ 214 while (cs) { 215 if (cs->divert_id == callid) break; /* found */ 216 cs = cs->next; 217 } /* search entry */ 218 if (!cs) return (-EINVAL); /* invalid callid */ 219 220 ic.driver = cs->ics.driver; 221 ic.arg = cs->ics.arg; 222 i = -EINVAL; 223 if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */ 224 switch (cmd & 0x7F) { 225 case 0: /* hangup */ 226 del_timer(&cs->timer); 227 ic.command = ISDN_CMD_HANGUP; 228 i = divert_if.ll_cmd(&ic); 229 spin_lock_irqsave(&divert_lock, flags); 230 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ 231 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); 232 add_timer(&cs->timer); 233 spin_unlock_irqrestore(&divert_lock, flags); 234 break; 235 236 case 1: /* alert */ 237 if (cs->akt_state == DEFLECT_ALERT) return (0); 238 cmd &= 0x7F; /* never wait */ 239 del_timer(&cs->timer); 240 ic.command = ISDN_CMD_ALERT; 241 if ((i = divert_if.ll_cmd(&ic))) { 242 spin_lock_irqsave(&divert_lock, flags); 243 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ 244 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); 245 add_timer(&cs->timer); 246 spin_unlock_irqrestore(&divert_lock, flags); 247 } else 248 cs->akt_state = DEFLECT_ALERT; 249 break; 250 251 case 2: /* redir */ 252 del_timer(&cs->timer); 253 strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone)); 254 strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual"); 255 ic.command = ISDN_CMD_REDIR; 256 if ((i = divert_if.ll_cmd(&ic))) { 257 spin_lock_irqsave(&divert_lock, flags); 258 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ 259 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); 260 add_timer(&cs->timer); 261 spin_unlock_irqrestore(&divert_lock, flags); 262 } else 263 cs->akt_state = DEFLECT_ALERT; 264 break; 265 266 } /* switch */ 267 return (i); 268} /* deflect_extern_action */ 269 270/********************************/ 271/* insert a new rule before idx */ 272/********************************/ 273int insertrule(int idx, divert_rule *newrule) 274{ 275 struct deflect_struc *ds, *ds1 = NULL; 276 unsigned long flags; 277 278 if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL))) 279 return (-ENOMEM); /* no memory */ 280 281 ds->rule = *newrule; /* set rule */ 282 283 spin_lock_irqsave(&divert_lock, flags); 284 285 if (idx >= 0) { 286 ds1 = table_head; 287 while ((ds1) && (idx > 0)) 288 { idx--; 289 ds1 = ds1->next; 290 } 291 if (!ds1) idx = -1; 292 } 293 294 if (idx < 0) { 295 ds->prev = table_tail; /* previous entry */ 296 ds->next = NULL; /* end of chain */ 297 if (ds->prev) 298 ds->prev->next = ds; /* last forward */ 299 else 300 table_head = ds; /* is first entry */ 301 table_tail = ds; /* end of queue */ 302 } else { 303 ds->next = ds1; /* next entry */ 304 ds->prev = ds1->prev; /* prev entry */ 305 ds1->prev = ds; /* backward chain old element */ 306 if (!ds->prev) 307 table_head = ds; /* first element */ 308 } 309 310 spin_unlock_irqrestore(&divert_lock, flags); 311 return (0); 312} /* insertrule */ 313 314/***********************************/ 315/* delete the rule at position idx */ 316/***********************************/ 317int deleterule(int idx) 318{ 319 struct deflect_struc *ds, *ds1; 320 unsigned long flags; 321 322 if (idx < 0) { 323 spin_lock_irqsave(&divert_lock, flags); 324 ds = table_head; 325 table_head = NULL; 326 table_tail = NULL; 327 spin_unlock_irqrestore(&divert_lock, flags); 328 while (ds) { 329 ds1 = ds; 330 ds = ds->next; 331 kfree(ds1); 332 } 333 return (0); 334 } 335 336 spin_lock_irqsave(&divert_lock, flags); 337 ds = table_head; 338 339 while ((ds) && (idx > 0)) { 340 idx--; 341 ds = ds->next; 342 } 343 344 if (!ds) { 345 spin_unlock_irqrestore(&divert_lock, flags); 346 return (-EINVAL); 347 } 348 349 if (ds->next) 350 ds->next->prev = ds->prev; /* backward chain */ 351 else 352 table_tail = ds->prev; /* end of chain */ 353 354 if (ds->prev) 355 ds->prev->next = ds->next; /* forward chain */ 356 else 357 table_head = ds->next; /* start of chain */ 358 359 spin_unlock_irqrestore(&divert_lock, flags); 360 kfree(ds); 361 return (0); 362} /* deleterule */ 363 364/*******************************************/ 365/* get a pointer to a specific rule number */ 366/*******************************************/ 367divert_rule *getruleptr(int idx) 368{ 369 struct deflect_struc *ds = table_head; 370 371 if (idx < 0) return (NULL); 372 while ((ds) && (idx >= 0)) { 373 if (!(idx--)) { 374 return (&ds->rule); 375 break; 376 } 377 ds = ds->next; 378 } 379 return (NULL); 380} /* getruleptr */ 381 382/*************************************************/ 383/* called from common module on an incoming call */ 384/*************************************************/ 385static int isdn_divert_icall(isdn_ctrl *ic) 386{ 387 int retval = 0; 388 unsigned long flags; 389 struct call_struc *cs = NULL; 390 struct deflect_struc *dv; 391 char *p, *p1; 392 u_char accept; 393 394 /* first check the internal deflection table */ 395 for (dv = table_head; dv; dv = dv->next) { 396 /* scan table */ 397 if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) || 398 ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL))) 399 continue; /* call option check */ 400 if (!(dv->rule.drvid & (1L << ic->driver))) 401 continue; /* driver not matching */ 402 if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1)) 403 continue; /* si1 not matching */ 404 if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2)) 405 continue; /* si2 not matching */ 406 407 p = dv->rule.my_msn; 408 p1 = ic->parm.setup.eazmsn; 409 accept = 0; 410 while (*p) { 411 /* complete compare */ 412 if (*p == '-') { 413 accept = 1; /* call accepted */ 414 break; 415 } 416 if (*p++ != *p1++) 417 break; /* not accepted */ 418 if ((!*p) && (!*p1)) 419 accept = 1; 420 } /* complete compare */ 421 if (!accept) continue; /* not accepted */ 422 423 if ((strcmp(dv->rule.caller, "0")) || 424 (ic->parm.setup.phone[0])) { 425 p = dv->rule.caller; 426 p1 = ic->parm.setup.phone; 427 accept = 0; 428 while (*p) { 429 /* complete compare */ 430 if (*p == '-') { 431 accept = 1; /* call accepted */ 432 break; 433 } 434 if (*p++ != *p1++) 435 break; /* not accepted */ 436 if ((!*p) && (!*p1)) 437 accept = 1; 438 } /* complete compare */ 439 if (!accept) continue; /* not accepted */ 440 } 441 442 switch (dv->rule.action) { 443 case DEFLECT_IGNORE: 444 return 0; 445 446 case DEFLECT_ALERT: 447 case DEFLECT_PROCEED: 448 case DEFLECT_REPORT: 449 case DEFLECT_REJECT: 450 if (dv->rule.action == DEFLECT_PROCEED) 451 if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime))) 452 return (0); /* no external deflection needed */ 453 if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC))) 454 return (0); /* no memory */ 455 init_timer(&cs->timer); 456 cs->info[0] = '\0'; 457 cs->timer.function = deflect_timer_expire; 458 cs->timer.data = (ulong) cs; /* pointer to own structure */ 459 460 cs->ics = *ic; /* copy incoming data */ 461 if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone, "0"); 462 if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn, "0"); 463 cs->ics.parm.setup.screen = dv->rule.screen; 464 if (dv->rule.waittime) 465 cs->timer.expires = jiffies + (HZ * dv->rule.waittime); 466 else if (dv->rule.action == DEFLECT_PROCEED) 467 cs->timer.expires = jiffies + (HZ * extern_wait_max); 468 else 469 cs->timer.expires = 0; 470 cs->akt_state = dv->rule.action; 471 spin_lock_irqsave(&divert_lock, flags); 472 cs->divert_id = next_id++; /* new sequence number */ 473 spin_unlock_irqrestore(&divert_lock, flags); 474 cs->prev = NULL; 475 if (cs->akt_state == DEFLECT_ALERT) { 476 strcpy(cs->deflect_dest, dv->rule.to_nr); 477 if (!cs->timer.expires) { 478 strcpy(ic->parm.setup.eazmsn, 479 "Testtext direct"); 480 ic->parm.setup.screen = dv->rule.screen; 481 strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone)); 482 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ 483 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); 484 retval = 5; 485 } else 486 retval = 1; /* alerting */ 487 } else { 488 cs->deflect_dest[0] = '\0'; 489 retval = 4; /* only proceed */ 490 } 491 sprintf(cs->info, "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n", 492 cs->akt_state, 493 cs->divert_id, 494 divert_if.drv_to_name(cs->ics.driver), 495 (ic->command == ISDN_STAT_ICALLW) ? "1" : "0", 496 cs->ics.parm.setup.phone, 497 cs->ics.parm.setup.eazmsn, 498 cs->ics.parm.setup.si1, 499 cs->ics.parm.setup.si2, 500 cs->ics.parm.setup.screen, 501 dv->rule.waittime, 502 cs->deflect_dest); 503 if ((dv->rule.action == DEFLECT_REPORT) || 504 (dv->rule.action == DEFLECT_REJECT)) { 505 put_info_buffer(cs->info); 506 kfree(cs); /* remove */ 507 return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */ 508 } 509 break; 510 511 default: 512 return 0; /* ignore call */ 513 } /* switch action */ 514 break; /* will break the 'for' looping */ 515 } /* scan_table */ 516 517 if (cs) { 518 cs->prev = NULL; 519 spin_lock_irqsave(&divert_lock, flags); 520 cs->next = divert_head; 521 divert_head = cs; 522 if (cs->timer.expires) add_timer(&cs->timer); 523 spin_unlock_irqrestore(&divert_lock, flags); 524 525 put_info_buffer(cs->info); 526 return (retval); 527 } else 528 return (0); 529} /* isdn_divert_icall */ 530 531 532void deleteprocs(void) 533{ 534 struct call_struc *cs, *cs1; 535 unsigned long flags; 536 537 spin_lock_irqsave(&divert_lock, flags); 538 cs = divert_head; 539 divert_head = NULL; 540 while (cs) { 541 del_timer(&cs->timer); 542 cs1 = cs; 543 cs = cs->next; 544 kfree(cs1); 545 } 546 spin_unlock_irqrestore(&divert_lock, flags); 547} /* deleteprocs */ 548 549/****************************************************/ 550/* put a address including address type into buffer */ 551/****************************************************/ 552static int put_address(char *st, u_char *p, int len) 553{ 554 u_char retval = 0; 555 u_char adr_typ = 0; /* network standard */ 556 557 if (len < 2) return (retval); 558 if (*p == 0xA1) { 559 retval = *(++p) + 2; /* total length */ 560 if (retval > len) return (0); /* too short */ 561 len = retval - 2; /* remaining length */ 562 if (len < 3) return (0); 563 if ((*(++p) != 0x0A) || (*(++p) != 1)) return (0); 564 adr_typ = *(++p); 565 len -= 3; 566 p++; 567 if (len < 2) return (0); 568 if (*p++ != 0x12) return (0); 569 if (*p > len) return (0); /* check number length */ 570 len = *p++; 571 } else if (*p == 0x80) { 572 retval = *(++p) + 2; /* total length */ 573 if (retval > len) return (0); 574 len = retval - 2; 575 p++; 576 } else 577 return (0); /* invalid address information */ 578 579 sprintf(st, "%d ", adr_typ); 580 st += strlen(st); 581 if (!len) 582 *st++ = '-'; 583 else 584 while (len--) 585 *st++ = *p++; 586 *st = '\0'; 587 return (retval); 588} /* put_address */ 589 590/*************************************/ 591/* report a successful interrogation */ 592/*************************************/ 593static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs) 594{ 595 char *src = ic->parm.dss1_io.data; 596 int restlen = ic->parm.dss1_io.datalen; 597 int cnt = 1; 598 u_char n, n1; 599 char st[90], *p, *stp; 600 601 if (restlen < 2) return (-100); /* frame too short */ 602 if (*src++ != 0x30) return (-101); 603 if ((n = *src++) > 0x81) return (-102); /* invalid length field */ 604 restlen -= 2; /* remaining bytes */ 605 if (n == 0x80) { 606 if (restlen < 2) return (-103); 607 if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104); 608 restlen -= 2; 609 } else if (n == 0x81) { 610 n = *src++; 611 restlen--; 612 if (n > restlen) return (-105); 613 restlen = n; 614 } else if (n > restlen) 615 return (-106); 616 else 617 restlen = n; /* standard format */ 618 if (restlen < 3) return (-107); /* no procedure */ 619 if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108); 620 restlen -= 3; 621 if (restlen < 2) return (-109); /* list missing */ 622 if (*src == 0x31) { 623 src++; 624 if ((n = *src++) > 0x81) return (-110); /* invalid length field */ 625 restlen -= 2; /* remaining bytes */ 626 if (n == 0x80) { 627 if (restlen < 2) return (-111); 628 if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112); 629 restlen -= 2; 630 } else if (n == 0x81) { 631 n = *src++; 632 restlen--; 633 if (n > restlen) return (-113); 634 restlen = n; 635 } else if (n > restlen) 636 return (-114); 637 else 638 restlen = n; /* standard format */ 639 } /* result list header */ 640 641 while (restlen >= 2) { 642 stp = st; 643 sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id, 644 cnt++, divert_if.drv_to_name(ic->driver)); 645 stp += strlen(stp); 646 if (*src++ != 0x30) return (-115); /* invalid enum */ 647 n = *src++; 648 restlen -= 2; 649 if (n > restlen) return (-116); /* enum length wrong */ 650 restlen -= n; 651 p = src; /* one entry */ 652 src += n; 653 if (!(n1 = put_address(stp, p, n & 0xFF))) continue; 654 stp += strlen(stp); 655 p += n1; 656 n -= n1; 657 if (n < 6) continue; /* no service and proc */ 658 if ((*p++ != 0x0A) || (*p++ != 1)) continue; 659 sprintf(stp, " 0x%02x ", (*p++) & 0xFF); 660 stp += strlen(stp); 661 if ((*p++ != 0x0A) || (*p++ != 1)) continue; 662 sprintf(stp, "%d ", (*p++) & 0xFF); 663 stp += strlen(stp); 664 n -= 6; 665 if (n > 2) { 666 if (*p++ != 0x30) continue; 667 if (*p > (n - 2)) continue; 668 n = *p++; 669 if (!(n1 = put_address(stp, p, n & 0xFF))) continue; 670 stp += strlen(stp); 671 } 672 sprintf(stp, "\n"); 673 put_info_buffer(st); 674 } /* while restlen */ 675 if (restlen) return (-117); 676 return (0); 677} /* interrogate_success */ 678 679/*********************************************/ 680/* callback for protocol specific extensions */ 681/*********************************************/ 682static int prot_stat_callback(isdn_ctrl *ic) 683{ 684 struct call_struc *cs, *cs1; 685 int i; 686 unsigned long flags; 687 688 cs = divert_head; /* start of list */ 689 cs1 = NULL; 690 while (cs) { 691 if (ic->driver == cs->ics.driver) { 692 switch (cs->ics.arg) { 693 case DSS1_CMD_INVOKE: 694 if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) && 695 (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) { 696 switch (ic->arg) { 697 case DSS1_STAT_INVOKE_ERR: 698 sprintf(cs->info, "128 0x%lx 0x%x\n", 699 ic->parm.dss1_io.ll_id, 700 ic->parm.dss1_io.timeout); 701 put_info_buffer(cs->info); 702 break; 703 704 case DSS1_STAT_INVOKE_RES: 705 switch (cs->ics.parm.dss1_io.proc) { 706 case 7: 707 case 8: 708 put_info_buffer(cs->info); 709 break; 710 711 case 11: 712 i = interrogate_success(ic, cs); 713 if (i) 714 sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT, 715 ic->parm.dss1_io.ll_id, i); 716 put_info_buffer(cs->info); 717 break; 718 719 default: 720 printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc); 721 break; 722 } 723 724 break; 725 726 default: 727 printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg); 728 break; 729 } 730 cs1 = cs; /* remember structure */ 731 cs = NULL; 732 continue; /* abort search */ 733 } /* id found */ 734 break; 735 736 case DSS1_CMD_INVOKE_ABORT: 737 printk(KERN_WARNING "dss1_divert unhandled invoke abort\n"); 738 break; 739 740 default: 741 printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n", cs->ics.arg); 742 break; 743 } /* switch ics.arg */ 744 cs = cs->next; 745 } /* driver ok */ 746 } 747 748 if (!cs1) { 749 printk(KERN_WARNING "dss1_divert unhandled process\n"); 750 return (0); 751 } 752 753 if (cs1->ics.driver == -1) { 754 spin_lock_irqsave(&divert_lock, flags); 755 del_timer(&cs1->timer); 756 if (cs1->prev) 757 cs1->prev->next = cs1->next; /* forward link */ 758 else 759 divert_head = cs1->next; 760 if (cs1->next) 761 cs1->next->prev = cs1->prev; /* back link */ 762 spin_unlock_irqrestore(&divert_lock, flags); 763 kfree(cs1); 764 } 765 766 return (0); 767} /* prot_stat_callback */ 768 769 770/***************************/ 771/* status callback from HL */ 772/***************************/ 773static int isdn_divert_stat_callback(isdn_ctrl *ic) 774{ 775 struct call_struc *cs, *cs1; 776 unsigned long flags; 777 int retval; 778 779 retval = -1; 780 cs = divert_head; /* start of list */ 781 while (cs) { 782 if ((ic->driver == cs->ics.driver) && 783 (ic->arg == cs->ics.arg)) { 784 switch (ic->command) { 785 case ISDN_STAT_DHUP: 786 sprintf(cs->info, "129 0x%lx\n", cs->divert_id); 787 del_timer(&cs->timer); 788 cs->ics.driver = -1; 789 break; 790 791 case ISDN_STAT_CAUSE: 792 sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num); 793 break; 794 795 case ISDN_STAT_REDIR: 796 sprintf(cs->info, "131 0x%lx\n", cs->divert_id); 797 del_timer(&cs->timer); 798 cs->ics.driver = -1; 799 break; 800 801 default: 802 sprintf(cs->info, "999 0x%lx 0x%x\n", cs->divert_id, (int)(ic->command)); 803 break; 804 } 805 put_info_buffer(cs->info); 806 retval = 0; 807 } 808 cs1 = cs; 809 cs = cs->next; 810 if (cs1->ics.driver == -1) { 811 spin_lock_irqsave(&divert_lock, flags); 812 if (cs1->prev) 813 cs1->prev->next = cs1->next; /* forward link */ 814 else 815 divert_head = cs1->next; 816 if (cs1->next) 817 cs1->next->prev = cs1->prev; /* back link */ 818 spin_unlock_irqrestore(&divert_lock, flags); 819 kfree(cs1); 820 } 821 } 822 return (retval); /* not found */ 823} /* isdn_divert_stat_callback */ 824 825 826/********************/ 827/* callback from ll */ 828/********************/ 829int ll_callback(isdn_ctrl *ic) 830{ 831 switch (ic->command) { 832 case ISDN_STAT_ICALL: 833 case ISDN_STAT_ICALLW: 834 return (isdn_divert_icall(ic)); 835 break; 836 837 case ISDN_STAT_PROT: 838 if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) { 839 if (ic->arg != DSS1_STAT_INVOKE_BRD) 840 return (prot_stat_callback(ic)); 841 else 842 return (0); /* DSS1 invoke broadcast */ 843 } else 844 return (-1); /* protocol not euro */ 845 846 default: 847 return (isdn_divert_stat_callback(ic)); 848 } 849} /* ll_callback */ 850