2 * Routines for ISO/OSI network and transport protocol packet disassembly
4 * $Id: packet-clnp.c,v 1.2 2000/04/16 09:10:53 deniel Exp $
5 * Laurent Deniel <deniel@worldnet.fr>
6 * Ralf Schneider <Ralf.Schneider@t-online.de>
8 * Ethereal - Network traffic analyzer
9 * By Gerald Combs <gerald@zing.org>
10 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
42 #include "packet-osi.h"
43 #include "packet-osi-options.h"
44 #include "packet-clnp.h"
45 #include "packet-isis.h"
46 #include "packet-esis.h"
47 #include "packet-h1.h"
50 /* protocols and fields */
52 static int proto_clnp = -1;
53 static int proto_cotp = -1;
54 static gint ett_clnp = -1;
55 static gint ett_cotp = -1;
57 static int hf_clnp_id = -1;
58 static int hf_clnp_length = -1;
59 static int hf_clnp_version = -1;
60 static int hf_clnp_ttl = -1;
61 static int hf_clnp_type = -1;
62 static int hf_clnp_pdu_length = -1;
63 static int hf_clnp_checksum = -1;
64 static int hf_clnp_dest_length = -1;
65 static int hf_clnp_dest = -1;
66 static int hf_clnp_src_length = -1;
67 static int hf_clnp_src = -1;
72 * ISO 8473 OSI CLNP definition (see RFC994)
74 * _________________________________
76 * |_________________________________|
78 * |_________________________________|
79 * | Segmentation Part (optional) |
80 * |_________________________________|
81 * | Options Part (optional) |
82 * |_________________________________|
84 * |_________________________________|
87 #define ISO8473_V1 0x01 /* CLNP version 1 */
92 u_char cnf_proto_id; /* network layer protocol identifier */
93 u_char cnf_hdr_len; /* length indicator (octets) */
94 u_char cnf_vers; /* version/protocol identifier extension */
95 u_char cnf_ttl; /* lifetime (500 milliseconds) */
96 u_char cnf_type; /* type code */
97 u_char cnf_seglen_msb; /* pdu segment length (octets) high byte */
98 u_char cnf_seglen_lsb; /* pdu segment length (octets) low byte */
99 u_char cnf_cksum_msb; /* checksum high byte */
100 u_char cnf_cksum_lsb; /* checksum low byte */
103 #define CNF_TYPE 0x1f
104 #define CNF_ERR_OK 0x20
105 #define CNF_MORE_SEGS 0x40
106 #define CNF_SEG_OK 0x80
111 #define ERQ_NPDU 0x1E
112 #define ERP_NPDU 0x1F
114 static const value_string npdu_type_vals[] = {
125 #define P_ADDRESS_PART 9
127 /* Segmentation part */
129 struct clnp_segment {
130 u_short cng_id; /* data unit identifier */
131 u_short cng_off; /* segment offset */
132 u_short cng_tot_len; /* total length */
137 #define NSEL_NET 0x00
142 * ISO8073 OSI COTP definition (see RFC905)
145 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
147 /* TPDU definition */
167 #define P_TPDU_NR_0_1 2
168 #define P_TPDU_NR_234 4
169 #define P_VAR_PART_NDT 5
170 #define P_VAR_PART_EDT 8
171 #define P_VAR_PART_NAK 5
172 #define P_VAR_PART_CC 7
173 #define P_VAR_PART_EAK 10
174 #define P_VAR_PART_DC 6
175 #define P_VAR_PART_DR 7
176 #define P_CDT_IN_AK 8
177 #define P_CDT_IN_RJ 8
178 #define P_REJECT_ER 4
179 #define P_REASON_IN_DR 6
180 #define P_CLASS_OPTION 6
182 /* TPDU length indicator */
184 #define LI_NORMAL_DT_CLASS_01 2
185 #define LI_NORMAL_DT_WITH_CHECKSUM 8
186 #define LI_NORMAL_DT_WITHOUT_CHECKSUM 4
187 #define LI_EXTENDED_DT_WITH_CHECKSUM 11
188 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM 7
189 #define LI_NORMAL_EA_WITH_CHECKSUM 8
190 #define LI_NORMAL_EA_WITHOUT_CHECKSUM 4
191 #define LI_EXTENDED_EA_WITH_CHECKSUM 11
192 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM 7
193 #define LI_NORMAL_RJ 4
194 #define LI_EXTENDED_RJ 9
200 #define LI_DC_WITH_CHECKSUM 9
201 #define LI_DC_WITHOUT_CHECKSUM 5
202 #define is_LI_NORMAL_AK(p) ( p & 0x01 )
206 #define VP_ACK_TIME 0x85
207 #define VP_RES_ERROR 0x86
208 #define VP_PRIORITY 0x87
209 #define VP_TRANSIT_DEL 0x88
210 #define VP_THROUGHPUT 0x89
211 #define VP_SEQ_NR 0x8A /* in AK */
212 #define VP_REASSIGNMENT 0x8B
213 #define VP_FLOW_CNTL 0x8C /* in AK */
214 #define VP_TPDU_SIZE 0xC0
215 #define VP_SRC_TSAP 0xC1 /* in CR/CC */
216 #define VP_DST_TSAP 0xC2
217 #define VP_CHECKSUM 0xC3
218 #define VP_VERSION_NR 0xC4
219 #define VP_PROTECTION 0xC5
220 #define VP_OPT_SEL 0xC6
221 #define VP_PROTO_CLASS 0xC7
225 #define EXTRACT_SHORT(p) pntohs(p)
226 #define EXTRACT_LONG(p) pntohl(p)
228 /* global variables */
230 static u_char li, tpdu, cdt; /* common fields */
231 static u_short dst_ref;
233 /* function definitions */
235 static int osi_decode_DR(const u_char *pd, int offset,
236 frame_data *fd, proto_tree *tree)
238 proto_tree *cotp_tree;
247 src_ref = EXTRACT_SHORT(&pd[offset + P_SRC_REF]);
248 reason = pd[offset + P_REASON_IN_DR];
251 case (128+0): str = "Normal Disconnect"; break;
252 case (128+1): str = "Remote transport entity congestion"; break;
253 case (128+2): str = "Connection negotiation failed"; break;
254 case (128+3): str = "Duplicate source reference"; break;
255 case (128+4): str = "Mismatched references"; break;
256 case (128+5): str = "Protocol error"; break;
257 case (128+7): str = "Reference overflow"; break;
258 case (128+8): str = "Connection requestion refused"; break;
259 case (128+10):str = "Header or parameter length invalid"; break;
260 case (0): str = "Reason not specified"; break;
261 case (1): str = "Congestion at TSAP"; break;
262 case (2): str = "Session entity not attached to TSAP"; break;
263 case (3): str = "Address unknown"; break;
269 if (check_col(fd, COL_INFO))
270 col_append_fstr(fd, COL_INFO, "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
274 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
275 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
276 proto_tree_add_text(cotp_tree, offset, 1,
277 "Length indicator: %u", li);
278 proto_tree_add_text(cotp_tree, offset + 1, 1,
279 "TPDU code: 0x%x (DR)", tpdu);
280 proto_tree_add_text(cotp_tree, offset + 2, 2,
281 "Destination reference: 0x%04x", dst_ref);
282 proto_tree_add_text(cotp_tree, offset + 4, 2,
283 "Source reference: 0x%04x", src_ref);
284 proto_tree_add_text(cotp_tree, offset + 6, 1,
289 dissect_data(pd, offset, fd, tree);
291 return pi.captured_len; /* we dissected all of the containing PDU */
293 } /* osi_decode_DR */
295 /* Returns TRUE if we called a sub-dissector, FALSE if not. */
296 static gboolean osi_decode_DT(const u_char *pd, int offset,
297 frame_data *fd, proto_tree *tree,
298 gboolean uses_inactive_subset)
300 proto_tree *cotp_tree;
303 u_short checksum = 0;
304 u_char code = 0, length = 0;
308 case LI_NORMAL_DT_WITH_CHECKSUM :
309 tpdu_nr = pd[offset + P_TPDU_NR_234];
310 if ( tpdu_nr & 0x80 )
311 tpdu_nr = tpdu_nr & 0x7F;
314 code = pd[offset + P_VAR_PART_NDT];
315 if (code == VP_CHECKSUM)
316 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NDT + 2]);
320 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
321 tpdu_nr = pd[offset + P_TPDU_NR_234];
322 if ( tpdu_nr & 0x80 )
323 tpdu_nr = tpdu_nr & 0x7F;
327 case LI_EXTENDED_DT_WITH_CHECKSUM :
328 tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
329 if ( tpdu_nr & 0x80000000 )
330 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
333 code = pd[offset + P_VAR_PART_EDT];
334 if (code == VP_CHECKSUM)
335 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EDT + 2]);
339 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
340 tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
341 if ( tpdu_nr & 0x80000000 )
342 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
346 case LI_NORMAL_DT_CLASS_01 :
347 tpdu_nr = pd[offset + P_TPDU_NR_0_1];
348 if ( tpdu_nr & 0x80 )
349 tpdu_nr = tpdu_nr & 0x7F;
353 default : /* bad TPDU */
359 if (check_col(fd, COL_INFO))
360 col_append_fstr(fd, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s",
363 (fragment)? "(fragment)" : "");
366 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
367 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
368 proto_tree_add_text(cotp_tree, offset, 1,
369 "Length indicator: %u", li);
370 proto_tree_add_text(cotp_tree, offset + 1, 1,
371 "TPDU code: 0x%x (DT)", tpdu);
373 if (li != LI_NORMAL_DT_CLASS_01)
374 proto_tree_add_text(cotp_tree, offset + 2, 2,
375 "Destination reference: 0x%04x", dst_ref);
378 case LI_NORMAL_DT_WITH_CHECKSUM :
379 proto_tree_add_text(cotp_tree, offset + 4, 1,
380 "TPDU number: 0x%02x (%s)",
382 (fragment)? "fragment":"complete");
383 proto_tree_add_text(cotp_tree,
384 offset + P_VAR_PART_NDT, 1,
385 "Parameter code: 0x%02x (checksum)", code);
386 proto_tree_add_text(cotp_tree,
387 offset + P_VAR_PART_NDT + 1, 1,
388 "Parameter length: %u", length);
389 proto_tree_add_text(cotp_tree,
390 offset + P_VAR_PART_NDT + 2, length,
391 "Checksum: 0x%04x", checksum);
393 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
394 proto_tree_add_text(cotp_tree, offset + 4, 1,
395 "TPDU number: 0x%02x (%s)",
397 (fragment)? "fragment":"complete");
399 case LI_EXTENDED_DT_WITH_CHECKSUM :
400 proto_tree_add_text(cotp_tree, offset + 4, 4,
401 "TPDU number: 0x%08x (%s)",
403 (fragment)? "fragment":"complete");
404 proto_tree_add_text(cotp_tree,
405 offset + P_VAR_PART_EDT, 1,
406 "Parameter code: 0x%02x (checksum)", code);
407 proto_tree_add_text(cotp_tree,
408 offset + P_VAR_PART_EDT + 1, 1,
409 "Parameter length: %u", length);
410 proto_tree_add_text(cotp_tree,
411 offset + P_VAR_PART_EDT + 2, length,
412 "Checksum: 0x%04x", checksum);
414 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
415 proto_tree_add_text(cotp_tree, offset + 4, 4,
416 "TPDU number: 0x%08x (%s)",
418 (fragment)? "fragment":"complete");
420 case LI_NORMAL_DT_CLASS_01 :
421 proto_tree_add_text(cotp_tree, offset + 2, 1,
422 "TPDU number: 0x%02x (%s)",
424 (fragment)? "fragment":"complete");
430 if (uses_inactive_subset){
431 dissect_h1(pd, offset, fd, tree);
435 dissect_data(pd, offset, fd, tree);
438 } /* osi_decode_DT */
440 static int osi_decode_ED(const u_char *pd, int offset,
441 frame_data *fd, proto_tree *tree)
443 proto_tree *cotp_tree;
446 u_short checksum = 0;
447 u_char code = 0, length = 0;
449 /* ED TPDUs are never fragmented */
452 case LI_NORMAL_DT_WITH_CHECKSUM :
453 tpdu_nr = pd[offset + P_TPDU_NR_234];
454 if ( tpdu_nr & 0x80 )
455 tpdu_nr = tpdu_nr & 0x7F;
458 code = pd[offset + P_VAR_PART_NDT];
459 length = pd[offset + P_VAR_PART_NDT + 1];
460 if (code == VP_CHECKSUM)
461 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NDT + 2]);
465 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
466 tpdu_nr = pd[offset + P_TPDU_NR_234];
467 if ( tpdu_nr & 0x80 )
468 tpdu_nr = tpdu_nr & 0x7F;
472 case LI_EXTENDED_DT_WITH_CHECKSUM :
473 tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
474 if ( tpdu_nr & 0x80000000 )
475 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
478 code = pd[offset + P_VAR_PART_EDT];
479 length = pd[offset + P_VAR_PART_EDT + 1];
480 if (code == VP_CHECKSUM)
481 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EDT + 2]);
485 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
486 tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
487 if ( tpdu_nr & 0x80000000 )
488 tpdu_nr = tpdu_nr & 0x7FFFFFFF;
492 default : /* bad TPDU */
498 if (check_col(fd, COL_INFO))
499 col_append_fstr(fd, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x",
503 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
504 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
505 proto_tree_add_text(cotp_tree, offset, 1,
506 "Length indicator: %u", li);
507 proto_tree_add_text(cotp_tree, offset + 1, 1,
508 "TPDU code: 0x%x (ED)", tpdu);
509 proto_tree_add_text(cotp_tree, offset + 2, 2,
510 "Destination reference: 0x%04x", dst_ref);
513 case LI_NORMAL_DT_WITH_CHECKSUM :
514 proto_tree_add_text(cotp_tree, offset + 4, 1,
515 "TPDU number: 0x%02x", tpdu_nr);
516 proto_tree_add_text(cotp_tree,
517 offset + P_VAR_PART_NDT, 1,
518 "Parameter code: 0x%02x (checksum)", code);
519 proto_tree_add_text(cotp_tree,
520 offset + P_VAR_PART_NDT + 1, 1,
521 "Parameter length: %u", length);
522 proto_tree_add_text(cotp_tree,
523 offset + P_VAR_PART_NDT + 2, length,
524 "Checksum: 0x%04x", checksum);
526 case LI_NORMAL_DT_WITHOUT_CHECKSUM :
527 proto_tree_add_text(cotp_tree, offset + 4, 1,
528 "TPDU number: 0x%02x", tpdu_nr);
530 case LI_EXTENDED_DT_WITH_CHECKSUM :
531 proto_tree_add_text(cotp_tree, offset + 4, 4,
532 "TPDU number: 0x%02x", tpdu_nr);
533 proto_tree_add_text(cotp_tree,
534 offset + P_VAR_PART_EDT, 1,
535 "Parameter code: 0x%02x (checksum)", code);
536 proto_tree_add_text(cotp_tree,
537 offset + P_VAR_PART_EDT + 1, 1,
538 "Parameter length: %u", length);
539 proto_tree_add_text(cotp_tree,
540 offset + P_VAR_PART_EDT + 2, length,
541 "Checksum: 0x%04x", checksum);
543 case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
544 proto_tree_add_text(cotp_tree, offset + 4, 4,
545 "TPDU number: 0x%02x", tpdu_nr);
551 dissect_data(pd, offset, fd, tree);
553 return pi.captured_len; /* we dissected all of the containing PDU */
555 } /* osi_decode_ED */
557 static int osi_decode_RJ(const u_char *pd, int offset,
558 frame_data *fd, proto_tree *tree)
560 proto_tree *cotp_tree;
567 tpdu_nr = pd[offset + P_TPDU_NR_234];
569 case LI_EXTENDED_RJ :
570 tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
571 credit = EXTRACT_SHORT(&pd[offset + P_CDT_IN_RJ]);
579 if (check_col(fd, COL_INFO))
580 col_append_fstr(fd, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x",
584 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
585 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
586 proto_tree_add_text(cotp_tree, offset, 1,
587 "Length indicator: %u", li);
588 proto_tree_add_text(cotp_tree, offset + 1, 1,
589 "TPDU code: 0x%x (RJ)", tpdu);
590 if (li == LI_NORMAL_RJ)
591 proto_tree_add_text(cotp_tree, offset + 1, 1,
593 proto_tree_add_text(cotp_tree, offset + 2, 2,
594 "Destination reference: 0x%04x", dst_ref);
595 if (li == LI_NORMAL_RJ)
596 proto_tree_add_text(cotp_tree, offset + 4, 1,
597 "Your TPDU number: 0x%02x", tpdu_nr);
599 proto_tree_add_text(cotp_tree, offset + 4, 4,
600 "Your TPDU number: 0x%02x", tpdu_nr);
601 proto_tree_add_text(cotp_tree, offset + 8, 2,
602 "Credit: 0x%02x", credit);
610 } /* osi_decode_RJ */
612 #define MAX_TSAP_LEN 32
614 static gchar *print_tsap(const u_char *tsap, int length)
617 static gchar str[3][MAX_TSAP_LEN * 2 + 1];
620 gboolean allprintable;
623 if (cur == &str[0][0]) {
625 } else if (cur == &str[1][0]) {
633 if (length <= 0 || length > MAX_TSAP_LEN)
634 sprintf(cur, "<unsupported TSAP length>");
637 for (i=0;i<length;i++) {
638 if (!isprint(tsap[i])) { /* if any byte is not printable */
639 allprintable=FALSE; /* switch to hexdump */
646 while (length != 0) {
648 sprintf(tmp, "%c", *tsap ++);
650 sprintf(tmp, "%02x", *tsap ++);
659 static int osi_decode_CC(const u_char *pd, int offset,
660 frame_data *fd, proto_tree *tree)
663 /* CC & CR decoding in the same function */
665 proto_tree *cotp_tree = NULL;
667 u_short src_ref, checksum;
668 u_char class_option, code, length;
671 src_ref = EXTRACT_SHORT(&pd[offset + P_SRC_REF]);
672 class_option = (pd[offset + P_CLASS_OPTION] >> 4 ) & 0x0F;
673 if (class_option > 4)
676 if (check_col(fd, COL_INFO))
677 col_append_fstr(fd, COL_INFO, "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
678 (tpdu == CR_TPDU) ? "CR" : "CC",
683 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
684 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
685 proto_tree_add_text(cotp_tree, offset, 1,
686 "Length indicator: %u", li);
687 proto_tree_add_text(cotp_tree, offset + 1, 1,
688 "TPDU code: 0x%x (%s)", tpdu,
689 (tpdu == CR_TPDU) ? "CR" : "CC");
690 proto_tree_add_text(cotp_tree, offset + 2, 2,
691 "Destination reference: 0x%04x", dst_ref);
692 proto_tree_add_text(cotp_tree, offset + 4, 2,
693 "Source reference: 0x%04x", src_ref);
694 proto_tree_add_text(cotp_tree, offset + 6, 1,
695 "Class option: 0x%02x", class_option);
699 while(li > P_VAR_PART_CC + i - 1) {
702 u_short s, s1,s2,s3,s4;
705 switch( (code = pd[offset + P_VAR_PART_CC + i]) ) {
707 length = pd[offset + P_VAR_PART_CC + i + 1];
708 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 2]);
709 proto_tree_add_text(cotp_tree,
710 offset + P_VAR_PART_CC + i, 1,
711 "Parameter code: 0x%02x (checksum)", code);
712 proto_tree_add_text(cotp_tree,
713 offset + P_VAR_PART_CC + i + 1, 1,
714 "Parameter length: %u", length);
715 proto_tree_add_text(cotp_tree,
716 offset + P_VAR_PART_CC + i + 2, length,
717 "Checksum: 0x%04x", checksum);
721 length = pd[offset + P_VAR_PART_CC + i + 1];
722 proto_tree_add_text(cotp_tree,
723 offset + P_VAR_PART_CC + i, 1,
724 "Parameter code: 0x%02x (src-tsap)", code);
725 proto_tree_add_text(cotp_tree,
726 offset + P_VAR_PART_CC + i + 1, 1,
727 "Parameter length: %u", length);
728 proto_tree_add_text(cotp_tree,
729 offset + P_VAR_PART_CC + i + 2, length,
731 print_tsap(&pd[offset + P_VAR_PART_CC + i + 2],
736 length = pd[offset + P_VAR_PART_CC + i + 1];
737 proto_tree_add_text(cotp_tree,
738 offset + P_VAR_PART_CC + i, 1,
739 "Parameter code: 0x%02x (dst-tsap)", code);
740 proto_tree_add_text(cotp_tree,
741 offset + P_VAR_PART_CC + i + 1, 1,
742 "Parameter length: %u", length);
743 proto_tree_add_text(cotp_tree,
744 offset + P_VAR_PART_CC + i + 2, length,
746 print_tsap(&pd[offset + P_VAR_PART_CC + i + 2],
751 length = pd[offset + P_VAR_PART_CC + i + 1];
752 c1 = pd[offset + P_VAR_PART_CC + i + 2] & 0x0F;
753 proto_tree_add_text(cotp_tree,
754 offset + P_VAR_PART_CC + i, 1,
755 "Parameter code: 0x%02x (tpdu-size)", code);
756 proto_tree_add_text(cotp_tree,
757 offset + P_VAR_PART_CC + i + 1, 1,
758 "Parameter length: %u", length);
759 proto_tree_add_text(cotp_tree,
760 offset + P_VAR_PART_CC + i + 2, length,
761 "TPDU size: %u", 2 << c1);
765 length = pd[offset + P_VAR_PART_CC + i + 1];
766 c1 = pd[offset + P_VAR_PART_CC + i + 2] & 0x0F;
767 proto_tree_add_text(cotp_tree,
768 offset + P_VAR_PART_CC + i, 1,
769 "Parameter code: 0x%02x (options)", code);
770 proto_tree_add_text(cotp_tree,
771 offset + P_VAR_PART_CC + i + 1, 1,
772 "Parameter length: %u", length);
773 if (class_option == 1) {
775 proto_tree_add_text(cotp_tree,
776 offset + P_VAR_PART_CC + i + 2, 1,
777 "Use of network expedited data");
779 proto_tree_add_text(cotp_tree,
780 offset + P_VAR_PART_CC + i + 2, 1,
781 "Non use of network expedited data");
783 proto_tree_add_text(cotp_tree,
784 offset + P_VAR_PART_CC + i + 2, 1,
785 "Use of Receipt confirmation");
787 proto_tree_add_text(cotp_tree,
788 offset + P_VAR_PART_CC + i + 2, 1,
789 "Use of explicit AK variant");
790 } else if (class_option == 4) {
792 proto_tree_add_text(cotp_tree,
793 offset + P_VAR_PART_CC + i + 2, 1,
794 "Use 16 bit checksum ");
796 proto_tree_add_text(cotp_tree,
797 offset + P_VAR_PART_CC + i + 2, 1,
798 "Non-use 16 bit checksum in class 4");
801 proto_tree_add_text(cotp_tree,
802 offset + P_VAR_PART_CC + i + 2, 1,
803 "Use of transport expedited data transfer\n");
805 proto_tree_add_text(cotp_tree,
806 offset + P_VAR_PART_CC + i + 2, 1,
807 "Non-use of transport expedited data transfer");
811 length = pd[offset + P_VAR_PART_CC + i + 1];
812 s = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 2]);
813 proto_tree_add_text(cotp_tree,
814 offset + P_VAR_PART_CC + i, 1,
815 "Parameter code: 0x%02x (ack time)", code);
816 proto_tree_add_text(cotp_tree,
817 offset + P_VAR_PART_CC + i + 1, 1,
818 "Parameter length: %u", length);
819 proto_tree_add_text(cotp_tree,
820 offset + P_VAR_PART_CC + i + 2, length,
821 "Ack time (ms): %u", s);
825 length = pd[offset + P_VAR_PART_CC + i + 1];
826 t1 = EXTRACT_LONG(&pd[offset + P_VAR_PART_CC + i + 1]);
827 t2 = EXTRACT_LONG(&pd[offset + P_VAR_PART_CC + i + 4]);
828 t3 = EXTRACT_LONG(&pd[offset + P_VAR_PART_CC + i + 7]);
829 t4 = EXTRACT_LONG(&pd[offset + P_VAR_PART_CC + i + 10]);
830 proto_tree_add_text(cotp_tree,
831 offset + P_VAR_PART_CC + i, 1,
832 "Parameter code: 0x%02x (throughput)", code);
833 proto_tree_add_text(cotp_tree,
834 offset + P_VAR_PART_CC + i + 1, 1,
835 "Parameter length: %u", length);
836 proto_tree_add_text(cotp_tree,
837 offset + P_VAR_PART_CC + i + 2, 4,
838 "Target value / calling-called: %u o/s", t1);
839 proto_tree_add_text(cotp_tree,
840 offset + P_VAR_PART_CC + i + 6, 4,
841 "Minimum / calling-called: %u o/s", t2);
842 proto_tree_add_text(cotp_tree,
843 offset + P_VAR_PART_CC + i + 10, 4,
844 "Target value / called-calling: %u o/s", t3);
845 proto_tree_add_text(cotp_tree,
846 offset + P_VAR_PART_CC + i + 14, 4,
847 "Minimum / called-calling: %u o/s", t4);
850 case VP_TRANSIT_DEL :
851 length = pd[offset + P_VAR_PART_CC + i + 1];
852 s1 = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 2]);
853 s2 = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 4]);
854 s3 = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 6]);
855 s4 = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 8]);
856 proto_tree_add_text(cotp_tree,
857 offset + P_VAR_PART_CC + i, 1,
858 "Parameter code: 0x%02x (transit delay)", code);
859 proto_tree_add_text(cotp_tree,
860 offset + P_VAR_PART_CC + i + 1, 1,
861 "Parameter length: %u", length);
862 proto_tree_add_text(cotp_tree,
863 offset + P_VAR_PART_CC + i + 2, 2,
864 "Target value / calling-called: %u ms", s1);
865 proto_tree_add_text(cotp_tree,
866 offset + P_VAR_PART_CC + i + 4, 2,
867 "Minimum / calling-called: %u ms", s2);
868 proto_tree_add_text(cotp_tree,
869 offset + P_VAR_PART_CC + i + 6, 2,
870 "Target value / called-calling: %u ms", s3);
871 proto_tree_add_text(cotp_tree,
872 offset + P_VAR_PART_CC + i + 8, 2,
873 "Minimum / called-calling: %u ms", s4);
877 length = pd[offset + P_VAR_PART_CC + i + 1];
878 s = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 2]);
879 proto_tree_add_text(cotp_tree,
880 offset + P_VAR_PART_CC + i, 1,
881 "Parameter code: 0x%02x (priority)", code);
882 proto_tree_add_text(cotp_tree,
883 offset + P_VAR_PART_CC + i + 1, 1,
884 "Parameter length: %u", length);
885 proto_tree_add_text(cotp_tree,
886 offset + P_VAR_PART_CC + i + 2, length,
892 length = pd[offset + P_VAR_PART_CC + i + 1];
893 c1 = pd[offset + P_VAR_PART_CC + i + 2];
894 proto_tree_add_text(cotp_tree,
895 offset + P_VAR_PART_CC + i, 1,
896 "Parameter code: 0x%02x (version)", code);
897 proto_tree_add_text(cotp_tree,
898 offset + P_VAR_PART_CC + i + 1, 1,
899 "Parameter length: %u", length);
900 proto_tree_add_text(cotp_tree,
901 offset + P_VAR_PART_CC + i + 2, length,
906 case VP_REASSIGNMENT: /* todo */
909 case VP_PROTO_CLASS :
910 default : /* no decoding */
911 length = pd[offset + P_VAR_PART_CC + i + 1];
912 proto_tree_add_text(cotp_tree,
913 offset + P_VAR_PART_CC + i + 0, 1,
914 "Parameter code: 0x%02x", code);
915 proto_tree_add_text(cotp_tree,
916 offset + P_VAR_PART_CC + i + 1, 1,
917 "Parameter length: %u", length);
918 proto_tree_add_text(cotp_tree,
919 offset + P_VAR_PART_CC + i + 2, length,
920 "Parameter value: <not shown>");
927 dissect_data(pd, offset, fd, tree);
929 return pi.captured_len; /* we dissected all of the containing PDU */
931 } /* osi_decode_CC */
933 static int osi_decode_DC(const u_char *pd, int offset,
934 frame_data *fd, proto_tree *tree)
936 proto_tree *cotp_tree;
938 u_short src_ref, checksum = 0;
939 u_char length = 0, code = 0;
944 src_ref = EXTRACT_SHORT(&pd[offset + P_SRC_REF]);
947 case LI_DC_WITHOUT_CHECKSUM :
949 case LI_DC_WITH_CHECKSUM :
950 if ((code = pd[offset + P_VAR_PART_DC]) != VP_CHECKSUM)
952 length = pd[offset + P_VAR_PART_DC + 1];
953 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_DC + 2]);
961 if (check_col(fd, COL_INFO))
962 col_append_fstr(fd, COL_INFO, "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x",
967 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
968 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
969 proto_tree_add_text(cotp_tree, offset, 1,
970 "Length indicator: %u", li);
971 proto_tree_add_text(cotp_tree, offset + 1, 1,
972 "TPDU code: 0x%x (DC)", tpdu);
973 proto_tree_add_text(cotp_tree, offset + 2, 2,
974 "Destination reference: 0x%04x", dst_ref);
975 proto_tree_add_text(cotp_tree, offset + 4, 2,
976 "Source reference: 0x%04x", src_ref);
978 proto_tree_add_text(cotp_tree,
979 offset + P_VAR_PART_DC + 0, 1,
980 "Parameter code: 0x%02x (checksum)", code);
981 proto_tree_add_text(cotp_tree,
982 offset + P_VAR_PART_DC + 1, 1,
983 "Parameter length: %u", length);
984 proto_tree_add_text(cotp_tree,
985 offset + P_VAR_PART_DC + 2, 2,
986 "Checksum: 0x%04x", checksum);
994 } /* osi_decode_DC */
996 static int osi_decode_AK(const u_char *pd, int offset,
997 frame_data *fd, proto_tree *tree)
999 proto_tree *cotp_tree = NULL;
1001 u_int tpdu_nr,i =0, r_lower_window_edge ;
1003 u_short checksum, seq_nr, r_seq_nr, r_cdt;
1004 u_char code, length;
1009 if (!is_LI_NORMAL_AK(li)) {
1010 tpdu_nr = pd[offset + P_TPDU_NR_234];
1012 if (check_col(fd, COL_INFO))
1013 col_append_fstr(fd, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1017 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
1018 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1019 proto_tree_add_text(cotp_tree, offset, 1,
1020 "Length indicator: %u", li);
1021 proto_tree_add_text(cotp_tree, offset + 1, 1,
1022 "TPDU code: 0x%x (AK)", tpdu);
1023 proto_tree_add_text(cotp_tree, offset + 1, 1,
1025 proto_tree_add_text(cotp_tree, offset + 2, 2,
1026 "Destination reference: 0x%04x", dst_ref);
1027 proto_tree_add_text(cotp_tree, offset + 4, 1,
1028 "Your TPDU number: 0x%02x", tpdu_nr);
1031 while(li > P_VAR_PART_NAK + i - 1) {
1032 switch( (code = pd[offset + P_VAR_PART_NAK + i]) ) {
1034 length = pd[offset + P_VAR_PART_NAK + i + 1];
1035 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 2]);
1037 proto_tree_add_text(cotp_tree,
1038 offset + P_VAR_PART_NAK + i + 0, 1,
1039 "Parameter code: 0x%02x (checksum)", code);
1040 proto_tree_add_text(cotp_tree,
1041 offset + P_VAR_PART_NAK + i + 1, 1,
1042 "Parameter length: %u", length);
1043 proto_tree_add_text(cotp_tree,
1044 offset + P_VAR_PART_NAK + i + 2, 2,
1045 "Checksum: 0x%04x", checksum);
1050 length = pd[offset + P_VAR_PART_NAK + i + 1];
1051 r_lower_window_edge =
1052 EXTRACT_LONG(&pd[offset + P_VAR_PART_NAK + i + 2]);
1053 r_seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 6]);
1054 r_cdt = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 8]);
1056 proto_tree_add_text(cotp_tree,
1057 offset + P_VAR_PART_NAK + i + 0, 1,
1058 "Parameter code: 0x%02x (flow control)",
1060 proto_tree_add_text(cotp_tree,
1061 offset + P_VAR_PART_NAK + i + 1, 1,
1062 "Parameter length: %u", length);
1063 proto_tree_add_text(cotp_tree,
1064 offset + P_VAR_PART_NAK + i + 2, 4,
1065 "Lower window edge: 0x%08x",
1066 r_lower_window_edge);
1067 proto_tree_add_text(cotp_tree,
1068 offset + P_VAR_PART_NAK + i + 6, 2,
1069 "Sequence number: 0x%04x",
1071 proto_tree_add_text(cotp_tree,
1072 offset + P_VAR_PART_NAK + i + 8, 2,
1079 length = pd[offset + P_VAR_PART_NAK + i + 1];
1080 seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 2]);
1082 proto_tree_add_text(cotp_tree,
1083 offset + P_VAR_PART_NAK + i + 0, 1,
1084 "Parameter code: 0x%02x (seq number)", code);
1085 proto_tree_add_text(cotp_tree,
1086 offset + P_VAR_PART_NAK + i + 1, 1,
1087 "Parameter length: %u", length);
1088 proto_tree_add_text(cotp_tree,
1089 offset + P_VAR_PART_NAK + i + 2, 2,
1090 "Sequence number: 0x%04x", seq_nr);
1095 length = pd[offset + P_VAR_PART_NAK + i + 1];
1097 proto_tree_add_text(cotp_tree,
1098 offset + P_VAR_PART_NAK + i + 0, 1,
1099 "Parameter code: 0x%02x (unknown)", code);
1100 proto_tree_add_text(cotp_tree,
1101 offset + P_VAR_PART_NAK + i + 1, 1,
1102 "Parameter length: %u", length);
1103 proto_tree_add_text(cotp_tree,
1104 offset + P_VAR_PART_NAK + i + 2, length,
1105 "Parameter value: <not shown>");
1111 } else { /* extended format */
1113 tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
1114 cdt_in_ak = EXTRACT_SHORT(&pd[offset + P_CDT_IN_AK]);
1116 if (check_col(fd, COL_INFO))
1117 col_append_fstr(fd, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x",
1121 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
1122 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1123 proto_tree_add_text(cotp_tree, offset, 1,
1124 "Length indicator: %u", li);
1125 proto_tree_add_text(cotp_tree, offset + 1, 1,
1126 "TPDU code: 0x%x (AK)", tpdu);
1127 proto_tree_add_text(cotp_tree, offset + 2, 2,
1128 "Destination reference: 0x%04x", dst_ref);
1129 proto_tree_add_text(cotp_tree, offset + 4, 4,
1130 "Your TPDU number: 0x%08x", tpdu_nr);
1131 proto_tree_add_text(cotp_tree, offset + 8, 2,
1132 "Credit: 0x%04x", cdt_in_ak);
1135 while(li > P_VAR_PART_EAK + i - 1) {
1136 switch( (code = pd[offset + P_VAR_PART_EAK + i]) ) {
1138 length = pd[offset + P_VAR_PART_EAK + i + 1];
1139 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 2]);
1141 proto_tree_add_text(cotp_tree,
1142 offset + P_VAR_PART_EAK + i + 0, 1,
1143 "Parameter code: 0x%02x (checksum)", code);
1144 proto_tree_add_text(cotp_tree,
1145 offset + P_VAR_PART_EAK + i + 1, 1,
1146 "Parameter length: %u", length);
1147 proto_tree_add_text(cotp_tree,
1148 offset + P_VAR_PART_EAK + i + 2, 2,
1149 "Checksum: 0x%04x", checksum);
1154 length = pd[offset + P_VAR_PART_EAK + i + 1];
1155 r_lower_window_edge =
1156 EXTRACT_LONG(&pd[offset + P_VAR_PART_EAK + i + 2]);
1157 r_seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 6]);
1158 r_cdt = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 8]);
1160 proto_tree_add_text(cotp_tree,
1161 offset + P_VAR_PART_EAK + i + 0, 1,
1162 "Parameter code: 0x%02x (flow control)",
1164 proto_tree_add_text(cotp_tree,
1165 offset + P_VAR_PART_EAK + i + 1, 1,
1166 "Parameter length: %u", length);
1167 proto_tree_add_text(cotp_tree,
1168 offset + P_VAR_PART_EAK + i + 2, 4,
1169 "Lower window edge: 0x%08x",
1170 r_lower_window_edge);
1171 proto_tree_add_text(cotp_tree,
1172 offset + P_VAR_PART_EAK + i + 6, 2,
1173 "Sequence number: 0x%04x",
1175 proto_tree_add_text(cotp_tree,
1176 offset + P_VAR_PART_EAK + i + 8, 2,
1183 length = pd[offset + P_VAR_PART_EAK + i + 1];
1184 seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 2]);
1186 proto_tree_add_text(cotp_tree,
1187 offset + P_VAR_PART_EAK + i + 0, 1,
1188 "Parameter code: 0x%02x (seq number)", code);
1189 proto_tree_add_text(cotp_tree,
1190 offset + P_VAR_PART_EAK + i + 1, 1,
1191 "Parameter length: %u", length);
1192 proto_tree_add_text(cotp_tree,
1193 offset + P_VAR_PART_EAK + i + 2, 2,
1194 "Sequence number: 0x%04x", seq_nr);
1199 length = pd[offset + P_VAR_PART_EAK + i + 1];
1201 proto_tree_add_text(cotp_tree,
1202 offset + P_VAR_PART_EAK + i + 0, 1,
1203 "Parameter code: 0x%02x (unknown)", code);
1204 proto_tree_add_text(cotp_tree,
1205 offset + P_VAR_PART_EAK + i + 1, 1,
1206 "Parameter length: %u", length);
1207 proto_tree_add_text(cotp_tree,
1208 offset + P_VAR_PART_EAK + i + 2, length,
1209 "Parameter value: <not shown>");
1216 } /* is_LI_NORMAL_AK */
1222 } /* osi_decode_AK */
1224 static int osi_decode_EA(const u_char *pd, int offset,
1225 frame_data *fd, proto_tree *tree)
1227 proto_tree *cotp_tree;
1230 u_short checksum = 0;
1238 case LI_NORMAL_EA_WITH_CHECKSUM :
1239 tpdu_nr = pd[offset + P_TPDU_NR_234];
1240 code = pd[offset + P_VAR_PART_NDT];
1241 length = pd[offset + P_VAR_PART_NDT + 1];
1242 if (code != VP_CHECKSUM || length != 1)
1244 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NDT + 2]);
1246 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1247 tpdu_nr = pd[offset + P_TPDU_NR_234];
1249 case LI_EXTENDED_EA_WITH_CHECKSUM :
1250 tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
1251 code = pd[offset + P_VAR_PART_EDT];
1252 length = pd[offset + P_VAR_PART_EDT + 1];
1253 if (code != VP_CHECKSUM || length != 1)
1255 checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EDT + 2]);
1257 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1258 tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
1260 default : /* bad TPDU */
1266 if (check_col(fd, COL_INFO))
1267 col_append_fstr(fd, COL_INFO,
1268 "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1271 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
1272 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1273 proto_tree_add_text(cotp_tree, offset, 1,
1274 "Length indicator: %u", li);
1275 proto_tree_add_text(cotp_tree, offset + 1, 1,
1276 "TPDU code: 0x%x (EA)", tpdu);
1277 proto_tree_add_text(cotp_tree, offset + 2, 2,
1278 "Destination reference: 0x%04x", dst_ref);
1281 case LI_NORMAL_EA_WITH_CHECKSUM :
1282 proto_tree_add_text(cotp_tree, offset + 4, 1,
1283 "Your TPDU number: 0x%02x", tpdu_nr);
1284 proto_tree_add_text(cotp_tree, offset + 5, 1,
1285 "Parameter code: 0x%02x (checksum)", code);
1286 proto_tree_add_text(cotp_tree, offset + 6, 1,
1287 "Parameter length: %u", length);
1288 proto_tree_add_text(cotp_tree, offset + 7, 2,
1289 "Checksum: 0x%04x", checksum);
1291 case LI_NORMAL_EA_WITHOUT_CHECKSUM :
1292 proto_tree_add_text(cotp_tree, offset + 4, 1,
1293 "Your TPDU number: 0x%02x", tpdu_nr);
1295 case LI_EXTENDED_EA_WITH_CHECKSUM :
1296 proto_tree_add_text(cotp_tree, offset + 4, 4,
1297 "Your TPDU number: 0x%08x", tpdu_nr);
1298 proto_tree_add_text(cotp_tree, offset + 8, 1,
1299 "Parameter code: 0x%02x (checksum)", code);
1300 proto_tree_add_text(cotp_tree, offset + 9, 1,
1301 "Parameter length: %u", length);
1302 proto_tree_add_text(cotp_tree, offset + 10, 2,
1303 "Checksum: 0x%04x", checksum);
1305 case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1306 proto_tree_add_text(cotp_tree, offset + 4, 4,
1307 "Your TPDU number: 0x%08x", tpdu_nr);
1318 } /* osi_decode_EA */
1320 static int osi_decode_ER(const u_char *pd, int offset,
1321 frame_data *fd, proto_tree *tree)
1323 proto_tree *cotp_tree;
1330 switch(pd[offset + P_REJECT_ER]) {
1332 str = "Reason not specified";
1335 str = "Invalid parameter code";
1338 str = "Invalid TPDU type";
1341 str = "Invalid parameter value";
1349 if (check_col(fd, COL_INFO))
1350 col_append_fstr(fd, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1353 ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
1354 cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1355 proto_tree_add_text(cotp_tree, offset, 1,
1356 "Length indicator: %u", li);
1357 proto_tree_add_text(cotp_tree, offset + 1, 1,
1358 "TPDU code: 0x%x (ER)", tpdu);
1359 proto_tree_add_text(cotp_tree, offset + 2, 2,
1360 "Destination reference: 0x%04x", dst_ref);
1361 proto_tree_add_text(cotp_tree, offset + 4, 1,
1362 "Reject cause: %s", str);
1369 } /* osi_decode_ER */
1371 /* Returns TRUE if we found at least one valid COTP PDU, FALSE
1373 static gboolean dissect_cotp_internal(const u_char *pd, int offset,
1374 frame_data *fd, proto_tree *tree,
1375 gboolean uses_inactive_subset)
1377 gboolean first_tpdu = TRUE;
1379 gboolean found_cotp = FALSE;
1380 gboolean subdissector_found = FALSE;
1382 /* Initialize the COL_INFO field; each of the TPDUs will have its
1383 information appended. */
1384 if (check_col(fd, COL_INFO))
1385 col_add_str(fd, COL_INFO, "");
1387 while (IS_DATA_IN_FRAME(offset)) {
1389 if (check_col(fd, COL_INFO))
1390 col_append_str(fd, COL_INFO, ", ");
1392 if ((li = pd[offset + P_LI]) == 0) {
1393 if (check_col(fd, COL_INFO))
1394 col_append_str(fd, COL_INFO, "Length indicator is zero");
1396 dissect_data(pd, offset, fd, tree);
1399 if (!BYTES_ARE_IN_FRAME(offset, P_LI + li + 1)) {
1400 if (check_col(fd, COL_INFO))
1401 col_append_str(fd, COL_INFO, "Captured data in frame doesn't include entire frame");
1403 dissect_data(pd, offset, fd, tree);
1407 tpdu = (pd[offset + P_TPDU] >> 4) & 0x0F;
1408 cdt = pd[offset + P_CDT] & 0x0F;
1409 dst_ref = EXTRACT_SHORT(&pd[offset + P_DST_REF]);
1414 new_offset = osi_decode_CC(pd, offset, fd, tree);
1417 new_offset = osi_decode_DR(pd, offset, fd, tree);
1420 if (osi_decode_DT(pd, offset, fd, tree, uses_inactive_subset))
1421 subdissector_found = TRUE;
1422 new_offset = pi.captured_len; /* DT PDUs run to the end of the packet */
1425 new_offset = osi_decode_ED(pd, offset, fd, tree);
1428 new_offset = osi_decode_RJ(pd, offset, fd, tree);
1431 new_offset = osi_decode_DC(pd, offset, fd, tree);
1434 new_offset = osi_decode_AK(pd, offset, fd, tree);
1437 new_offset = osi_decode_EA(pd, offset, fd, tree);
1440 new_offset = osi_decode_ER(pd, offset, fd, tree);
1443 if (first_tpdu && check_col(fd, COL_INFO))
1444 col_append_fstr(fd, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1445 new_offset = -1; /* bad PDU type */
1449 if (new_offset == -1) { /* incorrect TPDU */
1451 dissect_data(pd, offset, fd, tree);
1456 /* Well, we found at least one valid COTP PDU, so I guess this
1458 if (!subdissector_found && check_col(fd, COL_PROTOCOL))
1459 col_add_str(fd, COL_PROTOCOL, "COTP");
1463 offset = new_offset;
1467 } /* dissect_cotp_internal */
1469 void dissect_cotp(const u_char *pd, int offset, frame_data *fd,
1472 if (!dissect_cotp_internal(pd, offset, fd, tree, FALSE))
1473 dissect_data(pd, offset, fd, tree);
1478 * CLNP part / main entry point
1481 void dissect_clnp(const u_char *pd, int offset, frame_data *fd,
1485 struct clnp_header clnp;
1486 proto_tree *clnp_tree = NULL;
1488 u_char src_len, dst_len, nsel, opt_len = 0;
1489 u_int first_offset = offset;
1490 char flag_string[6+1];
1491 char *pdu_type_string;
1492 guint16 segment_length;
1493 guint16 segment_offset = 0;
1496 if (check_col(fd, COL_PROTOCOL))
1497 col_add_str(fd, COL_PROTOCOL, "CLNP");
1499 /* avoid alignment problem */
1500 memcpy(&clnp, &pd[offset], sizeof(clnp));
1502 if (clnp.cnf_proto_id == NLPID_NULL) {
1503 if (check_col(fd, COL_INFO))
1504 col_add_str(fd, COL_INFO, "Inactive subset");
1506 ti = proto_tree_add_item(tree, proto_clnp, offset, 1, NULL);
1507 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1508 proto_tree_add_uint_format(clnp_tree, hf_clnp_id, offset, 1,
1512 dissect_cotp_internal(pd, offset+1, fd, tree, TRUE);
1516 if (!BYTES_ARE_IN_FRAME(offset, sizeof(clnp))) {
1517 dissect_data(pd, offset, fd, tree);
1521 /* return if version not known */
1522 if (clnp.cnf_vers != ISO8473_V1) {
1523 dissect_data(pd, offset, fd, tree);
1527 /* fixed part decoding */
1528 opt_len = clnp.cnf_hdr_len;
1530 segment_length = EXTRACT_SHORT(&clnp.cnf_seglen_msb);
1531 flag_string[0] = '\0';
1532 if (clnp.cnf_type & CNF_SEG_OK)
1533 strcat(flag_string, "S ");
1534 if (clnp.cnf_type & CNF_MORE_SEGS)
1535 strcat(flag_string, "M ");
1536 if (clnp.cnf_type & CNF_ERR_OK)
1537 strcat(flag_string, "E ");
1538 pdu_type_string = val_to_str(clnp.cnf_type & CNF_TYPE, npdu_type_vals,
1539 "Unknown (0x%02x)");
1541 ti = proto_tree_add_item(tree, proto_clnp, offset, clnp.cnf_hdr_len, NULL);
1542 clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1543 proto_tree_add_item(clnp_tree, hf_clnp_id, offset, 1,
1545 proto_tree_add_item(clnp_tree, hf_clnp_length, offset + 1, 1,
1547 proto_tree_add_item(clnp_tree, hf_clnp_version, offset + 2, 1,
1549 proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, offset + 3, 1,
1551 "Holding Time : %u (%u secs)",
1552 clnp.cnf_ttl, clnp.cnf_ttl / 2);
1553 proto_tree_add_uint_format(clnp_tree, hf_clnp_type, offset + 4, 1,
1555 "PDU Type : 0x%02x (%s%s)",
1559 proto_tree_add_item(clnp_tree, hf_clnp_pdu_length, offset + 5, 2,
1561 proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, offset + 7, 2,
1562 EXTRACT_SHORT(&clnp.cnf_cksum_msb),
1563 "Checksum : 0x%04x",
1564 EXTRACT_SHORT(&clnp.cnf_cksum_msb));
1565 opt_len -= 9; /* Fixed part of Hesder */
1568 /* stop here if header is not complete */
1570 if (!BYTES_ARE_IN_FRAME(offset, clnp.cnf_hdr_len)) {
1571 if (check_col(fd, COL_INFO))
1572 col_add_fstr(fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1573 dissect_data(pd, offset, fd, tree);
1579 offset += P_ADDRESS_PART;
1580 dst_len = pd[offset];
1581 nsel = pd[offset + dst_len];
1582 src_len = pd[offset + dst_len + 1];
1585 proto_tree_add_item(clnp_tree, hf_clnp_dest_length, offset, 1,
1587 proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, offset + 1 , dst_len,
1590 print_nsap_net(&pd[offset + 1], dst_len));
1591 proto_tree_add_item(clnp_tree, hf_clnp_src_length,
1592 offset + 1 + dst_len, 1, src_len);
1593 proto_tree_add_bytes_format(clnp_tree, hf_clnp_src,
1594 offset + dst_len + 2, src_len,
1595 &pd[offset + dst_len + 2],
1597 print_nsap_net(&pd[offset + dst_len + 2], src_len));
1599 opt_len -= dst_len + src_len +2;
1602 if (check_col(fd, COL_RES_NET_SRC))
1603 col_add_fstr(fd, COL_RES_NET_SRC, "%s",
1604 print_nsap_net(&pd[offset + dst_len + 2], src_len));
1605 if (check_col(fd, COL_RES_NET_DST))
1606 col_add_fstr(fd, COL_RES_NET_DST, "%s",
1607 print_nsap_net(&pd[offset + 1], dst_len));
1609 /* Segmentation Part */
1611 offset += dst_len + src_len + 2;
1613 if (clnp.cnf_type & CNF_SEG_OK) {
1614 struct clnp_segment seg; /* XXX - not used */
1615 memcpy(&seg, &pd[offset], sizeof(seg)); /* XXX - not used */
1617 segment_offset = EXTRACT_SHORT(&pd[offset + 2]);
1619 proto_tree_add_text(clnp_tree, offset, 2,
1620 "Data unit identifier: %06u",
1621 EXTRACT_SHORT(&pd[offset]));
1622 proto_tree_add_text(clnp_tree, offset + 2 , 2,
1623 "Segment offset : %6u",
1625 proto_tree_add_text(clnp_tree, offset + 4 , 2,
1626 "Total length : %6u",
1627 EXTRACT_SHORT(&pd[offset + 4]));
1635 /* To do : decode options */
1637 proto_tree_add_text(clnp_tree, offset,
1638 clnp.cnf_hdr_len + first_offset - offset,
1639 "Options/Data: <not shown>");
1641 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1643 dissect_osi_options( 0xff,
1645 pd, offset, fd, clnp_tree );
1648 /* Length of CLNP datagram plus headers above it. */
1649 len = segment_length + first_offset;
1651 /* Set the payload and captured-payload lengths to the minima of (the
1652 datagram length plus the length of the headers above it) and the
1656 if (pi.captured_len > len)
1657 pi.captured_len = len;
1659 offset = first_offset + clnp.cnf_hdr_len;
1661 /* For now, dissect the payload of segments other than the initial
1662 segment as data, rather than handing them off to the transport
1663 protocol, just as we do with fragments other than the first
1664 fragment in a fragmented IP datagram; in the future, we will
1665 probably reassemble fragments for IP, and may reassemble segments
1667 if ((clnp.cnf_type & CNF_SEG_OK) && segment_offset != 0) {
1668 if (check_col(fd, COL_INFO))
1669 col_add_fstr(fd, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
1670 pdu_type_string, flag_string, segment_offset);
1671 dissect_data(pd, offset, fd, tree);
1675 if (IS_DATA_IN_FRAME(offset)) {
1676 switch (clnp.cnf_type & CNF_TYPE) {
1680 /* Continue with COTP if any data.
1681 XXX - if this isn't the first Derived PDU of a segmented Initial
1684 if (nsel == NSEL_TP) { /* just guessing here - valid for DECNet-OSI */
1685 if (dissect_cotp_internal(pd, offset, fd, tree, FALSE))
1686 return; /* yes, it appears to be COTP */
1691 /* The payload is the header and "none, some, or all of the data
1692 part of the discarded PDU", i.e. it's like an ICMP error;
1693 just as we don't yet trust ourselves to be able to dissect
1694 the payload of an ICMP error packet, we don't yet trust
1695 ourselves to dissect the payload of a CLNP ER packet. */
1700 /* XXX - dissect this */
1704 if (check_col(fd, COL_INFO))
1705 col_add_fstr(fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1706 dissect_data(pd, offset, fd, tree);
1708 } /* dissect_clnp */
1711 void proto_register_clnp(void)
1713 static hf_register_info hf[] = {
1715 { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX,
1716 VALS(nlpid_vals), 0x0, "" }},
1719 { "HDR Length ", "clnp.len", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1722 { "Version ", "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1725 { "Holding Time ", "clnp.ttl", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1728 { "PDU Type ", "clnp.type", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1730 { &hf_clnp_pdu_length,
1731 { "PDU length ", "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
1733 { &hf_clnp_checksum,
1734 { "Checksum ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
1736 { &hf_clnp_dest_length,
1737 { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1740 { " DA ", "clnp.dsap", FT_BYTES, BASE_NONE, NULL, 0x0, "" }},
1742 { &hf_clnp_src_length,
1743 { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1746 { " SA ", "clnp.ssap", FT_BYTES, BASE_NONE, NULL, 0x0, "" }},
1748 static gint *ett[] = {
1752 proto_clnp = proto_register_protocol(PROTO_STRING_CLNP, "clnp");
1753 proto_register_field_array(proto_clnp, hf, array_length(hf));
1754 proto_register_subtree_array(ett, array_length(ett));
1757 void proto_register_cotp(void)
1759 /* static hf_register_info hf[] = {
1761 { "Name", "cotp.abbreviation", TYPE, VALS_POINTER }},
1763 static gint *ett[] = {
1767 proto_cotp = proto_register_protocol(PROTO_STRING_COTP, "cotp");
1768 /* proto_register_field_array(proto_cotp, hf, array_length(hf));*/
1769 proto_register_subtree_array(ett, array_length(ett));