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