Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * CAPI encoder/decoder for | |
3 | * Portugal Telecom CAPI 2.0 | |
4 | * | |
5 | * Copyright (C) 1996 Universidade de Lisboa | |
475be4d8 | 6 | * |
1da177e4 LT |
7 | * Written by Pedro Roque Marques (roque@di.fc.ul.pt) |
8 | * | |
475be4d8 | 9 | * This software may be used and distributed according to the terms of |
1da177e4 LT |
10 | * the GNU General Public License, incorporated herein by reference. |
11 | * | |
12 | * Not compatible with the AVM Gmbh. CAPI 2.0 | |
13 | * | |
14 | */ | |
15 | ||
16 | /* | |
17 | * Documentation: | |
96de0e25 | 18 | * - "Common ISDN API - Perfil Português - Versão 2.1", |
1da177e4 | 19 | * Telecom Portugal, Fev 1992. |
96de0e25 | 20 | * - "Common ISDN API - Especificação de protocolos para |
1da177e4 LT |
21 | * acesso aos canais B", Inesc, Jan 1994. |
22 | */ | |
23 | ||
24 | /* | |
25 | * TODO: better decoding of Information Elements | |
26 | * for debug purposes mainly | |
27 | * encode our number in CallerPN and ConnectedPN | |
28 | */ | |
29 | ||
1da177e4 LT |
30 | #include <linux/string.h> |
31 | #include <linux/kernel.h> | |
32 | ||
33 | #include <linux/types.h> | |
34 | #include <linux/slab.h> | |
35 | #include <linux/mm.h> | |
36 | ||
37 | #include <linux/skbuff.h> | |
38 | ||
39 | #include <asm/io.h> | |
40 | #include <asm/string.h> | |
41 | ||
42 | #include <linux/isdnif.h> | |
43 | ||
44 | #include "pcbit.h" | |
45 | #include "edss1.h" | |
46 | #include "capi.h" | |
47 | ||
48 | ||
49 | /* | |
50 | * Encoding of CAPI messages | |
51 | * | |
52 | */ | |
53 | ||
475be4d8 | 54 | int capi_conn_req(const char *calledPN, struct sk_buff **skb, int proto) |
1da177e4 | 55 | { |
475be4d8 JP |
56 | ushort len; |
57 | ||
58 | /* | |
59 | * length | |
60 | * AppInfoMask - 2 | |
61 | * BC0 - 3 | |
62 | * BC1 - 1 | |
63 | * Chan - 2 | |
64 | * Keypad - 1 | |
65 | * CPN - 1 | |
66 | * CPSA - 1 | |
67 | * CalledPN - 2 + strlen | |
68 | * CalledPSA - 1 | |
69 | * rest... - 4 | |
70 | * ---------------- | |
71 | * Total 18 + strlen | |
72 | */ | |
73 | ||
74 | len = 18 + strlen(calledPN); | |
1da177e4 LT |
75 | |
76 | if (proto == ISDN_PROTO_L2_TRANS) | |
77 | len++; | |
78 | ||
79 | if ((*skb = dev_alloc_skb(len)) == NULL) { | |
475be4d8 JP |
80 | |
81 | printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n"); | |
1da177e4 LT |
82 | return -1; |
83 | } | |
84 | ||
475be4d8 JP |
85 | /* InfoElmMask */ |
86 | *((ushort *)skb_put(*skb, 2)) = AppInfoMask; | |
1da177e4 LT |
87 | |
88 | if (proto == ISDN_PROTO_L2_TRANS) | |
89 | { | |
90 | /* Bearer Capability - Mandatory*/ | |
91 | *(skb_put(*skb, 1)) = 3; /* BC0.Length */ | |
92 | *(skb_put(*skb, 1)) = 0x80; /* Speech */ | |
93 | *(skb_put(*skb, 1)) = 0x10; /* Circuit Mode */ | |
94 | *(skb_put(*skb, 1)) = 0x23; /* A-law */ | |
95 | } | |
96 | else | |
97 | { | |
98 | /* Bearer Capability - Mandatory*/ | |
99 | *(skb_put(*skb, 1)) = 2; /* BC0.Length */ | |
100 | *(skb_put(*skb, 1)) = 0x88; /* Digital Information */ | |
101 | *(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 */ | |
102 | } | |
103 | ||
475be4d8 JP |
104 | /* Bearer Capability - Optional*/ |
105 | *(skb_put(*skb, 1)) = 0; /* BC1.Length = 0 */ | |
1da177e4 | 106 | |
475be4d8 JP |
107 | *(skb_put(*skb, 1)) = 1; /* ChannelID.Length = 1 */ |
108 | *(skb_put(*skb, 1)) = 0x83; /* Basic Interface - Any Channel */ | |
1da177e4 | 109 | |
475be4d8 | 110 | *(skb_put(*skb, 1)) = 0; /* Keypad.Length = 0 */ |
1da177e4 | 111 | |
1da177e4 | 112 | |
475be4d8 JP |
113 | *(skb_put(*skb, 1)) = 0; /* CallingPN.Length = 0 */ |
114 | *(skb_put(*skb, 1)) = 0; /* CallingPSA.Length = 0 */ | |
1da177e4 | 115 | |
475be4d8 JP |
116 | /* Called Party Number */ |
117 | *(skb_put(*skb, 1)) = strlen(calledPN) + 1; | |
118 | *(skb_put(*skb, 1)) = 0x81; | |
119 | memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN)); | |
1da177e4 | 120 | |
475be4d8 | 121 | /* '#' */ |
1da177e4 | 122 | |
475be4d8 | 123 | *(skb_put(*skb, 1)) = 0; /* CalledPSA.Length = 0 */ |
1da177e4 | 124 | |
475be4d8 JP |
125 | /* LLC.Length = 0; */ |
126 | /* HLC0.Length = 0; */ | |
127 | /* HLC1.Length = 0; */ | |
128 | /* UTUS.Length = 0; */ | |
129 | memset(skb_put(*skb, 4), 0, 4); | |
130 | ||
131 | return len; | |
1da177e4 LT |
132 | } |
133 | ||
475be4d8 | 134 | int capi_conn_resp(struct pcbit_chan *chan, struct sk_buff **skb) |
1da177e4 | 135 | { |
475be4d8 | 136 | |
1da177e4 | 137 | if ((*skb = dev_alloc_skb(5)) == NULL) { |
475be4d8 | 138 | |
1da177e4 LT |
139 | printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n"); |
140 | return -1; | |
141 | } | |
142 | ||
475be4d8 JP |
143 | *((ushort *)skb_put(*skb, 2)) = chan->callref; |
144 | *(skb_put(*skb, 1)) = 0x01; /* ACCEPT_CALL */ | |
145 | *(skb_put(*skb, 1)) = 0; | |
146 | *(skb_put(*skb, 1)) = 0; | |
1da177e4 | 147 | |
475be4d8 | 148 | return 5; |
1da177e4 LT |
149 | } |
150 | ||
475be4d8 | 151 | int capi_conn_active_req(struct pcbit_chan *chan, struct sk_buff **skb) |
1da177e4 | 152 | { |
475be4d8 JP |
153 | /* |
154 | * 8 bytes | |
155 | */ | |
156 | ||
1da177e4 | 157 | if ((*skb = dev_alloc_skb(8)) == NULL) { |
475be4d8 | 158 | |
1da177e4 LT |
159 | printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n"); |
160 | return -1; | |
161 | } | |
162 | ||
475be4d8 | 163 | *((ushort *)skb_put(*skb, 2)) = chan->callref; |
1da177e4 LT |
164 | |
165 | #ifdef DEBUG | |
475be4d8 | 166 | printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref); |
1da177e4 LT |
167 | #endif |
168 | ||
475be4d8 JP |
169 | *(skb_put(*skb, 1)) = 0; /* BC.Length = 0; */ |
170 | *(skb_put(*skb, 1)) = 0; /* ConnectedPN.Length = 0 */ | |
171 | *(skb_put(*skb, 1)) = 0; /* PSA.Length */ | |
172 | *(skb_put(*skb, 1)) = 0; /* LLC.Length = 0; */ | |
173 | *(skb_put(*skb, 1)) = 0; /* HLC.Length = 0; */ | |
174 | *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */ | |
1da177e4 LT |
175 | |
176 | return 8; | |
177 | } | |
178 | ||
475be4d8 | 179 | int capi_conn_active_resp(struct pcbit_chan *chan, struct sk_buff **skb) |
1da177e4 | 180 | { |
475be4d8 JP |
181 | /* |
182 | * 2 bytes | |
183 | */ | |
184 | ||
1da177e4 | 185 | if ((*skb = dev_alloc_skb(2)) == NULL) { |
475be4d8 | 186 | |
1da177e4 LT |
187 | printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n"); |
188 | return -1; | |
189 | } | |
190 | ||
475be4d8 | 191 | *((ushort *)skb_put(*skb, 2)) = chan->callref; |
1da177e4 | 192 | |
475be4d8 | 193 | return 2; |
1da177e4 LT |
194 | } |
195 | ||
196 | ||
475be4d8 JP |
197 | int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb, |
198 | int outgoing) | |
1da177e4 LT |
199 | { |
200 | ||
475be4d8 JP |
201 | /* |
202 | * 18 bytes | |
203 | */ | |
1da177e4 LT |
204 | |
205 | if ((*skb = dev_alloc_skb(18)) == NULL) { | |
475be4d8 | 206 | |
1da177e4 LT |
207 | printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n"); |
208 | return -1; | |
209 | } | |
210 | ||
475be4d8 | 211 | *((ushort *)skb_put(*skb, 2)) = chan->callref; |
1da177e4 | 212 | |
475be4d8 | 213 | /* Layer2 protocol */ |
1da177e4 | 214 | |
475be4d8 JP |
215 | switch (chan->proto) { |
216 | case ISDN_PROTO_L2_X75I: | |
217 | *(skb_put(*skb, 1)) = 0x05; /* LAPB */ | |
218 | break; | |
219 | case ISDN_PROTO_L2_HDLC: | |
220 | *(skb_put(*skb, 1)) = 0x02; | |
221 | break; | |
1da177e4 | 222 | case ISDN_PROTO_L2_TRANS: |
475be4d8 | 223 | /* |
1da177e4 LT |
224 | * Voice (a-law) |
225 | */ | |
226 | *(skb_put(*skb, 1)) = 0x06; | |
227 | break; | |
475be4d8 JP |
228 | default: |
229 | #ifdef DEBUG | |
230 | printk(KERN_DEBUG "Transparent\n"); | |
1da177e4 | 231 | #endif |
475be4d8 JP |
232 | *(skb_put(*skb, 1)) = 0x03; |
233 | break; | |
234 | } | |
235 | ||
236 | *(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42); /* Don't ask */ | |
237 | *(skb_put(*skb, 1)) = 0x00; | |
238 | ||
239 | *((ushort *) skb_put(*skb, 2)) = MRU; | |
240 | ||
241 | ||
242 | *(skb_put(*skb, 1)) = 0x08; /* Modulo */ | |
243 | *(skb_put(*skb, 1)) = 0x07; /* Max Window */ | |
244 | ||
245 | *(skb_put(*skb, 1)) = 0x01; /* No Layer3 Protocol */ | |
246 | ||
247 | /* | |
248 | * 2 - layer3 MTU [10] | |
249 | * - Modulo [12] | |
250 | * - Window | |
251 | * - layer1 proto [14] | |
252 | * - bitrate | |
253 | * - sub-channel [16] | |
254 | * - layer1dataformat [17] | |
255 | */ | |
256 | ||
257 | memset(skb_put(*skb, 8), 0, 8); | |
258 | ||
259 | return 18; | |
1da177e4 LT |
260 | } |
261 | ||
262 | ||
263 | int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb) | |
264 | { | |
265 | ||
266 | if ((*skb = dev_alloc_skb(7)) == NULL) { | |
475be4d8 | 267 | |
1da177e4 LT |
268 | printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n"); |
269 | return -1; | |
270 | } | |
271 | ||
475be4d8 | 272 | *((ushort *)skb_put(*skb, 2)) = chan->callref; |
1da177e4 | 273 | |
1da177e4 | 274 | |
475be4d8 JP |
275 | *(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */ |
276 | *(skb_put(*skb, 1)) = 0x00; /* Transmit by default */ | |
1da177e4 | 277 | |
475be4d8 | 278 | *((ushort *) skb_put(*skb, 2)) = MRU; |
1da177e4 | 279 | |
475be4d8 JP |
280 | *(skb_put(*skb, 1)) = 0x01; /* Enables reception*/ |
281 | ||
282 | return 7; | |
1da177e4 LT |
283 | } |
284 | ||
475be4d8 | 285 | int capi_tdata_req(struct pcbit_chan *chan, struct sk_buff *skb) |
1da177e4 LT |
286 | { |
287 | ushort data_len; | |
1da177e4 | 288 | |
475be4d8 JP |
289 | |
290 | /* | |
291 | * callref - 2 | |
1da177e4 | 292 | * layer2link - 1 |
475be4d8 | 293 | * wBlockLength - 2 |
1da177e4 LT |
294 | * data - 4 |
295 | * sernum - 1 | |
296 | */ | |
475be4d8 | 297 | |
1da177e4 LT |
298 | data_len = skb->len; |
299 | ||
475be4d8 | 300 | if (skb_headroom(skb) < 10) |
1da177e4 LT |
301 | { |
302 | printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb); | |
303 | } | |
304 | else | |
475be4d8 | 305 | { |
1da177e4 LT |
306 | skb_push(skb, 10); |
307 | } | |
308 | ||
309 | *((u16 *) (skb->data)) = chan->callref; | |
310 | skb->data[2] = chan->layer2link; | |
311 | *((u16 *) (skb->data + 3)) = data_len; | |
312 | ||
313 | chan->s_refnum = (chan->s_refnum + 1) % 8; | |
314 | *((u32 *) (skb->data + 5)) = chan->s_refnum; | |
315 | ||
316 | skb->data[9] = 0; /* HDLC frame number */ | |
317 | ||
318 | return 10; | |
319 | } | |
320 | ||
475be4d8 JP |
321 | int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff **skb) |
322 | ||
1da177e4 LT |
323 | { |
324 | if ((*skb = dev_alloc_skb(4)) == NULL) { | |
475be4d8 | 325 | |
1da177e4 LT |
326 | printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n"); |
327 | return -1; | |
328 | } | |
329 | ||
475be4d8 | 330 | *((ushort *)skb_put(*skb, 2)) = chan->callref; |
1da177e4 | 331 | |
475be4d8 JP |
332 | *(skb_put(*skb, 1)) = chan->layer2link; |
333 | *(skb_put(*skb, 1)) = chan->r_refnum; | |
1da177e4 | 334 | |
475be4d8 | 335 | return (*skb)->len; |
1da177e4 LT |
336 | } |
337 | ||
338 | int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause) | |
339 | { | |
340 | ||
341 | if ((*skb = dev_alloc_skb(6)) == NULL) { | |
475be4d8 | 342 | |
1da177e4 LT |
343 | printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n"); |
344 | return -1; | |
345 | } | |
346 | ||
475be4d8 | 347 | *((ushort *)skb_put(*skb, 2)) = callref; |
1da177e4 | 348 | |
475be4d8 JP |
349 | *(skb_put(*skb, 1)) = 2; /* Cause.Length = 2; */ |
350 | *(skb_put(*skb, 1)) = 0x80; | |
351 | *(skb_put(*skb, 1)) = 0x80 | cause; | |
1da177e4 | 352 | |
475be4d8 JP |
353 | /* |
354 | * Change it: we should send 'Sic transit gloria Mundi' here ;-) | |
355 | */ | |
1da177e4 | 356 | |
475be4d8 | 357 | *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */ |
1da177e4 | 358 | |
475be4d8 | 359 | return 6; |
1da177e4 LT |
360 | } |
361 | ||
362 | int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb) | |
363 | { | |
364 | if ((*skb = dev_alloc_skb(2)) == NULL) { | |
475be4d8 | 365 | |
1da177e4 LT |
366 | printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n"); |
367 | return -1; | |
368 | } | |
369 | ||
475be4d8 | 370 | *((ushort *)skb_put(*skb, 2)) = chan->callref; |
1da177e4 | 371 | |
475be4d8 | 372 | return 2; |
1da177e4 LT |
373 | } |
374 | ||
375 | ||
376 | /* | |
377 | * Decoding of CAPI messages | |
378 | * | |
379 | */ | |
380 | ||
475be4d8 JP |
381 | int capi_decode_conn_ind(struct pcbit_chan *chan, |
382 | struct sk_buff *skb, | |
383 | struct callb_data *info) | |
1da177e4 | 384 | { |
475be4d8 | 385 | int CIlen, len; |
1da177e4 | 386 | |
475be4d8 JP |
387 | /* Call Reference [CAPI] */ |
388 | chan->callref = *((ushort *)skb->data); | |
389 | skb_pull(skb, 2); | |
1da177e4 LT |
390 | |
391 | #ifdef DEBUG | |
475be4d8 | 392 | printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref); |
1da177e4 LT |
393 | #endif |
394 | ||
475be4d8 | 395 | /* Channel Identification */ |
1da177e4 | 396 | |
475be4d8 JP |
397 | /* Expect |
398 | Len = 1 | |
399 | Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ] | |
400 | */ | |
1da177e4 | 401 | |
475be4d8 | 402 | CIlen = skb->data[0]; |
1da177e4 | 403 | #ifdef DEBUG |
475be4d8 | 404 | if (CIlen == 1) { |
1da177e4 | 405 | |
475be4d8 JP |
406 | if (((skb->data[1]) & 0xFC) == 0x48) |
407 | printk(KERN_DEBUG "decode_conn_ind: chan ok\n"); | |
408 | printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03); | |
409 | } | |
1da177e4 LT |
410 | else |
411 | printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen); | |
412 | #endif | |
475be4d8 | 413 | skb_pull(skb, CIlen + 1); |
1da177e4 | 414 | |
475be4d8 JP |
415 | /* Calling Party Number */ |
416 | /* An "additional service" as far as Portugal Telecom is concerned */ | |
1da177e4 | 417 | |
475be4d8 | 418 | len = skb->data[0]; |
1da177e4 LT |
419 | |
420 | if (len > 0) { | |
421 | int count = 1; | |
475be4d8 | 422 | |
1da177e4 LT |
423 | #ifdef DEBUG |
424 | printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]); | |
425 | #endif | |
426 | if ((skb->data[1] & 0x80) == 0) | |
427 | count = 2; | |
475be4d8 | 428 | |
1da177e4 LT |
429 | if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC))) |
430 | return -1; | |
475be4d8 | 431 | |
d626f62b ACM |
432 | skb_copy_from_linear_data_offset(skb, count + 1, |
433 | info->data.setup.CallingPN, | |
434 | len - count); | |
1da177e4 LT |
435 | info->data.setup.CallingPN[len - count] = 0; |
436 | ||
437 | } | |
438 | else { | |
439 | info->data.setup.CallingPN = NULL; | |
440 | printk(KERN_DEBUG "NULL CallingPN\n"); | |
441 | } | |
442 | ||
443 | skb_pull(skb, len + 1); | |
444 | ||
475be4d8 JP |
445 | /* Calling Party Subaddress */ |
446 | skb_pull(skb, skb->data[0] + 1); | |
1da177e4 | 447 | |
475be4d8 | 448 | /* Called Party Number */ |
1da177e4 | 449 | |
475be4d8 | 450 | len = skb->data[0]; |
1da177e4 LT |
451 | |
452 | if (len > 0) { | |
453 | int count = 1; | |
475be4d8 | 454 | |
1da177e4 LT |
455 | if ((skb->data[1] & 0x80) == 0) |
456 | count = 2; | |
475be4d8 | 457 | |
1da177e4 LT |
458 | if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC))) |
459 | return -1; | |
475be4d8 | 460 | |
d626f62b ACM |
461 | skb_copy_from_linear_data_offset(skb, count + 1, |
462 | info->data.setup.CalledPN, | |
463 | len - count); | |
1da177e4 LT |
464 | info->data.setup.CalledPN[len - count] = 0; |
465 | ||
466 | } | |
467 | else { | |
468 | info->data.setup.CalledPN = NULL; | |
469 | printk(KERN_DEBUG "NULL CalledPN\n"); | |
470 | } | |
471 | ||
472 | skb_pull(skb, len + 1); | |
473 | ||
475be4d8 JP |
474 | /* Called Party Subaddress */ |
475 | skb_pull(skb, skb->data[0] + 1); | |
1da177e4 | 476 | |
475be4d8 JP |
477 | /* LLC */ |
478 | skb_pull(skb, skb->data[0] + 1); | |
1da177e4 | 479 | |
475be4d8 JP |
480 | /* HLC */ |
481 | skb_pull(skb, skb->data[0] + 1); | |
1da177e4 | 482 | |
475be4d8 JP |
483 | /* U2U */ |
484 | skb_pull(skb, skb->data[0] + 1); | |
1da177e4 | 485 | |
475be4d8 | 486 | return 0; |
1da177e4 LT |
487 | } |
488 | ||
489 | /* | |
490 | * returns errcode | |
491 | */ | |
492 | ||
475be4d8 JP |
493 | int capi_decode_conn_conf(struct pcbit_chan *chan, struct sk_buff *skb, |
494 | int *complete) | |
1da177e4 | 495 | { |
475be4d8 JP |
496 | int errcode; |
497 | ||
498 | chan->callref = *((ushort *)skb->data); /* Update CallReference */ | |
499 | skb_pull(skb, 2); | |
500 | ||
501 | errcode = *((ushort *) skb->data); /* read errcode */ | |
502 | skb_pull(skb, 2); | |
1da177e4 | 503 | |
475be4d8 JP |
504 | *complete = *(skb->data); |
505 | skb_pull(skb, 1); | |
1da177e4 | 506 | |
475be4d8 JP |
507 | /* FIX ME */ |
508 | /* This is actually a firmware bug */ | |
509 | if (!*complete) | |
510 | { | |
511 | printk(KERN_DEBUG "complete=%02x\n", *complete); | |
512 | *complete = 1; | |
513 | } | |
1da177e4 | 514 | |
1da177e4 | 515 | |
475be4d8 JP |
516 | /* Optional Bearer Capability */ |
517 | skb_pull(skb, *(skb->data) + 1); | |
1da177e4 | 518 | |
475be4d8 JP |
519 | /* Channel Identification */ |
520 | skb_pull(skb, *(skb->data) + 1); | |
1da177e4 | 521 | |
475be4d8 JP |
522 | /* High Layer Compatibility follows */ |
523 | skb_pull(skb, *(skb->data) + 1); | |
1da177e4 | 524 | |
475be4d8 | 525 | return errcode; |
1da177e4 LT |
526 | } |
527 | ||
475be4d8 | 528 | int capi_decode_conn_actv_ind(struct pcbit_chan *chan, struct sk_buff *skb) |
1da177e4 | 529 | { |
475be4d8 | 530 | ushort len; |
1da177e4 | 531 | #ifdef DEBUG |
475be4d8 | 532 | char str[32]; |
1da177e4 LT |
533 | #endif |
534 | ||
475be4d8 JP |
535 | /* Yet Another Bearer Capability */ |
536 | skb_pull(skb, *(skb->data) + 1); | |
1da177e4 | 537 | |
475be4d8 JP |
538 | |
539 | /* Connected Party Number */ | |
540 | len = *(skb->data); | |
1da177e4 LT |
541 | |
542 | #ifdef DEBUG | |
543 | if (len > 1 && len < 31) { | |
d626f62b | 544 | skb_copy_from_linear_data_offset(skb, 2, str, len - 1); |
1da177e4 LT |
545 | str[len] = 0; |
546 | printk(KERN_DEBUG "Connected Party Number: %s\n", str); | |
547 | } | |
548 | else | |
549 | printk(KERN_DEBUG "actv_ind CPN len = %d\n", len); | |
550 | #endif | |
551 | ||
475be4d8 | 552 | skb_pull(skb, len + 1); |
1da177e4 | 553 | |
475be4d8 JP |
554 | /* Connected Subaddress */ |
555 | skb_pull(skb, *(skb->data) + 1); | |
1da177e4 | 556 | |
475be4d8 JP |
557 | /* Low Layer Capability */ |
558 | skb_pull(skb, *(skb->data) + 1); | |
1da177e4 | 559 | |
475be4d8 JP |
560 | /* High Layer Capability */ |
561 | skb_pull(skb, *(skb->data) + 1); | |
1da177e4 | 562 | |
475be4d8 | 563 | return 0; |
1da177e4 LT |
564 | } |
565 | ||
475be4d8 | 566 | int capi_decode_conn_actv_conf(struct pcbit_chan *chan, struct sk_buff *skb) |
1da177e4 | 567 | { |
475be4d8 JP |
568 | ushort errcode; |
569 | ||
570 | errcode = *((ushort *)skb->data); | |
571 | skb_pull(skb, 2); | |
572 | ||
573 | /* Channel Identification | |
574 | skb_pull(skb, skb->data[0] + 1); | |
575 | */ | |
576 | return errcode; | |
1da177e4 LT |
577 | } |
578 | ||
579 | ||
580 | int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb) | |
581 | { | |
475be4d8 | 582 | ushort errcode; |
1da177e4 | 583 | |
475be4d8 JP |
584 | chan->layer2link = *(skb->data); |
585 | skb_pull(skb, 1); | |
1da177e4 | 586 | |
475be4d8 JP |
587 | errcode = *((ushort *)skb->data); |
588 | skb_pull(skb, 2); | |
589 | ||
590 | return errcode; | |
1da177e4 LT |
591 | } |
592 | ||
593 | int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb) | |
594 | { | |
475be4d8 | 595 | ushort errcode; |
1da177e4 | 596 | |
475be4d8 JP |
597 | if (chan->layer2link != *(skb->data)) |
598 | printk("capi_decode_actv_trans_conf: layer2link doesn't match\n"); | |
1da177e4 | 599 | |
475be4d8 | 600 | skb_pull(skb, 1); |
1da177e4 | 601 | |
475be4d8 JP |
602 | errcode = *((ushort *)skb->data); |
603 | skb_pull(skb, 2); | |
1da177e4 | 604 | |
475be4d8 | 605 | return errcode; |
1da177e4 LT |
606 | } |
607 | ||
608 | int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb) | |
609 | { | |
475be4d8 | 610 | ushort len; |
1da177e4 | 611 | #ifdef DEBUG |
475be4d8 | 612 | int i; |
1da177e4 | 613 | #endif |
475be4d8 JP |
614 | /* Cause */ |
615 | ||
616 | len = *(skb->data); | |
617 | skb_pull(skb, 1); | |
1da177e4 LT |
618 | |
619 | #ifdef DEBUG | |
620 | ||
475be4d8 JP |
621 | for (i = 0; i < len; i++) |
622 | printk(KERN_DEBUG "Cause Octect %d: %02x\n", i + 3, | |
623 | *(skb->data + i)); | |
1da177e4 LT |
624 | #endif |
625 | ||
475be4d8 | 626 | skb_pull(skb, len); |
1da177e4 | 627 | |
475be4d8 | 628 | return 0; |
1da177e4 LT |
629 | } |
630 | ||
1da177e4 LT |
631 | #ifdef DEBUG |
632 | int capi_decode_debug_188(u_char *hdr, ushort hdrlen) | |
633 | { | |
475be4d8 JP |
634 | char str[64]; |
635 | int len; | |
1da177e4 | 636 | |
475be4d8 | 637 | len = hdr[0]; |
1da177e4 | 638 | |
475be4d8 JP |
639 | if (len < 64 && len == hdrlen - 1) { |
640 | memcpy(str, hdr + 1, hdrlen - 1); | |
641 | str[hdrlen - 1] = 0; | |
642 | printk("%s\n", str); | |
643 | } | |
644 | else | |
645 | printk("debug message incorrect\n"); | |
1da177e4 | 646 | |
475be4d8 JP |
647 | return 0; |
648 | } | |
649 | #endif |