Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Callbacks for the FSM | |
3 | * | |
4 | * Copyright (C) 1996 Universidade de Lisboa | |
475be4d8 | 5 | * |
1da177e4 LT |
6 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) |
7 | * | |
475be4d8 | 8 | * This software may be used and distributed according to the terms of |
1da177e4 LT |
9 | * the GNU General Public License, incorporated herein by reference. |
10 | */ | |
11 | ||
12 | /* | |
13 | * Fix: 19981230 - Carlos Morgado <chbm@techie.com> | |
475be4d8 | 14 | * Port of Nelson Escravana's <nelson.escravana@usa.net> fix to CalledPN |
1da177e4 LT |
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 | ||
475be4d8 JP |
42 | void cb_out_1(struct pcbit_dev *dev, struct pcbit_chan *chan, |
43 | struct callb_data *cbdata) | |
1da177e4 LT |
44 | { |
45 | struct sk_buff *skb; | |
46 | int len; | |
475be4d8 | 47 | ushort refnum; |
1da177e4 LT |
48 | |
49 | ||
50 | #ifdef DEBUG | |
475be4d8 JP |
51 | printk(KERN_DEBUG "Called Party Number: %s\n", |
52 | cbdata->data.setup.CalledPN); | |
1da177e4 | 53 | #endif |
475be4d8 JP |
54 | /* |
55 | * hdr - kmalloc in capi_conn_req | |
56 | * - kfree when msg has been sent | |
57 | */ | |
1da177e4 | 58 | |
475be4d8 | 59 | if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb, |
1da177e4 | 60 | chan->proto)) < 0) |
475be4d8 JP |
61 | { |
62 | printk("capi_conn_req failed\n"); | |
63 | return; | |
64 | } | |
1da177e4 LT |
65 | |
66 | ||
475be4d8 | 67 | refnum = last_ref_num++ & 0x7fffU; |
1da177e4 | 68 | |
475be4d8 JP |
69 | chan->callref = 0; |
70 | chan->layer2link = 0; | |
71 | chan->snum = 0; | |
72 | chan->s_refnum = refnum; | |
1da177e4 | 73 | |
475be4d8 | 74 | pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len); |
1da177e4 LT |
75 | } |
76 | ||
77 | /* | |
78 | * rcv CONNECT | |
79 | * will go into ACTIVE state | |
80 | * send CONN_ACTIVE_RESP | |
475be4d8 | 81 | * send Select protocol request |
1da177e4 LT |
82 | */ |
83 | ||
475be4d8 JP |
84 | void cb_out_2(struct pcbit_dev *dev, struct pcbit_chan *chan, |
85 | struct callb_data *data) | |
1da177e4 | 86 | { |
475be4d8 JP |
87 | isdn_ctrl ictl; |
88 | struct sk_buff *skb; | |
1da177e4 | 89 | int len; |
475be4d8 | 90 | ushort refnum; |
1da177e4 | 91 | |
475be4d8 JP |
92 | if ((len = capi_conn_active_resp(chan, &skb)) < 0) |
93 | { | |
94 | printk("capi_conn_active_req failed\n"); | |
95 | return; | |
96 | } | |
1da177e4 | 97 | |
475be4d8 JP |
98 | refnum = last_ref_num++ & 0x7fffU; |
99 | chan->s_refnum = refnum; | |
1da177e4 | 100 | |
475be4d8 | 101 | pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len); |
1da177e4 LT |
102 | |
103 | ||
475be4d8 JP |
104 | ictl.command = ISDN_STAT_DCONN; |
105 | ictl.driver = dev->id; | |
106 | ictl.arg = chan->id; | |
107 | dev->dev_if->statcallb(&ictl); | |
1da177e4 | 108 | |
475be4d8 | 109 | /* ACTIVE D-channel */ |
1da177e4 | 110 | |
475be4d8 | 111 | /* Select protocol */ |
1da177e4 | 112 | |
475be4d8 JP |
113 | if ((len = capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) { |
114 | printk("capi_select_proto_req failed\n"); | |
115 | return; | |
116 | } | |
1da177e4 | 117 | |
475be4d8 JP |
118 | refnum = last_ref_num++ & 0x7fffU; |
119 | chan->s_refnum = refnum; | |
1da177e4 | 120 | |
475be4d8 | 121 | pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); |
1da177e4 LT |
122 | } |
123 | ||
124 | ||
1da177e4 LT |
125 | /* |
126 | * Incoming call received | |
127 | * inform user | |
128 | */ | |
129 | ||
475be4d8 JP |
130 | void cb_in_1(struct pcbit_dev *dev, struct pcbit_chan *chan, |
131 | struct callb_data *cbdata) | |
1da177e4 | 132 | { |
475be4d8 JP |
133 | isdn_ctrl ictl; |
134 | unsigned short refnum; | |
135 | struct sk_buff *skb; | |
1da177e4 LT |
136 | int len; |
137 | ||
138 | ||
475be4d8 JP |
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 | */ | |
1da177e4 LT |
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 | ||
475be4d8 JP |
170 | dev->dev_if->statcallb(&ictl); |
171 | ||
1da177e4 | 172 | |
475be4d8 JP |
173 | if ((len = capi_conn_resp(chan, &skb)) < 0) { |
174 | printk(KERN_DEBUG "capi_conn_resp failed\n"); | |
175 | return; | |
1da177e4 LT |
176 | } |
177 | ||
475be4d8 JP |
178 | refnum = last_ref_num++ & 0x7fffU; |
179 | chan->s_refnum = refnum; | |
1da177e4 | 180 | |
475be4d8 | 181 | pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len); |
1da177e4 LT |
182 | } |
183 | ||
184 | /* | |
185 | * user has replied | |
186 | * open the channel | |
187 | * send CONNECT message CONNECT_ACTIVE_REQ in CAPI | |
188 | */ | |
189 | ||
475be4d8 | 190 | void cb_in_2(struct pcbit_dev *dev, struct pcbit_chan *chan, |
1da177e4 LT |
191 | struct callb_data *data) |
192 | { | |
475be4d8 | 193 | unsigned short refnum; |
1da177e4 | 194 | struct sk_buff *skb; |
475be4d8 JP |
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 | } | |
1da177e4 LT |
201 | |
202 | ||
475be4d8 JP |
203 | refnum = last_ref_num++ & 0x7fffU; |
204 | chan->s_refnum = refnum; | |
1da177e4 LT |
205 | |
206 | printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n"); | |
475be4d8 | 207 | pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len); |
1da177e4 LT |
208 | } |
209 | ||
210 | /* | |
211 | * CONN_ACK arrived | |
212 | * start b-proto selection | |
213 | * | |
214 | */ | |
215 | ||
475be4d8 | 216 | void cb_in_3(struct pcbit_dev *dev, struct pcbit_chan *chan, |
1da177e4 LT |
217 | struct callb_data *data) |
218 | { | |
475be4d8 JP |
219 | unsigned short refnum; |
220 | struct sk_buff *skb; | |
1da177e4 | 221 | int len; |
1da177e4 | 222 | |
475be4d8 JP |
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; | |
1da177e4 | 231 | |
475be4d8 | 232 | pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); |
1da177e4 LT |
233 | |
234 | } | |
235 | ||
236 | ||
237 | /* | |
238 | * Received disconnect ind on active state | |
239 | * send disconnect resp | |
240 | * send msg to user | |
241 | */ | |
475be4d8 | 242 | void cb_disc_1(struct pcbit_dev *dev, struct pcbit_chan *chan, |
1da177e4 LT |
243 | struct callb_data *data) |
244 | { | |
475be4d8 | 245 | struct sk_buff *skb; |
1da177e4 | 246 | int len; |
475be4d8 JP |
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); | |
1da177e4 LT |
264 | } |
265 | ||
475be4d8 | 266 | |
1da177e4 LT |
267 | /* |
268 | * User HANGUP on active/call proceeding state | |
269 | * send disc.req | |
270 | */ | |
475be4d8 | 271 | void cb_disc_2(struct pcbit_dev *dev, struct pcbit_chan *chan, |
1da177e4 LT |
272 | struct callb_data *data) |
273 | { | |
475be4d8 | 274 | struct sk_buff *skb; |
1da177e4 | 275 | int len; |
475be4d8 | 276 | ushort refnum; |
1da177e4 | 277 | |
475be4d8 JP |
278 | if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0) |
279 | { | |
280 | printk("capi_disc_req failed\n"); | |
281 | return; | |
282 | } | |
1da177e4 | 283 | |
475be4d8 JP |
284 | refnum = last_ref_num++ & 0x7fffU; |
285 | chan->s_refnum = refnum; | |
1da177e4 | 286 | |
475be4d8 | 287 | pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len); |
1da177e4 LT |
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 | */ | |
475be4d8 | 295 | void cb_disc_3(struct pcbit_dev *dev, struct pcbit_chan *chan, |
1da177e4 LT |
296 | struct callb_data *data) |
297 | { | |
475be4d8 | 298 | isdn_ctrl ictl; |
1da177e4 | 299 | |
475be4d8 JP |
300 | ictl.command = ISDN_STAT_BHUP; |
301 | ictl.driver = dev->id; | |
302 | ictl.arg = chan->id; | |
303 | dev->dev_if->statcallb(&ictl); | |
1da177e4 LT |
304 | } |
305 | ||
475be4d8 | 306 | void cb_notdone(struct pcbit_dev *dev, struct pcbit_chan *chan, |
1da177e4 LT |
307 | struct callb_data *data) |
308 | { | |
309 | } | |
310 | ||
311 | /* | |
312 | * send activate b-chan protocol | |
313 | */ | |
475be4d8 JP |
314 | void cb_selp_1(struct pcbit_dev *dev, struct pcbit_chan *chan, |
315 | struct callb_data *data) | |
1da177e4 | 316 | { |
475be4d8 | 317 | struct sk_buff *skb; |
1da177e4 | 318 | int len; |
475be4d8 | 319 | ushort refnum; |
1da177e4 | 320 | |
475be4d8 JP |
321 | if ((len = capi_activate_transp_req(chan, &skb)) < 0) |
322 | { | |
323 | printk("capi_conn_activate_transp_req failed\n"); | |
324 | return; | |
325 | } | |
1da177e4 | 326 | |
475be4d8 JP |
327 | refnum = last_ref_num++ & 0x7fffU; |
328 | chan->s_refnum = refnum; | |
1da177e4 | 329 | |
475be4d8 | 330 | pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len); |
1da177e4 LT |
331 | } |
332 | ||
333 | /* | |
334 | * Inform User that the B-channel is available | |
335 | */ | |
475be4d8 JP |
336 | void cb_open(struct pcbit_dev *dev, struct pcbit_chan *chan, |
337 | struct callb_data *data) | |
1da177e4 | 338 | { |
475be4d8 | 339 | isdn_ctrl ictl; |
1da177e4 | 340 | |
475be4d8 JP |
341 | ictl.command = ISDN_STAT_BCONN; |
342 | ictl.driver = dev->id; | |
343 | ictl.arg = chan->id; | |
344 | dev->dev_if->statcallb(&ictl); | |
1da177e4 | 345 | } |