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