Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | |
475be4d8 | 24 | iecpy(u_char *dest, u_char *iestart, int ieoffset) |
1da177e4 LT |
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 | ||
ba2d6ccb | 143 | #define MTSIZE ARRAY_SIZE(mtlist) |
1da177e4 LT |
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 | ||
ba2d6ccb | 160 | #define MT_N0_LEN ARRAY_SIZE(mt_n0) |
1da177e4 LT |
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 | ||
ba2d6ccb | 197 | #define MT_N1_LEN ARRAY_SIZE(mt_n1) |
1da177e4 LT |
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 * | |
475be4d8 | 218 | skipext(u_char *p) |
1da177e4 LT |
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 | ||
ba2d6ccb | 441 | #define CVSIZE ARRAY_SIZE(cvlist) |
1da177e4 LT |
442 | |
443 | static | |
444 | int | |
475be4d8 | 445 | prcause(char *dest, u_char *p) |
1da177e4 LT |
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 | ||
ba2d6ccb | 519 | static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6); |
1da177e4 LT |
520 | |
521 | static int | |
475be4d8 | 522 | prcause_1tr6(char *dest, u_char *p) |
1da177e4 LT |
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 | |
475be4d8 | 557 | prchident(char *dest, u_char *p) |
1da177e4 LT |
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 | |
475be4d8 | 569 | prcalled(char *dest, u_char *p) |
1da177e4 LT |
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 | |
475be4d8 | 586 | prcalling(char *dest, u_char *p) |
1da177e4 LT |
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 | |
475be4d8 | 613 | prbearer(char *dest, u_char *p) |
1da177e4 LT |
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 | |
475be4d8 | 661 | prbearer_ni1(char *dest, u_char *p) |
1da177e4 LT |
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++) { | |
475be4d8 JP |
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"); | |
1da177e4 LT |
682 | } |
683 | *dp++ = '\n'; | |
684 | dp += sprintf(dp, " octet 4 "); | |
685 | dp += prbits(dp, *p, 8, 8); | |
686 | switch (*p++) { | |
475be4d8 JP |
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"); | |
1da177e4 LT |
695 | } |
696 | *dp++ = '\n'; | |
697 | if (len > 2) { | |
698 | dp += sprintf(dp, " octet 5 "); | |
699 | dp += prbits(dp, *p, 8, 8); | |
700 | switch (*p++) { | |
475be4d8 JP |
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"); | |
1da177e4 LT |
711 | } |
712 | *dp++ = '\n'; | |
713 | } | |
714 | return (dp - dest); | |
715 | } | |
716 | ||
717 | static int | |
475be4d8 | 718 | general(char *dest, u_char *p) |
1da177e4 LT |
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 | |
475be4d8 | 745 | general_ni1(char *dest, u_char *p) |
1da177e4 LT |
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 | |
475be4d8 | 772 | prcharge(char *dest, u_char *p) |
1da177e4 LT |
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 | |
475be4d8 | 789 | prtext(char *dest, u_char *p) |
1da177e4 LT |
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 | |
475be4d8 | 805 | prfeatureind(char *dest, u_char *p) |
1da177e4 LT |
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'; | |
cd139781 | 813 | if (!(*p++ & 0x80)) { |
1da177e4 LT |
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) { | |
475be4d8 JP |
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; | |
1da177e4 LT |
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 | }; | |
ba2d6ccb | 868 | #define DTAGSIZE ARRAY_SIZE(dtaglist) |
1da177e4 LT |
869 | |
870 | static int | |
475be4d8 | 871 | disptext_ni1(char *dest, u_char *p) |
1da177e4 LT |
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"); | |
475be4d8 | 905 | } |
1da177e4 LT |
906 | } |
907 | return (dp - dest); | |
908 | } | |
909 | static int | |
475be4d8 | 910 | display(char *dest, u_char *p) |
1da177e4 LT |
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 | ||
672c3fd9 | 938 | static int |
475be4d8 | 939 | prfacility(char *dest, u_char *p) |
1da177e4 LT |
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 | ||
ba2d6ccb | 1077 | #define IESIZE ARRAY_SIZE(ielist) |
1da177e4 LT |
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 | ||
ba2d6ccb | 1105 | #define IESIZE_NI1 ARRAY_SIZE(ielist_ni1) |
1da177e4 LT |
1106 | |
1107 | static | |
1108 | struct InformationElement ielist_ni1_cs5[] = { | |
1109 | { 0x1d, "Operator system access", general_ni1 }, | |
1110 | { 0x2a, "Display text", disptext_ni1 }, | |
1111 | }; | |
1112 | ||
ba2d6ccb | 1113 | #define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5) |
1da177e4 LT |
1114 | |
1115 | static | |
1116 | struct InformationElement ielist_ni1_cs6[] = { | |
1117 | { 0x7b, "Call appearance", general_ni1 }, | |
1118 | }; | |
1119 | ||
ba2d6ccb | 1120 | #define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6) |
1da177e4 LT |
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 | ||
ba2d6ccb | 1136 | #define WE_0_LEN ARRAY_SIZE(we_0) |
1da177e4 LT |
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 | }; | |
ba2d6ccb | 1148 | #define WE_6_LEN ARRAY_SIZE(we_6) |
1da177e4 LT |
1149 | |
1150 | int | |
475be4d8 | 1151 | QuickHex(char *txt, u_char *p, int cnt) |
1da177e4 LT |
1152 | { |
1153 | register int i; | |
1154 | register char *t = txt; | |
1da177e4 LT |
1155 | |
1156 | for (i = 0; i < cnt; i++) { | |
1157 | *t++ = ' '; | |
735c65ce AS |
1158 | *t++ = hex_asc_hi(p[i]); |
1159 | *t++ = hex_asc_lo(p[i]); | |
1da177e4 LT |
1160 | } |
1161 | *t++ = 0; | |
1162 | return (t - txt); | |
1163 | } | |
1164 | ||
1165 | void | |
475be4d8 | 1166 | LogFrame(struct IsdnCardState *cs, u_char *buf, int size) |
1da177e4 LT |
1167 | { |
1168 | char *dp; | |
1169 | ||
1170 | if (size < 1) | |
1171 | return; | |
1172 | dp = cs->dlog; | |
1173 | if (size < MAX_DLOG_SPACE / 3 - 10) { | |
1174 | *dp++ = 'H'; | |
1175 | *dp++ = 'E'; | |
1176 | *dp++ = 'X'; | |
1177 | *dp++ = ':'; | |
1178 | dp += QuickHex(dp, buf, size); | |
1179 | dp--; | |
1180 | *dp++ = '\n'; | |
1181 | *dp = 0; | |
19cebbcb | 1182 | HiSax_putstatus(cs, NULL, cs->dlog); |
1da177e4 LT |
1183 | } else |
1184 | HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); | |
1185 | } | |
1186 | ||
1187 | void | |
1188 | dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) | |
1189 | { | |
1190 | u_char *bend, *buf; | |
1191 | char *dp; | |
1192 | unsigned char pd, cr_l, cr, mt; | |
1193 | unsigned char sapi, tei, ftyp; | |
1194 | int i, cset = 0, cs_old = 0, cs_fest = 0; | |
1195 | int size, finish = 0; | |
1196 | ||
1197 | if (skb->len < 3) | |
1198 | return; | |
1199 | /* display header */ | |
1200 | dp = cs->dlog; | |
1201 | dp += jiftime(dp, jiffies); | |
1202 | *dp++ = ' '; | |
1203 | sapi = skb->data[0] >> 2; | |
1204 | tei = skb->data[1] >> 1; | |
1205 | ftyp = skb->data[2]; | |
1206 | buf = skb->data; | |
1207 | dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network"); | |
1208 | size = skb->len; | |
475be4d8 | 1209 | |
1da177e4 LT |
1210 | if (tei == GROUP_TEI) { |
1211 | if (sapi == CTRL_SAPI) { /* sapi 0 */ | |
1212 | if (ftyp == 3) { | |
1213 | dp += sprintf(dp, "broadcast\n"); | |
1214 | buf += 3; | |
1215 | size -= 3; | |
1216 | } else { | |
1217 | dp += sprintf(dp, "no UI broadcast\n"); | |
1218 | finish = 1; | |
1219 | } | |
1220 | } else if (sapi == TEI_SAPI) { | |
1221 | dp += sprintf(dp, "tei management\n"); | |
1222 | finish = 1; | |
1223 | } else { | |
1224 | dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi); | |
1225 | finish = 1; | |
1226 | } | |
1227 | } else { | |
1228 | if (sapi == CTRL_SAPI) { | |
1229 | if (!(ftyp & 1)) { /* IFrame */ | |
1230 | dp += sprintf(dp, "with tei %d\n", tei); | |
1231 | buf += 4; | |
1232 | size -= 4; | |
1233 | } else { | |
1234 | dp += sprintf(dp, "SFrame with tei %d\n", tei); | |
1235 | finish = 1; | |
1236 | } | |
1237 | } else { | |
1238 | dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei); | |
1239 | finish = 1; | |
1240 | } | |
1241 | } | |
1242 | bend = skb->data + skb->len; | |
1243 | if (buf >= bend) { | |
1244 | dp += sprintf(dp, "frame too short\n"); | |
1245 | finish = 1; | |
1246 | } | |
1247 | if (finish) { | |
1248 | *dp = 0; | |
19cebbcb | 1249 | HiSax_putstatus(cs, NULL, cs->dlog); |
1da177e4 LT |
1250 | return; |
1251 | } | |
1252 | if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ | |
1253 | /* locate message type */ | |
1254 | pd = *buf++; | |
1255 | cr_l = *buf++; | |
1256 | if (cr_l) | |
1257 | cr = *buf++; | |
1258 | else | |
1259 | cr = 0; | |
1260 | mt = *buf++; | |
1261 | if (pd == PROTO_DIS_N0) { /* N0 */ | |
1262 | for (i = 0; i < MT_N0_LEN; i++) | |
1263 | if (mt_n0[i].nr == mt) | |
1264 | break; | |
1265 | /* display message type if it exists */ | |
1266 | if (i == MT_N0_LEN) | |
1267 | dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n", | |
1268 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | |
1269 | size, mt); | |
1270 | else | |
1271 | dp += sprintf(dp, "callref %d %s size %d message type %s\n", | |
1272 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | |
1273 | size, mt_n0[i].descr); | |
1274 | } else { /* N1 */ | |
1275 | for (i = 0; i < MT_N1_LEN; i++) | |
1276 | if (mt_n1[i].nr == mt) | |
1277 | break; | |
1278 | /* display message type if it exists */ | |
1279 | if (i == MT_N1_LEN) | |
1280 | dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n", | |
1281 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | |
1282 | size, mt); | |
1283 | else | |
1284 | dp += sprintf(dp, "callref %d %s size %d message type %s\n", | |
1285 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", | |
1286 | size, mt_n1[i].descr); | |
1287 | } | |
1288 | ||
1289 | /* display each information element */ | |
1290 | while (buf < bend) { | |
1291 | /* Is it a single octet information element? */ | |
1292 | if (*buf & 0x80) { | |
1293 | switch ((*buf >> 4) & 7) { | |
475be4d8 JP |
1294 | case 1: |
1295 | dp += sprintf(dp, " Shift %x\n", *buf & 0xf); | |
1296 | cs_old = cset; | |
1297 | cset = *buf & 7; | |
1298 | cs_fest = *buf & 8; | |
1299 | break; | |
1300 | case 3: | |
1301 | dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); | |
1302 | break; | |
1303 | case 2: | |
1304 | if (*buf == 0xa0) { | |
1305 | dp += sprintf(dp, " More data\n"); | |
1da177e4 | 1306 | break; |
475be4d8 JP |
1307 | } |
1308 | if (*buf == 0xa1) { | |
1309 | dp += sprintf(dp, " Sending complete\n"); | |
1310 | } | |
1311 | break; | |
1312 | /* fall through */ | |
1313 | default: | |
1314 | dp += sprintf(dp, " Reserved %x\n", *buf); | |
1315 | break; | |
1da177e4 LT |
1316 | } |
1317 | buf++; | |
1318 | continue; | |
1319 | } | |
1320 | /* No, locate it in the table */ | |
1321 | if (cset == 0) { | |
1322 | for (i = 0; i < WE_0_LEN; i++) | |
1323 | if (*buf == we_0[i].nr) | |
1324 | break; | |
1325 | ||
1326 | /* When found, give appropriate msg */ | |
1327 | if (i != WE_0_LEN) { | |
1328 | dp += sprintf(dp, " %s\n", we_0[i].descr); | |
1329 | dp += we_0[i].f(dp, buf); | |
1330 | } else | |
1331 | dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); | |
1332 | } else if (cset == 6) { | |
1333 | for (i = 0; i < WE_6_LEN; i++) | |
1334 | if (*buf == we_6[i].nr) | |
1335 | break; | |
1336 | ||
1337 | /* When found, give appropriate msg */ | |
1338 | if (i != WE_6_LEN) { | |
1339 | dp += sprintf(dp, " %s\n", we_6[i].descr); | |
1340 | dp += we_6[i].f(dp, buf); | |
1341 | } else | |
1342 | dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); | |
1343 | } else | |
1344 | dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); | |
1345 | /* Skip to next element */ | |
1346 | if (cs_fest == 8) { | |
1347 | cset = cs_old; | |
1348 | cs_old = 0; | |
1349 | cs_fest = 0; | |
1350 | } | |
1351 | buf += buf[1] + 2; | |
1352 | } | |
1353 | } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ | |
1354 | /* locate message type */ | |
1355 | buf++; | |
1356 | cr_l = *buf++; | |
1357 | if (cr_l) | |
1358 | cr = *buf++; | |
1359 | else | |
1360 | cr = 0; | |
1361 | mt = *buf++; | |
1362 | for (i = 0; i < MTSIZE; i++) | |
1363 | if (mtlist[i].nr == mt) | |
1364 | break; | |
1365 | ||
1366 | /* display message type if it exists */ | |
1367 | if (i == MTSIZE) | |
1368 | dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", | |
475be4d8 | 1369 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", |
1da177e4 LT |
1370 | size, mt); |
1371 | else | |
1372 | dp += sprintf(dp, "callref %d %s size %d message type %s\n", | |
475be4d8 | 1373 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", |
1da177e4 LT |
1374 | size, mtlist[i].descr); |
1375 | ||
1376 | /* display each information element */ | |
1377 | while (buf < bend) { | |
1378 | /* Is it a single octet information element? */ | |
1379 | if (*buf & 0x80) { | |
1380 | switch ((*buf >> 4) & 7) { | |
475be4d8 JP |
1381 | case 1: |
1382 | dp += sprintf(dp, " Shift %x\n", *buf & 0xf); | |
1383 | cs_old = cset; | |
1384 | cset = *buf & 7; | |
1385 | cs_fest = *buf & 8; | |
1386 | break; | |
1387 | default: | |
1388 | dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); | |
1389 | break; | |
1da177e4 LT |
1390 | } |
1391 | buf++; | |
1392 | continue; | |
1393 | } | |
1394 | /* No, locate it in the table */ | |
1395 | if (cset == 0) { | |
9f13fae2 | 1396 | for (i = 0; i < IESIZE_NI1; i++) |
1da177e4 LT |
1397 | if (*buf == ielist_ni1[i].nr) |
1398 | break; | |
1399 | ||
1400 | /* When not found, give appropriate msg */ | |
9f13fae2 | 1401 | if (i != IESIZE_NI1) { |
1da177e4 LT |
1402 | dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); |
1403 | dp += ielist_ni1[i].f(dp, buf); | |
1404 | } else | |
1405 | dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); | |
1406 | } else if (cset == 5) { | |
1407 | for (i = 0; i < IESIZE_NI1_CS5; i++) | |
1408 | if (*buf == ielist_ni1_cs5[i].nr) | |
1409 | break; | |
1410 | ||
1411 | /* When not found, give appropriate msg */ | |
1412 | if (i != IESIZE_NI1_CS5) { | |
1413 | dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); | |
1414 | dp += ielist_ni1_cs5[i].f(dp, buf); | |
1415 | } else | |
1416 | dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); | |
1417 | } else if (cset == 6) { | |
1418 | for (i = 0; i < IESIZE_NI1_CS6; i++) | |
1419 | if (*buf == ielist_ni1_cs6[i].nr) | |
1420 | break; | |
1421 | ||
1422 | /* When not found, give appropriate msg */ | |
1423 | if (i != IESIZE_NI1_CS6) { | |
1424 | dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); | |
1425 | dp += ielist_ni1_cs6[i].f(dp, buf); | |
1426 | } else | |
1427 | dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); | |
1428 | } else | |
1429 | dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); | |
1430 | ||
1431 | /* Skip to next element */ | |
1432 | if (cs_fest == 8) { | |
1433 | cset = cs_old; | |
1434 | cs_old = 0; | |
1435 | cs_fest = 0; | |
1436 | } | |
1437 | buf += buf[1] + 2; | |
1438 | } | |
1439 | } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ | |
1440 | /* locate message type */ | |
1441 | buf++; | |
1442 | cr_l = *buf++; | |
1443 | if (cr_l) | |
1444 | cr = *buf++; | |
1445 | else | |
1446 | cr = 0; | |
1447 | mt = *buf++; | |
1448 | for (i = 0; i < MTSIZE; i++) | |
1449 | if (mtlist[i].nr == mt) | |
1450 | break; | |
1451 | ||
1452 | /* display message type if it exists */ | |
1453 | if (i == MTSIZE) | |
1454 | dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", | |
475be4d8 | 1455 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", |
1da177e4 LT |
1456 | size, mt); |
1457 | else | |
1458 | dp += sprintf(dp, "callref %d %s size %d message type %s\n", | |
475be4d8 | 1459 | cr & 0x7f, (cr & 0x80) ? "called" : "caller", |
1da177e4 LT |
1460 | size, mtlist[i].descr); |
1461 | ||
1462 | /* display each information element */ | |
1463 | while (buf < bend) { | |
1464 | /* Is it a single octet information element? */ | |
1465 | if (*buf & 0x80) { | |
1466 | switch ((*buf >> 4) & 7) { | |
475be4d8 JP |
1467 | case 1: |
1468 | dp += sprintf(dp, " Shift %x\n", *buf & 0xf); | |
1469 | break; | |
1470 | case 3: | |
1471 | dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); | |
1472 | break; | |
1473 | case 5: | |
1474 | dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); | |
1475 | break; | |
1476 | case 2: | |
1477 | if (*buf == 0xa0) { | |
1478 | dp += sprintf(dp, " More data\n"); | |
1da177e4 | 1479 | break; |
475be4d8 JP |
1480 | } |
1481 | if (*buf == 0xa1) { | |
1482 | dp += sprintf(dp, " Sending complete\n"); | |
1483 | } | |
1484 | break; | |
1485 | /* fall through */ | |
1486 | default: | |
1487 | dp += sprintf(dp, " Reserved %x\n", *buf); | |
1488 | break; | |
1da177e4 LT |
1489 | } |
1490 | buf++; | |
1491 | continue; | |
1492 | } | |
1493 | /* No, locate it in the table */ | |
1494 | for (i = 0; i < IESIZE; i++) | |
1495 | if (*buf == ielist[i].nr) | |
1496 | break; | |
1497 | ||
1498 | /* When not found, give appropriate msg */ | |
1499 | if (i != IESIZE) { | |
1500 | dp += sprintf(dp, " %s\n", ielist[i].descr); | |
1501 | dp += ielist[i].f(dp, buf); | |
1502 | } else | |
1503 | dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); | |
1504 | ||
1505 | /* Skip to next element */ | |
1506 | buf += buf[1] + 2; | |
1507 | } | |
1508 | } else { | |
1509 | dp += sprintf(dp, "Unknown protocol %x!", buf[0]); | |
1510 | } | |
1511 | *dp = 0; | |
19cebbcb | 1512 | HiSax_putstatus(cs, NULL, cs->dlog); |
1da177e4 | 1513 | } |