Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6] / drivers / isdn / pcbit / callbacks.c
1 /*
2  * Callbacks for the FSM
3  *
4  * Copyright (C) 1996 Universidade de Lisboa
5  * 
6  * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
7  *
8  * This software may be used and distributed according to the terms of 
9  * the GNU General Public License, incorporated herein by reference.
10  */
11
12 /*
13  * Fix: 19981230 - Carlos Morgado <chbm@techie.com>
14  * Port of Nelson Escravana's <nelson.escravana@usa.net> fix to CalledPN 
15  * NULL pointer dereference in cb_in_1 (originally fixed in 2.0)
16  */
17
18 #include <linux/string.h>
19 #include <linux/kernel.h>
20
21 #include <linux/types.h>
22 #include <linux/slab.h>
23 #include <linux/mm.h>
24 #include <linux/skbuff.h>
25
26 #include <asm/io.h>
27
28 #include <linux/isdnif.h>
29
30 #include "pcbit.h"
31 #include "layer2.h"
32 #include "edss1.h"
33 #include "callbacks.h"
34 #include "capi.h"
35
36 ushort last_ref_num = 1;
37
38 /*
39  *  send_conn_req
40  *
41  */
42
43 void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan, 
44               struct callb_data *cbdata) 
45 {
46         struct sk_buff *skb;
47         int len;
48         ushort refnum;
49
50
51 #ifdef DEBUG
52         printk(KERN_DEBUG "Called Party Number: %s\n", 
53                cbdata->data.setup.CalledPN);
54 #endif
55         /*
56          * hdr - kmalloc in capi_conn_req
57          *     - kfree   when msg has been sent
58          */
59
60         if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb, 
61                                  chan->proto)) < 0)
62         {
63                 printk("capi_conn_req failed\n");
64                 return;
65         }
66
67
68         refnum = last_ref_num++ & 0x7fffU;
69
70         chan->callref = 0;
71         chan->layer2link = 0;
72         chan->snum = 0;
73         chan->s_refnum = refnum;
74
75         pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len);
76 }
77
78 /*
79  *  rcv CONNECT
80  *  will go into ACTIVE state
81  *  send CONN_ACTIVE_RESP
82  *  send Select protocol request 
83  */
84
85 void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, 
86               struct callb_data *data) 
87 {
88         isdn_ctrl ictl;
89         struct sk_buff *skb;
90         int len;
91         ushort refnum;
92
93         if ((len=capi_conn_active_resp(chan, &skb)) < 0)
94         {
95                 printk("capi_conn_active_req failed\n");
96                 return;
97         }
98
99         refnum = last_ref_num++ & 0x7fffU;
100         chan->s_refnum = refnum;
101
102         pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len);
103
104
105         ictl.command = ISDN_STAT_DCONN;
106         ictl.driver=dev->id;
107         ictl.arg=chan->id;
108         dev->dev_if->statcallb(&ictl);
109
110         /* ACTIVE D-channel */
111
112         /* Select protocol  */
113
114         if ((len=capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) { 
115                 printk("capi_select_proto_req failed\n");
116                 return;
117         }
118
119         refnum = last_ref_num++ & 0x7fffU;
120         chan->s_refnum = refnum;
121
122         pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
123 }
124
125
126 /*
127  * Incoming call received
128  * inform user
129  */
130
131 void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
132              struct callb_data *cbdata) 
133 {
134         isdn_ctrl ictl;
135         unsigned short refnum;
136         struct sk_buff *skb;
137         int len;
138
139
140         ictl.command = ISDN_STAT_ICALL;
141         ictl.driver=dev->id;
142         ictl.arg=chan->id;
143         
144         /*
145          *  ictl.num >= strlen() + strlen() + 5
146          */
147
148         if (cbdata->data.setup.CallingPN == NULL) {
149                 printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n");
150                 strcpy(ictl.parm.setup.phone, "0");
151         }
152         else {
153                 strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN);
154         }
155         if (cbdata->data.setup.CalledPN == NULL) {
156                 printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n");
157                 strcpy(ictl.parm.setup.eazmsn, "0");
158         }
159         else {
160                 strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN);
161         }
162         ictl.parm.setup.si1 = 7;
163         ictl.parm.setup.si2 = 0;
164         ictl.parm.setup.plan = 0;
165         ictl.parm.setup.screen = 0;
166
167 #ifdef DEBUG
168         printk(KERN_DEBUG "statstr: %s\n", ictl.num);
169 #endif
170
171         dev->dev_if->statcallb(&ictl);
172
173         
174         if ((len=capi_conn_resp(chan, &skb)) < 0) {
175                 printk(KERN_DEBUG "capi_conn_resp failed\n");
176                 return;
177         }
178
179         refnum = last_ref_num++ & 0x7fffU;
180         chan->s_refnum = refnum;
181
182         pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len);
183 }
184
185 /*
186  * user has replied
187  * open the channel
188  * send CONNECT message CONNECT_ACTIVE_REQ in CAPI
189  */
190
191 void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
192              struct callb_data *data)
193 {
194         unsigned short refnum;
195         struct sk_buff *skb;
196         int len;
197         
198         if ((len = capi_conn_active_req(chan, &skb)) < 0) {        
199                 printk(KERN_DEBUG "capi_conn_active_req failed\n");
200                 return;
201         }
202
203
204         refnum = last_ref_num++ & 0x7fffU;
205         chan->s_refnum = refnum;
206
207         printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n");
208         pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len);
209 }
210
211 /*
212  * CONN_ACK arrived
213  * start b-proto selection
214  *
215  */
216
217 void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan, 
218              struct callb_data *data)
219 {
220         unsigned short refnum;
221         struct sk_buff *skb;
222         int len;
223         
224         if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0)
225         {
226                 printk("capi_select_proto_req failed\n");
227                 return;
228         }
229
230         refnum = last_ref_num++ & 0x7fffU;
231         chan->s_refnum = refnum;
232
233         pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
234
235 }
236
237
238 /*
239  * Received disconnect ind on active state
240  * send disconnect resp
241  * send msg to user
242  */
243 void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan, 
244                struct callb_data *data)
245 {
246         struct sk_buff *skb;
247         int len;
248         ushort refnum;
249         isdn_ctrl ictl;
250   
251         if ((len = capi_disc_resp(chan, &skb)) < 0) {
252                 printk("capi_disc_resp failed\n");
253                 return;
254         }
255
256         refnum = last_ref_num++ & 0x7fffU;
257         chan->s_refnum = refnum;
258
259         pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len);    
260
261         ictl.command = ISDN_STAT_BHUP;
262         ictl.driver=dev->id;
263         ictl.arg=chan->id;
264         dev->dev_if->statcallb(&ictl);
265 }
266
267         
268 /*
269  *  User HANGUP on active/call proceeding state
270  *  send disc.req
271  */
272 void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan, 
273                struct callb_data *data)
274 {
275         struct sk_buff *skb;
276         int len;
277         ushort refnum;
278
279         if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0)
280         {
281                 printk("capi_disc_req failed\n");
282                 return;
283         }
284
285         refnum = last_ref_num++ & 0x7fffU;
286         chan->s_refnum = refnum;
287
288         pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len);  
289 }
290
291 /*
292  *  Disc confirm received send BHUP
293  *  Problem: when the HL driver sends the disc req itself
294  *           LL receives BHUP
295  */
296 void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan, 
297                struct callb_data *data)
298 {
299         isdn_ctrl ictl;
300
301         ictl.command = ISDN_STAT_BHUP;
302         ictl.driver=dev->id;
303         ictl.arg=chan->id;
304         dev->dev_if->statcallb(&ictl);
305 }
306
307 void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan, 
308                 struct callb_data *data)
309 {
310 }
311
312 /*
313  * send activate b-chan protocol
314  */
315 void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan, 
316                struct callb_data *data) 
317 {
318         struct sk_buff *skb;
319         int len;
320         ushort refnum;
321
322         if ((len = capi_activate_transp_req(chan, &skb)) < 0)
323         {
324                 printk("capi_conn_activate_transp_req failed\n");
325                 return;
326         }
327
328         refnum = last_ref_num++ & 0x7fffU;
329         chan->s_refnum = refnum;
330
331         pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len);
332 }
333
334 /*
335  *  Inform User that the B-channel is available
336  */
337 void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan, 
338              struct callb_data *data) 
339 {
340         isdn_ctrl ictl;
341
342         ictl.command = ISDN_STAT_BCONN;
343         ictl.driver=dev->id;
344         ictl.arg=chan->id;
345         dev->dev_if->statcallb(&ictl);
346 }
347
348
349