Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/isdn/divert/isdn_divert.c
17686 views
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
/********************************************/
37
struct 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 */
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 ",
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
/****************************************/
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);
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
/********************************/
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
/*******************************************/
371
divert_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
/*************************************************/
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,
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
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
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
/***************************/
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
/********************/
841
int 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
865