diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hisax/q931.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/hisax/q931.c')
-rw-r--r-- | drivers/isdn/hisax/q931.c | 1522 |
1 files changed, 1522 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c new file mode 100644 index 000000000000..170fcd4a3984 --- /dev/null +++ b/drivers/isdn/hisax/q931.c | |||
@@ -0,0 +1,1522 @@ | |||
1 | /* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $ | ||
2 | * | ||
3 | * code to decode ITU Q.931 call control messages | ||
4 | * | ||
5 | * Author Jan den Ouden | ||
6 | * Copyright by Jan den Ouden | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | * Changelog: | ||
12 | * | ||
13 | * Pauline Middelink general improvements | ||
14 | * Beat Doebeli cause texts, display information element | ||
15 | * Karsten Keil cause texts, display information element for 1TR6 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | |||
20 | #include "hisax.h" | ||
21 | #include "l3_1tr6.h" | ||
22 | |||
23 | void | ||
24 | iecpy(u_char * dest, u_char * iestart, int ieoffset) | ||
25 | { | ||
26 | u_char *p; | ||
27 | int l; | ||
28 | |||
29 | p = iestart + ieoffset + 2; | ||
30 | l = iestart[1] - ieoffset; | ||
31 | while (l--) | ||
32 | *dest++ = *p++; | ||
33 | *dest++ = '\0'; | ||
34 | } | ||
35 | |||
36 | /* | ||
37 | * According to Table 4-2/Q.931 | ||
38 | */ | ||
39 | static | ||
40 | struct MessageType { | ||
41 | u_char nr; | ||
42 | char *descr; | ||
43 | } mtlist[] = { | ||
44 | |||
45 | { | ||
46 | 0x1, "ALERTING" | ||
47 | }, | ||
48 | { | ||
49 | 0x2, "CALL PROCEEDING" | ||
50 | }, | ||
51 | { | ||
52 | 0x7, "CONNECT" | ||
53 | }, | ||
54 | { | ||
55 | 0xf, "CONNECT ACKNOWLEDGE" | ||
56 | }, | ||
57 | { | ||
58 | 0x3, "PROGRESS" | ||
59 | }, | ||
60 | { | ||
61 | 0x5, "SETUP" | ||
62 | }, | ||
63 | { | ||
64 | 0xd, "SETUP ACKNOWLEDGE" | ||
65 | }, | ||
66 | { | ||
67 | 0x24, "HOLD" | ||
68 | }, | ||
69 | { | ||
70 | 0x28, "HOLD ACKNOWLEDGE" | ||
71 | }, | ||
72 | { | ||
73 | 0x30, "HOLD REJECT" | ||
74 | }, | ||
75 | { | ||
76 | 0x31, "RETRIEVE" | ||
77 | }, | ||
78 | { | ||
79 | 0x33, "RETRIEVE ACKNOWLEDGE" | ||
80 | }, | ||
81 | { | ||
82 | 0x37, "RETRIEVE REJECT" | ||
83 | }, | ||
84 | { | ||
85 | 0x26, "RESUME" | ||
86 | }, | ||
87 | { | ||
88 | 0x2e, "RESUME ACKNOWLEDGE" | ||
89 | }, | ||
90 | { | ||
91 | 0x22, "RESUME REJECT" | ||
92 | }, | ||
93 | { | ||
94 | 0x25, "SUSPEND" | ||
95 | }, | ||
96 | { | ||
97 | 0x2d, "SUSPEND ACKNOWLEDGE" | ||
98 | }, | ||
99 | { | ||
100 | 0x21, "SUSPEND REJECT" | ||
101 | }, | ||
102 | { | ||
103 | 0x20, "USER INFORMATION" | ||
104 | }, | ||
105 | { | ||
106 | 0x45, "DISCONNECT" | ||
107 | }, | ||
108 | { | ||
109 | 0x4d, "RELEASE" | ||
110 | }, | ||
111 | { | ||
112 | 0x5a, "RELEASE COMPLETE" | ||
113 | }, | ||
114 | { | ||
115 | 0x46, "RESTART" | ||
116 | }, | ||
117 | { | ||
118 | 0x4e, "RESTART ACKNOWLEDGE" | ||
119 | }, | ||
120 | { | ||
121 | 0x60, "SEGMENT" | ||
122 | }, | ||
123 | { | ||
124 | 0x79, "CONGESTION CONTROL" | ||
125 | }, | ||
126 | { | ||
127 | 0x7b, "INFORMATION" | ||
128 | }, | ||
129 | { | ||
130 | 0x62, "FACILITY" | ||
131 | }, | ||
132 | { | ||
133 | 0x6e, "NOTIFY" | ||
134 | }, | ||
135 | { | ||
136 | 0x7d, "STATUS" | ||
137 | }, | ||
138 | { | ||
139 | 0x75, "STATUS ENQUIRY" | ||
140 | } | ||
141 | }; | ||
142 | |||
143 | #define MTSIZE sizeof(mtlist)/sizeof(struct MessageType) | ||
144 | |||
145 | static | ||
146 | struct MessageType mt_n0[] = | ||
147 | { | ||
148 | {MT_N0_REG_IND, "REGister INDication"}, | ||
149 | {MT_N0_CANC_IND, "CANCel INDication"}, | ||
150 | {MT_N0_FAC_STA, "FACility STAtus"}, | ||
151 | {MT_N0_STA_ACK, "STAtus ACKnowledge"}, | ||
152 | {MT_N0_STA_REJ, "STAtus REJect"}, | ||
153 | {MT_N0_FAC_INF, "FACility INFormation"}, | ||
154 | {MT_N0_INF_ACK, "INFormation ACKnowledge"}, | ||
155 | {MT_N0_INF_REJ, "INFormation REJect"}, | ||
156 | {MT_N0_CLOSE, "CLOSE"}, | ||
157 | {MT_N0_CLO_ACK, "CLOse ACKnowledge"} | ||
158 | }; | ||
159 | |||
160 | #define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType)) | ||
161 | |||
162 | static | ||
163 | struct MessageType mt_n1[] = | ||
164 | { | ||
165 | {MT_N1_ESC, "ESCape"}, | ||
166 | {MT_N1_ALERT, "ALERT"}, | ||
167 | {MT_N1_CALL_SENT, "CALL SENT"}, | ||
168 | {MT_N1_CONN, "CONNect"}, | ||
169 | {MT_N1_CONN_ACK, "CONNect ACKnowledge"}, | ||
170 | {MT_N1_SETUP, "SETUP"}, | ||
171 | {MT_N1_SETUP_ACK, "SETUP ACKnowledge"}, | ||
172 | {MT_N1_RES, "RESume"}, | ||
173 | {MT_N1_RES_ACK, "RESume ACKnowledge"}, | ||
174 | {MT_N1_RES_REJ, "RESume REJect"}, | ||
175 | {MT_N1_SUSP, "SUSPend"}, | ||
176 | {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"}, | ||
177 | {MT_N1_SUSP_REJ, "SUSPend REJect"}, | ||
178 | {MT_N1_USER_INFO, "USER INFO"}, | ||
179 | {MT_N1_DET, "DETach"}, | ||
180 | {MT_N1_DISC, "DISConnect"}, | ||
181 | {MT_N1_REL, "RELease"}, | ||
182 | {MT_N1_REL_ACK, "RELease ACKnowledge"}, | ||
183 | {MT_N1_CANC_ACK, "CANCel ACKnowledge"}, | ||
184 | {MT_N1_CANC_REJ, "CANCel REJect"}, | ||
185 | {MT_N1_CON_CON, "CONgestion CONtrol"}, | ||
186 | {MT_N1_FAC, "FACility"}, | ||
187 | {MT_N1_FAC_ACK, "FACility ACKnowledge"}, | ||
188 | {MT_N1_FAC_CAN, "FACility CANcel"}, | ||
189 | {MT_N1_FAC_REG, "FACility REGister"}, | ||
190 | {MT_N1_FAC_REJ, "FACility REJect"}, | ||
191 | {MT_N1_INFO, "INFOrmation"}, | ||
192 | {MT_N1_REG_ACK, "REGister ACKnowledge"}, | ||
193 | {MT_N1_REG_REJ, "REGister REJect"}, | ||
194 | {MT_N1_STAT, "STATus"} | ||
195 | }; | ||
196 | |||
197 | #define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType)) | ||
198 | |||
199 | |||
200 | static int | ||
201 | prbits(char *dest, u_char b, int start, int len) | ||
202 | { | ||
203 | char *dp = dest; | ||
204 | |||
205 | b = b << (8 - start); | ||
206 | while (len--) { | ||
207 | if (b & 0x80) | ||
208 | *dp++ = '1'; | ||
209 | else | ||
210 | *dp++ = '0'; | ||
211 | b = b << 1; | ||
212 | } | ||
213 | return (dp - dest); | ||
214 | } | ||
215 | |||
216 | static | ||
217 | u_char * | ||
218 | skipext(u_char * p) | ||
219 | { | ||
220 | while (!(*p++ & 0x80)); | ||
221 | return (p); | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Cause Values According to Q.850 | ||
226 | * edescr: English description | ||
227 | * ddescr: German description used by Swissnet II (Swiss Telecom | ||
228 | * not yet written... | ||
229 | */ | ||
230 | |||
231 | static | ||
232 | struct CauseValue { | ||
233 | u_char nr; | ||
234 | char *edescr; | ||
235 | char *ddescr; | ||
236 | } cvlist[] = { | ||
237 | |||
238 | { | ||
239 | 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt" | ||
240 | }, | ||
241 | { | ||
242 | 0x02, "No route to specified transit network", "" | ||
243 | }, | ||
244 | { | ||
245 | 0x03, "No route to destination", "" | ||
246 | }, | ||
247 | { | ||
248 | 0x04, "Send special information tone", "" | ||
249 | }, | ||
250 | { | ||
251 | 0x05, "Misdialled trunk prefix", "" | ||
252 | }, | ||
253 | { | ||
254 | 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar" | ||
255 | }, | ||
256 | { | ||
257 | 0x07, "Channel awarded and being delivered in an established channel", "" | ||
258 | }, | ||
259 | { | ||
260 | 0x08, "Preemption", "" | ||
261 | }, | ||
262 | { | ||
263 | 0x09, "Preemption - circuit reserved for reuse", "" | ||
264 | }, | ||
265 | { | ||
266 | 0x10, "Normal call clearing", "Normale Ausloesung" | ||
267 | }, | ||
268 | { | ||
269 | 0x11, "User busy", "TNB besetzt" | ||
270 | }, | ||
271 | { | ||
272 | 0x12, "No user responding", "" | ||
273 | }, | ||
274 | { | ||
275 | 0x13, "No answer from user (user alerted)", "" | ||
276 | }, | ||
277 | { | ||
278 | 0x14, "Subscriber absent", "" | ||
279 | }, | ||
280 | { | ||
281 | 0x15, "Call rejected", "" | ||
282 | }, | ||
283 | { | ||
284 | 0x16, "Number changed", "" | ||
285 | }, | ||
286 | { | ||
287 | 0x1a, "non-selected user clearing", "" | ||
288 | }, | ||
289 | { | ||
290 | 0x1b, "Destination out of order", "" | ||
291 | }, | ||
292 | { | ||
293 | 0x1c, "Invalid number format (address incomplete)", "" | ||
294 | }, | ||
295 | { | ||
296 | 0x1d, "Facility rejected", "" | ||
297 | }, | ||
298 | { | ||
299 | 0x1e, "Response to Status enquiry", "" | ||
300 | }, | ||
301 | { | ||
302 | 0x1f, "Normal, unspecified", "" | ||
303 | }, | ||
304 | { | ||
305 | 0x22, "No circuit/channel available", "" | ||
306 | }, | ||
307 | { | ||
308 | 0x26, "Network out of order", "" | ||
309 | }, | ||
310 | { | ||
311 | 0x27, "Permanent frame mode connection out-of-service", "" | ||
312 | }, | ||
313 | { | ||
314 | 0x28, "Permanent frame mode connection operational", "" | ||
315 | }, | ||
316 | { | ||
317 | 0x29, "Temporary failure", "" | ||
318 | }, | ||
319 | { | ||
320 | 0x2a, "Switching equipment congestion", "" | ||
321 | }, | ||
322 | { | ||
323 | 0x2b, "Access information discarded", "" | ||
324 | }, | ||
325 | { | ||
326 | 0x2c, "Requested circuit/channel not available", "" | ||
327 | }, | ||
328 | { | ||
329 | 0x2e, "Precedence call blocked", "" | ||
330 | }, | ||
331 | { | ||
332 | 0x2f, "Resource unavailable, unspecified", "" | ||
333 | }, | ||
334 | { | ||
335 | 0x31, "Quality of service unavailable", "" | ||
336 | }, | ||
337 | { | ||
338 | 0x32, "Requested facility not subscribed", "" | ||
339 | }, | ||
340 | { | ||
341 | 0x35, "Outgoing calls barred within CUG", "" | ||
342 | }, | ||
343 | { | ||
344 | 0x37, "Incoming calls barred within CUG", "" | ||
345 | }, | ||
346 | { | ||
347 | 0x39, "Bearer capability not authorized", "" | ||
348 | }, | ||
349 | { | ||
350 | 0x3a, "Bearer capability not presently available", "" | ||
351 | }, | ||
352 | { | ||
353 | 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " " | ||
354 | }, | ||
355 | { | ||
356 | 0x3f, "Service or option not available, unspecified", "" | ||
357 | }, | ||
358 | { | ||
359 | 0x41, "Bearer capability not implemented", "" | ||
360 | }, | ||
361 | { | ||
362 | 0x42, "Channel type not implemented", "" | ||
363 | }, | ||
364 | { | ||
365 | 0x43, "Requested facility not implemented", "" | ||
366 | }, | ||
367 | { | ||
368 | 0x44, "Only restricted digital information bearer capability is available", "" | ||
369 | }, | ||
370 | { | ||
371 | 0x4f, "Service or option not implemented", "" | ||
372 | }, | ||
373 | { | ||
374 | 0x51, "Invalid call reference value", "" | ||
375 | }, | ||
376 | { | ||
377 | 0x52, "Identified channel does not exist", "" | ||
378 | }, | ||
379 | { | ||
380 | 0x53, "A suspended call exists, but this call identity does not", "" | ||
381 | }, | ||
382 | { | ||
383 | 0x54, "Call identity in use", "" | ||
384 | }, | ||
385 | { | ||
386 | 0x55, "No call suspended", "" | ||
387 | }, | ||
388 | { | ||
389 | 0x56, "Call having the requested call identity has been cleared", "" | ||
390 | }, | ||
391 | { | ||
392 | 0x57, "User not member of CUG", "" | ||
393 | }, | ||
394 | { | ||
395 | 0x58, "Incompatible destination", "" | ||
396 | }, | ||
397 | { | ||
398 | 0x5a, "Non-existent CUG", "" | ||
399 | }, | ||
400 | { | ||
401 | 0x5b, "Invalid transit network selection", "" | ||
402 | }, | ||
403 | { | ||
404 | 0x5f, "Invalid message, unspecified", "" | ||
405 | }, | ||
406 | { | ||
407 | 0x60, "Mandatory information element is missing", "" | ||
408 | }, | ||
409 | { | ||
410 | 0x61, "Message type non-existent or not implemented", "" | ||
411 | }, | ||
412 | { | ||
413 | 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " " | ||
414 | }, | ||
415 | { | ||
416 | 0x63, "Information element/parameter non-existent or not implemented", "" | ||
417 | }, | ||
418 | { | ||
419 | 0x64, "Invalid information element contents", "" | ||
420 | }, | ||
421 | { | ||
422 | 0x65, "Message not compatible with call state", "" | ||
423 | }, | ||
424 | { | ||
425 | 0x66, "Recovery on timer expiry", "" | ||
426 | }, | ||
427 | { | ||
428 | 0x67, "Parameter non-existent or not implemented - passed on", "" | ||
429 | }, | ||
430 | { | ||
431 | 0x6e, "Message with unrecognized parameter discarded", "" | ||
432 | }, | ||
433 | { | ||
434 | 0x6f, "Protocol error, unspecified", "" | ||
435 | }, | ||
436 | { | ||
437 | 0x7f, "Interworking, unspecified", "" | ||
438 | }, | ||
439 | }; | ||
440 | |||
441 | #define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue) | ||
442 | |||
443 | static | ||
444 | int | ||
445 | prcause(char *dest, u_char * p) | ||
446 | { | ||
447 | u_char *end; | ||
448 | char *dp = dest; | ||
449 | int i, cause; | ||
450 | |||
451 | end = p + p[1] + 1; | ||
452 | p += 2; | ||
453 | dp += sprintf(dp, " coding "); | ||
454 | dp += prbits(dp, *p, 7, 2); | ||
455 | dp += sprintf(dp, " location "); | ||
456 | dp += prbits(dp, *p, 4, 4); | ||
457 | *dp++ = '\n'; | ||
458 | p = skipext(p); | ||
459 | |||
460 | cause = 0x7f & *p++; | ||
461 | |||
462 | /* locate cause value */ | ||
463 | for (i = 0; i < CVSIZE; i++) | ||
464 | if (cvlist[i].nr == cause) | ||
465 | break; | ||
466 | |||
467 | /* display cause value if it exists */ | ||
468 | if (i == CVSIZE) | ||
469 | dp += sprintf(dp, "Unknown cause type %x!\n", cause); | ||
470 | else | ||
471 | dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr); | ||
472 | |||
473 | while (!0) { | ||
474 | if (p > end) | ||
475 | break; | ||
476 | dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f); | ||
477 | dp += sprintf(dp, " rej %d ", *p & 0x7f); | ||
478 | if (*p & 0x80) { | ||
479 | *dp++ = '\n'; | ||
480 | break; | ||
481 | } else | ||
482 | dp += sprintf(dp, " av %d\n", (*++p) & 0x7f); | ||
483 | } | ||
484 | return (dp - dest); | ||
485 | |||
486 | } | ||
487 | |||
488 | static | ||
489 | struct MessageType cause_1tr6[] = | ||
490 | { | ||
491 | {CAUSE_InvCRef, "Invalid Call Reference"}, | ||
492 | {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"}, | ||
493 | {CAUSE_CIDunknown, "Caller Identity unknown"}, | ||
494 | {CAUSE_CIDinUse, "Caller Identity in Use"}, | ||
495 | {CAUSE_NoChans, "No Channels available"}, | ||
496 | {CAUSE_FacNotImpl, "Facility Not Implemented"}, | ||
497 | {CAUSE_FacNotSubscr, "Facility Not Subscribed"}, | ||
498 | {CAUSE_OutgoingBarred, "Outgoing calls barred"}, | ||
499 | {CAUSE_UserAccessBusy, "User Access Busy"}, | ||
500 | {CAUSE_NegativeGBG, "Negative GBG"}, | ||
501 | {CAUSE_UnknownGBG, "Unknown GBG"}, | ||
502 | {CAUSE_NoSPVknown, "No SPV known"}, | ||
503 | {CAUSE_DestNotObtain, "Destination not obtainable"}, | ||
504 | {CAUSE_NumberChanged, "Number changed"}, | ||
505 | {CAUSE_OutOfOrder, "Out Of Order"}, | ||
506 | {CAUSE_NoUserResponse, "No User Response"}, | ||
507 | {CAUSE_UserBusy, "User Busy"}, | ||
508 | {CAUSE_IncomingBarred, "Incoming Barred"}, | ||
509 | {CAUSE_CallRejected, "Call Rejected"}, | ||
510 | {CAUSE_NetworkCongestion, "Network Congestion"}, | ||
511 | {CAUSE_RemoteUser, "Remote User initiated"}, | ||
512 | {CAUSE_LocalProcErr, "Local Procedure Error"}, | ||
513 | {CAUSE_RemoteProcErr, "Remote Procedure Error"}, | ||
514 | {CAUSE_RemoteUserSuspend, "Remote User Suspend"}, | ||
515 | {CAUSE_RemoteUserResumed, "Remote User Resumed"}, | ||
516 | {CAUSE_UserInfoDiscarded, "User Info Discarded"} | ||
517 | }; | ||
518 | |||
519 | int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); | ||
520 | |||
521 | static int | ||
522 | prcause_1tr6(char *dest, u_char * p) | ||
523 | { | ||
524 | char *dp = dest; | ||
525 | int i, cause; | ||
526 | |||
527 | p++; | ||
528 | if (0 == *p) { | ||
529 | dp += sprintf(dp, " OK (cause length=0)\n"); | ||
530 | return (dp - dest); | ||
531 | } else if (*p > 1) { | ||
532 | dp += sprintf(dp, " coding "); | ||
533 | dp += prbits(dp, p[2], 7, 2); | ||
534 | dp += sprintf(dp, " location "); | ||
535 | dp += prbits(dp, p[2], 4, 4); | ||
536 | *dp++ = '\n'; | ||
537 | } | ||
538 | p++; | ||
539 | cause = 0x7f & *p; | ||
540 | |||
541 | /* locate cause value */ | ||
542 | for (i = 0; i < cause_1tr6_len; i++) | ||
543 | if (cause_1tr6[i].nr == cause) | ||
544 | break; | ||
545 | |||
546 | /* display cause value if it exists */ | ||
547 | if (i == cause_1tr6_len) | ||
548 | dp += sprintf(dp, "Unknown cause type %x!\n", cause); | ||
549 | else | ||
550 | dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr); | ||
551 | |||
552 | return (dp - dest); | ||
553 | |||
554 | } | ||
555 | |||
556 | static int | ||
557 | prchident(char *dest, u_char * p) | ||
558 | { | ||
559 | char *dp = dest; | ||
560 | |||
561 | p += 2; | ||
562 | dp += sprintf(dp, " octet 3 "); | ||
563 | dp += prbits(dp, *p, 8, 8); | ||
564 | *dp++ = '\n'; | ||
565 | return (dp - dest); | ||
566 | } | ||
567 | |||
568 | static int | ||
569 | prcalled(char *dest, u_char * p) | ||
570 | { | ||
571 | int l; | ||
572 | char *dp = dest; | ||
573 | |||
574 | p++; | ||
575 | l = *p++ - 1; | ||
576 | dp += sprintf(dp, " octet 3 "); | ||
577 | dp += prbits(dp, *p++, 8, 8); | ||
578 | *dp++ = '\n'; | ||
579 | dp += sprintf(dp, " number digits "); | ||
580 | while (l--) | ||
581 | *dp++ = *p++; | ||
582 | *dp++ = '\n'; | ||
583 | return (dp - dest); | ||
584 | } | ||
585 | static int | ||
586 | prcalling(char *dest, u_char * p) | ||
587 | { | ||
588 | int l; | ||
589 | char *dp = dest; | ||
590 | |||
591 | p++; | ||
592 | l = *p++ - 1; | ||
593 | dp += sprintf(dp, " octet 3 "); | ||
594 | dp += prbits(dp, *p, 8, 8); | ||
595 | *dp++ = '\n'; | ||
596 | if (!(*p & 0x80)) { | ||
597 | dp += sprintf(dp, " octet 3a "); | ||
598 | dp += prbits(dp, *++p, 8, 8); | ||
599 | *dp++ = '\n'; | ||
600 | l--; | ||
601 | }; | ||
602 | p++; | ||
603 | |||
604 | dp += sprintf(dp, " number digits "); | ||
605 | while (l--) | ||
606 | *dp++ = *p++; | ||
607 | *dp++ = '\n'; | ||
608 | return (dp - dest); | ||
609 | } | ||
610 | |||
611 | static | ||
612 | int | ||
613 | prbearer(char *dest, u_char * p) | ||
614 | { | ||
615 | char *dp = dest, ch; | ||
616 | |||
617 | p += 2; | ||
618 | dp += sprintf(dp, " octet 3 "); | ||
619 | dp += prbits(dp, *p++, 8, 8); | ||
620 | *dp++ = '\n'; | ||
621 | dp += sprintf(dp, " octet 4 "); | ||
622 | dp += prbits(dp, *p, 8, 8); | ||
623 | *dp++ = '\n'; | ||
624 | if ((*p++ & 0x1f) == 0x18) { | ||
625 | dp += sprintf(dp, " octet 4.1 "); | ||
626 | dp += prbits(dp, *p++, 8, 8); | ||
627 | *dp++ = '\n'; | ||
628 | } | ||
629 | /* check for user information layer 1 */ | ||
630 | if ((*p & 0x60) == 0x20) { | ||
631 | ch = ' '; | ||
632 | do { | ||
633 | dp += sprintf(dp, " octet 5%c ", ch); | ||
634 | dp += prbits(dp, *p, 8, 8); | ||
635 | *dp++ = '\n'; | ||
636 | if (ch == ' ') | ||
637 | ch = 'a'; | ||
638 | else | ||
639 | ch++; | ||
640 | } | ||
641 | while (!(*p++ & 0x80)); | ||
642 | } | ||
643 | /* check for user information layer 2 */ | ||
644 | if ((*p & 0x60) == 0x40) { | ||
645 | dp += sprintf(dp, " octet 6 "); | ||
646 | dp += prbits(dp, *p++, 8, 8); | ||
647 | *dp++ = '\n'; | ||
648 | } | ||
649 | /* check for user information layer 3 */ | ||
650 | if ((*p & 0x60) == 0x60) { | ||
651 | dp += sprintf(dp, " octet 7 "); | ||
652 | dp += prbits(dp, *p++, 8, 8); | ||
653 | *dp++ = '\n'; | ||
654 | } | ||
655 | return (dp - dest); | ||
656 | } | ||
657 | |||
658 | |||
659 | static | ||
660 | int | ||
661 | prbearer_ni1(char *dest, u_char * p) | ||
662 | { | ||
663 | char *dp = dest; | ||
664 | u_char len; | ||
665 | |||
666 | p++; | ||
667 | len = *p++; | ||
668 | dp += sprintf(dp, " octet 3 "); | ||
669 | dp += prbits(dp, *p, 8, 8); | ||
670 | switch (*p++) { | ||
671 | case 0x80: | ||
672 | dp += sprintf(dp, " Speech"); | ||
673 | break; | ||
674 | case 0x88: | ||
675 | dp += sprintf(dp, " Unrestricted digital information"); | ||
676 | break; | ||
677 | case 0x90: | ||
678 | dp += sprintf(dp, " 3.1 kHz audio"); | ||
679 | break; | ||
680 | default: | ||
681 | dp += sprintf(dp, " Unknown information-transfer capability"); | ||
682 | } | ||
683 | *dp++ = '\n'; | ||
684 | dp += sprintf(dp, " octet 4 "); | ||
685 | dp += prbits(dp, *p, 8, 8); | ||
686 | switch (*p++) { | ||
687 | case 0x90: | ||
688 | dp += sprintf(dp, " 64 kbps, circuit mode"); | ||
689 | break; | ||
690 | case 0xc0: | ||
691 | dp += sprintf(dp, " Packet mode"); | ||
692 | break; | ||
693 | default: | ||
694 | dp += sprintf(dp, " Unknown transfer mode"); | ||
695 | } | ||
696 | *dp++ = '\n'; | ||
697 | if (len > 2) { | ||
698 | dp += sprintf(dp, " octet 5 "); | ||
699 | dp += prbits(dp, *p, 8, 8); | ||
700 | switch (*p++) { | ||
701 | case 0x21: | ||
702 | dp += sprintf(dp, " Rate adaption\n"); | ||
703 | dp += sprintf(dp, " octet 5a "); | ||
704 | dp += prbits(dp, *p, 8, 8); | ||
705 | break; | ||
706 | case 0xa2: | ||
707 | dp += sprintf(dp, " u-law"); | ||
708 | break; | ||
709 | default: | ||
710 | dp += sprintf(dp, " Unknown UI layer 1 protocol"); | ||
711 | } | ||
712 | *dp++ = '\n'; | ||
713 | } | ||
714 | return (dp - dest); | ||
715 | } | ||
716 | |||
717 | static int | ||
718 | general(char *dest, u_char * p) | ||
719 | { | ||
720 | char *dp = dest; | ||
721 | char ch = ' '; | ||
722 | int l, octet = 3; | ||
723 | |||
724 | p++; | ||
725 | l = *p++; | ||
726 | /* Iterate over all octets in the information element */ | ||
727 | while (l--) { | ||
728 | dp += sprintf(dp, " octet %d%c ", octet, ch); | ||
729 | dp += prbits(dp, *p++, 8, 8); | ||
730 | *dp++ = '\n'; | ||
731 | |||
732 | /* last octet in group? */ | ||
733 | if (*p & 0x80) { | ||
734 | octet++; | ||
735 | ch = ' '; | ||
736 | } else if (ch == ' ') | ||
737 | ch = 'a'; | ||
738 | else | ||
739 | ch++; | ||
740 | } | ||
741 | return (dp - dest); | ||
742 | } | ||
743 | |||
744 | static int | ||
745 | general_ni1(char *dest, u_char * p) | ||
746 | { | ||
747 | char *dp = dest; | ||
748 | char ch = ' '; | ||
749 | int l, octet = 3; | ||
750 | |||
751 | p++; | ||
752 | l = *p++; | ||
753 | /* Iterate over all octets in the information element */ | ||
754 | while (l--) { | ||
755 | dp += sprintf(dp, " octet %d%c ", octet, ch); | ||
756 | dp += prbits(dp, *p, 8, 8); | ||
757 | *dp++ = '\n'; | ||
758 | |||
759 | /* last octet in group? */ | ||
760 | if (*p++ & 0x80) { | ||
761 | octet++; | ||
762 | ch = ' '; | ||
763 | } else if (ch == ' ') | ||
764 | ch = 'a'; | ||
765 | else | ||
766 | ch++; | ||
767 | } | ||
768 | return (dp - dest); | ||
769 | } | ||
770 | |||
771 | static int | ||
772 | prcharge(char *dest, u_char * p) | ||
773 | { | ||
774 | char *dp = dest; | ||
775 | int l; | ||
776 | |||
777 | p++; | ||
778 | l = *p++ - 1; | ||
779 | dp += sprintf(dp, " GEA "); | ||
780 | dp += prbits(dp, *p++, 8, 8); | ||
781 | dp += sprintf(dp, " Anzahl: "); | ||
782 | /* Iterate over all octets in the * information element */ | ||
783 | while (l--) | ||
784 | *dp++ = *p++; | ||
785 | *dp++ = '\n'; | ||
786 | return (dp - dest); | ||
787 | } | ||
788 | static int | ||
789 | prtext(char *dest, u_char * p) | ||
790 | { | ||
791 | char *dp = dest; | ||
792 | int l; | ||
793 | |||
794 | p++; | ||
795 | l = *p++; | ||
796 | dp += sprintf(dp, " "); | ||
797 | /* Iterate over all octets in the * information element */ | ||
798 | while (l--) | ||
799 | *dp++ = *p++; | ||
800 | *dp++ = '\n'; | ||
801 | return (dp - dest); | ||
802 | } | ||
803 | |||
804 | static int | ||
805 | prfeatureind(char *dest, u_char * p) | ||
806 | { | ||
807 | char *dp = dest; | ||
808 | |||
809 | p += 2; /* skip id, len */ | ||
810 | dp += sprintf(dp, " octet 3 "); | ||
811 | dp += prbits(dp, *p, 8, 8); | ||
812 | *dp++ = '\n'; | ||
813 | if (!(*p++ & 80)) { | ||
814 | dp += sprintf(dp, " octet 4 "); | ||
815 | dp += prbits(dp, *p++, 8, 8); | ||
816 | *dp++ = '\n'; | ||
817 | } | ||
818 | dp += sprintf(dp, " Status: "); | ||
819 | switch (*p) { | ||
820 | case 0: | ||
821 | dp += sprintf(dp, "Idle"); | ||
822 | break; | ||
823 | case 1: | ||
824 | dp += sprintf(dp, "Active"); | ||
825 | break; | ||
826 | case 2: | ||
827 | dp += sprintf(dp, "Prompt"); | ||
828 | break; | ||
829 | case 3: | ||
830 | dp += sprintf(dp, "Pending"); | ||
831 | break; | ||
832 | default: | ||
833 | dp += sprintf(dp, "(Reserved)"); | ||
834 | break; | ||
835 | } | ||
836 | *dp++ = '\n'; | ||
837 | return (dp - dest); | ||
838 | } | ||
839 | |||
840 | static | ||
841 | struct DTag { /* Display tags */ | ||
842 | u_char nr; | ||
843 | char *descr; | ||
844 | } dtaglist[] = { | ||
845 | { 0x82, "Continuation" }, | ||
846 | { 0x83, "Called address" }, | ||
847 | { 0x84, "Cause" }, | ||
848 | { 0x85, "Progress indicator" }, | ||
849 | { 0x86, "Notification indicator" }, | ||
850 | { 0x87, "Prompt" }, | ||
851 | { 0x88, "Accumlated digits" }, | ||
852 | { 0x89, "Status" }, | ||
853 | { 0x8a, "Inband" }, | ||
854 | { 0x8b, "Calling address" }, | ||
855 | { 0x8c, "Reason" }, | ||
856 | { 0x8d, "Calling party name" }, | ||
857 | { 0x8e, "Called party name" }, | ||
858 | { 0x8f, "Orignal called name" }, | ||
859 | { 0x90, "Redirecting name" }, | ||
860 | { 0x91, "Connected name" }, | ||
861 | { 0x92, "Originating restrictions" }, | ||
862 | { 0x93, "Date & time of day" }, | ||
863 | { 0x94, "Call Appearance ID" }, | ||
864 | { 0x95, "Feature address" }, | ||
865 | { 0x96, "Redirection name" }, | ||
866 | { 0x9e, "Text" }, | ||
867 | }; | ||
868 | #define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag) | ||
869 | |||
870 | static int | ||
871 | disptext_ni1(char *dest, u_char * p) | ||
872 | { | ||
873 | char *dp = dest; | ||
874 | int l, tag, len, i; | ||
875 | |||
876 | p++; | ||
877 | l = *p++ - 1; | ||
878 | if (*p++ != 0x80) { | ||
879 | dp += sprintf(dp, " Unknown display type\n"); | ||
880 | return (dp - dest); | ||
881 | } | ||
882 | /* Iterate over all tag,length,text fields */ | ||
883 | while (l > 0) { | ||
884 | tag = *p++; | ||
885 | len = *p++; | ||
886 | l -= len + 2; | ||
887 | /* Don't space or skip */ | ||
888 | if ((tag == 0x80) || (tag == 0x81)) p++; | ||
889 | else { | ||
890 | for (i = 0; i < DTAGSIZE; i++) | ||
891 | if (tag == dtaglist[i].nr) | ||
892 | break; | ||
893 | |||
894 | /* When not found, give appropriate msg */ | ||
895 | if (i != DTAGSIZE) { | ||
896 | dp += sprintf(dp, " %s: ", dtaglist[i].descr); | ||
897 | while (len--) | ||
898 | *dp++ = *p++; | ||
899 | } else { | ||
900 | dp += sprintf(dp, " (unknown display tag %2x): ", tag); | ||
901 | while (len--) | ||
902 | *dp++ = *p++; | ||
903 | } | ||
904 | dp += sprintf(dp, "\n"); | ||
905 | } | ||
906 | } | ||
907 | return (dp - dest); | ||
908 | } | ||
909 | static int | ||
910 | display(char *dest, u_char * p) | ||
911 | { | ||
912 | char *dp = dest; | ||
913 | char ch = ' '; | ||
914 | int l, octet = 3; | ||
915 | |||
916 | p++; | ||
917 | l = *p++; | ||
918 | /* Iterate over all octets in the * display-information element */ | ||
919 | dp += sprintf(dp, " \""); | ||
920 | while (l--) { | ||
921 | dp += sprintf(dp, "%c", *p++); | ||
922 | |||
923 | /* last octet in group? */ | ||
924 | if (*p & 0x80) { | ||
925 | octet++; | ||
926 | ch = ' '; | ||
927 | } else if (ch == ' ') | ||
928 | ch = 'a'; | ||
929 | |||
930 | else | ||
931 | ch++; | ||
932 | } | ||
933 | *dp++ = '\"'; | ||
934 | *dp++ = '\n'; | ||
935 | return (dp - dest); | ||
936 | } | ||
937 | |||
938 | int | ||
939 | prfacility(char *dest, u_char * p) | ||
940 | { | ||
941 | char *dp = dest; | ||
942 | int l, l2; | ||
943 | |||
944 | p++; | ||
945 | l = *p++; | ||
946 | dp += sprintf(dp, " octet 3 "); | ||
947 | dp += prbits(dp, *p++, 8, 8); | ||
948 | dp += sprintf(dp, "\n"); | ||
949 | l -= 1; | ||
950 | |||
951 | while (l > 0) { | ||
952 | dp += sprintf(dp, " octet 4 "); | ||
953 | dp += prbits(dp, *p++, 8, 8); | ||
954 | dp += sprintf(dp, "\n"); | ||
955 | dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f); | ||
956 | l -= 2; | ||
957 | dp += sprintf(dp, " contents "); | ||
958 | while (l2--) { | ||
959 | dp += sprintf(dp, "%2x ", *p++); | ||
960 | l--; | ||
961 | } | ||
962 | dp += sprintf(dp, "\n"); | ||
963 | } | ||
964 | |||
965 | return (dp - dest); | ||
966 | } | ||
967 | |||
968 | static | ||
969 | struct InformationElement { | ||
970 | u_char nr; | ||
971 | char *descr; | ||
972 | int (*f) (char *, u_char *); | ||
973 | } ielist[] = { | ||
974 | |||
975 | { | ||
976 | 0x00, "Segmented message", general | ||
977 | }, | ||
978 | { | ||
979 | 0x04, "Bearer capability", prbearer | ||
980 | }, | ||
981 | { | ||
982 | 0x08, "Cause", prcause | ||
983 | }, | ||
984 | { | ||
985 | 0x10, "Call identity", general | ||
986 | }, | ||
987 | { | ||
988 | 0x14, "Call state", general | ||
989 | }, | ||
990 | { | ||
991 | 0x18, "Channel identification", prchident | ||
992 | }, | ||
993 | { | ||
994 | 0x1c, "Facility", prfacility | ||
995 | }, | ||
996 | { | ||
997 | 0x1e, "Progress indicator", general | ||
998 | }, | ||
999 | { | ||
1000 | 0x20, "Network-specific facilities", general | ||
1001 | }, | ||
1002 | { | ||
1003 | 0x27, "Notification indicator", general | ||
1004 | }, | ||
1005 | { | ||
1006 | 0x28, "Display", display | ||
1007 | }, | ||
1008 | { | ||
1009 | 0x29, "Date/Time", general | ||
1010 | }, | ||
1011 | { | ||
1012 | 0x2c, "Keypad facility", general | ||
1013 | }, | ||
1014 | { | ||
1015 | 0x34, "Signal", general | ||
1016 | }, | ||
1017 | { | ||
1018 | 0x40, "Information rate", general | ||
1019 | }, | ||
1020 | { | ||
1021 | 0x42, "End-to-end delay", general | ||
1022 | }, | ||
1023 | { | ||
1024 | 0x43, "Transit delay selection and indication", general | ||
1025 | }, | ||
1026 | { | ||
1027 | 0x44, "Packet layer binary parameters", general | ||
1028 | }, | ||
1029 | { | ||
1030 | 0x45, "Packet layer window size", general | ||
1031 | }, | ||
1032 | { | ||
1033 | 0x46, "Packet size", general | ||
1034 | }, | ||
1035 | { | ||
1036 | 0x47, "Closed user group", general | ||
1037 | }, | ||
1038 | { | ||
1039 | 0x4a, "Reverse charge indication", general | ||
1040 | }, | ||
1041 | { | ||
1042 | 0x6c, "Calling party number", prcalling | ||
1043 | }, | ||
1044 | { | ||
1045 | 0x6d, "Calling party subaddress", general | ||
1046 | }, | ||
1047 | { | ||
1048 | 0x70, "Called party number", prcalled | ||
1049 | }, | ||
1050 | { | ||
1051 | 0x71, "Called party subaddress", general | ||
1052 | }, | ||
1053 | { | ||
1054 | 0x74, "Redirecting number", general | ||
1055 | }, | ||
1056 | { | ||
1057 | 0x78, "Transit network selection", general | ||
1058 | }, | ||
1059 | { | ||
1060 | 0x79, "Restart indicator", general | ||
1061 | }, | ||
1062 | { | ||
1063 | 0x7c, "Low layer compatibility", general | ||
1064 | }, | ||
1065 | { | ||
1066 | 0x7d, "High layer compatibility", general | ||
1067 | }, | ||
1068 | { | ||
1069 | 0x7e, "User-user", general | ||
1070 | }, | ||
1071 | { | ||
1072 | 0x7f, "Escape for extension", general | ||
1073 | }, | ||
1074 | }; | ||
1075 | |||
1076 | |||
1077 | #define IESIZE sizeof(ielist)/sizeof(struct InformationElement) | ||
1078 | |||
1079 | static | ||
1080 | struct InformationElement ielist_ni1[] = { | ||
1081 | { 0x04, "Bearer Capability", prbearer_ni1 }, | ||
1082 | { 0x08, "Cause", prcause }, | ||
1083 | { 0x14, "Call State", general_ni1 }, | ||
1084 | { 0x18, "Channel Identification", prchident }, | ||
1085 | { 0x1e, "Progress Indicator", general_ni1 }, | ||
1086 | { 0x27, "Notification Indicator", general_ni1 }, | ||
1087 | { 0x2c, "Keypad Facility", prtext }, | ||
1088 | { 0x32, "Information Request", general_ni1 }, | ||
1089 | { 0x34, "Signal", general_ni1 }, | ||
1090 | { 0x38, "Feature Activation", general_ni1 }, | ||
1091 | { 0x39, "Feature Indication", prfeatureind }, | ||
1092 | { 0x3a, "Service Profile Identification (SPID)", prtext }, | ||
1093 | { 0x3b, "Endpoint Identifier", general_ni1 }, | ||
1094 | { 0x6c, "Calling Party Number", prcalling }, | ||
1095 | { 0x6d, "Calling Party Subaddress", general_ni1 }, | ||
1096 | { 0x70, "Called Party Number", prcalled }, | ||
1097 | { 0x71, "Called Party Subaddress", general_ni1 }, | ||
1098 | { 0x74, "Redirecting Number", general_ni1 }, | ||
1099 | { 0x78, "Transit Network Selection", general_ni1 }, | ||
1100 | { 0x7c, "Low Layer Compatibility", general_ni1 }, | ||
1101 | { 0x7d, "High Layer Compatibility", general_ni1 }, | ||
1102 | }; | ||
1103 | |||
1104 | |||
1105 | #define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement) | ||
1106 | |||
1107 | static | ||
1108 | struct InformationElement ielist_ni1_cs5[] = { | ||
1109 | { 0x1d, "Operator system access", general_ni1 }, | ||
1110 | { 0x2a, "Display text", disptext_ni1 }, | ||
1111 | }; | ||
1112 | |||
1113 | #define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement) | ||
1114 | |||
1115 | static | ||
1116 | struct InformationElement ielist_ni1_cs6[] = { | ||
1117 | { 0x7b, "Call appearance", general_ni1 }, | ||
1118 | }; | ||
1119 | |||
1120 | #define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement) | ||
1121 | |||
1122 | static struct InformationElement we_0[] = | ||
1123 | { | ||
1124 | {WE0_cause, "Cause", prcause_1tr6}, | ||
1125 | {WE0_connAddr, "Connecting Address", prcalled}, | ||
1126 | {WE0_callID, "Call IDentity", general}, | ||
1127 | {WE0_chanID, "Channel IDentity", general}, | ||
1128 | {WE0_netSpecFac, "Network Specific Facility", general}, | ||
1129 | {WE0_display, "Display", general}, | ||
1130 | {WE0_keypad, "Keypad", general}, | ||
1131 | {WE0_origAddr, "Origination Address", prcalled}, | ||
1132 | {WE0_destAddr, "Destination Address", prcalled}, | ||
1133 | {WE0_userInfo, "User Info", general} | ||
1134 | }; | ||
1135 | |||
1136 | #define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement)) | ||
1137 | |||
1138 | static struct InformationElement we_6[] = | ||
1139 | { | ||
1140 | {WE6_serviceInd, "Service Indicator", general}, | ||
1141 | {WE6_chargingInfo, "Charging Information", prcharge}, | ||
1142 | {WE6_date, "Date", prtext}, | ||
1143 | {WE6_facSelect, "Facility Select", general}, | ||
1144 | {WE6_facStatus, "Facility Status", general}, | ||
1145 | {WE6_statusCalled, "Status Called", general}, | ||
1146 | {WE6_addTransAttr, "Additional Transmission Attributes", general} | ||
1147 | }; | ||
1148 | #define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement)) | ||
1149 | |||
1150 | int | ||
1151 | QuickHex(char *txt, u_char * p, int cnt) | ||
1152 | { | ||
1153 | register int i; | ||
1154 | register char *t = txt; | ||
1155 | register u_char w; | ||
1156 | |||
1157 | for (i = 0; i < cnt; i++) { | ||
1158 | *t++ = ' '; | ||
1159 | w = (p[i] >> 4) & 0x0f; | ||
1160 | if (w < 10) | ||
1161 | *t++ = '0' + w; | ||
1162 | else | ||
1163 | *t++ = 'A' - 10 + w; | ||
1164 | w = p[i] & 0x0f; | ||
1165 | if (w < 10) | ||
1166 | *t++ = '0' + w; | ||
1167 | else | ||
1168 | *t++ = 'A' - 10 + w; | ||
1169 | } | ||
1170 | *t++ = 0; | ||
1171 | return (t - txt); | ||
1172 | } | ||
1173 | |||
1174 | void | ||
1175 | LogFrame(struct IsdnCardState *cs, u_char * buf, int size) | ||
1176 | { | ||
1177 | char *dp; | ||
1178 | |||
1179 | if (size < 1) | ||
1180 | return; | ||
1181 | dp = cs->dlog; | ||
1182 | if (size < MAX_DLOG_SPACE / 3 - 10) { | ||
1183 | *dp++ = 'H'; | ||
1184 | *dp++ = 'E'; | ||
1185 | *dp++ = 'X'; | ||
1186 | *dp++ = ':'; | ||
1187 | dp += QuickHex(dp, buf, size); | ||
1188 | dp--; | ||
1189 | *dp++ = '\n'; | ||
1190 | *dp = 0; | ||
1191 | HiSax_putstatus(cs, NULL, cs->dlog); | ||
1192 | } else | ||
1193 | HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); | ||
1194 | } | ||
1195 | |||
1196 | void | ||
1197 | dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) | ||
1198 | { | ||
1199 | u_char *bend, *buf; | ||
1200 | char *dp; | ||
1201 | unsigned char pd, cr_l, cr, mt; | ||
1202 | unsigned char sapi, tei, ftyp; | ||
1203 | int i, cset = 0, cs_old = 0, cs_fest = 0; | ||
1204 | int size, finish = 0; | ||
1205 | |||
1206 | if (skb->len < 3) | ||
1207 | return; | ||
1208 | /* display header */ | ||
1209 | dp = cs->dlog; | ||
1210 | dp += jiftime(dp, jiffies); | ||
1211 | *dp++ = ' '; | ||
1212 | sapi = skb->data[0] >> 2; | ||
1213 | tei = skb->data[1] >> 1; | ||
1214 | ftyp = skb->data[2]; | ||
1215 | buf = skb->data; | ||
1216 | dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network"); | ||
1217 | size = skb->len; | ||
1218 | |||
1219 | if (tei == GROUP_TEI) { | ||
1220 | if (sapi == CTRL_SAPI) { /* sapi 0 */ | ||
1221 | if (ftyp == 3) { | ||
1222 | dp += sprintf(dp, "broadcast\n"); | ||
1223 | buf += 3; | ||
1224 | size -= 3; | ||
1225 | } else { | ||
1226 | dp += sprintf(dp, "no UI broadcast\n"); | ||
1227 | finish = 1; | ||
1228 | } | ||
1229 | } else if (sapi == TEI_SAPI) { | ||
1230 | dp += sprintf(dp, "tei management\n"); | ||
1231 | finish = 1; | ||
1232 | } else { | ||
1233 | dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi); | ||
1234 | finish = 1; | ||
1235 | } | ||
1236 | } else { | ||
1237 | if (sapi == CTRL_SAPI) { | ||
1238 | if (!(ftyp & 1)) { /* IFrame */ | ||
1239 | dp += sprintf(dp, "with tei %d\n", tei); | ||
1240 | buf += 4; | ||
1241 | size -= 4; | ||
1242 | } else { | ||
1243 | dp += sprintf(dp, "SFrame with tei %d\n", tei); | ||
1244 | finish = 1; | ||
1245 | } | ||
1246 | } else { | ||
1247 | dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei); | ||
1248 | finish = 1; | ||
1249 | } | ||
1250 | } | ||
1251 | bend = skb->data + skb->len; | ||
1252 | if (buf >= bend) { | ||
1253 | dp += sprintf(dp, "frame too short\n"); | ||
1254 | finish = 1; | ||
1255 | } | ||
1256 | if (finish) { | ||
1257 | *dp = 0; | ||
1258 | HiSax_putstatus(cs, NULL, cs->dlog); | ||
1259 | return; | ||
1260 | } | ||
1261 | if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ | ||
1262 | /* locate message type */ | ||
1263 | pd = *buf++; | ||
1264 | cr_l = *buf++; | ||
1265 | if (cr_l) | ||
1266 | cr = *buf++; | ||
1267 | else | ||
1268 | cr = 0; | ||
1269 | mt = *buf++; | ||
1270 | if (pd == PROTO_DIS_N0) { /* N0 */ | ||
1271 | for (i = 0; i < MT_N0_LEN; i++) | ||
1272 | if (mt_n0[i].nr == mt) | ||
1273 | break; | ||
1274 | /* display message type if it exists */ | ||
1275 | if (i == MT_N0_LEN) | ||
1276 | dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n", | ||
1277 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | ||
1278 | size, mt); | ||
1279 | else | ||
1280 | dp += sprintf(dp, "callref %d %s size %d message type %s\n", | ||
1281 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | ||
1282 | size, mt_n0[i].descr); | ||
1283 | } else { /* N1 */ | ||
1284 | for (i = 0; i < MT_N1_LEN; i++) | ||
1285 | if (mt_n1[i].nr == mt) | ||
1286 | break; | ||
1287 | /* display message type if it exists */ | ||
1288 | if (i == MT_N1_LEN) | ||
1289 | dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n", | ||
1290 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | ||
1291 | size, mt); | ||
1292 | else | ||
1293 | dp += sprintf(dp, "callref %d %s size %d message type %s\n", | ||
1294 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | ||
1295 | size, mt_n1[i].descr); | ||
1296 | } | ||
1297 | |||
1298 | /* display each information element */ | ||
1299 | while (buf < bend) { | ||
1300 | /* Is it a single octet information element? */ | ||
1301 | if (*buf & 0x80) { | ||
1302 | switch ((*buf >> 4) & 7) { | ||
1303 | case 1: | ||
1304 | dp += sprintf(dp, " Shift %x\n", *buf & 0xf); | ||
1305 | cs_old = cset; | ||
1306 | cset = *buf & 7; | ||
1307 | cs_fest = *buf & 8; | ||
1308 | break; | ||
1309 | case 3: | ||
1310 | dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); | ||
1311 | break; | ||
1312 | case 2: | ||
1313 | if (*buf == 0xa0) { | ||
1314 | dp += sprintf(dp, " More data\n"); | ||
1315 | break; | ||
1316 | } | ||
1317 | if (*buf == 0xa1) { | ||
1318 | dp += sprintf(dp, " Sending complete\n"); | ||
1319 | } | ||
1320 | break; | ||
1321 | /* fall through */ | ||
1322 | default: | ||
1323 | dp += sprintf(dp, " Reserved %x\n", *buf); | ||
1324 | break; | ||
1325 | } | ||
1326 | buf++; | ||
1327 | continue; | ||
1328 | } | ||
1329 | /* No, locate it in the table */ | ||
1330 | if (cset == 0) { | ||
1331 | for (i = 0; i < WE_0_LEN; i++) | ||
1332 | if (*buf == we_0[i].nr) | ||
1333 | break; | ||
1334 | |||
1335 | /* When found, give appropriate msg */ | ||
1336 | if (i != WE_0_LEN) { | ||
1337 | dp += sprintf(dp, " %s\n", we_0[i].descr); | ||
1338 | dp += we_0[i].f(dp, buf); | ||
1339 | } else | ||
1340 | dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); | ||
1341 | } else if (cset == 6) { | ||
1342 | for (i = 0; i < WE_6_LEN; i++) | ||
1343 | if (*buf == we_6[i].nr) | ||
1344 | break; | ||
1345 | |||
1346 | /* When found, give appropriate msg */ | ||
1347 | if (i != WE_6_LEN) { | ||
1348 | dp += sprintf(dp, " %s\n", we_6[i].descr); | ||
1349 | dp += we_6[i].f(dp, buf); | ||
1350 | } else | ||
1351 | dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); | ||
1352 | } else | ||
1353 | dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); | ||
1354 | /* Skip to next element */ | ||
1355 | if (cs_fest == 8) { | ||
1356 | cset = cs_old; | ||
1357 | cs_old = 0; | ||
1358 | cs_fest = 0; | ||
1359 | } | ||
1360 | buf += buf[1] + 2; | ||
1361 | } | ||
1362 | } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ | ||
1363 | /* locate message type */ | ||
1364 | buf++; | ||
1365 | cr_l = *buf++; | ||
1366 | if (cr_l) | ||
1367 | cr = *buf++; | ||
1368 | else | ||
1369 | cr = 0; | ||
1370 | mt = *buf++; | ||
1371 | for (i = 0; i < MTSIZE; i++) | ||
1372 | if (mtlist[i].nr == mt) | ||
1373 | break; | ||
1374 | |||
1375 | /* display message type if it exists */ | ||
1376 | if (i == MTSIZE) | ||
1377 | dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", | ||
1378 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | ||
1379 | size, mt); | ||
1380 | else | ||
1381 | dp += sprintf(dp, "callref %d %s size %d message type %s\n", | ||
1382 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | ||
1383 | size, mtlist[i].descr); | ||
1384 | |||
1385 | /* display each information element */ | ||
1386 | while (buf < bend) { | ||
1387 | /* Is it a single octet information element? */ | ||
1388 | if (*buf & 0x80) { | ||
1389 | switch ((*buf >> 4) & 7) { | ||
1390 | case 1: | ||
1391 | dp += sprintf(dp, " Shift %x\n", *buf & 0xf); | ||
1392 | cs_old = cset; | ||
1393 | cset = *buf & 7; | ||
1394 | cs_fest = *buf & 8; | ||
1395 | break; | ||
1396 | default: | ||
1397 | dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); | ||
1398 | break; | ||
1399 | } | ||
1400 | buf++; | ||
1401 | continue; | ||
1402 | } | ||
1403 | /* No, locate it in the table */ | ||
1404 | if (cset == 0) { | ||
1405 | for (i = 0; i < IESIZE; i++) | ||
1406 | if (*buf == ielist_ni1[i].nr) | ||
1407 | break; | ||
1408 | |||
1409 | /* When not found, give appropriate msg */ | ||
1410 | if (i != IESIZE) { | ||
1411 | dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); | ||
1412 | dp += ielist_ni1[i].f(dp, buf); | ||
1413 | } else | ||
1414 | dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); | ||
1415 | } else if (cset == 5) { | ||
1416 | for (i = 0; i < IESIZE_NI1_CS5; i++) | ||
1417 | if (*buf == ielist_ni1_cs5[i].nr) | ||
1418 | break; | ||
1419 | |||
1420 | /* When not found, give appropriate msg */ | ||
1421 | if (i != IESIZE_NI1_CS5) { | ||
1422 | dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); | ||
1423 | dp += ielist_ni1_cs5[i].f(dp, buf); | ||
1424 | } else | ||
1425 | dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); | ||
1426 | } else if (cset == 6) { | ||
1427 | for (i = 0; i < IESIZE_NI1_CS6; i++) | ||
1428 | if (*buf == ielist_ni1_cs6[i].nr) | ||
1429 | break; | ||
1430 | |||
1431 | /* When not found, give appropriate msg */ | ||
1432 | if (i != IESIZE_NI1_CS6) { | ||
1433 | dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); | ||
1434 | dp += ielist_ni1_cs6[i].f(dp, buf); | ||
1435 | } else | ||
1436 | dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); | ||
1437 | } else | ||
1438 | dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); | ||
1439 | |||
1440 | /* Skip to next element */ | ||
1441 | if (cs_fest == 8) { | ||
1442 | cset = cs_old; | ||
1443 | cs_old = 0; | ||
1444 | cs_fest = 0; | ||
1445 | } | ||
1446 | buf += buf[1] + 2; | ||
1447 | } | ||
1448 | } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ | ||
1449 | /* locate message type */ | ||
1450 | buf++; | ||
1451 | cr_l = *buf++; | ||
1452 | if (cr_l) | ||
1453 | cr = *buf++; | ||
1454 | else | ||
1455 | cr = 0; | ||
1456 | mt = *buf++; | ||
1457 | for (i = 0; i < MTSIZE; i++) | ||
1458 | if (mtlist[i].nr == mt) | ||
1459 | break; | ||
1460 | |||
1461 | /* display message type if it exists */ | ||
1462 | if (i == MTSIZE) | ||
1463 | dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", | ||
1464 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | ||
1465 | size, mt); | ||
1466 | else | ||
1467 | dp += sprintf(dp, "callref %d %s size %d message type %s\n", | ||
1468 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | ||
1469 | size, mtlist[i].descr); | ||
1470 | |||
1471 | /* display each information element */ | ||
1472 | while (buf < bend) { | ||
1473 | /* Is it a single octet information element? */ | ||
1474 | if (*buf & 0x80) { | ||
1475 | switch ((*buf >> 4) & 7) { | ||
1476 | case 1: | ||
1477 | dp += sprintf(dp, " Shift %x\n", *buf & 0xf); | ||
1478 | break; | ||
1479 | case 3: | ||
1480 | dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); | ||
1481 | break; | ||
1482 | case 5: | ||
1483 | dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); | ||
1484 | break; | ||
1485 | case 2: | ||
1486 | if (*buf == 0xa0) { | ||
1487 | dp += sprintf(dp, " More data\n"); | ||
1488 | break; | ||
1489 | } | ||
1490 | if (*buf == 0xa1) { | ||
1491 | dp += sprintf(dp, " Sending complete\n"); | ||
1492 | } | ||
1493 | break; | ||
1494 | /* fall through */ | ||
1495 | default: | ||
1496 | dp += sprintf(dp, " Reserved %x\n", *buf); | ||
1497 | break; | ||
1498 | } | ||
1499 | buf++; | ||
1500 | continue; | ||
1501 | } | ||
1502 | /* No, locate it in the table */ | ||
1503 | for (i = 0; i < IESIZE; i++) | ||
1504 | if (*buf == ielist[i].nr) | ||
1505 | break; | ||
1506 | |||
1507 | /* When not found, give appropriate msg */ | ||
1508 | if (i != IESIZE) { | ||
1509 | dp += sprintf(dp, " %s\n", ielist[i].descr); | ||
1510 | dp += ielist[i].f(dp, buf); | ||
1511 | } else | ||
1512 | dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); | ||
1513 | |||
1514 | /* Skip to next element */ | ||
1515 | buf += buf[1] + 2; | ||
1516 | } | ||
1517 | } else { | ||
1518 | dp += sprintf(dp, "Unknown protocol %x!", buf[0]); | ||
1519 | } | ||
1520 | *dp = 0; | ||
1521 | HiSax_putstatus(cs, NULL, cs->dlog); | ||
1522 | } | ||