Remove TODO comments about NSAP and ISIS decodings since
[obnox/wireshark/wip.git] / packet-clnp.c
1 /* packet-clnp.c
2  * Routines for ISO/OSI network and transport protocol packet disassembly
3  *
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>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@zing.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * 
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.
17  * 
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.
22  * 
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.
26  *
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <glib.h>
41 #include "packet.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"
48 #include "nlpid.h"
49
50 /* protocols and fields */
51
52 static int  proto_clnp         = -1;
53 static int  proto_cotp         = -1;
54 static gint ett_clnp           = -1;
55 static gint ett_cotp           = -1;
56
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;
68
69
70
71 /*
72  * ISO 8473 OSI CLNP definition (see RFC994)
73  *
74  *            _________________________________
75  *           |           Fixed Part            |
76  *           |_________________________________|
77  *           |          Address Part           |
78  *           |_________________________________|
79  *           |   Segmentation Part (optional)  |
80  *           |_________________________________|
81  *           |     Options Part (optional)     |
82  *           |_________________________________|
83  *           |         Data (optional)         |
84  *           |_________________________________|
85  */
86
87 #define ISO8473_V1  0x01    /* CLNP version 1 */
88
89 /* Fixed part */
90
91 struct clnp_header {
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 */
101 };
102
103 #define CNF_TYPE                0x1f
104 #define CNF_ERR_OK              0x20
105 #define CNF_MORE_SEGS           0x40
106 #define CNF_SEG_OK              0x80
107
108 #define DT_NPDU                 0x1C
109 #define MD_NPDU                 0x1D
110 #define ER_NPDU                 0x01
111 #define ERQ_NPDU                0x1E
112 #define ERP_NPDU                0x1F
113
114 static const value_string npdu_type_vals[] = {
115   { DT_NPDU,    "DT" },
116   { MD_NPDU,    "MD" },
117   { ER_NPDU,    "ER" },
118   { ERQ_NPDU,   "ERQ" },
119   { ERP_NPDU,   "ERP" },
120   { 0,          NULL }
121 };
122
123 /* field position */
124
125 #define P_ADDRESS_PART          9
126
127 /* Segmentation part */
128
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 */
133 };
134
135 /* NSAP selector */
136
137 #define NSEL_NET                0x00
138 #define NSEL_NP                 0x20
139 #define NSEL_TP                 0x21
140
141 /*
142  * ISO8073 OSI COTP definition (see RFC905)
143  */
144
145 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
146
147 /* TPDU definition */
148
149 #define ED_TPDU                 0x1
150 #define EA_TPDU                 0x2
151 #define RJ_TPDU                 0x5
152 #define AK_TPDU                 0x6
153 #define ER_TPDU                 0x7
154 #define DR_TPDU                 0x8
155 #define DC_TPDU                 0xC
156 #define CC_TPDU                 0xD
157 #define CR_TPDU                 0xE
158 #define DT_TPDU                 0xF
159
160 /* field position */
161
162 #define P_LI                    0
163 #define P_TPDU                  1
164 #define P_CDT                   1
165 #define P_DST_REF               2
166 #define P_SRC_REF               4
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
181
182 /* TPDU length indicator */
183
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
195 #define LI_MIN_DR                        6
196 #define LI_MAX_DC                        9
197 #define LI_MAX_AK                        27
198 #define LI_MAX_EA                        11
199 #define LI_MAX_ER                        8
200 #define LI_DC_WITH_CHECKSUM              9
201 #define LI_DC_WITHOUT_CHECKSUM           5
202 #define is_LI_NORMAL_AK(p)               ( p & 0x01 )
203
204 /* variant part */
205
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
222
223 /* misc */
224
225 #define EXTRACT_SHORT(p)        pntohs(p)
226 #define EXTRACT_LONG(p)         pntohl(p)
227
228 /* global variables */
229
230 static u_char  li, tpdu, cdt;   /* common fields */
231 static u_short dst_ref;
232
233 /* function definitions */
234
235 static int osi_decode_DR(const u_char *pd, int offset, 
236                          frame_data *fd, proto_tree *tree) 
237 {
238   proto_tree *cotp_tree;
239   proto_item *ti;
240   u_short src_ref;
241   u_char  reason;
242   char *str;
243   
244   if (li < LI_MIN_DR) 
245     return -1;
246   
247   src_ref = EXTRACT_SHORT(&pd[offset + P_SRC_REF]);
248   reason  = pd[offset + P_REASON_IN_DR];
249
250   switch(reason) {
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;
264     default:      return -1;
265       /*NOTREACHED*/
266       break;
267   }
268
269   if (check_col(fd, COL_INFO))
270     col_append_fstr(fd, COL_INFO, "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
271                  src_ref, dst_ref);
272
273   if (tree) {
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, 
285                         "Cause: %s", str);
286   }
287
288   offset += li + 1;
289   dissect_data(pd, offset, fd, tree);
290
291   return pi.captured_len;       /* we dissected all of the containing PDU */
292
293 } /* osi_decode_DR */
294
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)
299 {
300   proto_tree *cotp_tree;
301   proto_item *ti;
302   u_int    tpdu_nr ;
303   u_short  checksum = 0;
304   u_char   code = 0, length = 0;
305   u_int    fragment = 0;
306     
307   switch (li) {
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;
312       else
313         fragment = 1;
314       code = pd[offset + P_VAR_PART_NDT];
315       if (code == VP_CHECKSUM)
316         checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NDT + 2]);
317       else
318         return -1;
319       break;
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;
324       else
325         fragment = 1;
326       break;
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;
331       else
332         fragment = 1;
333       code = pd[offset + P_VAR_PART_EDT];
334       if (code == VP_CHECKSUM)
335         checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EDT + 2]);
336       else
337         return -1;
338       break;
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;
343       else
344         fragment = 1;
345       break;
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;
350       else
351         fragment = 1;      
352       break;
353     default : /* bad TPDU */
354       return -1;
355       /*NOTREACHED*/
356       break;
357   }
358
359   if (check_col(fd, COL_INFO))
360     col_append_fstr(fd, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s", 
361                  tpdu_nr,
362                  dst_ref,
363                  (fragment)? "(fragment)" : "");
364
365   if (tree) {
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); 
372
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);
376
377     switch (li) {
378       case LI_NORMAL_DT_WITH_CHECKSUM      :
379         proto_tree_add_text(cotp_tree, offset +  4, 1, 
380                             "TPDU number: 0x%02x (%s)", 
381                             tpdu_nr,
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);
392         break;
393       case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
394         proto_tree_add_text(cotp_tree, offset +  4, 1, 
395                             "TPDU number: 0x%02x (%s)", 
396                             tpdu_nr,
397                             (fragment)? "fragment":"complete");
398         break;
399       case LI_EXTENDED_DT_WITH_CHECKSUM    :
400         proto_tree_add_text(cotp_tree, offset +  4, 4, 
401                             "TPDU number: 0x%08x (%s)", 
402                             tpdu_nr,
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);
413         break;
414       case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
415         proto_tree_add_text(cotp_tree, offset +  4, 4, 
416                             "TPDU number: 0x%08x (%s)", 
417                             tpdu_nr,
418                             (fragment)? "fragment":"complete");
419         break;
420       case LI_NORMAL_DT_CLASS_01           :
421         proto_tree_add_text(cotp_tree, offset +  2, 1, 
422                             "TPDU number: 0x%02x (%s)", 
423                             tpdu_nr,
424                             (fragment)? "fragment":"complete");
425         break;
426     }
427   } /* tree */
428
429   offset += li + 1;
430   if (uses_inactive_subset){
431         dissect_h1(pd, offset, fd, tree);
432         return TRUE;
433         }
434   else {
435         dissect_data(pd, offset, fd, tree);
436         return FALSE;
437         }
438 } /* osi_decode_DT */
439
440 static int osi_decode_ED(const u_char *pd, int offset, 
441                          frame_data *fd, proto_tree *tree)
442 {
443   proto_tree *cotp_tree;
444   proto_item *ti;
445   u_int    tpdu_nr ;
446   u_short  checksum = 0;
447   u_char   code = 0, length = 0;
448
449   /* ED TPDUs are never fragmented */
450
451   switch (li) {
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;
456       else
457         return -1;
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]);
462       else
463         return -1;
464       break;
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;
469       else
470         return -1;
471       break;
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;
476       else
477         return -1;
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]);
482       else
483         return -1;
484       break;
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;
489       else
490         return -1;
491       break;
492     default : /* bad TPDU */
493       return -1;
494       /*NOTREACHED*/
495       break;
496   } /* li */
497
498   if (check_col(fd, COL_INFO))
499     col_append_fstr(fd, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x", 
500                  tpdu_nr, dst_ref);
501
502   if (tree) {
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);
511
512     switch (li) {
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);
525         break;
526       case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
527         proto_tree_add_text(cotp_tree, offset +  4, 1, 
528                             "TPDU number: 0x%02x", tpdu_nr);
529         break;
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);
542         break;
543       case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
544         proto_tree_add_text(cotp_tree, offset +  4, 4, 
545                             "TPDU number: 0x%02x", tpdu_nr);
546         break;
547     }
548   } /* tree */
549
550   offset += li + 1;
551   dissect_data(pd, offset, fd, tree);
552
553   return pi.captured_len;       /* we dissected all of the containing PDU */
554
555 } /* osi_decode_ED */
556
557 static int osi_decode_RJ(const u_char *pd, int offset, 
558                          frame_data *fd, proto_tree *tree)
559 {
560   proto_tree *cotp_tree;
561   proto_item *ti;
562   u_int    tpdu_nr ;
563   u_short  credit = 0;
564
565   switch(li) {
566     case LI_NORMAL_RJ   :
567       tpdu_nr = pd[offset + P_TPDU_NR_234];
568       break;
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]);
572       break;
573     default :
574       return -1;
575       /*NOTREACHED*/
576       break;
577   }
578
579   if (check_col(fd, COL_INFO))
580     col_append_fstr(fd, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x", 
581                  tpdu_nr, dst_ref);
582
583   if (tree) {
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, 
592                           "Credit: %u", cdt);
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);
598     else {
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);
603     }
604   }
605
606   offset += li + 1;
607
608   return offset;
609
610 } /* osi_decode_RJ */
611
612 #define MAX_TSAP_LEN    32
613
614 static gchar *print_tsap(const u_char *tsap, int length)
615 {
616
617   static gchar  str[3][MAX_TSAP_LEN * 2 + 1];
618   static gchar *cur;
619   gchar tmp[3];
620   gboolean allprintable;
621   int i;
622
623   if (cur == &str[0][0]) {
624     cur = &str[1][0];
625   } else if (cur == &str[1][0]) {  
626     cur = &str[2][0];
627   } else {  
628     cur = &str[0][0];
629   }
630
631
632   cur[0] = '\0';
633   if (length <= 0 || length > MAX_TSAP_LEN) 
634     sprintf(cur, "<unsupported TSAP length>");
635   else {    
636     allprintable=TRUE;
637     for (i=0;i<length;i++) {
638         if (!isprint(tsap[i])) { /* if any byte is not printable */
639           allprintable=FALSE;    /* switch to hexdump */
640           break;
641           }      
642         }
643     if (!allprintable){
644       strcat(cur,"0x");
645       }
646     while (length != 0) {
647       if (allprintable)
648         sprintf(tmp, "%c", *tsap ++);
649       else
650         sprintf(tmp, "%02x", *tsap ++);
651       strcat(cur, tmp);
652       length --;
653     }
654   }
655   return cur;
656
657 } /* print_tsap */
658
659 static int osi_decode_CC(const u_char *pd, int offset, 
660                          frame_data *fd, proto_tree *tree)
661 {
662
663   /* CC & CR decoding in the same function */
664
665   proto_tree *cotp_tree = NULL;
666   proto_item *ti;
667   u_short src_ref, checksum;
668   u_char  class_option, code, length;
669   u_int   i = 0;
670
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)
674     return -1;
675
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",
679                  src_ref,
680                  dst_ref);
681
682   if (tree) {
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);
696   }
697
698   if (tree)
699     while(li > P_VAR_PART_CC + i - 1) {
700       
701       u_char  c1;
702       u_short s, s1,s2,s3,s4;
703       u_int   t1,t2,t3,t4;
704       
705       switch( (code = pd[offset + P_VAR_PART_CC + i]) ) {
706         case VP_CHECKSUM :
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);
718           i += length + 2;
719           break;
720         case VP_SRC_TSAP    :
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, 
730                               "Calling TSAP:     %s", 
731                               print_tsap(&pd[offset + P_VAR_PART_CC + i + 2],
732                                          length));
733           i += length + 2;
734           break;
735         case VP_DST_TSAP    :
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, 
745                               "Called TSAP:      %s", 
746                               print_tsap(&pd[offset + P_VAR_PART_CC + i + 2],
747                                          length));
748           i += length + 2;
749           break;
750         case VP_TPDU_SIZE   :
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);
762           i += length + 2;
763           break;
764         case VP_OPT_SEL     :
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) {
774             if (c1 & 0x8)
775               proto_tree_add_text(cotp_tree, 
776                                   offset +  P_VAR_PART_CC + i + 2, 1,
777                                   "Use of network expedited data");
778             else
779               proto_tree_add_text(cotp_tree, 
780                                   offset +  P_VAR_PART_CC + i + 2, 1,
781                                   "Non use of network expedited data");
782             if (c1 & 0x4)
783               proto_tree_add_text(cotp_tree, 
784                                   offset +  P_VAR_PART_CC + i + 2, 1,
785                                   "Use of Receipt confirmation");
786             else
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) {
791             if (c1 & 0x2)
792               proto_tree_add_text(cotp_tree, 
793                                   offset +  P_VAR_PART_CC + i + 2, 1,
794                                   "Use 16 bit checksum ");
795             else
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");
799           }
800           if (c1 & 0x1)
801             proto_tree_add_text(cotp_tree, 
802                                 offset +  P_VAR_PART_CC + i + 2, 1,
803                                 "Use of transport expedited data transfer\n");
804           else
805             proto_tree_add_text(cotp_tree, 
806                                 offset +  P_VAR_PART_CC + i + 2, 1,
807                                 "Non-use of transport expedited data transfer");
808           i += length + 2;
809           break;
810         case VP_ACK_TIME    :
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);
822           i += length + 2;
823           break;
824         case VP_THROUGHPUT  :
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);
848           i += length + 2;
849           break;
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);
874           i += length + 2;
875           break;
876         case VP_PRIORITY    :
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,
887                               "Priority: %u", s);
888           i += length + 2;
889           break;
890         
891         case VP_VERSION_NR  :
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,
902                               "Version: %u", c1);
903           i += length + 2;
904           break;
905
906         case VP_REASSIGNMENT:     /* todo */
907         case VP_RES_ERROR   :
908         case VP_PROTECTION  :
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>");
921           i += length + 2;
922           break; 
923       }
924     } /* while */
925
926   offset += li + 1;
927   dissect_data(pd, offset, fd, tree);
928
929   return pi.captured_len;       /* we dissected all of the containing PDU */
930
931 } /* osi_decode_CC */
932
933 static int osi_decode_DC(const u_char *pd, int offset, 
934                          frame_data *fd, proto_tree *tree)
935 {
936   proto_tree *cotp_tree;
937   proto_item *ti;
938   u_short src_ref, checksum = 0;
939   u_char  length = 0, code = 0;
940
941   if (li > LI_MAX_DC) 
942     return -1;
943
944   src_ref = EXTRACT_SHORT(&pd[offset + P_SRC_REF]);
945
946   switch(li) {
947     case LI_DC_WITHOUT_CHECKSUM :
948       break;
949     case LI_DC_WITH_CHECKSUM :
950       if ((code = pd[offset + P_VAR_PART_DC]) != VP_CHECKSUM) 
951         return -1;
952       length   = pd[offset + P_VAR_PART_DC + 1];
953       checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_DC + 2]);
954       break;
955     default :
956       return -1;
957       /*NOTREACHED*/
958       break;
959   } /* li */
960
961   if (check_col(fd, COL_INFO))
962     col_append_fstr(fd, COL_INFO, "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x", 
963                  src_ref,
964                  dst_ref);
965
966   if (tree) {
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);
977     if (code) {
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);
987     }
988   }
989
990   offset += li + 1;
991
992   return offset;
993
994 } /* osi_decode_DC */
995
996 static int osi_decode_AK(const u_char *pd, int offset, 
997                          frame_data *fd, proto_tree *tree)
998 {
999   proto_tree *cotp_tree = NULL;
1000   proto_item *ti;
1001   u_int      tpdu_nr,i =0, r_lower_window_edge ;
1002   u_short    cdt_in_ak;
1003   u_short    checksum, seq_nr, r_seq_nr, r_cdt;
1004   u_char     code, length;
1005
1006   if (li > LI_MAX_AK) 
1007     return -1;
1008
1009   if (!is_LI_NORMAL_AK(li)) {
1010     tpdu_nr = pd[offset + P_TPDU_NR_234];
1011
1012     if (check_col(fd, COL_INFO))
1013       col_append_fstr(fd, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x", 
1014                    tpdu_nr, dst_ref);
1015     
1016     if (tree) {
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, 
1024                           "Credit: %u", cdt);
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);
1029     }
1030
1031     while(li > P_VAR_PART_NAK + i - 1) {
1032       switch( (code = pd[offset + P_VAR_PART_NAK + i]) ) {
1033         case VP_CHECKSUM :
1034           length   = pd[offset + P_VAR_PART_NAK + i + 1];
1035           checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 2]);
1036           if (tree) {
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);
1046           }
1047           i += length + 2;
1048           break;
1049         case VP_FLOW_CNTL :
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]);
1055           if (tree) {
1056             proto_tree_add_text(cotp_tree, 
1057                                 offset +  P_VAR_PART_NAK + i + 0, 1, 
1058                                 "Parameter code: 0x%02x (flow control)", 
1059                                 code);
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", 
1070                                 r_seq_nr);
1071             proto_tree_add_text(cotp_tree, 
1072                                 offset +  P_VAR_PART_NAK + i + 8, 2, 
1073                                 "Credit: 0x%04x", 
1074                                 r_cdt);
1075           }
1076           i += length + 2;
1077           break;
1078         case VP_SEQ_NR :
1079           length = pd[offset + P_VAR_PART_NAK + i + 1];
1080           seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 2]);
1081           if (tree) {
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);
1091           }
1092           i += length + 2;
1093           break;
1094         default :
1095           length = pd[offset + P_VAR_PART_NAK + i + 1];
1096           if (tree) {
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>");
1106           }
1107           i += length + 2;
1108           break;
1109       } /* code */
1110     }
1111   } else { /* extended format */
1112     
1113     tpdu_nr   = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
1114     cdt_in_ak = EXTRACT_SHORT(&pd[offset + P_CDT_IN_AK]);
1115
1116     if (check_col(fd, COL_INFO))
1117       col_append_fstr(fd, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x", 
1118                    tpdu_nr, dst_ref);
1119     
1120     if (tree) {
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);
1133     }
1134     
1135     while(li > P_VAR_PART_EAK + i - 1) {
1136       switch( (code = pd[offset + P_VAR_PART_EAK + i]) ) {
1137         case VP_CHECKSUM :
1138           length   = pd[offset + P_VAR_PART_EAK + i + 1];
1139           checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 2]);
1140           if (tree) {
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);
1150           }
1151           i += length + 2;
1152           break;
1153         case VP_FLOW_CNTL :
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]);
1159           if (tree) {
1160             proto_tree_add_text(cotp_tree, 
1161                                 offset +  P_VAR_PART_EAK + i + 0, 1, 
1162                                 "Parameter code: 0x%02x (flow control)",
1163                                 code);
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", 
1174                                 r_seq_nr);
1175             proto_tree_add_text(cotp_tree, 
1176                                 offset +  P_VAR_PART_EAK + i + 8, 2, 
1177                                 "Credit: 0x%04x", 
1178                                 r_cdt);
1179           }
1180           i += length + 2;
1181           break;
1182         case VP_SEQ_NR :
1183           length   = pd[offset + P_VAR_PART_EAK + i + 1];
1184           seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 2]);
1185           if (tree) {
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);
1195           }
1196           i += length + 2;
1197           break;
1198         default :
1199           length   = pd[offset + P_VAR_PART_EAK + i + 1];
1200           if (tree) {
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>");
1210           }
1211           i += length + 2;
1212           break;
1213       } /* code */
1214     }
1215     
1216   } /* is_LI_NORMAL_AK */
1217
1218   offset += li + 1;
1219
1220   return offset;
1221
1222 } /* osi_decode_AK */
1223
1224 static int osi_decode_EA(const u_char *pd, int offset, 
1225                          frame_data *fd, proto_tree *tree)
1226 {
1227   proto_tree *cotp_tree;
1228   proto_item *ti;
1229   u_int    tpdu_nr ;
1230   u_short  checksum = 0;
1231   u_char   code = 0;
1232   u_char   length = 0;
1233
1234   if (li > LI_MAX_EA) 
1235     return -1;
1236
1237   switch (li) {
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)
1243         return -1;
1244       checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NDT + 2]);
1245       break;
1246     case LI_NORMAL_EA_WITHOUT_CHECKSUM   :
1247       tpdu_nr = pd[offset + P_TPDU_NR_234];
1248       break;
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)
1254         return -1;
1255       checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EDT + 2]);
1256       break;
1257     case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1258       tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
1259       break;
1260     default : /* bad TPDU */
1261       return -1;
1262       /*NOTREACHED*/
1263       break;
1264   } /* li */
1265
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);
1269
1270   if (tree) {
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);
1279
1280     switch (li) {
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);
1290         break;
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);
1294         break;
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);
1304         break;
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);
1308         break;
1309       default :
1310         break;
1311     } /* li */
1312   } /* tree */
1313
1314   offset += li + 1;
1315
1316   return offset;
1317
1318 } /* osi_decode_EA */
1319
1320 static int osi_decode_ER(const u_char *pd, int offset, 
1321                          frame_data *fd, proto_tree *tree)
1322 {
1323   proto_tree *cotp_tree;
1324   proto_item *ti;
1325   u_char *str;
1326
1327   if (li > LI_MAX_ER) 
1328     return -1;
1329
1330   switch(pd[offset + P_REJECT_ER]) {
1331     case 0 :
1332       str = "Reason not specified";
1333       break;
1334     case 1 :
1335       str = "Invalid parameter code";
1336       break;
1337     case 2 :
1338       str = "Invalid TPDU type";
1339       break;
1340     case 3 :
1341       str = "Invalid parameter value";
1342       break;
1343     default:
1344       return -1;
1345       /*NOTREACHED*/
1346       break;
1347   }
1348
1349   if (check_col(fd, COL_INFO))
1350     col_append_fstr(fd, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1351
1352   if (tree) {
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);
1363   }
1364
1365   offset += li + 1;
1366
1367   return offset;
1368
1369 } /* osi_decode_ER */
1370
1371 /* Returns TRUE if we found at least one valid COTP PDU, FALSE
1372    otherwise. */
1373 static gboolean dissect_cotp_internal(const u_char *pd, int offset,
1374                   frame_data *fd, proto_tree *tree,
1375                   gboolean uses_inactive_subset) 
1376 {
1377   gboolean first_tpdu = TRUE;
1378   int new_offset;
1379   gboolean found_cotp = FALSE;
1380   gboolean subdissector_found = FALSE;
1381
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, "");
1386
1387   while (IS_DATA_IN_FRAME(offset)) {
1388     if (!first_tpdu) {
1389       if (check_col(fd, COL_INFO))
1390         col_append_str(fd, COL_INFO, ", ");
1391     }
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");
1395       if (!first_tpdu)
1396         dissect_data(pd, offset, fd, tree);
1397       return found_cotp;
1398     }
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");
1402       if (!first_tpdu)
1403         dissect_data(pd, offset, fd, tree);
1404       return found_cotp;
1405     }
1406
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]);
1410
1411     switch (tpdu) {
1412       case CC_TPDU :
1413       case CR_TPDU :
1414         new_offset = osi_decode_CC(pd, offset, fd, tree);
1415         break;
1416       case DR_TPDU :
1417         new_offset = osi_decode_DR(pd, offset, fd, tree);
1418         break;
1419       case DT_TPDU :
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 */
1423         break;
1424       case ED_TPDU :
1425         new_offset = osi_decode_ED(pd, offset, fd, tree);
1426         break;
1427       case RJ_TPDU :
1428         new_offset = osi_decode_RJ(pd, offset, fd, tree);
1429         break;
1430       case DC_TPDU :
1431         new_offset = osi_decode_DC(pd, offset, fd, tree);
1432         break;
1433       case AK_TPDU :
1434         new_offset = osi_decode_AK(pd, offset, fd, tree);
1435         break;
1436       case EA_TPDU :
1437         new_offset = osi_decode_EA(pd, offset, fd, tree);
1438         break;
1439       case ER_TPDU :
1440         new_offset = osi_decode_ER(pd, offset, fd, tree);
1441         break;
1442       default      :
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 */
1446         break;
1447     }
1448
1449     if (new_offset == -1) { /* incorrect TPDU */
1450       if (!first_tpdu)
1451         dissect_data(pd, offset, fd, tree);
1452       break;
1453     }
1454
1455     if (first_tpdu) {
1456       /* Well, we found at least one valid COTP PDU, so I guess this
1457          is COTP. */
1458       if (!subdissector_found && check_col(fd, COL_PROTOCOL))
1459         col_add_str(fd, COL_PROTOCOL, "COTP");
1460       found_cotp = TRUE;
1461     }
1462
1463     offset = new_offset;
1464     first_tpdu = FALSE;
1465   }
1466   return found_cotp;
1467 } /* dissect_cotp_internal */
1468
1469 void dissect_cotp(const u_char *pd, int offset, frame_data *fd,
1470                   proto_tree *tree) 
1471 {
1472   if (!dissect_cotp_internal(pd, offset, fd, tree, FALSE))
1473     dissect_data(pd, offset, fd, tree);
1474 }
1475
1476
1477 /*
1478  *  CLNP part / main entry point 
1479 */
1480
1481 void dissect_clnp(const u_char *pd, int offset, frame_data *fd,
1482                   proto_tree *tree) 
1483 {
1484
1485   struct clnp_header clnp;
1486   proto_tree *clnp_tree = NULL;
1487   proto_item *ti;
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;
1494   guint len;
1495
1496   if (check_col(fd, COL_PROTOCOL))
1497     col_add_str(fd, COL_PROTOCOL, "CLNP");
1498
1499   /* avoid alignment problem */
1500   memcpy(&clnp, &pd[offset], sizeof(clnp));
1501
1502   if (clnp.cnf_proto_id == NLPID_NULL) {
1503     if (check_col(fd, COL_INFO))
1504       col_add_str(fd, COL_INFO, "Inactive subset");
1505     if (tree) {
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, 
1509                                  clnp.cnf_proto_id,
1510                                  "Inactive subset");
1511     } 
1512     dissect_cotp_internal(pd, offset+1, fd, tree, TRUE);
1513     return;
1514   } 
1515  
1516   if (!BYTES_ARE_IN_FRAME(offset, sizeof(clnp))) {
1517     dissect_data(pd, offset, fd, tree);
1518     return;
1519   }
1520
1521   /* return if version not known */
1522   if (clnp.cnf_vers != ISO8473_V1) {
1523     dissect_data(pd, offset, fd, tree);
1524     return;
1525   }
1526
1527   /* fixed part decoding */
1528   opt_len = clnp.cnf_hdr_len;
1529
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)");
1540   if (tree) {
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, 
1544                                clnp.cnf_proto_id);
1545     proto_tree_add_item(clnp_tree, hf_clnp_length, offset +  1, 1, 
1546                         clnp.cnf_hdr_len); 
1547     proto_tree_add_item(clnp_tree, hf_clnp_version, offset +  2, 1, 
1548                         clnp.cnf_vers);
1549     proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, offset +  3, 1, 
1550                                clnp.cnf_ttl,
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, 
1554                                clnp.cnf_type,
1555                                "PDU Type     : 0x%02x (%s%s)",
1556                                clnp.cnf_type,
1557                                flag_string,
1558                                pdu_type_string);
1559     proto_tree_add_item(clnp_tree, hf_clnp_pdu_length, offset +  5, 2, 
1560                         segment_length);
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 */
1566   } /* tree */
1567
1568   /* stop here if header is not complete */
1569
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);
1574     return;
1575   }
1576
1577   /* address part */
1578   
1579   offset += P_ADDRESS_PART;
1580   dst_len = pd[offset];
1581   nsel    = pd[offset + dst_len];
1582   src_len = pd[offset + dst_len + 1];
1583
1584   if (tree) {
1585     proto_tree_add_item(clnp_tree, hf_clnp_dest_length, offset, 1, 
1586                         dst_len);
1587     proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, offset + 1 , dst_len, 
1588                                &pd[offset + 1],
1589                                " DA : %s", 
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],
1596                                " SA : %s", 
1597                                print_nsap_net(&pd[offset + dst_len + 2], src_len));
1598
1599     opt_len -= dst_len + src_len +2;
1600   }
1601
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));
1608
1609   /* Segmentation Part */
1610
1611   offset += dst_len + src_len + 2;
1612
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 */
1616     
1617     segment_offset = EXTRACT_SHORT(&pd[offset + 2]);
1618     if (tree) {
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", 
1624                         segment_offset);
1625       proto_tree_add_text(clnp_tree, offset + 4 , 2,
1626                         "Total length        : %6u", 
1627                         EXTRACT_SHORT(&pd[offset + 4]));
1628     }
1629     
1630     offset  += 6;
1631     opt_len -= 6;
1632   }
1633
1634   if (tree) {
1635     /* To do : decode options  */
1636 /*
1637     proto_tree_add_text(clnp_tree, offset, 
1638                         clnp.cnf_hdr_len + first_offset - offset,
1639                         "Options/Data: <not shown>");
1640 */
1641 /* QUICK HACK Option Len:= PDU_Hd_length-( FixedPart+AddresPart+SegmentPart )*/
1642
1643     dissect_osi_options( 0xff, 
1644                          opt_len,
1645                          pd, offset, fd, clnp_tree ); 
1646   }
1647
1648   /* Length of CLNP datagram plus headers above it. */
1649   len = segment_length + first_offset;
1650
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
1653      frame lengths. */
1654   if (pi.len > len)
1655     pi.len = len;
1656   if (pi.captured_len > len)
1657     pi.captured_len = len;
1658
1659   offset = first_offset + clnp.cnf_hdr_len;
1660
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
1666      for CLNP. */
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);
1672     return;
1673   }
1674
1675   if (IS_DATA_IN_FRAME(offset)) {
1676     switch (clnp.cnf_type & CNF_TYPE) {
1677
1678     case DT_NPDU:
1679     case MD_NPDU:
1680       /* Continue with COTP if any data.
1681          XXX - if this isn't the first Derived PDU of a segmented Initial
1682          PDU, skip that? */
1683
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 */
1687       }
1688       break;
1689
1690     case ER_NPDU:
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. */
1696       break;
1697
1698     case ERQ_NPDU:
1699     case ERP_NPDU:
1700       /* XXX - dissect this */
1701       break;
1702     }
1703   }
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);
1707
1708 } /* dissect_clnp */
1709
1710
1711 void proto_register_clnp(void)
1712 {
1713   static hf_register_info hf[] = {
1714     { &hf_clnp_id,
1715       { "Network Layer Protocol Identifier", "clnp.nlpi", FT_UINT8, BASE_HEX, 
1716         VALS(nlpid_vals), 0x0, "" }},
1717
1718     { &hf_clnp_length,
1719       { "HDR Length   ", "clnp.len",       FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1720
1721     { &hf_clnp_version,
1722       { "Version      ", "clnp.version",  FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1723
1724     { &hf_clnp_ttl,
1725       { "Holding Time ", "clnp.ttl",       FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1726
1727     { &hf_clnp_type,
1728       { "PDU Type     ", "clnp.type",     FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1729
1730     { &hf_clnp_pdu_length,
1731       { "PDU length   ", "clnp.pdu.len",  FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
1732
1733     { &hf_clnp_checksum,
1734       { "Checksum     ", "clnp.checksum", FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
1735
1736     { &hf_clnp_dest_length,
1737       { "DAL ", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1738
1739     { &hf_clnp_dest,
1740       { " DA ", "clnp.dsap",     FT_BYTES, BASE_NONE, NULL, 0x0, "" }},
1741
1742     { &hf_clnp_src_length,
1743       { "SAL ", "clnp.ssap.len", FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
1744
1745     { &hf_clnp_src,
1746       { " SA ", "clnp.ssap",     FT_BYTES, BASE_NONE, NULL, 0x0, "" }},
1747   };
1748   static gint *ett[] = {
1749     &ett_clnp,
1750   };
1751
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));
1755 }
1756
1757 void proto_register_cotp(void)
1758 {
1759   /*        static hf_register_info hf[] = {
1760                 { &variable,
1761                 { "Name",           "cotp.abbreviation", TYPE, VALS_POINTER }},
1762         };*/
1763         static gint *ett[] = {
1764                 &ett_cotp,
1765         };
1766
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));
1770 }