Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
isdn_divert.c
Go to the documentation of this file.
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 ([email protected])
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 /**********************************/
22 struct 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 /********************************************/
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 */
47 static struct call_struc *divert_head = NULL; /* head of remembered entrys */
48 static ulong next_id = 1; /* next info id */
49 static struct deflect_struc *table_head = NULL;
50 static struct deflect_struc *table_tail = NULL;
51 static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
52 
53 DEFINE_SPINLOCK(divert_lock);
54 
55 /***************************/
56 /* timer callback function */
57 /***************************/
58 static 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 /*****************************************/
111 int 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 ",
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 /****************************************/
205 int 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);
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 /********************************/
276 int 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 /***********************************/
321 int 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 /*******************************************/
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 /*************************************************/
388 static 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,
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 
538 void 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 /****************************************************/
557 static 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 /*************************************/
600 static 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 /*********************************************/
694 static 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 
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 
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 /***************************/
786 static 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 /********************/
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 */