]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 |