| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 519 | static int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 938 | static int | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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) { | 
| Eric Sesterhenn | 9f13fae | 2006-06-26 00:25:32 -0700 | [diff] [blame] | 1405 | 				for (i = 0; i < IESIZE_NI1; i++) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1406 | 					if (*buf == ielist_ni1[i].nr) | 
 | 1407 | 						break; | 
 | 1408 |  | 
 | 1409 | 				/* When not found, give appropriate msg */ | 
| Eric Sesterhenn | 9f13fae | 2006-06-26 00:25:32 -0700 | [diff] [blame] | 1410 | 				if (i != IESIZE_NI1) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | } |