1 /* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $
3 * DSS1 main diversion supplementary handling for i4l.
5 * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
12 #include <linux/version.h>
13 #include <linux/proc_fs.h>
15 #include "isdn_divert.h"
17 /**********************************/
18 /* structure keeping calling info */
19 /**********************************/
21 { isdn_ctrl ics; /* delivered setup + driver parameters */
22 ulong divert_id; /* Id delivered to user */
23 unsigned char akt_state; /* actual state */
24 char deflect_dest[35]; /* deflection destination */
25 struct timer_list timer; /* timer control structure */
26 char info[90]; /* device info output */
27 struct call_struc *next; /* pointer to next entry */
28 struct call_struc *prev;
32 /********************************************/
33 /* structure keeping deflection table entry */
34 /********************************************/
36 { struct deflect_struc *next,*prev;
37 divert_rule rule; /* used rule */
41 /*****************************************/
42 /* variables for main diversion services */
43 /*****************************************/
44 /* diversion/deflection processes */
45 static struct call_struc *divert_head = NULL; /* head of remembered entrys */
46 static ulong next_id = 1; /* next info id */
47 static struct deflect_struc *table_head = NULL;
48 static struct deflect_struc *table_tail = NULL;
49 static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
51 DEFINE_SPINLOCK(divert_lock);
53 /***************************/
54 /* timer callback function */
55 /***************************/
56 static void deflect_timer_expire(ulong arg)
59 struct call_struc *cs = (struct call_struc *) arg;
61 spin_lock_irqsave(&divert_lock, flags);
62 del_timer(&cs->timer); /* delete active timer */
63 spin_unlock_irqrestore(&divert_lock, flags);
66 { case DEFLECT_PROCEED:
67 cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
68 divert_if.ll_cmd(&cs->ics);
69 spin_lock_irqsave(&divert_lock, flags);
70 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
71 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
72 add_timer(&cs->timer);
73 spin_unlock_irqrestore(&divert_lock, flags);
77 cs->ics.command = ISDN_CMD_REDIR; /* protocol */
78 strcpy(cs->ics.parm.setup.phone,cs->deflect_dest);
79 strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed");
80 divert_if.ll_cmd(&cs->ics);
81 spin_lock_irqsave(&divert_lock, flags);
82 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
83 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
84 add_timer(&cs->timer);
85 spin_unlock_irqrestore(&divert_lock, flags);
90 spin_lock_irqsave(&divert_lock, flags);
92 cs->prev->next = cs->next; /* forward link */
94 divert_head = cs->next;
96 cs->next->prev = cs->prev; /* back link */
97 spin_unlock_irqrestore(&divert_lock, flags);
102 } /* deflect_timer_func */
105 /*****************************************/
106 /* handle call forwarding de/activations */
107 /* 0 = deact, 1 = act, 2 = interrogate */
108 /*****************************************/
109 int cf_command(int drvid, int mode,
110 u_char proc, char *msn,
111 u_char service, char *fwd_nr, ulong *procid)
112 { unsigned long flags;
115 char *p,*ielenp,tmp[60];
116 struct call_struc *cs;
118 if (strchr(msn,'.')) return(-EINVAL); /* subaddress not allowed in msn */
119 if ((proc & 0x7F) > 2) return(-EINVAL);
122 *p++ = 0x30; /* enumeration */
123 ielenp = p++; /* remember total length position */
124 *p++ = 0xa; /* proc tag */
125 *p++ = 1; /* length */
126 *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */
127 *p++ = 0xa; /* service tag */
128 *p++ = 1; /* length */
129 *p++ = service; /* service to handle */
132 { if (!*fwd_nr) return(-EINVAL); /* destination missing */
133 if (strchr(fwd_nr,'.')) return(-EINVAL); /* subaddress not allowed */
134 fwd_len = strlen(fwd_nr);
135 *p++ = 0x30; /* number enumeration */
136 *p++ = fwd_len + 2; /* complete forward to len */
137 *p++ = 0x80; /* fwd to nr */
138 *p++ = fwd_len; /* length of number */
139 strcpy(p,fwd_nr); /* copy number */
140 p += fwd_len; /* pointer beyond fwd */
143 msnlen = strlen(msn);
144 *p++ = 0x80; /* msn number */
146 { *p++ = msnlen; /* length */
152 *ielenp = p - ielenp - 1; /* set total IE length */
154 /* allocate mem for information struct */
155 if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
156 return(-ENOMEM); /* no memory */
157 init_timer(&cs->timer);
159 cs->timer.function = deflect_timer_expire;
160 cs->timer.data = (ulong) cs; /* pointer to own structure */
161 cs->ics.driver = drvid;
162 cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
163 cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
164 cs->ics.parm.dss1_io.proc = (mode == 1) ? 7: (mode == 2) ? 11:8; /* operation */
165 cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */
166 cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
167 cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
169 spin_lock_irqsave(&divert_lock, flags);
170 cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
171 spin_unlock_irqrestore(&divert_lock, flags);
172 *procid = cs->ics.parm.dss1_io.ll_id;
174 sprintf(cs->info,"%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
175 (!mode ) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
176 cs->ics.parm.dss1_io.ll_id,
177 (mode != 2) ? "" : "0 ",
178 divert_if.drv_to_name(cs->ics.driver),
182 (mode != 1) ? "" : " 0 ",
183 (mode != 1) ? "" : fwd_nr);
185 retval = divert_if.ll_cmd(&cs->ics); /* excute command */
189 spin_lock_irqsave(&divert_lock, flags);
190 cs->next = divert_head;
192 spin_unlock_irqrestore(&divert_lock, flags);
200 /****************************************/
201 /* handle a external deflection command */
202 /****************************************/
203 int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
204 { struct call_struc *cs;
209 if ((cmd & 0x7F) > 2) return(-EINVAL); /* invalid command */
210 cs = divert_head; /* start of parameter list */
212 { if (cs->divert_id == callid) break; /* found */
215 if (!cs) return(-EINVAL); /* invalid callid */
217 ic.driver = cs->ics.driver;
218 ic.arg = cs->ics.arg;
220 if (cs->akt_state == DEFLECT_AUTODEL) return(i); /* no valid call */
222 { case 0: /* hangup */
223 del_timer(&cs->timer);
224 ic.command = ISDN_CMD_HANGUP;
225 i = divert_if.ll_cmd(&ic);
226 spin_lock_irqsave(&divert_lock, flags);
227 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
228 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
229 add_timer(&cs->timer);
230 spin_unlock_irqrestore(&divert_lock, flags);
234 if (cs->akt_state == DEFLECT_ALERT) return(0);
235 cmd &= 0x7F; /* never wait */
236 del_timer(&cs->timer);
237 ic.command = ISDN_CMD_ALERT;
238 if ((i = divert_if.ll_cmd(&ic)))
240 spin_lock_irqsave(&divert_lock, flags);
241 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
242 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
243 add_timer(&cs->timer);
244 spin_unlock_irqrestore(&divert_lock, flags);
247 cs->akt_state = DEFLECT_ALERT;
251 del_timer(&cs->timer);
252 strcpy(cs->ics.parm.setup.phone, to_nr);
253 strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
254 ic.command = ISDN_CMD_REDIR;
255 if ((i = divert_if.ll_cmd(&ic)))
257 spin_lock_irqsave(&divert_lock, flags);
258 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
259 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
260 add_timer(&cs->timer);
261 spin_unlock_irqrestore(&divert_lock, flags);
264 cs->akt_state = DEFLECT_ALERT;
269 } /* deflect_extern_action */
271 /********************************/
272 /* insert a new rule before idx */
273 /********************************/
274 int insertrule(int idx, divert_rule *newrule)
275 { struct deflect_struc *ds,*ds1=NULL;
278 if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc),
280 return(-ENOMEM); /* no memory */
282 ds->rule = *newrule; /* set rule */
284 spin_lock_irqsave(&divert_lock, flags);
288 while ((ds1) && (idx > 0))
296 { ds->prev = table_tail; /* previous entry */
297 ds->next = NULL; /* end of chain */
299 ds->prev->next = ds; /* last forward */
301 table_head = ds; /* is first entry */
302 table_tail = ds; /* end of queue */
305 { ds->next = ds1; /* next entry */
306 ds->prev = ds1->prev; /* prev entry */
307 ds1->prev = ds; /* backward chain old element */
309 table_head = ds; /* first element */
312 spin_unlock_irqrestore(&divert_lock, flags);
316 /***********************************/
317 /* delete the rule at position idx */
318 /***********************************/
319 int deleterule(int idx)
320 { struct deflect_struc *ds,*ds1;
324 { spin_lock_irqsave(&divert_lock, flags);
328 spin_unlock_irqrestore(&divert_lock, flags);
337 spin_lock_irqsave(&divert_lock, flags);
340 while ((ds) && (idx > 0))
347 spin_unlock_irqrestore(&divert_lock, flags);
352 ds->next->prev = ds->prev; /* backward chain */
354 table_tail = ds->prev; /* end of chain */
357 ds->prev->next = ds->next; /* forward chain */
359 table_head = ds->next; /* start of chain */
361 spin_unlock_irqrestore(&divert_lock, flags);
366 /*******************************************/
367 /* get a pointer to a specific rule number */
368 /*******************************************/
369 divert_rule *getruleptr(int idx)
370 { struct deflect_struc *ds = table_head;
372 if (idx < 0) return(NULL);
373 while ((ds) && (idx >= 0))
383 /*************************************************/
384 /* called from common module on an incoming call */
385 /*************************************************/
386 static int isdn_divert_icall(isdn_ctrl *ic)
389 struct call_struc *cs = NULL;
390 struct deflect_struc *dv;
394 /* first check the internal deflection table */
395 for (dv = table_head; dv ; dv = dv->next )
397 if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
398 ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
399 continue; /* call option check */
400 if (!(dv->rule.drvid & (1L << ic->driver)))
401 continue; /* driver not matching */
402 if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
403 continue; /* si1 not matching */
404 if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
405 continue; /* si2 not matching */
408 p1 = ic->parm.setup.eazmsn;
411 { /* complete compare */
413 { accept = 1; /* call accepted */
417 break; /* not accepted */
420 } /* complete compare */
421 if (!accept) continue; /* not accepted */
423 if ((strcmp(dv->rule.caller,"0")) || (ic->parm.setup.phone[0]))
424 { p = dv->rule.caller;
425 p1 = ic->parm.setup.phone;
428 { /* complete compare */
430 { accept = 1; /* call accepted */
434 break; /* not accepted */
437 } /* complete compare */
438 if (!accept) continue; /* not accepted */
441 switch (dv->rule.action)
442 { case DEFLECT_IGNORE:
447 case DEFLECT_PROCEED:
450 if (dv->rule.action == DEFLECT_PROCEED)
451 if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
452 return(0); /* no external deflection needed */
453 if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
454 return(0); /* no memory */
455 init_timer(&cs->timer);
457 cs->timer.function = deflect_timer_expire;
458 cs->timer.data = (ulong) cs; /* pointer to own structure */
460 cs->ics = *ic; /* copy incoming data */
461 if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone,"0");
462 if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn,"0");
463 cs->ics.parm.setup.screen = dv->rule.screen;
464 if (dv->rule.waittime)
465 cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
467 if (dv->rule.action == DEFLECT_PROCEED)
468 cs->timer.expires = jiffies + (HZ * extern_wait_max);
470 cs->timer.expires = 0;
471 cs->akt_state = dv->rule.action;
472 spin_lock_irqsave(&divert_lock, flags);
473 cs->divert_id = next_id++; /* new sequence number */
474 spin_unlock_irqrestore(&divert_lock, flags);
476 if (cs->akt_state == DEFLECT_ALERT)
477 { strcpy(cs->deflect_dest,dv->rule.to_nr);
478 if (!cs->timer.expires)
479 { strcpy(ic->parm.setup.eazmsn,"Testtext direct");
480 ic->parm.setup.screen = dv->rule.screen;
481 strcpy(ic->parm.setup.phone,dv->rule.to_nr);
482 cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
483 cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
487 retval = 1; /* alerting */
490 { cs->deflect_dest[0] = '\0';
491 retval = 4; /* only proceed */
493 sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
496 divert_if.drv_to_name(cs->ics.driver),
497 (ic->command == ISDN_STAT_ICALLW) ? "1":"0",
498 cs->ics.parm.setup.phone,
499 cs->ics.parm.setup.eazmsn,
500 cs->ics.parm.setup.si1,
501 cs->ics.parm.setup.si2,
502 cs->ics.parm.setup.screen,
505 if ((dv->rule.action == DEFLECT_REPORT) ||
506 (dv->rule.action == DEFLECT_REJECT))
507 { put_info_buffer(cs->info);
508 kfree(cs); /* remove */
509 return((dv->rule.action == DEFLECT_REPORT) ? 0:2); /* nothing to do */
514 return(0); /* ignore call */
516 } /* switch action */
522 spin_lock_irqsave(&divert_lock, flags);
523 cs->next = divert_head;
525 if (cs->timer.expires) add_timer(&cs->timer);
526 spin_unlock_irqrestore(&divert_lock, flags);
528 put_info_buffer(cs->info);
533 } /* isdn_divert_icall */
536 void deleteprocs(void)
537 { struct call_struc *cs, *cs1;
540 spin_lock_irqsave(&divert_lock, flags);
544 { del_timer(&cs->timer);
549 spin_unlock_irqrestore(&divert_lock, flags);
552 /****************************************************/
553 /* put a address including address type into buffer */
554 /****************************************************/
555 static int put_address(char *st, u_char *p, int len)
557 u_char adr_typ = 0; /* network standard */
559 if (len < 2) return(retval);
561 { retval = *(++p) + 2; /* total length */
562 if (retval > len) return(0); /* too short */
563 len = retval - 2; /* remaining length */
564 if (len < 3) return(0);
565 if ((*(++p) != 0x0A) || (*(++p) != 1)) return(0);
569 if (len < 2) return(0);
570 if (*p++ != 0x12) return(0);
571 if (*p > len) return(0); /* check number length */
576 { retval = *(++p) + 2; /* total length */
577 if (retval > len) return(0);
582 return(0); /* invalid address information */
584 sprintf(st,"%d ",adr_typ);
595 /*************************************/
596 /* report a succesfull interrogation */
597 /*************************************/
598 static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
599 { char *src = ic->parm.dss1_io.data;
600 int restlen = ic->parm.dss1_io.datalen;
603 char st[90], *p, *stp;
605 if (restlen < 2) return(-100); /* frame too short */
606 if (*src++ != 0x30) return(-101);
607 if ((n = *src++) > 0x81) return(-102); /* invalid length field */
608 restlen -= 2; /* remaining bytes */
610 { if (restlen < 2) return(-103);
611 if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-104);
618 if (n > restlen) return(-105);
622 if (n > restlen) return(-106);
624 restlen = n; /* standard format */
625 if (restlen < 3) return(-107); /* no procedure */
626 if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return(-108);
628 if (restlen < 2) return(-109); /* list missing */
631 if ((n = *src++) > 0x81) return(-110); /* invalid length field */
632 restlen -= 2; /* remaining bytes */
634 { if (restlen < 2) return(-111);
635 if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-112);
642 if (n > restlen) return(-113);
646 if (n > restlen) return(-114);
648 restlen = n; /* standard format */
649 } /* result list header */
653 sprintf(stp,"%d 0x%lx %d %s ",DIVERT_REPORT, ic->parm.dss1_io.ll_id,
654 cnt++,divert_if.drv_to_name(ic->driver));
656 if (*src++ != 0x30) return(-115); /* invalid enum */
659 if (n > restlen) return(-116); /* enum length wrong */
661 p = src; /* one entry */
663 if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
667 if (n < 6) continue; /* no service and proc */
668 if ((*p++ != 0x0A) || (*p++ != 1)) continue;
669 sprintf(stp," 0x%02x ",(*p++) & 0xFF);
671 if ((*p++ != 0x0A) || (*p++ != 1)) continue;
672 sprintf(stp,"%d ",(*p++) & 0xFF);
676 { if (*p++ != 0x30) continue;
677 if (*p > (n-2)) continue;
679 if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
684 } /* while restlen */
685 if (restlen) return(-117);
687 } /* interrogate_success */
689 /*********************************************/
690 /* callback for protocol specific extensions */
691 /*********************************************/
692 static int prot_stat_callback(isdn_ctrl *ic)
693 { struct call_struc *cs, *cs1;
697 cs = divert_head; /* start of list */
700 { if (ic->driver == cs->ics.driver)
701 { switch (cs->ics.arg)
702 { case DSS1_CMD_INVOKE:
703 if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
704 (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id))
706 { case DSS1_STAT_INVOKE_ERR:
707 sprintf(cs->info,"128 0x%lx 0x%x\n",
708 ic->parm.dss1_io.ll_id,
709 ic->parm.dss1_io.timeout);
710 put_info_buffer(cs->info);
713 case DSS1_STAT_INVOKE_RES:
714 switch (cs->ics.parm.dss1_io.proc)
717 put_info_buffer(cs->info);
721 i = interrogate_success(ic,cs);
723 sprintf(cs->info,"%d 0x%lx %d\n",DIVERT_REPORT,
724 ic->parm.dss1_io.ll_id,i);
725 put_info_buffer(cs->info);
729 printk(KERN_WARNING "dss1_divert: unknown proc %d\n",cs->ics.parm.dss1_io.proc);
737 printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n",ic->arg);
740 cs1 = cs; /* remember structure */
742 continue; /* abort search */
746 case DSS1_CMD_INVOKE_ABORT:
747 printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
751 printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n",cs->ics.arg);
753 } /* switch ics.arg */
759 { printk(KERN_WARNING "dss1_divert unhandled process\n");
763 if (cs1->ics.driver == -1)
765 spin_lock_irqsave(&divert_lock, flags);
766 del_timer(&cs1->timer);
768 cs1->prev->next = cs1->next; /* forward link */
770 divert_head = cs1->next;
772 cs1->next->prev = cs1->prev; /* back link */
773 spin_unlock_irqrestore(&divert_lock, flags);
778 } /* prot_stat_callback */
781 /***************************/
782 /* status callback from HL */
783 /***************************/
784 static int isdn_divert_stat_callback(isdn_ctrl *ic)
785 { struct call_struc *cs, *cs1;
790 cs = divert_head; /* start of list */
792 { if ((ic->driver == cs->ics.driver) && (ic->arg == cs->ics.arg))
793 { switch (ic->command)
794 { case ISDN_STAT_DHUP:
795 sprintf(cs->info,"129 0x%lx\n",cs->divert_id);
796 del_timer(&cs->timer);
800 case ISDN_STAT_CAUSE:
801 sprintf(cs->info,"130 0x%lx %s\n",cs->divert_id,ic->parm.num);
804 case ISDN_STAT_REDIR:
805 sprintf(cs->info,"131 0x%lx\n",cs->divert_id);
806 del_timer(&cs->timer);
811 sprintf(cs->info,"999 0x%lx 0x%x\n",cs->divert_id,(int)(ic->command));
814 put_info_buffer(cs->info);
819 if (cs1->ics.driver == -1)
821 spin_lock_irqsave(&divert_lock, flags);
823 cs1->prev->next = cs1->next; /* forward link */
825 divert_head = cs1->next;
827 cs1->next->prev = cs1->prev; /* back link */
828 spin_unlock_irqrestore(&divert_lock, flags);
832 return(retval); /* not found */
833 } /* isdn_divert_stat_callback */
836 /********************/
837 /* callback from ll */
838 /********************/
839 int ll_callback(isdn_ctrl *ic)
842 { case ISDN_STAT_ICALL:
843 case ISDN_STAT_ICALLW:
844 return(isdn_divert_icall(ic));
848 if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO)
849 { if (ic->arg != DSS1_STAT_INVOKE_BRD)
850 return(prot_stat_callback(ic));
852 return(0); /* DSS1 invoke broadcast */
855 return(-1); /* protocol not euro */
858 return(isdn_divert_stat_callback(ic));