aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/divert
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/divert
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/isdn/divert')
-rw-r--r--drivers/isdn/divert/Makefile9
-rw-r--r--drivers/isdn/divert/divert_init.c83
-rw-r--r--drivers/isdn/divert/divert_procfs.c319
-rw-r--r--drivers/isdn/divert/isdn_divert.c861
-rw-r--r--drivers/isdn/divert/isdn_divert.h132
5 files changed, 1404 insertions, 0 deletions
diff --git a/drivers/isdn/divert/Makefile b/drivers/isdn/divert/Makefile
new file mode 100644
index 000000000000..dd4a202e0bc2
--- /dev/null
+++ b/drivers/isdn/divert/Makefile
@@ -0,0 +1,9 @@
1# Makefile for the dss1_divert ISDN module
2
3# Each configuration option enables a list of files.
4
5obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o
6
7# Multipart objects.
8
9dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o
diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c
new file mode 100644
index 000000000000..434e684f5dbb
--- /dev/null
+++ b/drivers/isdn/divert/divert_init.c
@@ -0,0 +1,83 @@
1/* $Id divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $
2 *
3 * Module init for DSS1 diversion services 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/module.h>
13#include <linux/version.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16
17#include "isdn_divert.h"
18
19MODULE_DESCRIPTION("ISDN4Linux: Call diversion support");
20MODULE_AUTHOR("Werner Cornelius");
21MODULE_LICENSE("GPL");
22
23/****************************************/
24/* structure containing interface to hl */
25/****************************************/
26isdn_divert_if divert_if =
27 { DIVERT_IF_MAGIC, /* magic value */
28 DIVERT_CMD_REG, /* register cmd */
29 ll_callback, /* callback routine from ll */
30 NULL, /* command still not specified */
31 NULL, /* drv_to_name */
32 NULL, /* name_to_drv */
33 };
34
35/*************************/
36/* Module interface code */
37/* no cmd line parms */
38/*************************/
39static int __init divert_init(void)
40{ int i;
41
42 if (divert_dev_init())
43 { printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n");
44 return(-EIO);
45 }
46 if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
47 { divert_dev_deinit();
48 printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n",i);
49 return(-EIO);
50 }
51 printk(KERN_INFO "dss1_divert module successfully installed\n");
52 return(0);
53}
54
55/**********************/
56/* Module deinit code */
57/**********************/
58static void __exit divert_exit(void)
59{
60 unsigned long flags;
61 int i;
62
63 spin_lock_irqsave(&divert_lock, flags);
64 divert_if.cmd = DIVERT_CMD_REL; /* release */
65 if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR)
66 { printk(KERN_WARNING "dss1_divert: error %d releasing module\n",i);
67 spin_unlock_irqrestore(&divert_lock, flags);
68 return;
69 }
70 if (divert_dev_deinit())
71 { printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n");
72 spin_unlock_irqrestore(&divert_lock, flags);
73 return;
74 }
75 spin_unlock_irqrestore(&divert_lock, flags);
76 deleterule(-1); /* delete all rules and free mem */
77 deleteprocs();
78 printk(KERN_INFO "dss1_divert module successfully removed \n");
79}
80
81module_init(divert_init);
82module_exit(divert_exit);
83
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
new file mode 100644
index 000000000000..e1f0d87de0eb
--- /dev/null
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -0,0 +1,319 @@
1/* $Id: divert_procfs.c,v 1.11.6.2 2001/09/23 22:24:36 kai Exp $
2 *
3 * Filesystem handling for the diversion supplementary services.
4 *
5 * Copyright 1998 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/config.h>
13#include <linux/module.h>
14#include <linux/version.h>
15#include <linux/poll.h>
16#include <linux/smp_lock.h>
17#ifdef CONFIG_PROC_FS
18#include <linux/proc_fs.h>
19#else
20#include <linux/fs.h>
21#endif
22#include <linux/isdnif.h>
23#include "isdn_divert.h"
24
25
26/*********************************/
27/* Variables for interface queue */
28/*********************************/
29ulong if_used = 0; /* number of interface users */
30static struct divert_info *divert_info_head = NULL; /* head of queue */
31static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */
32static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */
33static wait_queue_head_t rd_queue;
34
35/*********************************/
36/* put an info buffer into queue */
37/*********************************/
38void
39put_info_buffer(char *cp)
40{
41 struct divert_info *ib;
42 unsigned long flags;
43
44 if (if_used <= 0)
45 return;
46 if (!cp)
47 return;
48 if (!*cp)
49 return;
50 if (!(ib = (struct divert_info *) kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC)))
51 return; /* no memory */
52 strcpy(ib->info_start, cp); /* set output string */
53 ib->next = NULL;
54 spin_lock_irqsave( &divert_info_lock, flags );
55 ib->usage_cnt = if_used;
56 if (!divert_info_head)
57 divert_info_head = ib; /* new head */
58 else
59 divert_info_tail->next = ib; /* follows existing messages */
60 divert_info_tail = ib; /* new tail */
61
62 /* delete old entrys */
63 while (divert_info_head->next) {
64 if ((divert_info_head->usage_cnt <= 0) &&
65 (divert_info_head->next->usage_cnt <= 0)) {
66 ib = divert_info_head;
67 divert_info_head = divert_info_head->next;
68 kfree(ib);
69 } else
70 break;
71 } /* divert_info_head->next */
72 spin_unlock_irqrestore( &divert_info_lock, flags );
73 wake_up_interruptible(&(rd_queue));
74} /* put_info_buffer */
75
76/**********************************/
77/* deflection device read routine */
78/**********************************/
79static ssize_t
80isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t * off)
81{
82 struct divert_info *inf;
83 int len;
84
85 if (!*((struct divert_info **) file->private_data)) {
86 if (file->f_flags & O_NONBLOCK)
87 return -EAGAIN;
88 interruptible_sleep_on(&(rd_queue));
89 }
90 if (!(inf = *((struct divert_info **) file->private_data)))
91 return (0);
92
93 inf->usage_cnt--; /* new usage count */
94 file->private_data = &inf->next; /* next structure */
95 if ((len = strlen(inf->info_start)) <= count) {
96 if (copy_to_user(buf, inf->info_start, len))
97 return -EFAULT;
98 *off += len;
99 return (len);
100 }
101 return (0);
102} /* isdn_divert_read */
103
104/**********************************/
105/* deflection device write routine */
106/**********************************/
107static ssize_t
108isdn_divert_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
109{
110 return (-ENODEV);
111} /* isdn_divert_write */
112
113
114/***************************************/
115/* select routines for various kernels */
116/***************************************/
117static unsigned int
118isdn_divert_poll(struct file *file, poll_table * wait)
119{
120 unsigned int mask = 0;
121
122 poll_wait(file, &(rd_queue), wait);
123 /* mask = POLLOUT | POLLWRNORM; */
124 if (*((struct divert_info **) file->private_data)) {
125 mask |= POLLIN | POLLRDNORM;
126 }
127 return mask;
128} /* isdn_divert_poll */
129
130/****************/
131/* Open routine */
132/****************/
133static int
134isdn_divert_open(struct inode *ino, struct file *filep)
135{
136 unsigned long flags;
137
138 spin_lock_irqsave( &divert_info_lock, flags );
139 if_used++;
140 if (divert_info_head)
141 filep->private_data = &(divert_info_tail->next);
142 else
143 filep->private_data = &divert_info_head;
144 spin_unlock_irqrestore( &divert_info_lock, flags );
145 /* start_divert(); */
146 return nonseekable_open(ino, filep);
147} /* isdn_divert_open */
148
149/*******************/
150/* close routine */
151/*******************/
152static int
153isdn_divert_close(struct inode *ino, struct file *filep)
154{
155 struct divert_info *inf;
156 unsigned long flags;
157
158 spin_lock_irqsave( &divert_info_lock, flags );
159 if_used--;
160 inf = *((struct divert_info **) filep->private_data);
161 while (inf) {
162 inf->usage_cnt--;
163 inf = inf->next;
164 }
165 if (if_used <= 0)
166 while (divert_info_head) {
167 inf = divert_info_head;
168 divert_info_head = divert_info_head->next;
169 kfree(inf);
170 }
171 spin_unlock_irqrestore( &divert_info_lock, flags );
172 return (0);
173} /* isdn_divert_close */
174
175/*********/
176/* IOCTL */
177/*********/
178static int
179isdn_divert_ioctl(struct inode *inode, struct file *file,
180 uint cmd, ulong arg)
181{
182 divert_ioctl dioctl;
183 int i;
184 unsigned long flags;
185 divert_rule *rulep;
186 char *cp;
187
188 if (copy_from_user(&dioctl, (void __user *) arg, sizeof(dioctl)))
189 return -EFAULT;
190
191 switch (cmd) {
192 case IIOCGETVER:
193 dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */
194 break;
195
196 case IIOCGETDRV:
197 if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0)
198 return (-EINVAL);
199 break;
200
201 case IIOCGETNAM:
202 cp = divert_if.drv_to_name(dioctl.getid.drvid);
203 if (!cp)
204 return (-EINVAL);
205 if (!*cp)
206 return (-EINVAL);
207 strcpy(dioctl.getid.drvnam, cp);
208 break;
209
210 case IIOCGETRULE:
211 if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
212 return (-EINVAL);
213 dioctl.getsetrule.rule = *rulep; /* copy data */
214 break;
215
216 case IIOCMODRULE:
217 if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx)))
218 return (-EINVAL);
219 spin_lock_irqsave(&divert_lock, flags);
220 *rulep = dioctl.getsetrule.rule; /* copy data */
221 spin_unlock_irqrestore(&divert_lock, flags);
222 return (0); /* no copy required */
223 break;
224
225 case IIOCINSRULE:
226 return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule));
227 break;
228
229 case IIOCDELRULE:
230 return (deleterule(dioctl.getsetrule.ruleidx));
231 break;
232
233 case IIOCDODFACT:
234 return (deflect_extern_action(dioctl.fwd_ctrl.subcmd,
235 dioctl.fwd_ctrl.callid,
236 dioctl.fwd_ctrl.to_nr));
237
238 case IIOCDOCFACT:
239 case IIOCDOCFDIS:
240 case IIOCDOCFINT:
241 if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid))
242 return (-EINVAL); /* invalid driver */
243 if ((i = cf_command(dioctl.cf_ctrl.drvid,
244 (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2,
245 dioctl.cf_ctrl.cfproc,
246 dioctl.cf_ctrl.msn,
247 dioctl.cf_ctrl.service,
248 dioctl.cf_ctrl.fwd_nr,
249 &dioctl.cf_ctrl.procid)))
250 return (i);
251 break;
252
253 default:
254 return (-EINVAL);
255 } /* switch cmd */
256 return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
257} /* isdn_divert_ioctl */
258
259
260#ifdef CONFIG_PROC_FS
261static struct file_operations isdn_fops =
262{
263 .owner = THIS_MODULE,
264 .llseek = no_llseek,
265 .read = isdn_divert_read,
266 .write = isdn_divert_write,
267 .poll = isdn_divert_poll,
268 .ioctl = isdn_divert_ioctl,
269 .open = isdn_divert_open,
270 .release = isdn_divert_close,
271};
272
273/****************************/
274/* isdn subdir in /proc/net */
275/****************************/
276static struct proc_dir_entry *isdn_proc_entry = NULL;
277static struct proc_dir_entry *isdn_divert_entry = NULL;
278#endif /* CONFIG_PROC_FS */
279
280/***************************************************************************/
281/* divert_dev_init must be called before the proc filesystem may be used */
282/***************************************************************************/
283int
284divert_dev_init(void)
285{
286
287 init_waitqueue_head(&rd_queue);
288
289#ifdef CONFIG_PROC_FS
290 isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
291 if (!isdn_proc_entry)
292 return (-1);
293 isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
294 if (!isdn_divert_entry) {
295 remove_proc_entry("isdn", proc_net);
296 return (-1);
297 }
298 isdn_divert_entry->proc_fops = &isdn_fops;
299 isdn_divert_entry->owner = THIS_MODULE;
300#endif /* CONFIG_PROC_FS */
301
302 return (0);
303} /* divert_dev_init */
304
305/***************************************************************************/
306/* divert_dev_deinit must be called before leaving isdn when included as */
307/* a module. */
308/***************************************************************************/
309int
310divert_dev_deinit(void)
311{
312
313#ifdef CONFIG_PROC_FS
314 remove_proc_entry("divert", isdn_proc_entry);
315 remove_proc_entry("isdn", proc_net);
316#endif /* CONFIG_PROC_FS */
317
318 return (0);
319} /* divert_dev_deinit */
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
new file mode 100644
index 000000000000..1eb112213f0c
--- /dev/null
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -0,0 +1,861 @@
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/version.h>
13#include <linux/proc_fs.h>
14
15#include "isdn_divert.h"
16
17/**********************************/
18/* structure keeping calling info */
19/**********************************/
20struct call_struc
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;
29 };
30
31
32/********************************************/
33/* structure keeping deflection table entry */
34/********************************************/
35struct deflect_struc
36 { struct deflect_struc *next,*prev;
37 divert_rule rule; /* used rule */
38 };
39
40
41/*****************************************/
42/* variables for main diversion services */
43/*****************************************/
44/* diversion/deflection processes */
45static struct call_struc *divert_head = NULL; /* head of remembered entrys */
46static ulong next_id = 1; /* next info id */
47static struct deflect_struc *table_head = NULL;
48static struct deflect_struc *table_tail = NULL;
49static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
50
51DEFINE_SPINLOCK(divert_lock);
52
53/***************************/
54/* timer callback function */
55/***************************/
56static void deflect_timer_expire(ulong arg)
57{
58 unsigned long flags;
59 struct call_struc *cs = (struct call_struc *) arg;
60
61 spin_lock_irqsave(&divert_lock, flags);
62 del_timer(&cs->timer); /* delete active timer */
63 spin_unlock_irqrestore(&divert_lock, flags);
64
65 switch(cs->akt_state)
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);
74 break;
75
76 case DEFLECT_ALERT:
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);
86 break;
87
88 case DEFLECT_AUTODEL:
89 default:
90 spin_lock_irqsave(&divert_lock, flags);
91 if (cs->prev)
92 cs->prev->next = cs->next; /* forward link */
93 else
94 divert_head = cs->next;
95 if (cs->next)
96 cs->next->prev = cs->prev; /* back link */
97 spin_unlock_irqrestore(&divert_lock, flags);
98 kfree(cs);
99 return;
100
101 } /* switch */
102} /* deflect_timer_func */
103
104
105/*****************************************/
106/* handle call forwarding de/activations */
107/* 0 = deact, 1 = act, 2 = interrogate */
108/*****************************************/
109int 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;
113 int retval,msnlen;
114 int fwd_len;
115 char *p,*ielenp,tmp[60];
116 struct call_struc *cs;
117
118 if (strchr(msn,'.')) return(-EINVAL); /* subaddress not allowed in msn */
119 if ((proc & 0x7F) > 2) return(-EINVAL);
120 proc &= 3;
121 p = tmp;
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 */
130
131 if (mode == 1)
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 */
141 } /* activate */
142
143 msnlen = strlen(msn);
144 *p++ = 0x80; /* msn number */
145 if (msnlen > 1)
146 { *p++ = msnlen; /* length */
147 strcpy(p,msn);
148 p += msnlen;
149 }
150 else *p++ = 0;
151
152 *ielenp = p - ielenp - 1; /* set total IE length */
153
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);
158 cs->info[0] = '\0';
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 */
168
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;
173
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),
179 msn,
180 service & 0xFF,
181 proc,
182 (mode != 1) ? "" : " 0 ",
183 (mode != 1) ? "" : fwd_nr);
184
185 retval = divert_if.ll_cmd(&cs->ics); /* excute command */
186
187 if (!retval)
188 { cs->prev = NULL;
189 spin_lock_irqsave(&divert_lock, flags);
190 cs->next = divert_head;
191 divert_head = cs;
192 spin_unlock_irqrestore(&divert_lock, flags);
193 }
194 else
195 kfree(cs);
196 return(retval);
197} /* cf_command */
198
199
200/****************************************/
201/* handle a external deflection command */
202/****************************************/
203int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
204{ struct call_struc *cs;
205 isdn_ctrl ic;
206 unsigned long flags;
207 int i;
208
209 if ((cmd & 0x7F) > 2) return(-EINVAL); /* invalid command */
210 cs = divert_head; /* start of parameter list */
211 while (cs)
212 { if (cs->divert_id == callid) break; /* found */
213 cs = cs->next;
214 } /* search entry */
215 if (!cs) return(-EINVAL); /* invalid callid */
216
217 ic.driver = cs->ics.driver;
218 ic.arg = cs->ics.arg;
219 i = -EINVAL;
220 if (cs->akt_state == DEFLECT_AUTODEL) return(i); /* no valid call */
221 switch (cmd & 0x7F)
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);
231 break;
232
233 case 1: /* alert */
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)))
239 {
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);
245 }
246 else
247 cs->akt_state = DEFLECT_ALERT;
248 break;
249
250 case 2: /* redir */
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)))
256 {
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);
262 }
263 else
264 cs->akt_state = DEFLECT_ALERT;
265 break;
266
267 } /* switch */
268 return(i);
269} /* deflect_extern_action */
270
271/********************************/
272/* insert a new rule before idx */
273/********************************/
274int insertrule(int idx, divert_rule *newrule)
275{ struct deflect_struc *ds,*ds1=NULL;
276 unsigned long flags;
277
278 if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc),
279 GFP_KERNEL)))
280 return(-ENOMEM); /* no memory */
281
282 ds->rule = *newrule; /* set rule */
283
284 spin_lock_irqsave(&divert_lock, flags);
285
286 if (idx >= 0)
287 { ds1 = table_head;
288 while ((ds1) && (idx > 0))
289 { idx--;
290 ds1 = ds1->next;
291 }
292 if (!ds1) idx = -1;
293 }
294
295 if (idx < 0)
296 { ds->prev = table_tail; /* previous entry */
297 ds->next = NULL; /* end of chain */
298 if (ds->prev)
299 ds->prev->next = ds; /* last forward */
300 else
301 table_head = ds; /* is first entry */
302 table_tail = ds; /* end of queue */
303 }
304 else
305 { ds->next = ds1; /* next entry */
306 ds->prev = ds1->prev; /* prev entry */
307 ds1->prev = ds; /* backward chain old element */
308 if (!ds->prev)
309 table_head = ds; /* first element */
310 }
311
312 spin_unlock_irqrestore(&divert_lock, flags);
313 return(0);
314} /* insertrule */
315
316/***********************************/
317/* delete the rule at position idx */
318/***********************************/
319int deleterule(int idx)
320{ struct deflect_struc *ds,*ds1;
321 unsigned long flags;
322
323 if (idx < 0)
324 { spin_lock_irqsave(&divert_lock, flags);
325 ds = table_head;
326 table_head = NULL;
327 table_tail = NULL;
328 spin_unlock_irqrestore(&divert_lock, flags);
329 while (ds)
330 { ds1 = ds;
331 ds = ds->next;
332 kfree(ds1);
333 }
334 return(0);
335 }
336
337 spin_lock_irqsave(&divert_lock, flags);
338 ds = table_head;
339
340 while ((ds) && (idx > 0))
341 { idx--;
342 ds = ds->next;
343 }
344
345 if (!ds)
346 {
347 spin_unlock_irqrestore(&divert_lock, flags);
348 return(-EINVAL);
349 }
350
351 if (ds->next)
352 ds->next->prev = ds->prev; /* backward chain */
353 else
354 table_tail = ds->prev; /* end of chain */
355
356 if (ds->prev)
357 ds->prev->next = ds->next; /* forward chain */
358 else
359 table_head = ds->next; /* start of chain */
360
361 spin_unlock_irqrestore(&divert_lock, flags);
362 kfree(ds);
363 return(0);
364} /* deleterule */
365
366/*******************************************/
367/* get a pointer to a specific rule number */
368/*******************************************/
369divert_rule *getruleptr(int idx)
370{ struct deflect_struc *ds = table_head;
371
372 if (idx < 0) return(NULL);
373 while ((ds) && (idx >= 0))
374 { if (!(idx--))
375 { return(&ds->rule);
376 break;
377 }
378 ds = ds->next;
379 }
380 return(NULL);
381} /* getruleptr */
382
383/*************************************************/
384/* called from common module on an incoming call */
385/*************************************************/
386int isdn_divert_icall(isdn_ctrl *ic)
387{ int retval = 0;
388 unsigned long flags;
389 struct call_struc *cs = NULL;
390 struct deflect_struc *dv;
391 char *p,*p1;
392 u_char accept;
393
394 /* first check the internal deflection table */
395 for (dv = table_head; dv ; dv = dv->next )
396 { /* scan table */
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 */
406
407 p = dv->rule.my_msn;
408 p1 = ic->parm.setup.eazmsn;
409 accept = 0;
410 while (*p)
411 { /* complete compare */
412 if (*p == '-')
413 { accept = 1; /* call accepted */
414 break;
415 }
416 if (*p++ != *p1++)
417 break; /* not accepted */
418 if ((!*p) && (!*p1))
419 accept = 1;
420 } /* complete compare */
421 if (!accept) continue; /* not accepted */
422
423 if ((strcmp(dv->rule.caller,"0")) || (ic->parm.setup.phone[0]))
424 { p = dv->rule.caller;
425 p1 = ic->parm.setup.phone;
426 accept = 0;
427 while (*p)
428 { /* complete compare */
429 if (*p == '-')
430 { accept = 1; /* call accepted */
431 break;
432 }
433 if (*p++ != *p1++)
434 break; /* not accepted */
435 if ((!*p) && (!*p1))
436 accept = 1;
437 } /* complete compare */
438 if (!accept) continue; /* not accepted */
439 }
440
441 switch (dv->rule.action)
442 { case DEFLECT_IGNORE:
443 return(0);
444 break;
445
446 case DEFLECT_ALERT:
447 case DEFLECT_PROCEED:
448 case DEFLECT_REPORT:
449 case DEFLECT_REJECT:
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);
456 cs->info[0] = '\0';
457 cs->timer.function = deflect_timer_expire;
458 cs->timer.data = (ulong) cs; /* pointer to own structure */
459
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);
466 else
467 if (dv->rule.action == DEFLECT_PROCEED)
468 cs->timer.expires = jiffies + (HZ * extern_wait_max);
469 else
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);
475 cs->prev = NULL;
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);
484 retval = 5;
485 }
486 else
487 retval = 1; /* alerting */
488 }
489 else
490 { cs->deflect_dest[0] = '\0';
491 retval = 4; /* only proceed */
492 }
493 sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
494 cs->akt_state,
495 cs->divert_id,
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,
503 dv->rule.waittime,
504 cs->deflect_dest);
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 */
510 }
511 break;
512
513 default:
514 return(0); /* ignore call */
515 break;
516 } /* switch action */
517 break;
518 } /* scan_table */
519
520 if (cs)
521 { cs->prev = NULL;
522 spin_lock_irqsave(&divert_lock, flags);
523 cs->next = divert_head;
524 divert_head = cs;
525 if (cs->timer.expires) add_timer(&cs->timer);
526 spin_unlock_irqrestore(&divert_lock, flags);
527
528 put_info_buffer(cs->info);
529 return(retval);
530 }
531 else
532 return(0);
533} /* isdn_divert_icall */
534
535
536void deleteprocs(void)
537{ struct call_struc *cs, *cs1;
538 unsigned long flags;
539
540 spin_lock_irqsave(&divert_lock, flags);
541 cs = divert_head;
542 divert_head = NULL;
543 while (cs)
544 { del_timer(&cs->timer);
545 cs1 = cs;
546 cs = cs->next;
547 kfree(cs1);
548 }
549 spin_unlock_irqrestore(&divert_lock, flags);
550} /* deleteprocs */
551
552/****************************************************/
553/* put a address including address type into buffer */
554/****************************************************/
555int put_address(char *st, u_char *p, int len)
556{ u_char retval = 0;
557 u_char adr_typ = 0; /* network standard */
558
559 if (len < 2) return(retval);
560 if (*p == 0xA1)
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);
566 adr_typ = *(++p);
567 len -= 3;
568 p++;
569 if (len < 2) return(0);
570 if (*p++ != 0x12) return(0);
571 if (*p > len) return(0); /* check number length */
572 len = *p++;
573 }
574 else
575 if (*p == 0x80)
576 { retval = *(++p) + 2; /* total length */
577 if (retval > len) return(0);
578 len = retval - 2;
579 p++;
580 }
581 else
582 return(0); /* invalid address information */
583
584 sprintf(st,"%d ",adr_typ);
585 st += strlen(st);
586 if (!len)
587 *st++ = '-';
588 else
589 while (len--)
590 *st++ = *p++;
591 *st = '\0';
592 return(retval);
593} /* put_address */
594
595/*************************************/
596/* report a succesfull interrogation */
597/*************************************/
598int 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;
601 int cnt = 1;
602 u_char n,n1;
603 char st[90], *p, *stp;
604
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 */
609 if (n == 0x80)
610 { if (restlen < 2) return(-103);
611 if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-104);
612 restlen -= 2;
613 }
614 else
615 if ( n == 0x81)
616 { n = *src++;
617 restlen--;
618 if (n > restlen) return(-105);
619 restlen = n;
620 }
621 else
622 if (n > restlen) return(-106);
623 else
624 restlen = n; /* standard format */
625 if (restlen < 3) return(-107); /* no procedure */
626 if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return(-108);
627 restlen -= 3;
628 if (restlen < 2) return(-109); /* list missing */
629 if (*src == 0x31)
630 { src++;
631 if ((n = *src++) > 0x81) return(-110); /* invalid length field */
632 restlen -= 2; /* remaining bytes */
633 if (n == 0x80)
634 { if (restlen < 2) return(-111);
635 if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-112);
636 restlen -= 2;
637 }
638 else
639 if ( n == 0x81)
640 { n = *src++;
641 restlen--;
642 if (n > restlen) return(-113);
643 restlen = n;
644 }
645 else
646 if (n > restlen) return(-114);
647 else
648 restlen = n; /* standard format */
649 } /* result list header */
650
651 while (restlen >= 2)
652 { stp = st;
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));
655 stp += strlen(stp);
656 if (*src++ != 0x30) return(-115); /* invalid enum */
657 n = *src++;
658 restlen -= 2;
659 if (n > restlen) return(-116); /* enum length wrong */
660 restlen -= n;
661 p = src; /* one entry */
662 src += n;
663 if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
664 stp += strlen(stp);
665 p += n1;
666 n -= n1;
667 if (n < 6) continue; /* no service and proc */
668 if ((*p++ != 0x0A) || (*p++ != 1)) continue;
669 sprintf(stp," 0x%02x ",(*p++) & 0xFF);
670 stp += strlen(stp);
671 if ((*p++ != 0x0A) || (*p++ != 1)) continue;
672 sprintf(stp,"%d ",(*p++) & 0xFF);
673 stp += strlen(stp);
674 n -= 6;
675 if (n > 2)
676 { if (*p++ != 0x30) continue;
677 if (*p > (n-2)) continue;
678 n = *p++;
679 if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
680 stp += strlen(stp);
681 }
682 sprintf(stp,"\n");
683 put_info_buffer(st);
684 } /* while restlen */
685 if (restlen) return(-117);
686 return(0);
687} /* interrogate_success */
688
689/*********************************************/
690/* callback for protocol specific extensions */
691/*********************************************/
692int prot_stat_callback(isdn_ctrl *ic)
693{ struct call_struc *cs, *cs1;
694 int i;
695 unsigned long flags;
696
697 cs = divert_head; /* start of list */
698 cs1 = NULL;
699 while (cs)
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))
705 { switch (ic->arg)
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);
711 break;
712
713 case DSS1_STAT_INVOKE_RES:
714 switch (cs->ics.parm.dss1_io.proc)
715 { case 7:
716 case 8:
717 put_info_buffer(cs->info);
718 break;
719
720 case 11:
721 i = interrogate_success(ic,cs);
722 if (i)
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);
726 break;
727
728 default:
729 printk(KERN_WARNING "dss1_divert: unknown proc %d\n",cs->ics.parm.dss1_io.proc);
730 break;
731 }
732
733
734 break;
735
736 default:
737 printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n",ic->arg);
738 break;
739 }
740 cs1 = cs; /* remember structure */
741 cs = NULL;
742 continue; /* abort search */
743 } /* id found */
744 break;
745
746 case DSS1_CMD_INVOKE_ABORT:
747 printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
748 break;
749
750 default:
751 printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n",cs->ics.arg);
752 break;
753 } /* switch ics.arg */
754 cs = cs->next;
755 } /* driver ok */
756 }
757
758 if (!cs1)
759 { printk(KERN_WARNING "dss1_divert unhandled process\n");
760 return(0);
761 }
762
763 if (cs1->ics.driver == -1)
764 {
765 spin_lock_irqsave(&divert_lock, flags);
766 del_timer(&cs1->timer);
767 if (cs1->prev)
768 cs1->prev->next = cs1->next; /* forward link */
769 else
770 divert_head = cs1->next;
771 if (cs1->next)
772 cs1->next->prev = cs1->prev; /* back link */
773 spin_unlock_irqrestore(&divert_lock, flags);
774 kfree(cs1);
775 }
776
777 return(0);
778} /* prot_stat_callback */
779
780
781/***************************/
782/* status callback from HL */
783/***************************/
784int isdn_divert_stat_callback(isdn_ctrl *ic)
785{ struct call_struc *cs, *cs1;
786 unsigned long flags;
787 int retval;
788
789 retval = -1;
790 cs = divert_head; /* start of list */
791 while (cs)
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);
797 cs->ics.driver = -1;
798 break;
799
800 case ISDN_STAT_CAUSE:
801 sprintf(cs->info,"130 0x%lx %s\n",cs->divert_id,ic->parm.num);
802 break;
803
804 case ISDN_STAT_REDIR:
805 sprintf(cs->info,"131 0x%lx\n",cs->divert_id);
806 del_timer(&cs->timer);
807 cs->ics.driver = -1;
808 break;
809
810 default:
811 sprintf(cs->info,"999 0x%lx 0x%x\n",cs->divert_id,(int)(ic->command));
812 break;
813 }
814 put_info_buffer(cs->info);
815 retval = 0;
816 }
817 cs1 = cs;
818 cs = cs->next;
819 if (cs1->ics.driver == -1)
820 {
821 spin_lock_irqsave(&divert_lock, flags);
822 if (cs1->prev)
823 cs1->prev->next = cs1->next; /* forward link */
824 else
825 divert_head = cs1->next;
826 if (cs1->next)
827 cs1->next->prev = cs1->prev; /* back link */
828 spin_unlock_irqrestore(&divert_lock, flags);
829 kfree(cs1);
830 }
831 }
832 return(retval); /* not found */
833} /* isdn_divert_stat_callback */
834
835
836/********************/
837/* callback from ll */
838/********************/
839int ll_callback(isdn_ctrl *ic)
840{
841 switch (ic->command)
842 { case ISDN_STAT_ICALL:
843 case ISDN_STAT_ICALLW:
844 return(isdn_divert_icall(ic));
845 break;
846
847 case ISDN_STAT_PROT:
848 if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO)
849 { if (ic->arg != DSS1_STAT_INVOKE_BRD)
850 return(prot_stat_callback(ic));
851 else
852 return(0); /* DSS1 invoke broadcast */
853 }
854 else
855 return(-1); /* protocol not euro */
856
857 default:
858 return(isdn_divert_stat_callback(ic));
859 }
860} /* ll_callback */
861
diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h
new file mode 100644
index 000000000000..19439a6176a9
--- /dev/null
+++ b/drivers/isdn/divert/isdn_divert.h
@@ -0,0 +1,132 @@
1/* $Id: isdn_divert.h,v 1.5.6.1 2001/09/23 22:24:36 kai Exp $
2 *
3 * Header for the diversion supplementary ioctl interface.
4 *
5 * Copyright 1998 by Werner Cornelius (werner@ikt.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/ioctl.h>
13#include <linux/types.h>
14
15/******************************************/
16/* IOCTL codes for interface to user prog */
17/******************************************/
18#define DIVERT_IIOC_VERSION 0x01 /* actual version */
19#define IIOCGETVER _IO('I', 1) /* get version of interface */
20#define IIOCGETDRV _IO('I', 2) /* get driver number */
21#define IIOCGETNAM _IO('I', 3) /* get driver name */
22#define IIOCGETRULE _IO('I', 4) /* read one rule */
23#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */
24#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */
25#define IIOCDELRULE _IO('I', 7) /* delete a rule */
26#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */
27#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */
28#define IIOCDOCFDIS _IO('I',10) /* deactivate control forwarding in PBX */
29#define IIOCDOCFINT _IO('I',11) /* interrogate control forwarding in PBX */
30
31/*************************************/
32/* states reported through interface */
33/*************************************/
34#define DEFLECT_IGNORE 0 /* ignore incoming call */
35#define DEFLECT_REPORT 1 /* only report */
36#define DEFLECT_PROCEED 2 /* deflect when externally triggered */
37#define DEFLECT_ALERT 3 /* alert and deflect after delay */
38#define DEFLECT_REJECT 4 /* reject immediately */
39#define DIVERT_ACTIVATE 5 /* diversion activate */
40#define DIVERT_DEACTIVATE 6 /* diversion deactivate */
41#define DIVERT_REPORT 7 /* interrogation result */
42#define DEFLECT_AUTODEL 255 /* only for internal use */
43
44#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
45
46typedef struct
47 { ulong drvid; /* driver ids, bit mapped */
48 char my_msn[35]; /* desired msn, subaddr allowed */
49 char caller[35]; /* caller id, partial string with * + subaddr allowed */
50 char to_nr[35]; /* deflected to number incl. subaddress */
51 u_char si1,si2; /* service indicators, si1=bitmask, si1+2 0 = all */
52 u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */
53 u_char callopt; /* option for call handling:
54 0 = all calls
55 1 = only non waiting calls
56 2 = only waiting calls */
57 u_char action; /* desired action:
58 0 = don't report call -> ignore
59 1 = report call, do not allow/proceed for deflection
60 2 = report call, send proceed, wait max waittime secs
61 3 = report call, alert and deflect after waittime
62 4 = report call, reject immediately
63 actions 1-2 only take place if interface is opened
64 */
65 u_char waittime; /* maximum wait time for proceeding */
66 } divert_rule;
67
68typedef union
69 { int drv_version; /* return of driver version */
70 struct
71 { int drvid; /* id of driver */
72 char drvnam[30]; /* name of driver */
73 } getid;
74 struct
75 { int ruleidx; /* index of rule */
76 divert_rule rule; /* rule parms */
77 } getsetrule;
78 struct
79 { u_char subcmd; /* 0 = hangup/reject,
80 1 = alert,
81 2 = deflect */
82 ulong callid; /* id of call delivered by ascii output */
83 char to_nr[35]; /* destination when deflect,
84 else uus1 string (maxlen 31),
85 data from rule used if empty */
86 } fwd_ctrl;
87 struct
88 { int drvid; /* id of driver */
89 u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */
90 ulong procid; /* process id returned when no error */
91 u_char service; /* basically coded service, 0 = all */
92 char msn[25]; /* desired msn, empty = all */
93 char fwd_nr[35];/* forwarded to number + subaddress */
94 } cf_ctrl;
95 } divert_ioctl;
96
97#ifdef __KERNEL__
98
99#include <linux/isdnif.h>
100#include <linux/isdn_divertif.h>
101
102#define AUTODEL_TIME 30 /* timeout in s to delete internal entries */
103
104/**************************************************/
105/* structure keeping ascii info for device output */
106/**************************************************/
107struct divert_info
108 { struct divert_info *next;
109 ulong usage_cnt; /* number of files still to work */
110 char info_start[2]; /* info string start */
111 };
112
113
114/**************/
115/* Prototypes */
116/**************/
117extern spinlock_t divert_lock;
118
119extern ulong if_used; /* number of interface users */
120extern int divert_dev_deinit(void);
121extern int divert_dev_init(void);
122extern void put_info_buffer(char *);
123extern int ll_callback(isdn_ctrl *);
124extern isdn_divert_if divert_if;
125extern divert_rule *getruleptr(int);
126extern int insertrule(int, divert_rule *);
127extern int deleterule(int);
128extern void deleteprocs(void);
129extern int deflect_extern_action(u_char, ulong, char *);
130extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *);
131
132#endif /* __KERNEL__ */