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 /**********************************/
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 /***************************/
deflect_timer_expire(ulong arg)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 /*****************************************/
cf_command(int drvid,int mode,u_char proc,char * msn,u_char service,char * fwd_nr,ulong * procid)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 /****************************************/
deflect_extern_action(u_char cmd,ulong callid,char * to_nr)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 /********************************/
insertrule(int idx,divert_rule * newrule)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 /***********************************/
deleterule(int idx)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 /*******************************************/
getruleptr(int idx)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 /*************************************************/
isdn_divert_icall(isdn_ctrl * ic)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 
deleteprocs(void)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 /****************************************************/
put_address(char * st,u_char * p,int len)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 /*************************************/
interrogate_success(isdn_ctrl * ic,struct call_struc * cs)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 /*********************************************/
prot_stat_callback(isdn_ctrl * ic)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 /***************************/
isdn_divert_stat_callback(isdn_ctrl * ic)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 /********************/
ll_callback(isdn_ctrl * ic)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