blob: 3f66ca20b5e544e3c0593f91cdf5c3e5139f894e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: capi.c,v 1.9.6.2 2001/09/23 22:24:32 kai Exp $
2 *
3 * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
4 * CAPI encoder/decoder
5 *
6 * Author Fritz Elfert
7 * Copyright by Fritz Elfert <fritz@isdn4linux.de>
Joe Perches475be4d2012-02-19 19:52:38 -08008 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 * Thanks to Friedemann Baitinger and IBM Germany
13 *
14 */
15
16#include "act2000.h"
17#include "capi.h"
18
19static actcapi_msgdsc valid_msg[] = {
20 {{ 0x86, 0x02}, "DATA_B3_IND"}, /* DATA_B3_IND/CONF must be first because of speed!!! */
21 {{ 0x86, 0x01}, "DATA_B3_CONF"},
22 {{ 0x02, 0x01}, "CONNECT_CONF"},
23 {{ 0x02, 0x02}, "CONNECT_IND"},
24 {{ 0x09, 0x01}, "CONNECT_INFO_CONF"},
25 {{ 0x03, 0x02}, "CONNECT_ACTIVE_IND"},
26 {{ 0x04, 0x01}, "DISCONNECT_CONF"},
27 {{ 0x04, 0x02}, "DISCONNECT_IND"},
28 {{ 0x05, 0x01}, "LISTEN_CONF"},
29 {{ 0x06, 0x01}, "GET_PARAMS_CONF"},
30 {{ 0x07, 0x01}, "INFO_CONF"},
31 {{ 0x07, 0x02}, "INFO_IND"},
32 {{ 0x08, 0x01}, "DATA_CONF"},
33 {{ 0x08, 0x02}, "DATA_IND"},
34 {{ 0x40, 0x01}, "SELECT_B2_PROTOCOL_CONF"},
35 {{ 0x80, 0x01}, "SELECT_B3_PROTOCOL_CONF"},
36 {{ 0x81, 0x01}, "LISTEN_B3_CONF"},
37 {{ 0x82, 0x01}, "CONNECT_B3_CONF"},
38 {{ 0x82, 0x02}, "CONNECT_B3_IND"},
39 {{ 0x83, 0x02}, "CONNECT_B3_ACTIVE_IND"},
40 {{ 0x84, 0x01}, "DISCONNECT_B3_CONF"},
41 {{ 0x84, 0x02}, "DISCONNECT_B3_IND"},
42 {{ 0x85, 0x01}, "GET_B3_PARAMS_CONF"},
43 {{ 0x01, 0x01}, "RESET_B3_CONF"},
44 {{ 0x01, 0x02}, "RESET_B3_IND"},
45 /* {{ 0x87, 0x02, "HANDSET_IND"}, not implemented */
46 {{ 0xff, 0x01}, "MANUFACTURER_CONF"},
47 {{ 0xff, 0x02}, "MANUFACTURER_IND"},
48#ifdef DEBUG_MSG
49 /* Requests */
50 {{ 0x01, 0x00}, "RESET_B3_REQ"},
51 {{ 0x02, 0x00}, "CONNECT_REQ"},
52 {{ 0x04, 0x00}, "DISCONNECT_REQ"},
53 {{ 0x05, 0x00}, "LISTEN_REQ"},
54 {{ 0x06, 0x00}, "GET_PARAMS_REQ"},
55 {{ 0x07, 0x00}, "INFO_REQ"},
56 {{ 0x08, 0x00}, "DATA_REQ"},
57 {{ 0x09, 0x00}, "CONNECT_INFO_REQ"},
58 {{ 0x40, 0x00}, "SELECT_B2_PROTOCOL_REQ"},
59 {{ 0x80, 0x00}, "SELECT_B3_PROTOCOL_REQ"},
60 {{ 0x81, 0x00}, "LISTEN_B3_REQ"},
61 {{ 0x82, 0x00}, "CONNECT_B3_REQ"},
62 {{ 0x84, 0x00}, "DISCONNECT_B3_REQ"},
63 {{ 0x85, 0x00}, "GET_B3_PARAMS_REQ"},
64 {{ 0x86, 0x00}, "DATA_B3_REQ"},
65 {{ 0xff, 0x00}, "MANUFACTURER_REQ"},
66 /* Responses */
Joe Perches475be4d2012-02-19 19:52:38 -080067 {{ 0x01, 0x03}, "RESET_B3_RESP"},
68 {{ 0x02, 0x03}, "CONNECT_RESP"},
69 {{ 0x03, 0x03}, "CONNECT_ACTIVE_RESP"},
70 {{ 0x04, 0x03}, "DISCONNECT_RESP"},
71 {{ 0x07, 0x03}, "INFO_RESP"},
72 {{ 0x08, 0x03}, "DATA_RESP"},
73 {{ 0x82, 0x03}, "CONNECT_B3_RESP"},
74 {{ 0x83, 0x03}, "CONNECT_B3_ACTIVE_RESP"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"},
76 {{ 0x86, 0x03}, "DATA_B3_RESP"},
77 {{ 0xff, 0x03}, "MANUFACTURER_RESP"},
78#endif
79 {{ 0x00, 0x00}, NULL},
80};
Linus Torvalds1da177e2005-04-16 15:20:36 -070081#define num_valid_imsg 27 /* MANUFACTURER_IND */
82
83/*
84 * Check for a valid incoming CAPI message.
85 * Return:
86 * 0 = Invalid message
87 * 1 = Valid message, no B-Channel-data
88 * 2 = Valid message, B-Channel-data
89 */
90int
Joe Perches475be4d2012-02-19 19:52:38 -080091actcapi_chkhdr(act2000_card *card, actcapi_msghdr *hdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070092{
93 int i;
94
95 if (hdr->applicationID != 1)
96 return 0;
97 if (hdr->len < 9)
98 return 0;
99 for (i = 0; i < num_valid_imsg; i++)
100 if ((hdr->cmd.cmd == valid_msg[i].cmd.cmd) &&
101 (hdr->cmd.subcmd == valid_msg[i].cmd.subcmd)) {
Joe Perches475be4d2012-02-19 19:52:38 -0800102 return (i ? 1 : 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 }
104 return 0;
105}
106
Joe Perches475be4d2012-02-19 19:52:38 -0800107#define ACTCAPI_MKHDR(l, c, s) { \
108 skb = alloc_skb(l + 8, GFP_ATOMIC); \
109 if (skb) { \
110 m = (actcapi_msg *)skb_put(skb, l + 8); \
111 m->hdr.len = l + 8; \
112 m->hdr.applicationID = 1; \
113 m->hdr.cmd.cmd = c; \
114 m->hdr.cmd.subcmd = s; \
115 m->hdr.msgnum = actcapi_nextsmsg(card); \
116 } else m = NULL; \
117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Joe Perches475be4d2012-02-19 19:52:38 -0800119#define ACTCAPI_CHKSKB if (!skb) { \
120 printk(KERN_WARNING "actcapi: alloc_skb failed\n"); \
121 return; \
122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Joe Perches475be4d2012-02-19 19:52:38 -0800124#define ACTCAPI_QUEUE_TX { \
125 actcapi_debug_msg(skb, 1); \
126 skb_queue_tail(&card->sndq, skb); \
127 act2000_schedule_tx(card); \
128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130int
131actcapi_listen_req(act2000_card *card)
132{
133 __u16 eazmask = 0;
134 int i;
135 actcapi_msg *m;
136 struct sk_buff *skb;
137
138 for (i = 0; i < ACT2000_BCH; i++)
139 eazmask |= card->bch[i].eazmask;
140 ACTCAPI_MKHDR(9, 0x05, 0x00);
Joe Perches475be4d2012-02-19 19:52:38 -0800141 if (!skb) {
142 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
143 return -ENOMEM;
144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 m->msg.listen_req.controller = 0;
146 m->msg.listen_req.infomask = 0x3f; /* All information */
147 m->msg.listen_req.eazmask = eazmask;
Joe Perches475be4d2012-02-19 19:52:38 -0800148 m->msg.listen_req.simask = (eazmask) ? 0x86 : 0; /* All SI's */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 ACTCAPI_QUEUE_TX;
Joe Perches475be4d2012-02-19 19:52:38 -0800150 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151}
152
153int
154actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone,
155 char eaz, int si1, int si2)
156{
157 actcapi_msg *m;
158 struct sk_buff *skb;
159
160 ACTCAPI_MKHDR((11 + strlen(phone)), 0x02, 0x00);
161 if (!skb) {
Joe Perches475be4d2012-02-19 19:52:38 -0800162 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 chan->fsm_state = ACT2000_STATE_NULL;
164 return -ENOMEM;
165 }
166 m->msg.connect_req.controller = 0;
167 m->msg.connect_req.bchan = 0x83;
168 m->msg.connect_req.infomask = 0x3f;
169 m->msg.connect_req.si1 = si1;
170 m->msg.connect_req.si2 = si2;
Joe Perches475be4d2012-02-19 19:52:38 -0800171 m->msg.connect_req.eaz = eaz ? eaz : '0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 m->msg.connect_req.addr.len = strlen(phone) + 1;
173 m->msg.connect_req.addr.tnp = 0x81;
174 memcpy(m->msg.connect_req.addr.num, phone, strlen(phone));
175 chan->callref = m->hdr.msgnum;
176 ACTCAPI_QUEUE_TX;
177 return 0;
178}
179
180static void
181actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan)
182{
183 actcapi_msg *m;
184 struct sk_buff *skb;
185
186 ACTCAPI_MKHDR(17, 0x82, 0x00);
187 ACTCAPI_CHKSKB;
188 m->msg.connect_b3_req.plci = chan->plci;
189 memset(&m->msg.connect_b3_req.ncpi, 0,
190 sizeof(m->msg.connect_b3_req.ncpi));
191 m->msg.connect_b3_req.ncpi.len = 13;
192 m->msg.connect_b3_req.ncpi.modulo = 8;
193 ACTCAPI_QUEUE_TX;
194}
195
196/*
197 * Set net type (1TR6) or (EDSS1)
198 */
199int
200actcapi_manufacturer_req_net(act2000_card *card)
201{
202 actcapi_msg *m;
203 struct sk_buff *skb;
204
205 ACTCAPI_MKHDR(5, 0xff, 0x00);
Joe Perches475be4d2012-02-19 19:52:38 -0800206 if (!skb) {
207 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
208 return -ENOMEM;
209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 m->msg.manufacturer_req_net.manuf_msg = 0x11;
211 m->msg.manufacturer_req_net.controller = 1;
Joe Perches475be4d2012-02-19 19:52:38 -0800212 m->msg.manufacturer_req_net.nettype = (card->ptype == ISDN_PTYPE_EURO) ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 ACTCAPI_QUEUE_TX;
214 printk(KERN_INFO "act2000 %s: D-channel protocol now %s\n",
Joe Perches475be4d2012-02-19 19:52:38 -0800215 card->interface.id, (card->ptype == ISDN_PTYPE_EURO) ? "euro" : "1tr6");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 card->interface.features &=
217 ~(ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_P_EURO | ISDN_FEATURE_P_1TR6);
218 card->interface.features |=
Joe Perches475be4d2012-02-19 19:52:38 -0800219 ((card->ptype == ISDN_PTYPE_EURO) ? ISDN_FEATURE_P_EURO : ISDN_FEATURE_P_1TR6);
220 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221}
222
223/*
224 * Switch V.42 on or off
225 */
Adrian Bunk23b34f42005-06-25 14:58:38 -0700226#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227int
228actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
229{
230 actcapi_msg *m;
231 struct sk_buff *skb;
232
233 ACTCAPI_MKHDR(8, 0xff, 0x00);
Joe Perches475be4d2012-02-19 19:52:38 -0800234 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Joe Perches475be4d2012-02-19 19:52:38 -0800236 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
237 return -ENOMEM;
238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 m->msg.manufacturer_req_v42.manuf_msg = 0x10;
240 m->msg.manufacturer_req_v42.controller = 0;
Joe Perches475be4d2012-02-19 19:52:38 -0800241 m->msg.manufacturer_req_v42.v42control = (arg ? 1 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 ACTCAPI_QUEUE_TX;
Joe Perches475be4d2012-02-19 19:52:38 -0800243 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244}
Adrian Bunk23b34f42005-06-25 14:58:38 -0700245#endif /* 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247/*
248 * Set error-handler
249 */
250int
251actcapi_manufacturer_req_errh(act2000_card *card)
252{
253 actcapi_msg *m;
254 struct sk_buff *skb;
255
256 ACTCAPI_MKHDR(4, 0xff, 0x00);
Joe Perches475be4d2012-02-19 19:52:38 -0800257 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Joe Perches475be4d2012-02-19 19:52:38 -0800259 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
260 return -ENOMEM;
261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 m->msg.manufacturer_req_err.manuf_msg = 0x03;
263 m->msg.manufacturer_req_err.controller = 0;
264 ACTCAPI_QUEUE_TX;
Joe Perches475be4d2012-02-19 19:52:38 -0800265 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266}
267
268/*
269 * Set MSN-Mapping.
270 */
271int
272actcapi_manufacturer_req_msn(act2000_card *card)
273{
274 msn_entry *p = card->msn_list;
275 actcapi_msg *m;
276 struct sk_buff *skb;
277 int len;
278
279 while (p) {
280 int i;
281
282 len = strlen(p->msn);
283 for (i = 0; i < 2; i++) {
284 ACTCAPI_MKHDR(6 + len, 0xff, 0x00);
285 if (!skb) {
286 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
287 return -ENOMEM;
288 }
289 m->msg.manufacturer_req_msn.manuf_msg = 0x13 + i;
290 m->msg.manufacturer_req_msn.controller = 0;
291 m->msg.manufacturer_req_msn.msnmap.eaz = p->eaz;
292 m->msg.manufacturer_req_msn.msnmap.len = len;
293 memcpy(m->msg.manufacturer_req_msn.msnmap.msn, p->msn, len);
294 ACTCAPI_QUEUE_TX;
295 }
296 p = p->next;
297 }
Joe Perches475be4d2012-02-19 19:52:38 -0800298 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299}
300
301void
302actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan)
303{
304 actcapi_msg *m;
305 struct sk_buff *skb;
306
307 ACTCAPI_MKHDR(10, 0x40, 0x00);
308 ACTCAPI_CHKSKB;
309 m->msg.select_b2_protocol_req.plci = chan->plci;
310 memset(&m->msg.select_b2_protocol_req.dlpd, 0,
311 sizeof(m->msg.select_b2_protocol_req.dlpd));
312 m->msg.select_b2_protocol_req.dlpd.len = 6;
313 switch (chan->l2prot) {
Joe Perches475be4d2012-02-19 19:52:38 -0800314 case ISDN_PROTO_L2_TRANS:
315 m->msg.select_b2_protocol_req.protocol = 0x03;
316 m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
317 break;
318 case ISDN_PROTO_L2_HDLC:
319 m->msg.select_b2_protocol_req.protocol = 0x02;
320 m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
321 break;
322 case ISDN_PROTO_L2_X75I:
323 case ISDN_PROTO_L2_X75UI:
324 case ISDN_PROTO_L2_X75BUI:
325 m->msg.select_b2_protocol_req.protocol = 0x01;
326 m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
327 m->msg.select_b2_protocol_req.dlpd.laa = 3;
328 m->msg.select_b2_protocol_req.dlpd.lab = 1;
329 m->msg.select_b2_protocol_req.dlpd.win = 7;
330 m->msg.select_b2_protocol_req.dlpd.modulo = 8;
331 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 }
333 ACTCAPI_QUEUE_TX;
334}
335
336static void
337actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan)
338{
339 actcapi_msg *m;
340 struct sk_buff *skb;
341
342 ACTCAPI_MKHDR(17, 0x80, 0x00);
343 ACTCAPI_CHKSKB;
344 m->msg.select_b3_protocol_req.plci = chan->plci;
345 memset(&m->msg.select_b3_protocol_req.ncpd, 0,
346 sizeof(m->msg.select_b3_protocol_req.ncpd));
347 switch (chan->l3prot) {
Joe Perches475be4d2012-02-19 19:52:38 -0800348 case ISDN_PROTO_L3_TRANS:
349 m->msg.select_b3_protocol_req.protocol = 0x04;
350 m->msg.select_b3_protocol_req.ncpd.len = 13;
351 m->msg.select_b3_protocol_req.ncpd.modulo = 8;
352 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 }
354 ACTCAPI_QUEUE_TX;
355}
356
357static void
358actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan)
359{
360 actcapi_msg *m;
361 struct sk_buff *skb;
362
363 ACTCAPI_MKHDR(2, 0x81, 0x00);
364 ACTCAPI_CHKSKB;
365 m->msg.listen_b3_req.plci = chan->plci;
366 ACTCAPI_QUEUE_TX;
367}
368
369static void
370actcapi_disconnect_req(act2000_card *card, act2000_chan *chan)
371{
372 actcapi_msg *m;
373 struct sk_buff *skb;
374
375 ACTCAPI_MKHDR(3, 0x04, 0x00);
376 ACTCAPI_CHKSKB;
377 m->msg.disconnect_req.plci = chan->plci;
378 m->msg.disconnect_req.cause = 0;
379 ACTCAPI_QUEUE_TX;
380}
381
382void
383actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan)
384{
385 actcapi_msg *m;
386 struct sk_buff *skb;
387
388 ACTCAPI_MKHDR(17, 0x84, 0x00);
389 ACTCAPI_CHKSKB;
390 m->msg.disconnect_b3_req.ncci = chan->ncci;
391 memset(&m->msg.disconnect_b3_req.ncpi, 0,
392 sizeof(m->msg.disconnect_b3_req.ncpi));
393 m->msg.disconnect_b3_req.ncpi.len = 13;
394 m->msg.disconnect_b3_req.ncpi.modulo = 8;
395 chan->fsm_state = ACT2000_STATE_BHWAIT;
396 ACTCAPI_QUEUE_TX;
397}
398
399void
400actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause)
401{
402 actcapi_msg *m;
403 struct sk_buff *skb;
404
405 ACTCAPI_MKHDR(3, 0x02, 0x03);
406 ACTCAPI_CHKSKB;
407 m->msg.connect_resp.plci = chan->plci;
408 m->msg.connect_resp.rejectcause = cause;
409 if (cause) {
410 chan->fsm_state = ACT2000_STATE_NULL;
411 chan->plci = 0x8000;
412 } else
413 chan->fsm_state = ACT2000_STATE_IWAIT;
414 ACTCAPI_QUEUE_TX;
415}
416
417static void
418actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan)
419{
420 actcapi_msg *m;
421 struct sk_buff *skb;
422
423 ACTCAPI_MKHDR(2, 0x03, 0x03);
424 ACTCAPI_CHKSKB;
425 m->msg.connect_resp.plci = chan->plci;
426 if (chan->fsm_state == ACT2000_STATE_IWAIT)
427 chan->fsm_state = ACT2000_STATE_IBWAIT;
428 ACTCAPI_QUEUE_TX;
429}
430
431static void
432actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause)
433{
434 actcapi_msg *m;
435 struct sk_buff *skb;
436
Joe Perches475be4d2012-02-19 19:52:38 -0800437 ACTCAPI_MKHDR((rejectcause ? 3 : 17), 0x82, 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 ACTCAPI_CHKSKB;
439 m->msg.connect_b3_resp.ncci = chan->ncci;
440 m->msg.connect_b3_resp.rejectcause = rejectcause;
441 if (!rejectcause) {
442 memset(&m->msg.connect_b3_resp.ncpi, 0,
443 sizeof(m->msg.connect_b3_resp.ncpi));
444 m->msg.connect_b3_resp.ncpi.len = 13;
445 m->msg.connect_b3_resp.ncpi.modulo = 8;
446 chan->fsm_state = ACT2000_STATE_BWAIT;
447 }
448 ACTCAPI_QUEUE_TX;
449}
450
451static void
452actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan)
453{
454 actcapi_msg *m;
455 struct sk_buff *skb;
456
457 ACTCAPI_MKHDR(2, 0x83, 0x03);
458 ACTCAPI_CHKSKB;
459 m->msg.connect_b3_active_resp.ncci = chan->ncci;
460 chan->fsm_state = ACT2000_STATE_ACTIVE;
461 ACTCAPI_QUEUE_TX;
462}
463
464static void
465actcapi_info_resp(act2000_card *card, act2000_chan *chan)
466{
467 actcapi_msg *m;
468 struct sk_buff *skb;
469
470 ACTCAPI_MKHDR(2, 0x07, 0x03);
471 ACTCAPI_CHKSKB;
472 m->msg.info_resp.plci = chan->plci;
473 ACTCAPI_QUEUE_TX;
474}
475
476static void
477actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan)
478{
479 actcapi_msg *m;
480 struct sk_buff *skb;
481
482 ACTCAPI_MKHDR(2, 0x84, 0x03);
483 ACTCAPI_CHKSKB;
484 m->msg.disconnect_b3_resp.ncci = chan->ncci;
485 chan->ncci = 0x8000;
486 chan->queued = 0;
487 ACTCAPI_QUEUE_TX;
488}
489
490static void
491actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan)
492{
493 actcapi_msg *m;
494 struct sk_buff *skb;
495
496 ACTCAPI_MKHDR(2, 0x04, 0x03);
497 ACTCAPI_CHKSKB;
498 m->msg.disconnect_resp.plci = chan->plci;
499 chan->plci = 0x8000;
500 ACTCAPI_QUEUE_TX;
501}
502
503static int
504new_plci(act2000_card *card, __u16 plci)
505{
506 int i;
507 for (i = 0; i < ACT2000_BCH; i++)
508 if (card->bch[i].plci == 0x8000) {
509 card->bch[i].plci = plci;
510 return i;
511 }
512 return -1;
513}
514
515static int
516find_plci(act2000_card *card, __u16 plci)
517{
518 int i;
519 for (i = 0; i < ACT2000_BCH; i++)
520 if (card->bch[i].plci == plci)
521 return i;
522 return -1;
523}
524
525static int
526find_ncci(act2000_card *card, __u16 ncci)
527{
528 int i;
529 for (i = 0; i < ACT2000_BCH; i++)
530 if (card->bch[i].ncci == ncci)
531 return i;
532 return -1;
533}
534
535static int
536find_dialing(act2000_card *card, __u16 callref)
537{
538 int i;
539 for (i = 0; i < ACT2000_BCH; i++)
540 if ((card->bch[i].callref == callref) &&
541 (card->bch[i].fsm_state == ACT2000_STATE_OCALL))
542 return i;
543 return -1;
544}
545
546static int
547actcapi_data_b3_ind(act2000_card *card, struct sk_buff *skb) {
548 __u16 plci;
549 __u16 ncci;
550 __u16 controller;
551 __u8 blocknr;
552 int chan;
553 actcapi_msg *msg = (actcapi_msg *)skb->data;
554
555 EVAL_NCCI(msg->msg.data_b3_ind.fakencci, plci, controller, ncci);
556 chan = find_ncci(card, ncci);
557 if (chan < 0)
558 return 0;
559 if (card->bch[chan].fsm_state != ACT2000_STATE_ACTIVE)
560 return 0;
561 if (card->bch[chan].plci != plci)
562 return 0;
563 blocknr = msg->msg.data_b3_ind.blocknr;
564 skb_pull(skb, 19);
565 card->interface.rcvcallb_skb(card->myid, chan, skb);
Joe Perches475be4d2012-02-19 19:52:38 -0800566 if (!(skb = alloc_skb(11, GFP_ATOMIC))) {
567 printk(KERN_WARNING "actcapi: alloc_skb failed\n");
568 return 1;
569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 msg = (actcapi_msg *)skb_put(skb, 11);
571 msg->hdr.len = 11;
572 msg->hdr.applicationID = 1;
573 msg->hdr.cmd.cmd = 0x86;
574 msg->hdr.cmd.subcmd = 0x03;
575 msg->hdr.msgnum = actcapi_nextsmsg(card);
576 msg->msg.data_b3_resp.ncci = ncci;
577 msg->msg.data_b3_resp.blocknr = blocknr;
578 ACTCAPI_QUEUE_TX;
579 return 1;
580}
581
582/*
583 * Walk over ackq, unlink DATA_B3_REQ from it, if
584 * ncci and blocknr are matching.
585 * Decrement queued-bytes counter.
586 */
587static int
588handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) {
589 unsigned long flags;
590 struct sk_buff *skb;
591 struct sk_buff *tmp;
592 struct actcapi_msg *m;
593 int ret = 0;
594
595 spin_lock_irqsave(&card->lock, flags);
596 skb = skb_peek(&card->ackq);
597 spin_unlock_irqrestore(&card->lock, flags);
Joe Perches475be4d2012-02-19 19:52:38 -0800598 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
600 return 0;
601 }
Joe Perches475be4d2012-02-19 19:52:38 -0800602 tmp = skb;
603 while (1) {
604 m = (actcapi_msg *)tmp->data;
605 if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 (m->msg.data_b3_req.blocknr == blocknr)) {
607 /* found corresponding DATA_B3_REQ */
Joe Perches475be4d2012-02-19 19:52:38 -0800608 skb_unlink(tmp, &card->ackq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 chan->queued -= m->msg.data_b3_req.datalen;
610 if (m->msg.data_b3_req.flags)
611 ret = m->msg.data_b3_req.datalen;
612 dev_kfree_skb(tmp);
613 if (chan->queued < 0)
614 chan->queued = 0;
Joe Perches475be4d2012-02-19 19:52:38 -0800615 return ret;
616 }
617 spin_lock_irqsave(&card->lock, flags);
618 tmp = skb_peek((struct sk_buff_head *)tmp);
619 spin_unlock_irqrestore(&card->lock, flags);
620 if ((tmp == skb) || (tmp == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 /* reached end of queue */
622 printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
Joe Perches475be4d2012-02-19 19:52:38 -0800623 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 }
Joe Perches475be4d2012-02-19 19:52:38 -0800625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626}
627
628void
David Howellsc4028952006-11-22 14:57:56 +0000629actcapi_dispatch(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
David Howellsc4028952006-11-22 14:57:56 +0000631 struct act2000_card *card =
632 container_of(work, struct act2000_card, rcv_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 struct sk_buff *skb;
634 actcapi_msg *msg;
635 __u16 ccmd;
636 int chan;
637 int len;
638 act2000_chan *ctmp;
639 isdn_ctrl cmd;
640 char tmp[170];
641
642 while ((skb = skb_dequeue(&card->rcvq))) {
643 actcapi_debug_msg(skb, 0);
644 msg = (actcapi_msg *)skb->data;
645 ccmd = ((msg->hdr.cmd.cmd << 8) | msg->hdr.cmd.subcmd);
646 switch (ccmd) {
Joe Perches475be4d2012-02-19 19:52:38 -0800647 case 0x8602:
648 /* DATA_B3_IND */
649 if (actcapi_data_b3_ind(card, skb))
650 return;
651 break;
652 case 0x8601:
653 /* DATA_B3_CONF */
654 chan = find_ncci(card, msg->msg.data_b3_conf.ncci);
655 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_ACTIVE)) {
656 if (msg->msg.data_b3_conf.info != 0)
657 printk(KERN_WARNING "act2000: DATA_B3_CONF: %04x\n",
658 msg->msg.data_b3_conf.info);
659 len = handle_ack(card, &card->bch[chan],
660 msg->msg.data_b3_conf.blocknr);
661 if (len) {
662 cmd.driver = card->myid;
663 cmd.command = ISDN_STAT_BSENT;
664 cmd.arg = chan;
665 cmd.parm.length = len;
666 card->interface.statcallb(&cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 }
Joe Perches475be4d2012-02-19 19:52:38 -0800668 }
669 break;
670 case 0x0201:
671 /* CONNECT_CONF */
672 chan = find_dialing(card, msg->hdr.msgnum);
673 if (chan >= 0) {
674 if (msg->msg.connect_conf.info) {
675 card->bch[chan].fsm_state = ACT2000_STATE_NULL;
676 cmd.driver = card->myid;
677 cmd.command = ISDN_STAT_DHUP;
678 cmd.arg = chan;
679 card->interface.statcallb(&cmd);
680 } else {
681 card->bch[chan].fsm_state = ACT2000_STATE_OWAIT;
682 card->bch[chan].plci = msg->msg.connect_conf.plci;
683 }
684 }
685 break;
686 case 0x0202:
687 /* CONNECT_IND */
688 chan = new_plci(card, msg->msg.connect_ind.plci);
689 if (chan < 0) {
690 ctmp = (act2000_chan *)tmp;
691 ctmp->plci = msg->msg.connect_ind.plci;
692 actcapi_connect_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
693 } else {
694 card->bch[chan].fsm_state = ACT2000_STATE_ICALL;
695 cmd.driver = card->myid;
696 cmd.command = ISDN_STAT_ICALL;
697 cmd.arg = chan;
698 cmd.parm.setup.si1 = msg->msg.connect_ind.si1;
699 cmd.parm.setup.si2 = msg->msg.connect_ind.si2;
700 if (card->ptype == ISDN_PTYPE_EURO)
701 strcpy(cmd.parm.setup.eazmsn,
702 act2000_find_eaz(card, msg->msg.connect_ind.eaz));
703 else {
704 cmd.parm.setup.eazmsn[0] = msg->msg.connect_ind.eaz;
705 cmd.parm.setup.eazmsn[1] = 0;
706 }
707 memset(cmd.parm.setup.phone, 0, sizeof(cmd.parm.setup.phone));
708 memcpy(cmd.parm.setup.phone, msg->msg.connect_ind.addr.num,
709 msg->msg.connect_ind.addr.len - 1);
710 cmd.parm.setup.plan = msg->msg.connect_ind.addr.tnp;
711 cmd.parm.setup.screen = 0;
712 if (card->interface.statcallb(&cmd) == 2)
713 actcapi_connect_resp(card, &card->bch[chan], 0x15); /* Reject Call */
714 }
715 break;
716 case 0x0302:
717 /* CONNECT_ACTIVE_IND */
718 chan = find_plci(card, msg->msg.connect_active_ind.plci);
719 if (chan >= 0)
720 switch (card->bch[chan].fsm_state) {
721 case ACT2000_STATE_IWAIT:
722 actcapi_connect_active_resp(card, &card->bch[chan]);
723 break;
724 case ACT2000_STATE_OWAIT:
725 actcapi_connect_active_resp(card, &card->bch[chan]);
726 actcapi_select_b2_protocol_req(card, &card->bch[chan]);
727 break;
728 }
729 break;
730 case 0x8202:
731 /* CONNECT_B3_IND */
732 chan = find_plci(card, msg->msg.connect_b3_ind.plci);
733 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_IBWAIT)) {
734 card->bch[chan].ncci = msg->msg.connect_b3_ind.ncci;
735 actcapi_connect_b3_resp(card, &card->bch[chan], 0);
736 } else {
737 ctmp = (act2000_chan *)tmp;
738 ctmp->ncci = msg->msg.connect_b3_ind.ncci;
739 actcapi_connect_b3_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
740 }
741 break;
742 case 0x8302:
743 /* CONNECT_B3_ACTIVE_IND */
744 chan = find_ncci(card, msg->msg.connect_b3_active_ind.ncci);
745 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BWAIT)) {
746 actcapi_connect_b3_active_resp(card, &card->bch[chan]);
747 cmd.driver = card->myid;
748 cmd.command = ISDN_STAT_BCONN;
749 cmd.arg = chan;
750 card->interface.statcallb(&cmd);
751 }
752 break;
753 case 0x8402:
754 /* DISCONNECT_B3_IND */
755 chan = find_ncci(card, msg->msg.disconnect_b3_ind.ncci);
756 if (chan >= 0) {
757 ctmp = &card->bch[chan];
758 actcapi_disconnect_b3_resp(card, ctmp);
759 switch (ctmp->fsm_state) {
760 case ACT2000_STATE_ACTIVE:
761 ctmp->fsm_state = ACT2000_STATE_DHWAIT2;
762 cmd.driver = card->myid;
763 cmd.command = ISDN_STAT_BHUP;
764 cmd.arg = chan;
765 card->interface.statcallb(&cmd);
766 break;
767 case ACT2000_STATE_BHWAIT2:
768 actcapi_disconnect_req(card, ctmp);
769 ctmp->fsm_state = ACT2000_STATE_DHWAIT;
770 cmd.driver = card->myid;
771 cmd.command = ISDN_STAT_BHUP;
772 cmd.arg = chan;
773 card->interface.statcallb(&cmd);
774 break;
775 }
776 }
777 break;
778 case 0x0402:
779 /* DISCONNECT_IND */
780 chan = find_plci(card, msg->msg.disconnect_ind.plci);
781 if (chan >= 0) {
782 ctmp = &card->bch[chan];
783 actcapi_disconnect_resp(card, ctmp);
784 ctmp->fsm_state = ACT2000_STATE_NULL;
785 cmd.driver = card->myid;
786 cmd.command = ISDN_STAT_DHUP;
787 cmd.arg = chan;
788 card->interface.statcallb(&cmd);
789 } else {
790 ctmp = (act2000_chan *)tmp;
791 ctmp->plci = msg->msg.disconnect_ind.plci;
792 actcapi_disconnect_resp(card, ctmp);
793 }
794 break;
795 case 0x4001:
796 /* SELECT_B2_PROTOCOL_CONF */
797 chan = find_plci(card, msg->msg.select_b2_protocol_conf.plci);
798 if (chan >= 0)
799 switch (card->bch[chan].fsm_state) {
800 case ACT2000_STATE_ICALL:
801 case ACT2000_STATE_OWAIT:
802 ctmp = &card->bch[chan];
803 if (msg->msg.select_b2_protocol_conf.info == 0)
804 actcapi_select_b3_protocol_req(card, ctmp);
805 else {
806 ctmp->fsm_state = ACT2000_STATE_NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 cmd.driver = card->myid;
808 cmd.command = ISDN_STAT_DHUP;
809 cmd.arg = chan;
810 card->interface.statcallb(&cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 }
Joe Perches475be4d2012-02-19 19:52:38 -0800812 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 }
Joe Perches475be4d2012-02-19 19:52:38 -0800814 break;
815 case 0x8001:
816 /* SELECT_B3_PROTOCOL_CONF */
817 chan = find_plci(card, msg->msg.select_b3_protocol_conf.plci);
818 if (chan >= 0)
819 switch (card->bch[chan].fsm_state) {
820 case ACT2000_STATE_ICALL:
821 case ACT2000_STATE_OWAIT:
822 ctmp = &card->bch[chan];
823 if (msg->msg.select_b3_protocol_conf.info == 0)
824 actcapi_listen_b3_req(card, ctmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 else {
Joe Perches475be4d2012-02-19 19:52:38 -0800826 ctmp->fsm_state = ACT2000_STATE_NULL;
827 cmd.driver = card->myid;
828 cmd.command = ISDN_STAT_DHUP;
829 cmd.arg = chan;
830 card->interface.statcallb(&cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 }
Joe Perches475be4d2012-02-19 19:52:38 -0800833 break;
834 case 0x8101:
835 /* LISTEN_B3_CONF */
836 chan = find_plci(card, msg->msg.listen_b3_conf.plci);
837 if (chan >= 0)
838 switch (card->bch[chan].fsm_state) {
839 case ACT2000_STATE_ICALL:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 ctmp = &card->bch[chan];
Joe Perches475be4d2012-02-19 19:52:38 -0800841 if (msg->msg.listen_b3_conf.info == 0)
842 actcapi_connect_resp(card, ctmp, 0);
843 else {
844 ctmp->fsm_state = ACT2000_STATE_NULL;
845 cmd.driver = card->myid;
846 cmd.command = ISDN_STAT_DHUP;
847 cmd.arg = chan;
848 card->interface.statcallb(&cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 }
Joe Perches475be4d2012-02-19 19:52:38 -0800850 break;
851 case ACT2000_STATE_OWAIT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 ctmp = &card->bch[chan];
Joe Perches475be4d2012-02-19 19:52:38 -0800853 if (msg->msg.listen_b3_conf.info == 0) {
854 actcapi_connect_b3_req(card, ctmp);
855 ctmp->fsm_state = ACT2000_STATE_OBWAIT;
856 cmd.driver = card->myid;
857 cmd.command = ISDN_STAT_DCONN;
858 cmd.arg = chan;
859 card->interface.statcallb(&cmd);
860 } else {
861 ctmp->fsm_state = ACT2000_STATE_NULL;
862 cmd.driver = card->myid;
863 cmd.command = ISDN_STAT_DHUP;
864 cmd.arg = chan;
865 card->interface.statcallb(&cmd);
866 }
867 break;
868 }
869 break;
870 case 0x8201:
871 /* CONNECT_B3_CONF */
872 chan = find_plci(card, msg->msg.connect_b3_conf.plci);
873 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_OBWAIT)) {
874 ctmp = &card->bch[chan];
875 if (msg->msg.connect_b3_conf.info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 ctmp->fsm_state = ACT2000_STATE_NULL;
877 cmd.driver = card->myid;
878 cmd.command = ISDN_STAT_DHUP;
879 cmd.arg = chan;
880 card->interface.statcallb(&cmd);
881 } else {
Joe Perches475be4d2012-02-19 19:52:38 -0800882 ctmp->ncci = msg->msg.connect_b3_conf.ncci;
883 ctmp->fsm_state = ACT2000_STATE_BWAIT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
Joe Perches475be4d2012-02-19 19:52:38 -0800885 }
886 break;
887 case 0x8401:
888 /* DISCONNECT_B3_CONF */
889 chan = find_ncci(card, msg->msg.disconnect_b3_conf.ncci);
890 if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BHWAIT))
891 card->bch[chan].fsm_state = ACT2000_STATE_BHWAIT2;
892 break;
893 case 0x0702:
894 /* INFO_IND */
895 chan = find_plci(card, msg->msg.info_ind.plci);
896 if (chan >= 0)
897 /* TODO: Eval Charging info / cause */
898 actcapi_info_resp(card, &card->bch[chan]);
899 break;
900 case 0x0401:
901 /* LISTEN_CONF */
902 case 0x0501:
903 /* LISTEN_CONF */
904 case 0xff01:
905 /* MANUFACTURER_CONF */
906 break;
907 case 0xff02:
908 /* MANUFACTURER_IND */
909 if (msg->msg.manuf_msg == 3) {
910 memset(tmp, 0, sizeof(tmp));
911 strncpy(tmp,
912 &msg->msg.manufacturer_ind_err.errstring,
913 msg->hdr.len - 16);
914 if (msg->msg.manufacturer_ind_err.errcode)
915 printk(KERN_WARNING "act2000: %s\n", tmp);
916 else {
917 printk(KERN_DEBUG "act2000: %s\n", tmp);
918 if ((!strncmp(tmp, "INFO: Trace buffer con", 22)) ||
919 (!strncmp(tmp, "INFO: Compile Date/Tim", 22))) {
920 card->flags |= ACT2000_FLAGS_RUNNING;
921 cmd.command = ISDN_STAT_RUN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 cmd.driver = card->myid;
Joe Perches475be4d2012-02-19 19:52:38 -0800923 cmd.arg = 0;
924 actcapi_manufacturer_req_net(card);
925 actcapi_manufacturer_req_msn(card);
926 actcapi_listen_req(card);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 card->interface.statcallb(&cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 }
929 }
Joe Perches475be4d2012-02-19 19:52:38 -0800930 }
931 break;
932 default:
933 printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd);
934 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 }
936 dev_kfree_skb(skb);
937 }
938}
939
940#ifdef DEBUG_MSG
941static void
942actcapi_debug_caddr(actcapi_addr *addr)
943{
944 char tmp[30];
945
946 printk(KERN_DEBUG " Alen = %d\n", addr->len);
947 if (addr->len > 0)
948 printk(KERN_DEBUG " Atnp = 0x%02x\n", addr->tnp);
949 if (addr->len > 1) {
950 memset(tmp, 0, 30);
951 memcpy(tmp, addr->num, addr->len - 1);
952 printk(KERN_DEBUG " Anum = '%s'\n", tmp);
953 }
954}
955
956static void
957actcapi_debug_ncpi(actcapi_ncpi *ncpi)
958{
959 printk(KERN_DEBUG " ncpi.len = %d\n", ncpi->len);
960 if (ncpi->len >= 2)
961 printk(KERN_DEBUG " ncpi.lic = 0x%04x\n", ncpi->lic);
962 if (ncpi->len >= 4)
963 printk(KERN_DEBUG " ncpi.hic = 0x%04x\n", ncpi->hic);
964 if (ncpi->len >= 6)
965 printk(KERN_DEBUG " ncpi.ltc = 0x%04x\n", ncpi->ltc);
966 if (ncpi->len >= 8)
967 printk(KERN_DEBUG " ncpi.htc = 0x%04x\n", ncpi->htc);
968 if (ncpi->len >= 10)
969 printk(KERN_DEBUG " ncpi.loc = 0x%04x\n", ncpi->loc);
970 if (ncpi->len >= 12)
971 printk(KERN_DEBUG " ncpi.hoc = 0x%04x\n", ncpi->hoc);
972 if (ncpi->len >= 13)
973 printk(KERN_DEBUG " ncpi.mod = %d\n", ncpi->modulo);
974}
975
976static void
977actcapi_debug_dlpd(actcapi_dlpd *dlpd)
978{
979 printk(KERN_DEBUG " dlpd.len = %d\n", dlpd->len);
980 if (dlpd->len >= 2)
981 printk(KERN_DEBUG " dlpd.dlen = 0x%04x\n", dlpd->dlen);
982 if (dlpd->len >= 3)
983 printk(KERN_DEBUG " dlpd.laa = 0x%02x\n", dlpd->laa);
984 if (dlpd->len >= 4)
985 printk(KERN_DEBUG " dlpd.lab = 0x%02x\n", dlpd->lab);
986 if (dlpd->len >= 5)
987 printk(KERN_DEBUG " dlpd.modulo = %d\n", dlpd->modulo);
988 if (dlpd->len >= 6)
989 printk(KERN_DEBUG " dlpd.win = %d\n", dlpd->win);
990}
991
992#ifdef DEBUG_DUMP_SKB
993static void dump_skb(struct sk_buff *skb) {
994 char tmp[80];
995 char *p = skb->data;
996 char *t = tmp;
997 int i;
998
999 for (i = 0; i < skb->len; i++) {
1000 t += sprintf(t, "%02x ", *p++ & 0xff);
1001 if ((i & 0x0f) == 8) {
1002 printk(KERN_DEBUG "dump: %s\n", tmp);
1003 t = tmp;
1004 }
1005 }
1006 if (i & 0x07)
1007 printk(KERN_DEBUG "dump: %s\n", tmp);
1008}
1009#endif
1010
1011void
1012actcapi_debug_msg(struct sk_buff *skb, int direction)
1013{
1014 actcapi_msg *msg = (actcapi_msg *)skb->data;
1015 char *descr;
1016 int i;
1017 char tmp[170];
Joe Perches475be4d2012-02-19 19:52:38 -08001018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019#ifndef DEBUG_DATA_MSG
1020 if (msg->hdr.cmd.cmd == 0x86)
1021 return;
1022#endif
1023 descr = "INVALID";
1024#ifdef DEBUG_DUMP_SKB
1025 dump_skb(skb);
1026#endif
Karsten Keilba2d6cc2009-07-24 18:26:08 +02001027 for (i = 0; i < ARRAY_SIZE(valid_msg); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
1029 (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
1030 descr = valid_msg[i].description;
1031 break;
1032 }
Joe Perches475be4d2012-02-19 19:52:38 -08001033 printk(KERN_DEBUG "%s %s msg\n", direction ? "Outgoing" : "Incoming", descr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 printk(KERN_DEBUG " ApplID = %d\n", msg->hdr.applicationID);
1035 printk(KERN_DEBUG " Len = %d\n", msg->hdr.len);
1036 printk(KERN_DEBUG " MsgNum = 0x%04x\n", msg->hdr.msgnum);
1037 printk(KERN_DEBUG " Cmd = 0x%02x\n", msg->hdr.cmd.cmd);
1038 printk(KERN_DEBUG " SubCmd = 0x%02x\n", msg->hdr.cmd.subcmd);
1039 switch (i) {
Joe Perches475be4d2012-02-19 19:52:38 -08001040 case 0:
1041 /* DATA B3 IND */
1042 printk(KERN_DEBUG " BLOCK = 0x%02x\n",
1043 msg->msg.data_b3_ind.blocknr);
1044 break;
1045 case 2:
1046 /* CONNECT CONF */
1047 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1048 msg->msg.connect_conf.plci);
1049 printk(KERN_DEBUG " Info = 0x%04x\n",
1050 msg->msg.connect_conf.info);
1051 break;
1052 case 3:
1053 /* CONNECT IND */
1054 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1055 msg->msg.connect_ind.plci);
1056 printk(KERN_DEBUG " Contr = %d\n",
1057 msg->msg.connect_ind.controller);
1058 printk(KERN_DEBUG " SI1 = %d\n",
1059 msg->msg.connect_ind.si1);
1060 printk(KERN_DEBUG " SI2 = %d\n",
1061 msg->msg.connect_ind.si2);
1062 printk(KERN_DEBUG " EAZ = '%c'\n",
1063 msg->msg.connect_ind.eaz);
1064 actcapi_debug_caddr(&msg->msg.connect_ind.addr);
1065 break;
1066 case 5:
1067 /* CONNECT ACTIVE IND */
1068 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1069 msg->msg.connect_active_ind.plci);
1070 actcapi_debug_caddr(&msg->msg.connect_active_ind.addr);
1071 break;
1072 case 8:
1073 /* LISTEN CONF */
1074 printk(KERN_DEBUG " Contr = %d\n",
1075 msg->msg.listen_conf.controller);
1076 printk(KERN_DEBUG " Info = 0x%04x\n",
1077 msg->msg.listen_conf.info);
1078 break;
1079 case 11:
1080 /* INFO IND */
1081 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1082 msg->msg.info_ind.plci);
1083 printk(KERN_DEBUG " Imsk = 0x%04x\n",
1084 msg->msg.info_ind.nr.mask);
1085 if (msg->hdr.len > 12) {
1086 int l = msg->hdr.len - 12;
1087 int j;
1088 char *p = tmp;
1089 for (j = 0; j < l; j++)
1090 p += sprintf(p, "%02x ", msg->msg.info_ind.el.display[j]);
1091 printk(KERN_DEBUG " D = '%s'\n", tmp);
1092 }
1093 break;
1094 case 14:
1095 /* SELECT B2 PROTOCOL CONF */
1096 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1097 msg->msg.select_b2_protocol_conf.plci);
1098 printk(KERN_DEBUG " Info = 0x%04x\n",
1099 msg->msg.select_b2_protocol_conf.info);
1100 break;
1101 case 15:
1102 /* SELECT B3 PROTOCOL CONF */
1103 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1104 msg->msg.select_b3_protocol_conf.plci);
1105 printk(KERN_DEBUG " Info = 0x%04x\n",
1106 msg->msg.select_b3_protocol_conf.info);
1107 break;
1108 case 16:
1109 /* LISTEN B3 CONF */
1110 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1111 msg->msg.listen_b3_conf.plci);
1112 printk(KERN_DEBUG " Info = 0x%04x\n",
1113 msg->msg.listen_b3_conf.info);
1114 break;
1115 case 18:
1116 /* CONNECT B3 IND */
1117 printk(KERN_DEBUG " NCCI = 0x%04x\n",
1118 msg->msg.connect_b3_ind.ncci);
1119 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1120 msg->msg.connect_b3_ind.plci);
1121 actcapi_debug_ncpi(&msg->msg.connect_b3_ind.ncpi);
1122 break;
1123 case 19:
1124 /* CONNECT B3 ACTIVE IND */
1125 printk(KERN_DEBUG " NCCI = 0x%04x\n",
1126 msg->msg.connect_b3_active_ind.ncci);
1127 actcapi_debug_ncpi(&msg->msg.connect_b3_active_ind.ncpi);
1128 break;
1129 case 26:
1130 /* MANUFACTURER IND */
1131 printk(KERN_DEBUG " Mmsg = 0x%02x\n",
1132 msg->msg.manufacturer_ind_err.manuf_msg);
1133 switch (msg->msg.manufacturer_ind_err.manuf_msg) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 case 3:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 printk(KERN_DEBUG " Contr = %d\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001136 msg->msg.manufacturer_ind_err.controller);
1137 printk(KERN_DEBUG " Code = 0x%08x\n",
1138 msg->msg.manufacturer_ind_err.errcode);
1139 memset(tmp, 0, sizeof(tmp));
1140 strncpy(tmp, &msg->msg.manufacturer_ind_err.errstring,
1141 msg->hdr.len - 16);
1142 printk(KERN_DEBUG " Emsg = '%s'\n", tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 break;
Joe Perches475be4d2012-02-19 19:52:38 -08001144 }
1145 break;
1146 case 30:
1147 /* LISTEN REQ */
1148 printk(KERN_DEBUG " Imsk = 0x%08x\n",
1149 msg->msg.listen_req.infomask);
1150 printk(KERN_DEBUG " Emsk = 0x%04x\n",
1151 msg->msg.listen_req.eazmask);
1152 printk(KERN_DEBUG " Smsk = 0x%04x\n",
1153 msg->msg.listen_req.simask);
1154 break;
1155 case 35:
1156 /* SELECT_B2_PROTOCOL_REQ */
1157 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1158 msg->msg.select_b2_protocol_req.plci);
1159 printk(KERN_DEBUG " prot = 0x%02x\n",
1160 msg->msg.select_b2_protocol_req.protocol);
1161 if (msg->hdr.len >= 11)
1162 printk(KERN_DEBUG "No dlpd\n");
1163 else
1164 actcapi_debug_dlpd(&msg->msg.select_b2_protocol_req.dlpd);
1165 break;
1166 case 44:
1167 /* CONNECT RESP */
1168 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1169 msg->msg.connect_resp.plci);
1170 printk(KERN_DEBUG " CAUSE = 0x%02x\n",
1171 msg->msg.connect_resp.rejectcause);
1172 break;
1173 case 45:
1174 /* CONNECT ACTIVE RESP */
1175 printk(KERN_DEBUG " PLCI = 0x%04x\n",
1176 msg->msg.connect_active_resp.plci);
1177 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 }
1179}
1180#endif