diff options
Diffstat (limited to 'drivers/isdn/pcbit/callbacks.c')
-rw-r--r-- | drivers/isdn/pcbit/callbacks.c | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c new file mode 100644 index 000000000000..692ec72d1ee8 --- /dev/null +++ b/drivers/isdn/pcbit/callbacks.c | |||
@@ -0,0 +1,367 @@ | |||
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/sched.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/kernel.h> | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/skbuff.h> | ||
26 | |||
27 | #include <asm/io.h> | ||
28 | |||
29 | #include <linux/isdnif.h> | ||
30 | |||
31 | #include "pcbit.h" | ||
32 | #include "layer2.h" | ||
33 | #include "edss1.h" | ||
34 | #include "callbacks.h" | ||
35 | #include "capi.h" | ||
36 | |||
37 | ushort last_ref_num = 1; | ||
38 | |||
39 | /* | ||
40 | * send_conn_req | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
45 | struct callb_data *cbdata) | ||
46 | { | ||
47 | struct sk_buff *skb; | ||
48 | int len; | ||
49 | ushort refnum; | ||
50 | |||
51 | |||
52 | #ifdef DEBUG | ||
53 | printk(KERN_DEBUG "Called Party Number: %s\n", | ||
54 | cbdata->data.setup.CalledPN); | ||
55 | #endif | ||
56 | /* | ||
57 | * hdr - kmalloc in capi_conn_req | ||
58 | * - kfree when msg has been sent | ||
59 | */ | ||
60 | |||
61 | if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb, | ||
62 | chan->proto)) < 0) | ||
63 | { | ||
64 | printk("capi_conn_req failed\n"); | ||
65 | return; | ||
66 | } | ||
67 | |||
68 | |||
69 | refnum = last_ref_num++ & 0x7fffU; | ||
70 | |||
71 | chan->callref = 0; | ||
72 | chan->layer2link = 0; | ||
73 | chan->snum = 0; | ||
74 | chan->s_refnum = refnum; | ||
75 | |||
76 | pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len); | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * rcv CONNECT | ||
81 | * will go into ACTIVE state | ||
82 | * send CONN_ACTIVE_RESP | ||
83 | * send Select protocol request | ||
84 | */ | ||
85 | |||
86 | void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
87 | struct callb_data *data) | ||
88 | { | ||
89 | isdn_ctrl ictl; | ||
90 | struct sk_buff *skb; | ||
91 | int len; | ||
92 | ushort refnum; | ||
93 | |||
94 | if ((len=capi_conn_active_resp(chan, &skb)) < 0) | ||
95 | { | ||
96 | printk("capi_conn_active_req failed\n"); | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | refnum = last_ref_num++ & 0x7fffU; | ||
101 | chan->s_refnum = refnum; | ||
102 | |||
103 | pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len); | ||
104 | |||
105 | |||
106 | ictl.command = ISDN_STAT_DCONN; | ||
107 | ictl.driver=dev->id; | ||
108 | ictl.arg=chan->id; | ||
109 | dev->dev_if->statcallb(&ictl); | ||
110 | |||
111 | /* ACTIVE D-channel */ | ||
112 | |||
113 | /* Select protocol */ | ||
114 | |||
115 | if ((len=capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) { | ||
116 | printk("capi_select_proto_req failed\n"); | ||
117 | return; | ||
118 | } | ||
119 | |||
120 | refnum = last_ref_num++ & 0x7fffU; | ||
121 | chan->s_refnum = refnum; | ||
122 | |||
123 | pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); | ||
124 | } | ||
125 | |||
126 | |||
127 | /* | ||
128 | * Disconnect received (actually RELEASE COMPLETE) | ||
129 | * This means we were not able to establish connection with remote | ||
130 | * Inform the big boss above | ||
131 | */ | ||
132 | void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
133 | struct callb_data *data) | ||
134 | { | ||
135 | isdn_ctrl ictl; | ||
136 | |||
137 | ictl.command = ISDN_STAT_DHUP; | ||
138 | ictl.driver=dev->id; | ||
139 | ictl.arg=chan->id; | ||
140 | dev->dev_if->statcallb(&ictl); | ||
141 | } | ||
142 | |||
143 | |||
144 | /* | ||
145 | * Incoming call received | ||
146 | * inform user | ||
147 | */ | ||
148 | |||
149 | void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
150 | struct callb_data *cbdata) | ||
151 | { | ||
152 | isdn_ctrl ictl; | ||
153 | unsigned short refnum; | ||
154 | struct sk_buff *skb; | ||
155 | int len; | ||
156 | |||
157 | |||
158 | ictl.command = ISDN_STAT_ICALL; | ||
159 | ictl.driver=dev->id; | ||
160 | ictl.arg=chan->id; | ||
161 | |||
162 | /* | ||
163 | * ictl.num >= strlen() + strlen() + 5 | ||
164 | */ | ||
165 | |||
166 | if (cbdata->data.setup.CallingPN == NULL) { | ||
167 | printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n"); | ||
168 | strcpy(ictl.parm.setup.phone, "0"); | ||
169 | } | ||
170 | else { | ||
171 | strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN); | ||
172 | } | ||
173 | if (cbdata->data.setup.CalledPN == NULL) { | ||
174 | printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n"); | ||
175 | strcpy(ictl.parm.setup.eazmsn, "0"); | ||
176 | } | ||
177 | else { | ||
178 | strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN); | ||
179 | } | ||
180 | ictl.parm.setup.si1 = 7; | ||
181 | ictl.parm.setup.si2 = 0; | ||
182 | ictl.parm.setup.plan = 0; | ||
183 | ictl.parm.setup.screen = 0; | ||
184 | |||
185 | #ifdef DEBUG | ||
186 | printk(KERN_DEBUG "statstr: %s\n", ictl.num); | ||
187 | #endif | ||
188 | |||
189 | dev->dev_if->statcallb(&ictl); | ||
190 | |||
191 | |||
192 | if ((len=capi_conn_resp(chan, &skb)) < 0) { | ||
193 | printk(KERN_DEBUG "capi_conn_resp failed\n"); | ||
194 | return; | ||
195 | } | ||
196 | |||
197 | refnum = last_ref_num++ & 0x7fffU; | ||
198 | chan->s_refnum = refnum; | ||
199 | |||
200 | pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len); | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * user has replied | ||
205 | * open the channel | ||
206 | * send CONNECT message CONNECT_ACTIVE_REQ in CAPI | ||
207 | */ | ||
208 | |||
209 | void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
210 | struct callb_data *data) | ||
211 | { | ||
212 | unsigned short refnum; | ||
213 | struct sk_buff *skb; | ||
214 | int len; | ||
215 | |||
216 | if ((len = capi_conn_active_req(chan, &skb)) < 0) { | ||
217 | printk(KERN_DEBUG "capi_conn_active_req failed\n"); | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | |||
222 | refnum = last_ref_num++ & 0x7fffU; | ||
223 | chan->s_refnum = refnum; | ||
224 | |||
225 | printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n"); | ||
226 | pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len); | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * CONN_ACK arrived | ||
231 | * start b-proto selection | ||
232 | * | ||
233 | */ | ||
234 | |||
235 | void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
236 | struct callb_data *data) | ||
237 | { | ||
238 | unsigned short refnum; | ||
239 | struct sk_buff *skb; | ||
240 | int len; | ||
241 | |||
242 | if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0) | ||
243 | { | ||
244 | printk("capi_select_proto_req failed\n"); | ||
245 | return; | ||
246 | } | ||
247 | |||
248 | refnum = last_ref_num++ & 0x7fffU; | ||
249 | chan->s_refnum = refnum; | ||
250 | |||
251 | pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); | ||
252 | |||
253 | } | ||
254 | |||
255 | |||
256 | /* | ||
257 | * Received disconnect ind on active state | ||
258 | * send disconnect resp | ||
259 | * send msg to user | ||
260 | */ | ||
261 | void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
262 | struct callb_data *data) | ||
263 | { | ||
264 | struct sk_buff *skb; | ||
265 | int len; | ||
266 | ushort refnum; | ||
267 | isdn_ctrl ictl; | ||
268 | |||
269 | if ((len = capi_disc_resp(chan, &skb)) < 0) { | ||
270 | printk("capi_disc_resp failed\n"); | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | refnum = last_ref_num++ & 0x7fffU; | ||
275 | chan->s_refnum = refnum; | ||
276 | |||
277 | pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len); | ||
278 | |||
279 | ictl.command = ISDN_STAT_BHUP; | ||
280 | ictl.driver=dev->id; | ||
281 | ictl.arg=chan->id; | ||
282 | dev->dev_if->statcallb(&ictl); | ||
283 | } | ||
284 | |||
285 | |||
286 | /* | ||
287 | * User HANGUP on active/call proceeding state | ||
288 | * send disc.req | ||
289 | */ | ||
290 | void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
291 | struct callb_data *data) | ||
292 | { | ||
293 | struct sk_buff *skb; | ||
294 | int len; | ||
295 | ushort refnum; | ||
296 | |||
297 | if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0) | ||
298 | { | ||
299 | printk("capi_disc_req failed\n"); | ||
300 | return; | ||
301 | } | ||
302 | |||
303 | refnum = last_ref_num++ & 0x7fffU; | ||
304 | chan->s_refnum = refnum; | ||
305 | |||
306 | pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len); | ||
307 | } | ||
308 | |||
309 | /* | ||
310 | * Disc confirm received send BHUP | ||
311 | * Problem: when the HL driver sends the disc req itself | ||
312 | * LL receives BHUP | ||
313 | */ | ||
314 | void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
315 | struct callb_data *data) | ||
316 | { | ||
317 | isdn_ctrl ictl; | ||
318 | |||
319 | ictl.command = ISDN_STAT_BHUP; | ||
320 | ictl.driver=dev->id; | ||
321 | ictl.arg=chan->id; | ||
322 | dev->dev_if->statcallb(&ictl); | ||
323 | } | ||
324 | |||
325 | void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
326 | struct callb_data *data) | ||
327 | { | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * send activate b-chan protocol | ||
332 | */ | ||
333 | void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
334 | struct callb_data *data) | ||
335 | { | ||
336 | struct sk_buff *skb; | ||
337 | int len; | ||
338 | ushort refnum; | ||
339 | |||
340 | if ((len = capi_activate_transp_req(chan, &skb)) < 0) | ||
341 | { | ||
342 | printk("capi_conn_activate_transp_req failed\n"); | ||
343 | return; | ||
344 | } | ||
345 | |||
346 | refnum = last_ref_num++ & 0x7fffU; | ||
347 | chan->s_refnum = refnum; | ||
348 | |||
349 | pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len); | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Inform User that the B-channel is available | ||
354 | */ | ||
355 | void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan, | ||
356 | struct callb_data *data) | ||
357 | { | ||
358 | isdn_ctrl ictl; | ||
359 | |||
360 | ictl.command = ISDN_STAT_BCONN; | ||
361 | ictl.driver=dev->id; | ||
362 | ictl.arg=chan->id; | ||
363 | dev->dev_if->statcallb(&ictl); | ||
364 | } | ||
365 | |||
366 | |||
367 | |||