In the COTP dissector, don't forcibly set the protocol to COTP if we
[obnox/wireshark/wip.git] / packet-osi.c
1 /* packet-osi.c
2  * Routines for ISO/OSI network and transport protocol packet disassembly
3  *
4  * $Id: packet-osi.c,v 1.29 2000/04/15 21:27:12 guy Exp $
5  * Laurent Deniel <deniel@worldnet.fr>
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  *
27  * To do:
28  *
29  * - add other network protocols (ES,IS-IS)
30  * - add NSAP decoding & resolution
31  * - complete CLNP decoding (options)
32  *
33  */
34
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #ifdef HAVE_SYS_TYPES_H
40 # include <sys/types.h>
41 #endif
42
43 #include <stdio.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include <glib.h>
47 #include "packet.h"
48 #include "packet-isis.h"
49 #include "packet-h1.h"
50 #include "nlpid.h"
51
52 /* protocols and fields */
53
54 static int proto_clnp = -1;
55
56 static int hf_clnp_id = -1;
57 static int hf_clnp_length = -1;
58 static int hf_clnp_version = -1;
59 static int hf_clnp_ttl = -1;
60 static int hf_clnp_type = -1;
61 static int hf_clnp_pdu_length = -1;
62 static int hf_clnp_checksum = -1;
63 static int hf_clnp_dest_length = -1;
64 static int hf_clnp_dest = -1;
65 static int hf_clnp_src_length = -1;
66 static int hf_clnp_src = -1;
67
68 static gint ett_clnp = -1;
69
70 static int proto_cotp = -1;
71
72 static gint ett_cotp = -1;
73
74 /*
75  * ISO8473 OSI CLNP definition (see RFC994)
76  *
77  *            _________________________________
78  *           |           Fixed Part            |
79  *           |_________________________________|
80  *           |          Address Part           |
81  *           |_________________________________|
82  *           |   Segmentation Part (optional)  |
83  *           |_________________________________|
84  *           |     Options Part (optional)     |
85  *           |_________________________________|
86  *           |         Data (optional)         |
87  *           |_________________________________|
88  */
89
90 #define ISO8473_V1              0x01    /* CLNP version 1 */
91
92 /* Fixed part */
93
94 struct clnp_header {
95   u_char        cnf_proto_id;   /* network layer protocol identifier */
96   u_char        cnf_hdr_len;    /* length indicator (octets) */
97   u_char        cnf_vers;       /* version/protocol identifier extension */
98   u_char        cnf_ttl;        /* lifetime (500 milliseconds) */
99   u_char        cnf_type;       /* type code */
100   u_char        cnf_seglen_msb; /* pdu segment length (octets) high byte */
101   u_char        cnf_seglen_lsb; /* pdu segment length (octets) low byte */
102   u_char        cnf_cksum_msb;  /* checksum high byte */
103   u_char        cnf_cksum_lsb;  /* checksum low byte */
104 };
105
106 #define CNF_TYPE                0x1f
107 #define CNF_ERR_OK              0x20
108 #define CNF_MORE_SEGS           0x40
109 #define CNF_SEG_OK              0x80
110
111 #define DT_NPDU                 0x1C
112 #define MD_NPDU                 0x1D
113 #define ER_NPDU                 0x01
114 #define ERQ_NPDU                0x1E
115 #define ERP_NPDU                0x1F
116
117 static const value_string npdu_type_vals[] = {
118   { DT_NPDU,    "DT" },
119   { MD_NPDU,    "MD" },
120   { ER_NPDU,    "ER" },
121   { ERQ_NPDU,   "ERQ" },
122   { ERP_NPDU,   "ERP" },
123   { 0,          NULL }
124 };
125
126 /* field position */
127
128 #define P_ADDRESS_PART          9
129
130 /* Segmentation part */
131
132 struct clnp_segment {
133   u_short       cng_id;         /* data unit identifier */
134   u_short       cng_off;        /* segment offset */
135   u_short       cng_tot_len;    /* total length */
136 };
137
138 /* NSAP selector */
139
140 #define NSEL_NET                0x00
141 #define NSEL_NP                 0x20
142 #define NSEL_TP                 0x21
143
144 /*
145  * ISO8073 OSI COTP definition (see RFC905)
146  */
147
148 /* don't use specific TPDU types to avoid alignment problems & copy overhead */
149
150 /* TPDU definition */
151
152 #define ED_TPDU                 0x1
153 #define EA_TPDU                 0x2
154 #define RJ_TPDU                 0x5
155 #define AK_TPDU                 0x6
156 #define ER_TPDU                 0x7
157 #define DR_TPDU                 0x8
158 #define DC_TPDU                 0xC
159 #define CC_TPDU                 0xD
160 #define CR_TPDU                 0xE
161 #define DT_TPDU                 0xF
162
163 /* field position */
164
165 #define P_LI                    0
166 #define P_TPDU                  1
167 #define P_CDT                   1
168 #define P_DST_REF               2
169 #define P_SRC_REF               4
170 #define P_TPDU_NR_0_1           2
171 #define P_TPDU_NR_234           4
172 #define P_VAR_PART_NDT          5
173 #define P_VAR_PART_EDT          8
174 #define P_VAR_PART_NAK          5
175 #define P_VAR_PART_CC           7
176 #define P_VAR_PART_EAK          10
177 #define P_VAR_PART_DC           6
178 #define P_VAR_PART_DR           7
179 #define P_CDT_IN_AK             8
180 #define P_CDT_IN_RJ             8
181 #define P_REJECT_ER             4
182 #define P_REASON_IN_DR          6
183 #define P_CLASS_OPTION          6
184
185 /* TPDU length indicator */
186
187 #define LI_NORMAL_DT_CLASS_01            2
188 #define LI_NORMAL_DT_WITH_CHECKSUM       8
189 #define LI_NORMAL_DT_WITHOUT_CHECKSUM    4
190 #define LI_EXTENDED_DT_WITH_CHECKSUM     11
191 #define LI_EXTENDED_DT_WITHOUT_CHECKSUM  7
192 #define LI_NORMAL_EA_WITH_CHECKSUM       8
193 #define LI_NORMAL_EA_WITHOUT_CHECKSUM    4
194 #define LI_EXTENDED_EA_WITH_CHECKSUM     11
195 #define LI_EXTENDED_EA_WITHOUT_CHECKSUM  7
196 #define LI_NORMAL_RJ                     4
197 #define LI_EXTENDED_RJ                   9
198 #define LI_MIN_DR                        6
199 #define LI_MAX_DC                        9
200 #define LI_MAX_AK                        27
201 #define LI_MAX_EA                        11
202 #define LI_MAX_ER                        8
203 #define LI_DC_WITH_CHECKSUM              9
204 #define LI_DC_WITHOUT_CHECKSUM           5
205 #define is_LI_NORMAL_AK(p)               ( p & 0x01 )
206
207 /* variant part */
208
209 #define VP_ACK_TIME             0x85
210 #define VP_RES_ERROR            0x86
211 #define VP_PRIORITY             0x87
212 #define VP_TRANSIT_DEL          0x88
213 #define VP_THROUGHPUT           0x89
214 #define VP_SEQ_NR               0x8A         /* in AK */
215 #define VP_REASSIGNMENT         0x8B
216 #define VP_FLOW_CNTL            0x8C         /* in AK */
217 #define VP_TPDU_SIZE            0xC0
218 #define VP_SRC_TSAP             0xC1         /* in CR/CC */
219 #define VP_DST_TSAP             0xC2
220 #define VP_CHECKSUM             0xC3
221 #define VP_VERSION_NR           0xC4
222 #define VP_PROTECTION           0xC5
223 #define VP_OPT_SEL              0xC6
224 #define VP_PROTO_CLASS          0xC7
225
226 /* misc */
227
228 #define EXTRACT_SHORT(p)        pntohs(p)
229 #define EXTRACT_LONG(p)         pntohl(p)
230
231 /* global variables */
232
233 static u_char  li, tpdu, cdt;   /* common fields */
234 static u_short dst_ref;
235
236 /* function definitions */
237
238 static int osi_decode_DR(const u_char *pd, int offset, 
239                          frame_data *fd, proto_tree *tree) 
240 {
241   proto_tree *cotp_tree;
242   proto_item *ti;
243   u_short src_ref;
244   u_char  reason;
245   char *str;
246   
247   if (li < LI_MIN_DR) 
248     return -1;
249   
250   src_ref = EXTRACT_SHORT(&pd[offset + P_SRC_REF]);
251   reason  = pd[offset + P_REASON_IN_DR];
252
253   switch(reason) {
254     case (128+0): str = "Normal Disconnect"; break;
255     case (128+1): str = "Remote transport entity congestion"; break;
256     case (128+2): str = "Connection negotiation failed"; break;
257     case (128+3): str = "Duplicate source reference"; break;
258     case (128+4): str = "Mismatched references"; break;
259     case (128+5): str = "Protocol error"; break;
260     case (128+7): str = "Reference overflow"; break;
261     case (128+8): str = "Connection requestion refused"; break;
262     case (128+10):str = "Header or parameter length invalid"; break;
263     case (0):     str = "Reason not specified"; break;
264     case (1):     str = "Congestion at TSAP"; break;
265     case (2):     str = "Session entity not attached to TSAP"; break;
266     case (3):     str = "Address unknown"; break;
267     default:      return -1;
268       /*NOTREACHED*/
269       break;
270   }
271
272   if (check_col(fd, COL_INFO))
273     col_append_fstr(fd, COL_INFO, "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
274                  src_ref, dst_ref);
275
276   if (tree) {
277     ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
278     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
279     proto_tree_add_text(cotp_tree, offset,      1,
280                         "Length indicator: %d", li);
281     proto_tree_add_text(cotp_tree, offset +  1, 1, 
282                         "TPDU code: 0x%x (DR)", tpdu); 
283     proto_tree_add_text(cotp_tree, offset +  2, 2, 
284                         "Destination reference: 0x%04x", dst_ref);
285     proto_tree_add_text(cotp_tree, offset +  4, 2, 
286                         "Source reference: 0x%04x", src_ref);
287     proto_tree_add_text(cotp_tree, offset +  6, 1, 
288                         "Cause: %s", str);
289   }
290
291   offset += li + 1;
292   dissect_data(pd, offset, fd, tree);
293
294   return pi.captured_len;       /* we dissected all of the containing PDU */
295
296 } /* osi_decode_DR */
297
298 /* Returns TRUE if we called a sub-dissector, FALSE if not. */
299 static gboolean osi_decode_DT(const u_char *pd, int offset, 
300                          frame_data *fd, proto_tree *tree,
301                          gboolean uses_inactive_subset)
302 {
303   proto_tree *cotp_tree;
304   proto_item *ti;
305   u_int    tpdu_nr ;
306   u_short  checksum = 0;
307   u_char   code = 0, length = 0;
308   u_int    fragment = 0;
309     
310   switch (li) {
311     case LI_NORMAL_DT_WITH_CHECKSUM      :
312       tpdu_nr = pd[offset + P_TPDU_NR_234];
313       if ( tpdu_nr & 0x80 )
314         tpdu_nr = tpdu_nr & 0x7F;
315       else
316         fragment = 1;
317       code = pd[offset + P_VAR_PART_NDT];
318       if (code == VP_CHECKSUM)
319         checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NDT + 2]);
320       else
321         return -1;
322       break;
323     case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
324       tpdu_nr = pd[offset + P_TPDU_NR_234];
325       if ( tpdu_nr & 0x80 )
326         tpdu_nr = tpdu_nr & 0x7F;
327       else
328         fragment = 1;
329       break;
330     case LI_EXTENDED_DT_WITH_CHECKSUM    :
331       tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
332       if ( tpdu_nr & 0x80000000 )
333         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
334       else
335         fragment = 1;
336       code = pd[offset + P_VAR_PART_EDT];
337       if (code == VP_CHECKSUM)
338         checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EDT + 2]);
339       else
340         return -1;
341       break;
342     case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
343       tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
344       if ( tpdu_nr & 0x80000000 )
345         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
346       else
347         fragment = 1;
348       break;
349     case LI_NORMAL_DT_CLASS_01           :
350       tpdu_nr = pd[offset + P_TPDU_NR_0_1];
351       if ( tpdu_nr & 0x80 )
352         tpdu_nr = tpdu_nr & 0x7F;
353       else
354         fragment = 1;      
355       break;
356     default : /* bad TPDU */
357       return -1;
358       /*NOTREACHED*/
359       break;
360   }
361
362   if (check_col(fd, COL_INFO))
363     col_append_fstr(fd, COL_INFO, "DT TPDU (%d) dst-ref: 0x%04x %s", 
364                  tpdu_nr,
365                  dst_ref,
366                  (fragment)? "(fragment)" : "");
367
368   if (tree) {
369     ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
370     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
371     proto_tree_add_text(cotp_tree, offset,      1,
372                         "Length indicator: %d", li);
373     proto_tree_add_text(cotp_tree, offset +  1, 1, 
374                         "TPDU code: 0x%x (DT)", tpdu); 
375
376     if (li != LI_NORMAL_DT_CLASS_01)
377       proto_tree_add_text(cotp_tree, offset +  2, 2, 
378                           "Destination reference: 0x%04x", dst_ref);
379
380     switch (li) {
381       case LI_NORMAL_DT_WITH_CHECKSUM      :
382         proto_tree_add_text(cotp_tree, offset +  4, 1, 
383                             "TPDU number: 0x%02x (%s)", 
384                             tpdu_nr,
385                             (fragment)? "fragment":"complete");
386         proto_tree_add_text(cotp_tree, 
387                             offset +  P_VAR_PART_NDT, 1, 
388                             "Parameter code: 0x%02x (checksum)", code);
389         proto_tree_add_text(cotp_tree, 
390                             offset +  P_VAR_PART_NDT + 1, 1, 
391                             "Parameter length: %u", length);
392         proto_tree_add_text(cotp_tree, 
393                             offset +  P_VAR_PART_NDT + 2, length, 
394                             "Checksum: 0x%04x", checksum);
395         break;
396       case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
397         proto_tree_add_text(cotp_tree, offset +  4, 1, 
398                             "TPDU number: 0x%02x (%s)", 
399                             tpdu_nr,
400                             (fragment)? "fragment":"complete");
401         break;
402       case LI_EXTENDED_DT_WITH_CHECKSUM    :
403         proto_tree_add_text(cotp_tree, offset +  4, 4, 
404                             "TPDU number: 0x%08x (%s)", 
405                             tpdu_nr,
406                             (fragment)? "fragment":"complete");
407         proto_tree_add_text(cotp_tree, 
408                             offset +  P_VAR_PART_EDT, 1, 
409                             "Parameter code: 0x%02x (checksum)", code);
410         proto_tree_add_text(cotp_tree, 
411                             offset +  P_VAR_PART_EDT + 1, 1, 
412                             "Parameter length: %u", length);
413         proto_tree_add_text(cotp_tree, 
414                             offset +  P_VAR_PART_EDT + 2, length, 
415                             "Checksum: 0x%04x", checksum);
416         break;
417       case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
418         proto_tree_add_text(cotp_tree, offset +  4, 4, 
419                             "TPDU number: 0x%08x (%s)", 
420                             tpdu_nr,
421                             (fragment)? "fragment":"complete");
422         break;
423       case LI_NORMAL_DT_CLASS_01           :
424         proto_tree_add_text(cotp_tree, offset +  2, 1, 
425                             "TPDU number: 0x%02x (%s)", 
426                             tpdu_nr,
427                             (fragment)? "fragment":"complete");
428         break;
429     }
430   } /* tree */
431
432   offset += li + 1;
433   if (uses_inactive_subset){
434         dissect_h1(pd, offset, fd, tree);
435         return TRUE;
436         }
437   else {
438         dissect_data(pd, offset, fd, tree);
439         return FALSE;
440         }
441 } /* osi_decode_DT */
442
443 static int osi_decode_ED(const u_char *pd, int offset, 
444                          frame_data *fd, proto_tree *tree)
445 {
446   proto_tree *cotp_tree;
447   proto_item *ti;
448   u_int    tpdu_nr ;
449   u_short  checksum = 0;
450   u_char   code = 0, length = 0;
451
452   /* ED TPDUs are never fragmented */
453
454   switch (li) {
455     case LI_NORMAL_DT_WITH_CHECKSUM      :
456       tpdu_nr = pd[offset + P_TPDU_NR_234];
457       if ( tpdu_nr & 0x80 )
458         tpdu_nr = tpdu_nr & 0x7F;
459       else
460         return -1;
461       code = pd[offset + P_VAR_PART_NDT];
462       length = pd[offset + P_VAR_PART_NDT + 1];
463       if (code == VP_CHECKSUM)
464         checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NDT + 2]);
465       else
466         return -1;
467       break;
468     case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
469       tpdu_nr = pd[offset + P_TPDU_NR_234];
470       if ( tpdu_nr & 0x80 )
471         tpdu_nr = tpdu_nr & 0x7F;
472       else
473         return -1;
474       break;
475     case LI_EXTENDED_DT_WITH_CHECKSUM    :
476       tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
477       if ( tpdu_nr & 0x80000000 )
478         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
479       else
480         return -1;
481       code = pd[offset + P_VAR_PART_EDT];
482       length = pd[offset + P_VAR_PART_EDT + 1];
483       if (code == VP_CHECKSUM)
484         checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EDT + 2]);
485       else
486         return -1;
487       break;
488     case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
489       tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
490       if ( tpdu_nr & 0x80000000 )
491         tpdu_nr = tpdu_nr & 0x7FFFFFFF;
492       else
493         return -1;
494       break;
495     default : /* bad TPDU */
496       return -1;
497       /*NOTREACHED*/
498       break;
499   } /* li */
500
501   if (check_col(fd, COL_INFO))
502     col_append_fstr(fd, COL_INFO, "ED TPDU (%d) dst-ref: 0x%04x", 
503                  tpdu_nr, dst_ref);
504
505   if (tree) {
506     ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
507     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
508     proto_tree_add_text(cotp_tree, offset,      1,
509                         "Length indicator: %d", li);
510     proto_tree_add_text(cotp_tree, offset +  1, 1, 
511                         "TPDU code: 0x%x (ED)", tpdu); 
512     proto_tree_add_text(cotp_tree, offset +  2, 2, 
513                         "Destination reference: 0x%04x", dst_ref);
514
515     switch (li) {
516       case LI_NORMAL_DT_WITH_CHECKSUM      :
517         proto_tree_add_text(cotp_tree, offset +  4, 1, 
518                             "TPDU number: 0x%02x", tpdu_nr);    
519         proto_tree_add_text(cotp_tree, 
520                             offset +  P_VAR_PART_NDT, 1, 
521                             "Parameter code: 0x%02x (checksum)", code);
522         proto_tree_add_text(cotp_tree, 
523                             offset +  P_VAR_PART_NDT + 1, 1, 
524                             "Parameter length: %u", length);
525         proto_tree_add_text(cotp_tree, 
526                             offset +  P_VAR_PART_NDT + 2, length, 
527                             "Checksum: 0x%04x", checksum);
528         break;
529       case LI_NORMAL_DT_WITHOUT_CHECKSUM   :
530         proto_tree_add_text(cotp_tree, offset +  4, 1, 
531                             "TPDU number: 0x%02x", tpdu_nr);
532         break;
533       case LI_EXTENDED_DT_WITH_CHECKSUM    :
534         proto_tree_add_text(cotp_tree, offset +  4, 4, 
535                             "TPDU number: 0x%02x", tpdu_nr);    
536         proto_tree_add_text(cotp_tree, 
537                             offset +  P_VAR_PART_EDT, 1, 
538                             "Parameter code: 0x%02x (checksum)", code);
539         proto_tree_add_text(cotp_tree, 
540                             offset +  P_VAR_PART_EDT + 1, 1, 
541                             "Parameter length: %u", length);
542         proto_tree_add_text(cotp_tree, 
543                             offset +  P_VAR_PART_EDT + 2, length, 
544                             "Checksum: 0x%04x", checksum);
545         break;
546       case LI_EXTENDED_DT_WITHOUT_CHECKSUM :
547         proto_tree_add_text(cotp_tree, offset +  4, 4, 
548                             "TPDU number: 0x%02x", tpdu_nr);
549         break;
550     }
551   } /* tree */
552
553   offset += li + 1;
554   dissect_data(pd, offset, fd, tree);
555
556   return pi.captured_len;       /* we dissected all of the containing PDU */
557
558 } /* osi_decode_ED */
559
560 static int osi_decode_RJ(const u_char *pd, int offset, 
561                          frame_data *fd, proto_tree *tree)
562 {
563   proto_tree *cotp_tree;
564   proto_item *ti;
565   u_int    tpdu_nr ;
566   u_short  credit = 0;
567
568   switch(li) {
569     case LI_NORMAL_RJ   :
570       tpdu_nr = pd[offset + P_TPDU_NR_234];
571       break;
572     case LI_EXTENDED_RJ :
573       tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
574       credit = EXTRACT_SHORT(&pd[offset + P_CDT_IN_RJ]);
575       break;
576     default :
577       return -1;
578       /*NOTREACHED*/
579       break;
580   }
581
582   if (check_col(fd, COL_INFO))
583     col_append_fstr(fd, COL_INFO, "RJ TPDU (%d) dst-ref: 0x%04x", 
584                  tpdu_nr, dst_ref);
585
586   if (tree) {
587     ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
588     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
589     proto_tree_add_text(cotp_tree, offset,      1,
590                         "Length indicator: %d", li);
591     proto_tree_add_text(cotp_tree, offset +  1, 1, 
592                         "TPDU code: 0x%x (RJ)", tpdu); 
593     if (li == LI_NORMAL_RJ)
594       proto_tree_add_text(cotp_tree, offset +  1, 1, 
595                           "Credit: %d", cdt);
596     proto_tree_add_text(cotp_tree, offset +  2, 2, 
597                         "Destination reference: 0x%04x", dst_ref);
598     if (li == LI_NORMAL_RJ)
599       proto_tree_add_text(cotp_tree, offset +  4, 1, 
600                           "Your TPDU number: 0x%02x", tpdu_nr);
601     else {
602       proto_tree_add_text(cotp_tree, offset +  4, 4, 
603                           "Your TPDU number: 0x%02x", tpdu_nr);
604       proto_tree_add_text(cotp_tree, offset +  8, 2, 
605                           "Credit: 0x%02x", credit);
606     }
607   }
608
609   offset += li + 1;
610
611   return offset;
612
613 } /* osi_decode_RJ */
614
615 #define MAX_TSAP_LEN    32
616
617 static gchar *print_tsap(const u_char *tsap, int length)
618 {
619
620   static gchar  str[3][MAX_TSAP_LEN * 2 + 1];
621   static gchar *cur;
622   gchar tmp[3];
623   gboolean allprintable;
624   int i;
625
626   if (cur == &str[0][0]) {
627     cur = &str[1][0];
628   } else if (cur == &str[1][0]) {  
629     cur = &str[2][0];
630   } else {  
631     cur = &str[0][0];
632   }
633
634
635   cur[0] = '\0';
636   if (length <= 0 || length > MAX_TSAP_LEN) 
637     sprintf(cur, "<unsupported TSAP length>");
638   else {    
639     allprintable=TRUE;
640     for (i=0;i<length;i++) {
641         if (!isprint(tsap[i])) { /* if any byte is not printable */
642           allprintable=FALSE;    /* switch to hexdump */
643           break;
644           }      
645         }
646     if (!allprintable){
647       strcat(cur,"0x");
648       }
649     while (length != 0) {
650       if (allprintable)
651         sprintf(tmp, "%c", *tsap ++);
652       else
653         sprintf(tmp, "%02x", *tsap ++);
654       strcat(cur, tmp);
655       length --;
656     }
657   }
658   return cur;
659
660 } /* print_tsap */
661
662 static int osi_decode_CC(const u_char *pd, int offset, 
663                          frame_data *fd, proto_tree *tree)
664 {
665
666   /* CC & CR decoding in the same function */
667
668   proto_tree *cotp_tree = NULL;
669   proto_item *ti;
670   u_short src_ref, checksum;
671   u_char  class_option, code, length;
672   u_int   i = 0;
673
674   src_ref = EXTRACT_SHORT(&pd[offset + P_SRC_REF]);
675   class_option = (pd[offset + P_CLASS_OPTION] >> 4 ) & 0x0F;
676   if (class_option > 4)
677     return -1;
678
679   if (check_col(fd, COL_INFO))
680     col_append_fstr(fd, COL_INFO, "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
681                  (tpdu == CR_TPDU) ? "CR" : "CC",
682                  src_ref,
683                  dst_ref);
684
685   if (tree) {
686     ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
687     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
688     proto_tree_add_text(cotp_tree, offset,      1,
689                         "Length indicator: %d", li);
690     proto_tree_add_text(cotp_tree, offset +  1, 1, 
691                         "TPDU code: 0x%x (%s)", tpdu,
692                         (tpdu == CR_TPDU) ? "CR" : "CC"); 
693     proto_tree_add_text(cotp_tree, offset +  2, 2, 
694                         "Destination reference: 0x%04x", dst_ref);
695     proto_tree_add_text(cotp_tree, offset +  4, 2, 
696                         "Source reference: 0x%04x", src_ref);
697     proto_tree_add_text(cotp_tree, offset +  6, 1, 
698                         "Class option: 0x%02x", class_option);
699   }
700
701   if (tree)
702     while(li > P_VAR_PART_CC + i - 1) {
703       
704       u_char  c1;
705       u_short s, s1,s2,s3,s4;
706       u_int   t1,t2,t3,t4;
707       
708       switch( (code = pd[offset + P_VAR_PART_CC + i]) ) {
709         case VP_CHECKSUM :
710           length   = pd[offset + P_VAR_PART_CC + i + 1];
711           checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 2]);
712           proto_tree_add_text(cotp_tree, 
713                               offset +  P_VAR_PART_CC + i, 1, 
714                               "Parameter code: 0x%02x (checksum)", code);
715           proto_tree_add_text(cotp_tree, 
716                               offset +  P_VAR_PART_CC + i + 1, 1, 
717                               "Parameter length: %u", length);
718           proto_tree_add_text(cotp_tree, 
719                               offset +  P_VAR_PART_CC + i + 2, length, 
720                               "Checksum: 0x%04x", checksum);
721           i += length + 2;
722           break;
723         case VP_SRC_TSAP    :
724           length = pd[offset + P_VAR_PART_CC + i + 1];
725           proto_tree_add_text(cotp_tree, 
726                               offset +  P_VAR_PART_CC + i, 1, 
727                               "Parameter code: 0x%02x (src-tsap)", code);
728           proto_tree_add_text(cotp_tree, 
729                               offset +  P_VAR_PART_CC + i + 1, 1, 
730                               "Parameter length: %u", length);
731           proto_tree_add_text(cotp_tree, 
732                               offset +  P_VAR_PART_CC + i + 2, length, 
733                               "Calling TSAP: %s", 
734                               print_tsap(&pd[offset + P_VAR_PART_CC + i + 2],
735                                          length));
736           i += length + 2;
737           break;
738         case VP_DST_TSAP    :
739           length = pd[offset + P_VAR_PART_CC + i + 1];
740           proto_tree_add_text(cotp_tree, 
741                               offset +  P_VAR_PART_CC + i, 1, 
742                               "Parameter code: 0x%02x (dst-tsap)", code);
743           proto_tree_add_text(cotp_tree, 
744                               offset +  P_VAR_PART_CC + i + 1, 1, 
745                               "Parameter length: %u", length);
746           proto_tree_add_text(cotp_tree, 
747                               offset +  P_VAR_PART_CC + i + 2, length, 
748                               "Called TSAP: %s", 
749                               print_tsap(&pd[offset + P_VAR_PART_CC + i + 2],
750                                          length));
751           i += length + 2;
752           break;
753         case VP_TPDU_SIZE   :
754           length = pd[offset + P_VAR_PART_CC + i + 1];
755           c1 = pd[offset + P_VAR_PART_CC + i + 2] & 0x0F;
756           proto_tree_add_text(cotp_tree, 
757                               offset +  P_VAR_PART_CC + i, 1, 
758                               "Parameter code: 0x%02x (tpdu-size)", code);
759           proto_tree_add_text(cotp_tree, 
760                               offset +  P_VAR_PART_CC + i + 1, 1, 
761                               "Parameter length: %u", length);
762           proto_tree_add_text(cotp_tree, 
763                               offset +  P_VAR_PART_CC + i + 2, length, 
764                               "TPDU size: %u", 2 << c1);
765           i += length + 2;
766           break;
767         case VP_OPT_SEL     :
768           length = pd[offset + P_VAR_PART_CC + i + 1];
769           c1 = pd[offset + P_VAR_PART_CC + i + 2] & 0x0F;
770           proto_tree_add_text(cotp_tree, 
771                               offset +  P_VAR_PART_CC + i, 1, 
772                               "Parameter code: 0x%02x (options)", code);
773           proto_tree_add_text(cotp_tree, 
774                               offset +  P_VAR_PART_CC + i + 1, 1, 
775                               "Parameter length: %u", length);
776           if (class_option == 1) {
777             if (c1 & 0x8)
778               proto_tree_add_text(cotp_tree, 
779                                   offset +  P_VAR_PART_CC + i + 2, 1,
780                                   "Use of network expedited data");
781             else
782               proto_tree_add_text(cotp_tree, 
783                                   offset +  P_VAR_PART_CC + i + 2, 1,
784                                   "Non use of network expedited data");
785             if (c1 & 0x4)
786               proto_tree_add_text(cotp_tree, 
787                                   offset +  P_VAR_PART_CC + i + 2, 1,
788                                   "Use of Receipt confirmation");
789             else
790               proto_tree_add_text(cotp_tree, 
791                                   offset +  P_VAR_PART_CC + i + 2, 1,
792                                   "Use of explicit AK variant");
793           } else if (class_option == 4) {
794             if (c1 & 0x2)
795               proto_tree_add_text(cotp_tree, 
796                                   offset +  P_VAR_PART_CC + i + 2, 1,
797                                   "Use 16 bit checksum ");
798             else
799               proto_tree_add_text(cotp_tree, 
800                                   offset +  P_VAR_PART_CC + i + 2, 1,
801                                   "Non-use 16 bit checksum in class 4");
802           }
803           if (c1 & 0x1)
804             proto_tree_add_text(cotp_tree, 
805                                 offset +  P_VAR_PART_CC + i + 2, 1,
806                                 "Use of transport expedited data transfer\n");
807           else
808             proto_tree_add_text(cotp_tree, 
809                                 offset +  P_VAR_PART_CC + i + 2, 1,
810                                 "Non-use of transport expedited data transfer");
811           i += length + 2;
812           break;
813         case VP_ACK_TIME    :
814           length = pd[offset + P_VAR_PART_CC + i + 1];
815           s = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 2]);
816           proto_tree_add_text(cotp_tree, 
817                               offset +  P_VAR_PART_CC + i, 1, 
818                               "Parameter code: 0x%02x (ack time)", code);
819           proto_tree_add_text(cotp_tree, 
820                               offset +  P_VAR_PART_CC + i + 1, 1, 
821                               "Parameter length: %u", length);
822           proto_tree_add_text(cotp_tree, 
823                               offset +  P_VAR_PART_CC + i + 2, length, 
824                               "Ack time (ms): %u", s);
825           i += length + 2;
826           break;
827         case VP_THROUGHPUT  :
828           length = pd[offset + P_VAR_PART_CC + i + 1];
829           t1 = EXTRACT_LONG(&pd[offset + P_VAR_PART_CC + i + 1]);
830           t2 = EXTRACT_LONG(&pd[offset + P_VAR_PART_CC + i + 4]);
831           t3 = EXTRACT_LONG(&pd[offset + P_VAR_PART_CC + i + 7]);
832           t4 = EXTRACT_LONG(&pd[offset + P_VAR_PART_CC + i + 10]);
833           proto_tree_add_text(cotp_tree, 
834                               offset +  P_VAR_PART_CC + i, 1, 
835                               "Parameter code: 0x%02x (throughput)", code);
836           proto_tree_add_text(cotp_tree, 
837                               offset +  P_VAR_PART_CC + i + 1, 1, 
838                               "Parameter length: %u", length);
839           proto_tree_add_text(cotp_tree, 
840                               offset +  P_VAR_PART_CC + i + 2, 4, 
841                               "Target value / calling-called: %u o/s", t1);
842           proto_tree_add_text(cotp_tree, 
843                               offset +  P_VAR_PART_CC + i + 6, 4, 
844                               "Minimum / calling-called: %u o/s", t2);
845           proto_tree_add_text(cotp_tree, 
846                               offset +  P_VAR_PART_CC + i + 10, 4, 
847                               "Target value / called-calling: %u o/s", t3);
848           proto_tree_add_text(cotp_tree, 
849                               offset +  P_VAR_PART_CC + i + 14, 4, 
850                               "Minimum / called-calling: %u o/s", t4);
851           i += length + 2;
852           break;
853         case VP_TRANSIT_DEL :
854           length = pd[offset + P_VAR_PART_CC + i + 1];
855           s1 = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 2]);
856           s2 = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 4]);
857           s3 = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 6]);
858           s4 = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 8]);
859           proto_tree_add_text(cotp_tree, 
860                               offset +  P_VAR_PART_CC + i, 1, 
861                               "Parameter code: 0x%02x (transit delay)", code);
862           proto_tree_add_text(cotp_tree, 
863                               offset +  P_VAR_PART_CC + i + 1, 1, 
864                               "Parameter length: %u", length);
865           proto_tree_add_text(cotp_tree, 
866                               offset +  P_VAR_PART_CC + i + 2, 2, 
867                               "Target value / calling-called: %u ms", s1);
868           proto_tree_add_text(cotp_tree, 
869                               offset +  P_VAR_PART_CC + i + 4, 2, 
870                               "Minimum / calling-called: %u ms", s2);
871           proto_tree_add_text(cotp_tree, 
872                               offset +  P_VAR_PART_CC + i + 6, 2, 
873                               "Target value / called-calling: %u ms", s3);
874           proto_tree_add_text(cotp_tree, 
875                               offset +  P_VAR_PART_CC + i + 8, 2, 
876                               "Minimum / called-calling: %u ms", s4);
877           i += length + 2;
878           break;
879         case VP_PRIORITY    :
880           length = pd[offset + P_VAR_PART_CC + i + 1];
881           s = EXTRACT_SHORT(&pd[offset + P_VAR_PART_CC + i + 2]);
882           proto_tree_add_text(cotp_tree, 
883                               offset +  P_VAR_PART_CC + i, 1, 
884                               "Parameter code: 0x%02x (priority)", code);
885           proto_tree_add_text(cotp_tree, 
886                               offset +  P_VAR_PART_CC + i + 1, 1, 
887                               "Parameter length: %u", length);
888           proto_tree_add_text(cotp_tree, 
889                               offset +  P_VAR_PART_CC + i + 2, length,
890                               "Priority: %u", s);
891           i += length + 2;
892           break;
893         
894         case VP_VERSION_NR  :
895           length = pd[offset + P_VAR_PART_CC + i + 1];
896           c1 = pd[offset + P_VAR_PART_CC + i + 2];
897           proto_tree_add_text(cotp_tree, 
898                               offset +  P_VAR_PART_CC + i, 1, 
899                               "Parameter code: 0x%02x (version)", code);
900           proto_tree_add_text(cotp_tree, 
901                               offset +  P_VAR_PART_CC + i + 1, 1, 
902                               "Parameter length: %u", length);
903           proto_tree_add_text(cotp_tree, 
904                               offset +  P_VAR_PART_CC + i + 2, length,
905                               "Version: %u", c1);
906           i += length + 2;
907           break;
908
909         case VP_REASSIGNMENT:     /* todo */
910         case VP_RES_ERROR   :
911         case VP_PROTECTION  :
912         case VP_PROTO_CLASS :
913         default             :     /* no decoding */
914           length = pd[offset + P_VAR_PART_CC + i + 1];
915           proto_tree_add_text(cotp_tree, 
916                               offset +  P_VAR_PART_CC + i + 0, 1, 
917                               "Parameter code: 0x%02x", code);
918           proto_tree_add_text(cotp_tree, 
919                               offset +  P_VAR_PART_CC + i + 1, 1, 
920                               "Parameter length: %u", length);
921           proto_tree_add_text(cotp_tree, 
922                               offset +  P_VAR_PART_CC + i + 2, length, 
923                               "Parameter value: <not shown>");
924           i += length + 2;
925           break; 
926       }
927     } /* while */
928
929   offset += li + 1;
930   dissect_data(pd, offset, fd, tree);
931
932   return pi.captured_len;       /* we dissected all of the containing PDU */
933
934 } /* osi_decode_CC */
935
936 static int osi_decode_DC(const u_char *pd, int offset, 
937                          frame_data *fd, proto_tree *tree)
938 {
939   proto_tree *cotp_tree;
940   proto_item *ti;
941   u_short src_ref, checksum = 0;
942   u_char  length = 0, code = 0;
943
944   if (li > LI_MAX_DC) 
945     return -1;
946
947   src_ref = EXTRACT_SHORT(&pd[offset + P_SRC_REF]);
948
949   switch(li) {
950     case LI_DC_WITHOUT_CHECKSUM :
951       break;
952     case LI_DC_WITH_CHECKSUM :
953       if ((code = pd[offset + P_VAR_PART_DC]) != VP_CHECKSUM) 
954         return -1;
955       length   = pd[offset + P_VAR_PART_DC + 1];
956       checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_DC + 2]);
957       break;
958     default :
959       return -1;
960       /*NOTREACHED*/
961       break;
962   } /* li */
963
964   if (check_col(fd, COL_INFO))
965     col_append_fstr(fd, COL_INFO, "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x", 
966                  src_ref,
967                  dst_ref);
968
969   if (tree) {
970     ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
971     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
972     proto_tree_add_text(cotp_tree, offset,      1,
973                         "Length indicator: %d", li);
974     proto_tree_add_text(cotp_tree, offset +  1, 1, 
975                         "TPDU code: 0x%x (DC)", tpdu); 
976     proto_tree_add_text(cotp_tree, offset +  2, 2, 
977                         "Destination reference: 0x%04x", dst_ref);
978     proto_tree_add_text(cotp_tree, offset +  4, 2, 
979                         "Source reference: 0x%04x", src_ref);
980     if (code) {
981       proto_tree_add_text(cotp_tree, 
982                           offset +  P_VAR_PART_DC + 0, 1, 
983                           "Parameter code: 0x%02x (checksum)", code);
984       proto_tree_add_text(cotp_tree, 
985                           offset +  P_VAR_PART_DC + 1, 1, 
986                           "Parameter length: %u", length);
987       proto_tree_add_text(cotp_tree, 
988                           offset +  P_VAR_PART_DC + 2, 2, 
989                           "Checksum: 0x%04x", checksum);
990     }
991   }
992
993   offset += li + 1;
994
995   return offset;
996
997 } /* osi_decode_DC */
998
999 static int osi_decode_AK(const u_char *pd, int offset, 
1000                          frame_data *fd, proto_tree *tree)
1001 {
1002   proto_tree *cotp_tree = NULL;
1003   proto_item *ti;
1004   u_int      tpdu_nr,i =0, r_lower_window_edge ;
1005   u_short    cdt_in_ak;
1006   u_short    checksum, seq_nr, r_seq_nr, r_cdt;
1007   u_char     code, length;
1008
1009   if (li > LI_MAX_AK) 
1010     return -1;
1011
1012   if (!is_LI_NORMAL_AK(li)) {
1013     tpdu_nr = pd[offset + P_TPDU_NR_234];
1014
1015     if (check_col(fd, COL_INFO))
1016       col_append_fstr(fd, COL_INFO, "AK TPDU (%d) dst-ref: 0x%04x", 
1017                    tpdu_nr, dst_ref);
1018     
1019     if (tree) {
1020       ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
1021       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1022       proto_tree_add_text(cotp_tree, offset,      1,
1023                           "Length indicator: %d", li);
1024       proto_tree_add_text(cotp_tree, offset +  1, 1, 
1025                           "TPDU code: 0x%x (AK)", tpdu); 
1026       proto_tree_add_text(cotp_tree, offset +  1, 1, 
1027                           "Credit: %d", cdt);
1028       proto_tree_add_text(cotp_tree, offset +  2, 2, 
1029                           "Destination reference: 0x%04x", dst_ref);
1030       proto_tree_add_text(cotp_tree, offset +  4, 1, 
1031                           "Your TPDU number: 0x%02x", tpdu_nr);
1032     }
1033
1034     while(li > P_VAR_PART_NAK + i - 1) {
1035       switch( (code = pd[offset + P_VAR_PART_NAK + i]) ) {
1036         case VP_CHECKSUM :
1037           length   = pd[offset + P_VAR_PART_NAK + i + 1];
1038           checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 2]);
1039           if (tree) {
1040             proto_tree_add_text(cotp_tree, 
1041                                 offset +  P_VAR_PART_NAK + i + 0, 1, 
1042                                 "Parameter code: 0x%02x (checksum)", code);
1043             proto_tree_add_text(cotp_tree, 
1044                                 offset +  P_VAR_PART_NAK + i + 1, 1, 
1045                                 "Parameter length: %u", length);
1046             proto_tree_add_text(cotp_tree, 
1047                                 offset +  P_VAR_PART_NAK + i + 2, 2, 
1048                                 "Checksum: 0x%04x", checksum);
1049           }
1050           i += length + 2;
1051           break;
1052         case VP_FLOW_CNTL :
1053           length = pd[offset + P_VAR_PART_NAK + i + 1];
1054           r_lower_window_edge = 
1055             EXTRACT_LONG(&pd[offset + P_VAR_PART_NAK + i + 2]);
1056           r_seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 6]);
1057           r_cdt = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 8]);
1058           if (tree) {
1059             proto_tree_add_text(cotp_tree, 
1060                                 offset +  P_VAR_PART_NAK + i + 0, 1, 
1061                                 "Parameter code: 0x%02x (flow control)", 
1062                                 code);
1063             proto_tree_add_text(cotp_tree, 
1064                                 offset +  P_VAR_PART_NAK + i + 1, 1, 
1065                                 "Parameter length: %u", length);
1066             proto_tree_add_text(cotp_tree, 
1067                                 offset +  P_VAR_PART_NAK + i + 2, 4, 
1068                                 "Lower window edge: 0x%08x", 
1069                                 r_lower_window_edge);
1070             proto_tree_add_text(cotp_tree, 
1071                                 offset +  P_VAR_PART_NAK + i + 6, 2, 
1072                                 "Sequence number: 0x%04x", 
1073                                 r_seq_nr);
1074             proto_tree_add_text(cotp_tree, 
1075                                 offset +  P_VAR_PART_NAK + i + 8, 2, 
1076                                 "Credit: 0x%04x", 
1077                                 r_cdt);
1078           }
1079           i += length + 2;
1080           break;
1081         case VP_SEQ_NR :
1082           length = pd[offset + P_VAR_PART_NAK + i + 1];
1083           seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NAK + i + 2]);
1084           if (tree) {
1085             proto_tree_add_text(cotp_tree, 
1086                                 offset +  P_VAR_PART_NAK + i + 0, 1, 
1087                                 "Parameter code: 0x%02x (seq number)", code);
1088             proto_tree_add_text(cotp_tree, 
1089                                 offset +  P_VAR_PART_NAK + i + 1, 1, 
1090                                 "Parameter length: %u", length);
1091             proto_tree_add_text(cotp_tree, 
1092                                 offset +  P_VAR_PART_NAK + i + 2, 2, 
1093                                 "Sequence number: 0x%04x", seq_nr);
1094           }
1095           i += length + 2;
1096           break;
1097         default :
1098           length = pd[offset + P_VAR_PART_NAK + i + 1];
1099           if (tree) {
1100             proto_tree_add_text(cotp_tree, 
1101                                 offset +  P_VAR_PART_NAK + i + 0, 1, 
1102                                 "Parameter code: 0x%02x (unknown)", code);
1103             proto_tree_add_text(cotp_tree, 
1104                                 offset +  P_VAR_PART_NAK + i + 1, 1, 
1105                                 "Parameter length: %u", length);
1106             proto_tree_add_text(cotp_tree, 
1107                                 offset +  P_VAR_PART_NAK + i + 2, length, 
1108                                 "Parameter value: <not shown>");
1109           }
1110           i += length + 2;
1111           break;
1112       } /* code */
1113     }
1114   } else { /* extended format */
1115     
1116     tpdu_nr   = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
1117     cdt_in_ak = EXTRACT_SHORT(&pd[offset + P_CDT_IN_AK]);
1118
1119     if (check_col(fd, COL_INFO))
1120       col_append_fstr(fd, COL_INFO, "AK TPDU (%d) dst-ref: 0x%04x", 
1121                    tpdu_nr, dst_ref);
1122     
1123     if (tree) {
1124       ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
1125       cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1126       proto_tree_add_text(cotp_tree, offset,      1,
1127                           "Length indicator: %d", li);
1128       proto_tree_add_text(cotp_tree, offset +  1, 1, 
1129                           "TPDU code: 0x%x (AK)", tpdu); 
1130       proto_tree_add_text(cotp_tree, offset +  2, 2, 
1131                           "Destination reference: 0x%04x", dst_ref);
1132       proto_tree_add_text(cotp_tree, offset +  4, 4, 
1133                           "Your TPDU number: 0x%08x", tpdu_nr);
1134       proto_tree_add_text(cotp_tree, offset +  8, 2, 
1135                           "Credit: 0x%04x", cdt_in_ak);
1136     }
1137     
1138     while(li > P_VAR_PART_EAK + i - 1) {
1139       switch( (code = pd[offset + P_VAR_PART_EAK + i]) ) {
1140         case VP_CHECKSUM :
1141           length   = pd[offset + P_VAR_PART_EAK + i + 1];
1142           checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 2]);
1143           if (tree) {
1144             proto_tree_add_text(cotp_tree, 
1145                                 offset +  P_VAR_PART_EAK + i + 0, 1, 
1146                                 "Parameter code: 0x%02x (checksum)", code);
1147             proto_tree_add_text(cotp_tree, 
1148                                 offset +  P_VAR_PART_EAK + i + 1, 1, 
1149                                 "Parameter length: %u", length);
1150             proto_tree_add_text(cotp_tree, 
1151                                 offset +  P_VAR_PART_EAK + i + 2, 2, 
1152                                 "Checksum: 0x%04x", checksum);
1153           }
1154           i += length + 2;
1155           break;
1156         case VP_FLOW_CNTL :
1157           length   = pd[offset + P_VAR_PART_EAK + i + 1];
1158           r_lower_window_edge = 
1159             EXTRACT_LONG(&pd[offset + P_VAR_PART_EAK + i + 2]);
1160           r_seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 6]);
1161           r_cdt = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 8]);
1162           if (tree) {
1163             proto_tree_add_text(cotp_tree, 
1164                                 offset +  P_VAR_PART_EAK + i + 0, 1, 
1165                                 "Parameter code: 0x%02x (flow control)",
1166                                 code);
1167             proto_tree_add_text(cotp_tree, 
1168                                 offset +  P_VAR_PART_EAK + i + 1, 1, 
1169                                 "Parameter length: %u", length);
1170             proto_tree_add_text(cotp_tree, 
1171                                 offset +  P_VAR_PART_EAK + i + 2, 4, 
1172                                 "Lower window edge: 0x%08x", 
1173                                 r_lower_window_edge);
1174             proto_tree_add_text(cotp_tree, 
1175                                 offset +  P_VAR_PART_EAK + i + 6, 2, 
1176                                 "Sequence number: 0x%04x", 
1177                                 r_seq_nr);
1178             proto_tree_add_text(cotp_tree, 
1179                                 offset +  P_VAR_PART_EAK + i + 8, 2, 
1180                                 "Credit: 0x%04x", 
1181                                 r_cdt);
1182           }
1183           i += length + 2;
1184           break;
1185         case VP_SEQ_NR :
1186           length   = pd[offset + P_VAR_PART_EAK + i + 1];
1187           seq_nr = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EAK + i + 2]);
1188           if (tree) {
1189             proto_tree_add_text(cotp_tree, 
1190                                 offset +  P_VAR_PART_EAK + i + 0, 1, 
1191                                 "Parameter code: 0x%02x (seq number)", code);
1192             proto_tree_add_text(cotp_tree, 
1193                                 offset +  P_VAR_PART_EAK + i + 1, 1, 
1194                                 "Parameter length: %u", length);
1195             proto_tree_add_text(cotp_tree, 
1196                                 offset +  P_VAR_PART_EAK + i + 2, 2, 
1197                                 "Sequence number: 0x%04x", seq_nr);
1198           }
1199           i += length + 2;
1200           break;
1201         default :
1202           length   = pd[offset + P_VAR_PART_EAK + i + 1];
1203           if (tree) {
1204             proto_tree_add_text(cotp_tree, 
1205                                 offset +  P_VAR_PART_EAK + i + 0, 1, 
1206                                 "Parameter code: 0x%02x (unknown)", code);
1207             proto_tree_add_text(cotp_tree, 
1208                                 offset +  P_VAR_PART_EAK + i + 1, 1, 
1209                                 "Parameter length: %u", length);
1210             proto_tree_add_text(cotp_tree, 
1211                                 offset +  P_VAR_PART_EAK + i + 2, length, 
1212                                 "Parameter value: <not shown>");
1213           }
1214           i += length + 2;
1215           break;
1216       } /* code */
1217     }
1218     
1219   } /* is_LI_NORMAL_AK */
1220
1221   offset += li + 1;
1222
1223   return offset;
1224
1225 } /* osi_decode_AK */
1226
1227 static int osi_decode_EA(const u_char *pd, int offset, 
1228                          frame_data *fd, proto_tree *tree)
1229 {
1230   proto_tree *cotp_tree;
1231   proto_item *ti;
1232   u_int    tpdu_nr ;
1233   u_short  checksum = 0;
1234   u_char   code = 0;
1235   u_char   length = 0;
1236
1237   if (li > LI_MAX_EA) 
1238     return -1;
1239
1240   switch (li) {
1241     case LI_NORMAL_EA_WITH_CHECKSUM      :
1242       tpdu_nr = pd[offset + P_TPDU_NR_234];
1243       code    = pd[offset + P_VAR_PART_NDT];
1244       length  = pd[offset + P_VAR_PART_NDT + 1];
1245       if (code != VP_CHECKSUM || length != 1)
1246         return -1;
1247       checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_NDT + 2]);
1248       break;
1249     case LI_NORMAL_EA_WITHOUT_CHECKSUM   :
1250       tpdu_nr = pd[offset + P_TPDU_NR_234];
1251       break;
1252     case LI_EXTENDED_EA_WITH_CHECKSUM    :
1253       tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
1254       code    = pd[offset + P_VAR_PART_EDT];
1255       length  = pd[offset + P_VAR_PART_EDT + 1];
1256       if (code != VP_CHECKSUM || length != 1)
1257         return -1;
1258       checksum = EXTRACT_SHORT(&pd[offset + P_VAR_PART_EDT + 2]);
1259       break;
1260     case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1261       tpdu_nr = EXTRACT_LONG(&pd[offset + P_TPDU_NR_234]);
1262       break;
1263     default : /* bad TPDU */
1264       return -1;
1265       /*NOTREACHED*/
1266       break;
1267   } /* li */
1268
1269   if (check_col(fd, COL_INFO))
1270     col_append_fstr(fd, COL_INFO, 
1271                  "EA TPDU (%d) dst-ref: 0x%04x", tpdu_nr, dst_ref);
1272
1273   if (tree) {
1274     ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
1275     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1276     proto_tree_add_text(cotp_tree, offset,      1,
1277                         "Length indicator: %d", li);
1278     proto_tree_add_text(cotp_tree, offset +  1, 1, 
1279                         "TPDU code: 0x%x (EA)", tpdu); 
1280     proto_tree_add_text(cotp_tree, offset +  2, 2, 
1281                         "Destination reference: 0x%04x", dst_ref);
1282
1283     switch (li) {
1284       case LI_NORMAL_EA_WITH_CHECKSUM      :
1285         proto_tree_add_text(cotp_tree, offset +  4, 1, 
1286                             "Your TPDU number: 0x%02x", tpdu_nr);
1287         proto_tree_add_text(cotp_tree, offset +  5, 1, 
1288                             "Parameter code: 0x%02x (checksum)", code);
1289         proto_tree_add_text(cotp_tree, offset +  6, 1, 
1290                             "Parameter length: %u", length);
1291         proto_tree_add_text(cotp_tree, offset +  7, 2, 
1292                             "Checksum: 0x%04x", checksum);
1293         break;
1294       case LI_NORMAL_EA_WITHOUT_CHECKSUM   :
1295         proto_tree_add_text(cotp_tree, offset +  4, 1, 
1296                             "Your TPDU number: 0x%02x", tpdu_nr);
1297         break;
1298       case LI_EXTENDED_EA_WITH_CHECKSUM    :
1299         proto_tree_add_text(cotp_tree, offset +  4, 4, 
1300                             "Your TPDU number: 0x%08x", tpdu_nr);
1301         proto_tree_add_text(cotp_tree, offset +  8, 1, 
1302                             "Parameter code: 0x%02x (checksum)", code);
1303         proto_tree_add_text(cotp_tree, offset +  9, 1, 
1304                             "Parameter length: %u", length);
1305         proto_tree_add_text(cotp_tree, offset +  10, 2, 
1306                             "Checksum: 0x%04x", checksum);
1307         break;
1308       case LI_EXTENDED_EA_WITHOUT_CHECKSUM :
1309         proto_tree_add_text(cotp_tree, offset +  4, 4, 
1310                             "Your TPDU number: 0x%08x", tpdu_nr);
1311         break;
1312       default :
1313         break;
1314     } /* li */
1315   } /* tree */
1316
1317   offset += li + 1;
1318
1319   return offset;
1320
1321 } /* osi_decode_EA */
1322
1323 static int osi_decode_ER(const u_char *pd, int offset, 
1324                          frame_data *fd, proto_tree *tree)
1325 {
1326   proto_tree *cotp_tree;
1327   proto_item *ti;
1328   u_char *str;
1329
1330   if (li > LI_MAX_ER) 
1331     return -1;
1332
1333   switch(pd[offset + P_REJECT_ER]) {
1334     case 0 :
1335       str = "Reason not specified";
1336       break;
1337     case 1 :
1338       str = "Invalid parameter code";
1339       break;
1340     case 2 :
1341       str = "Invalid TPDU type";
1342       break;
1343     case 3 :
1344       str = "Invalid parameter value";
1345       break;
1346     default:
1347       return -1;
1348       /*NOTREACHED*/
1349       break;
1350   }
1351
1352   if (check_col(fd, COL_INFO))
1353     col_append_fstr(fd, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
1354
1355   if (tree) {
1356     ti = proto_tree_add_item(tree, proto_cotp, offset, li + 1, NULL);
1357     cotp_tree = proto_item_add_subtree(ti, ett_cotp);
1358     proto_tree_add_text(cotp_tree, offset,      1,
1359                         "Length indicator: %d", li);
1360     proto_tree_add_text(cotp_tree, offset +  1, 1, 
1361                         "TPDU code: 0x%x (ER)", tpdu); 
1362     proto_tree_add_text(cotp_tree, offset +  2, 2, 
1363                         "Destination reference: 0x%04x", dst_ref);
1364     proto_tree_add_text(cotp_tree, offset +  4, 1, 
1365                         "Reject cause: %s", str);
1366   }
1367
1368   offset += li + 1;
1369
1370   return offset;
1371
1372 } /* osi_decode_ER */
1373
1374 /* Returns TRUE if we found at least one valid COTP PDU, FALSE
1375    otherwise. */
1376 static gboolean dissect_cotp_internal(const u_char *pd, int offset,
1377                   frame_data *fd, proto_tree *tree,
1378                   gboolean uses_inactive_subset) 
1379 {
1380   gboolean first_tpdu = TRUE;
1381   int new_offset;
1382   gboolean found_cotp = FALSE;
1383   gboolean subdissector_found = FALSE;
1384
1385   /* Initialize the COL_INFO field; each of the TPDUs will have its
1386      information appended. */
1387   if (check_col(fd, COL_INFO))
1388     col_add_str(fd, COL_INFO, "");
1389
1390   while (IS_DATA_IN_FRAME(offset)) {
1391     if (!first_tpdu) {
1392       if (check_col(fd, COL_INFO))
1393         col_append_str(fd, COL_INFO, ", ");
1394     }
1395     if ((li = pd[offset + P_LI]) == 0) {
1396       if (check_col(fd, COL_INFO))
1397         col_append_str(fd, COL_INFO, "Length indicator is zero");
1398       if (!first_tpdu)
1399         dissect_data(pd, offset, fd, tree);
1400       return found_cotp;
1401     }
1402     if (!BYTES_ARE_IN_FRAME(offset, P_LI + li + 1)) {
1403       if (check_col(fd, COL_INFO))
1404         col_append_str(fd, COL_INFO, "Captured data in frame doesn't include entire frame");
1405       if (!first_tpdu)
1406         dissect_data(pd, offset, fd, tree);
1407       return found_cotp;
1408     }
1409
1410     tpdu    = (pd[offset + P_TPDU] >> 4) & 0x0F;
1411     cdt     = pd[offset + P_CDT] & 0x0F;
1412     dst_ref = EXTRACT_SHORT(&pd[offset + P_DST_REF]);
1413
1414     switch (tpdu) {
1415       case CC_TPDU :
1416       case CR_TPDU :
1417         new_offset = osi_decode_CC(pd, offset, fd, tree);
1418         break;
1419       case DR_TPDU :
1420         new_offset = osi_decode_DR(pd, offset, fd, tree);
1421         break;
1422       case DT_TPDU :
1423         if (osi_decode_DT(pd, offset, fd, tree, uses_inactive_subset))
1424           subdissector_found = TRUE;
1425         new_offset = pi.captured_len;   /* DT PDUs run to the end of the packet */
1426         break;
1427       case ED_TPDU :
1428         new_offset = osi_decode_ED(pd, offset, fd, tree);
1429         break;
1430       case RJ_TPDU :
1431         new_offset = osi_decode_RJ(pd, offset, fd, tree);
1432         break;
1433       case DC_TPDU :
1434         new_offset = osi_decode_DC(pd, offset, fd, tree);
1435         break;
1436       case AK_TPDU :
1437         new_offset = osi_decode_AK(pd, offset, fd, tree);
1438         break;
1439       case EA_TPDU :
1440         new_offset = osi_decode_EA(pd, offset, fd, tree);
1441         break;
1442       case ER_TPDU :
1443         new_offset = osi_decode_ER(pd, offset, fd, tree);
1444         break;
1445       default      :
1446         if (first_tpdu && check_col(fd, COL_INFO))
1447           col_append_fstr(fd, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
1448         new_offset = -1;        /* bad PDU type */
1449         break;
1450     }
1451
1452     if (new_offset == -1) { /* incorrect TPDU */
1453       if (!first_tpdu)
1454         dissect_data(pd, offset, fd, tree);
1455       break;
1456     }
1457
1458     if (first_tpdu) {
1459       /* Well, we found at least one valid COTP PDU, so I guess this
1460          is COTP. */
1461       if (!subdissector_found && check_col(fd, COL_PROTOCOL))
1462         col_add_str(fd, COL_PROTOCOL, "COTP");
1463       found_cotp = TRUE;
1464     }
1465
1466     offset = new_offset;
1467     first_tpdu = FALSE;
1468   }
1469   return found_cotp;
1470 } /* dissect_cotp_internal */
1471
1472 void dissect_cotp(const u_char *pd, int offset, frame_data *fd,
1473                   proto_tree *tree) 
1474 {
1475   if (!dissect_cotp_internal(pd, offset, fd, tree, FALSE))
1476     dissect_data(pd, offset, fd, tree);
1477 }
1478
1479
1480 /*
1481  *  CLNP part 
1482  */
1483
1484 #define MAX_NSAP_LEN    20
1485
1486 static gchar *print_nsap(const u_char *nsap, int length)
1487 {
1488
1489   /* to do : real NSAP decoding */
1490
1491   static gchar  str[3][MAX_NSAP_LEN * 3 + 1];
1492   static gchar *cur;
1493   gchar tmp[5];
1494
1495   if (cur == &str[0][0]) {
1496     cur = &str[1][0];
1497   } else if (cur == &str[1][0]) {  
1498     cur = &str[2][0];
1499   } else {  
1500     cur = &str[0][0];
1501   }
1502
1503   cur[0] = '\0';
1504   if (length <= 0 || length > MAX_NSAP_LEN) 
1505     sprintf(cur, "<invalid NSAP>");
1506   else
1507     while (length != 1) {
1508       sprintf(tmp, "%02x:", *nsap ++);
1509       strcat(cur, tmp);
1510       length --;
1511     }
1512   sprintf(tmp, "%02x", *nsap);
1513   strcat(cur, tmp);
1514   return cur;
1515
1516 } /* print_nsap */
1517
1518 void dissect_clnp(const u_char *pd, int offset, frame_data *fd,
1519                   proto_tree *tree) 
1520 {
1521
1522   struct clnp_header clnp;
1523   proto_tree *clnp_tree = NULL;
1524   proto_item *ti;
1525   u_char src_len, dst_len, nsel;
1526   u_int first_offset = offset;
1527   char flag_string[6+1];
1528   char *pdu_type_string;
1529   guint16 segment_length;
1530   guint16 segment_offset = 0;
1531   guint len;
1532
1533   if (check_col(fd, COL_PROTOCOL))
1534     col_add_str(fd, COL_PROTOCOL, "CLNP");
1535
1536   /* avoid alignment problem */
1537   memcpy(&clnp, &pd[offset], sizeof(clnp));
1538
1539   if (clnp.cnf_proto_id == NLPID_NULL) {
1540     if (check_col(fd, COL_INFO))
1541       col_add_str(fd, COL_INFO, "Inactive subset");
1542     if (tree) {
1543       ti = proto_tree_add_item(tree, proto_clnp, offset, 1, NULL);
1544       clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1545       proto_tree_add_uint_format(clnp_tree, hf_clnp_id, offset, 1, 
1546                                  clnp.cnf_proto_id,
1547                                  "Inactive subset");
1548     } 
1549     dissect_cotp_internal(pd, offset+1, fd, tree, TRUE);
1550     return;
1551   } 
1552  
1553   if (!BYTES_ARE_IN_FRAME(offset, sizeof(clnp))) {
1554     dissect_data(pd, offset, fd, tree);
1555     return;
1556   }
1557
1558   /* return if version not known */
1559   if (clnp.cnf_vers != ISO8473_V1) {
1560     dissect_data(pd, offset, fd, tree);
1561     return;
1562   }
1563
1564   /* fixed part decoding */
1565
1566   segment_length = EXTRACT_SHORT(&clnp.cnf_seglen_msb);
1567   flag_string[0] = '\0';
1568   if (clnp.cnf_type & CNF_SEG_OK)
1569     strcat(flag_string, "S ");
1570   if (clnp.cnf_type & CNF_MORE_SEGS)
1571     strcat(flag_string, "M ");
1572   if (clnp.cnf_type & CNF_ERR_OK)
1573     strcat(flag_string, "E ");
1574   pdu_type_string = val_to_str(clnp.cnf_type & CNF_TYPE, npdu_type_vals,
1575                                 "Unknown (0x%02x)");
1576   if (tree) {
1577     ti = proto_tree_add_item(tree, proto_clnp, offset, clnp.cnf_hdr_len, NULL);
1578     clnp_tree = proto_item_add_subtree(ti, ett_clnp);
1579     proto_tree_add_item(clnp_tree, hf_clnp_id, offset, 1, 
1580                                clnp.cnf_proto_id);
1581     proto_tree_add_item(clnp_tree, hf_clnp_length, offset +  1, 1, 
1582                         clnp.cnf_hdr_len); 
1583     proto_tree_add_item(clnp_tree, hf_clnp_version, offset +  2, 1, 
1584                         clnp.cnf_vers);
1585     proto_tree_add_uint_format(clnp_tree, hf_clnp_ttl, offset +  3, 1, 
1586                                clnp.cnf_ttl,
1587                                "TTL: %d (%d secs)", 
1588                                clnp.cnf_ttl, clnp.cnf_ttl / 2);
1589     proto_tree_add_uint_format(clnp_tree, hf_clnp_type, offset +  4, 1, 
1590                                clnp.cnf_type,
1591                                "Type code: 0x%02x (%s%s)",
1592                                clnp.cnf_type,
1593                                flag_string,
1594                                pdu_type_string);
1595     proto_tree_add_item(clnp_tree, hf_clnp_pdu_length, offset +  5, 2, 
1596                         segment_length);
1597     proto_tree_add_uint_format(clnp_tree, hf_clnp_checksum, offset +  7, 2,
1598                                EXTRACT_SHORT(&clnp.cnf_cksum_msb),
1599                                "Checksum: 0x%04x",
1600                                EXTRACT_SHORT(&clnp.cnf_cksum_msb));
1601   } /* tree */
1602
1603   /* stop here if header is not complete */
1604
1605   if (!BYTES_ARE_IN_FRAME(offset, clnp.cnf_hdr_len)) {
1606     if (check_col(fd, COL_INFO))
1607       col_add_fstr(fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1608     dissect_data(pd, offset, fd, tree);
1609     return;
1610   }
1611
1612   /* address part */
1613   
1614   offset += P_ADDRESS_PART;
1615   dst_len = pd[offset];
1616   nsel    = pd[offset + dst_len];
1617   src_len = pd[offset + dst_len + 1];
1618
1619   if (tree) {
1620     proto_tree_add_item(clnp_tree, hf_clnp_dest_length, offset, 1, 
1621                         dst_len);
1622     proto_tree_add_bytes_format(clnp_tree, hf_clnp_dest, offset + 1 , dst_len, 
1623                                &pd[offset + 1],
1624                                "Destination address: %s", 
1625                                print_nsap(&pd[offset + 1], dst_len));
1626     proto_tree_add_item(clnp_tree, hf_clnp_src_length, 
1627                         offset + 1 + dst_len, 1, src_len);
1628     proto_tree_add_bytes_format(clnp_tree, hf_clnp_src, 
1629                                offset + dst_len + 2, src_len,
1630                                &pd[offset + dst_len + 2],
1631                                "Source address: %s", 
1632                                print_nsap(&pd[offset + dst_len + 2], src_len));
1633   }
1634
1635   if (check_col(fd, COL_RES_NET_SRC))
1636     col_add_fstr(fd, COL_RES_NET_SRC, "%s", 
1637                  print_nsap(&pd[offset + dst_len + 2], src_len));
1638   if (check_col(fd, COL_RES_NET_DST))
1639     col_add_fstr(fd, COL_RES_NET_DST, "%s", 
1640                  print_nsap(&pd[offset + 1], dst_len));
1641
1642   /* Segmentation Part */
1643
1644   offset += dst_len + src_len + 2;
1645
1646   if (clnp.cnf_type & CNF_SEG_OK) {
1647     struct clnp_segment seg;                    /* XXX - not used */
1648     memcpy(&seg, &pd[offset], sizeof(seg));     /* XXX - not used */
1649     
1650     segment_offset = EXTRACT_SHORT(&pd[offset + 2]);
1651     if (tree) {
1652       proto_tree_add_text(clnp_tree, offset, 2, 
1653                         "Data unit identifier: 0x%04x",
1654                         EXTRACT_SHORT(&pd[offset]));
1655       proto_tree_add_text(clnp_tree, offset + 2 , 2,
1656                         "Segment offset: %u", 
1657                         segment_offset);
1658       proto_tree_add_text(clnp_tree, offset + 4 , 2,
1659                         "Total length: %u", 
1660                         EXTRACT_SHORT(&pd[offset + 4]));
1661     }
1662     
1663     offset += 6;
1664   }
1665
1666   if (tree) {
1667     /* To do : decode options  */
1668
1669     proto_tree_add_text(clnp_tree, offset, 
1670                         clnp.cnf_hdr_len + first_offset - offset,
1671                         "Options/Data: <not shown>");
1672   }
1673
1674   /* Length of CLNP datagram plus headers above it. */
1675   len = segment_length + first_offset;
1676
1677   /* Set the payload and captured-payload lengths to the minima of (the
1678      datagram length plus the length of the headers above it) and the
1679      frame lengths. */
1680   if (pi.len > len)
1681     pi.len = len;
1682   if (pi.captured_len > len)
1683     pi.captured_len = len;
1684
1685   offset = first_offset + clnp.cnf_hdr_len;
1686
1687   /* For now, dissect the payload of segments other than the initial
1688      segment as data, rather than handing them off to the transport
1689      protocol, just as we do with fragments other than the first
1690      fragment in a fragmented IP datagram; in the future, we will
1691      probably reassemble fragments for IP, and may reassemble segments
1692      for CLNP. */
1693   if ((clnp.cnf_type & CNF_SEG_OK) && segment_offset != 0) {
1694     if (check_col(fd, COL_INFO))
1695       col_add_fstr(fd, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
1696                 pdu_type_string, flag_string, segment_offset);
1697     dissect_data(pd, offset, fd, tree);
1698     return;
1699   }
1700
1701   if (IS_DATA_IN_FRAME(offset)) {
1702     switch (clnp.cnf_type & CNF_TYPE) {
1703
1704     case DT_NPDU:
1705     case MD_NPDU:
1706       /* Continue with COTP if any data.
1707          XXX - if this isn't the first Derived PDU of a segmented Initial
1708          PDU, skip that? */
1709
1710       if (nsel == NSEL_TP) {    /* just guessing here - valid for DECNet-OSI */
1711         if (dissect_cotp_internal(pd, offset, fd, tree, FALSE))
1712           return;       /* yes, it appears to be COTP */
1713       }
1714       break;
1715
1716     case ER_NPDU:
1717       /* The payload is the header and "none, some, or all of the data
1718          part of the discarded PDU", i.e. it's like an ICMP error;
1719          just as we don't yet trust ourselves to be able to dissect
1720          the payload of an ICMP error packet, we don't yet trust
1721          ourselves to dissect the payload of a CLNP ER packet. */
1722       break;
1723
1724     case ERQ_NPDU:
1725     case ERP_NPDU:
1726       /* XXX - dissect this */
1727       break;
1728     }
1729   }
1730   if (check_col(fd, COL_INFO))
1731     col_add_fstr(fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
1732   dissect_data(pd, offset, fd, tree);
1733
1734 } /* dissect_clnp */
1735
1736
1737 /* main entry point */
1738
1739 const value_string nlpid_vals[] = {
1740         { NLPID_NULL,            "NULL" },
1741         { NLPID_T_70,            "T.70" },
1742         { NLPID_X_633,           "X.633" },
1743         { NLPID_Q_931,           "Q.931" },
1744         { NLPID_Q_2931,          "Q.2931" },
1745         { NLPID_Q_2119,          "Q.2119" },
1746         { NLPID_SNAP,            "SNAP" },
1747         { NLPID_ISO8473_CLNP,    "CLNP" },
1748         { NLPID_ISO9542_ESIS,    "ESIS" },
1749         { NLPID_ISO10589_ISIS,   "ISIS" },
1750         { NLPID_ISO10747,        "ISO 10747" },
1751         { NLPID_ISO9542X25_ESIS, "ESIS (X.25)" },
1752         { NLPID_ISO10030,        "ISO 10030" },
1753         { NLPID_ISO11577,        "ISO 11577" },
1754         { NLPID_IP,              "IP" },
1755         { NLPID_PPP,             "PPP" },
1756         { 0,                     NULL },
1757 };
1758
1759 void dissect_osi(const u_char *pd, int offset, frame_data *fd, 
1760                  proto_tree *tree) 
1761 {
1762
1763   switch (pd[offset]) {
1764
1765     /* ESIS is not currently decoded */
1766
1767     case NLPID_ISO8473_CLNP:
1768     case NLPID_NULL:    /* "Inactive Subset" of ISO 8473 CLNP */
1769       dissect_clnp(pd, offset, fd, tree);
1770       break;
1771     case NLPID_ISO9542_ESIS:
1772       if (check_col(fd, COL_PROTOCOL)) {
1773         col_add_str(fd, COL_PROTOCOL, "ESIS");
1774       }
1775       dissect_data(pd, offset, fd, tree);
1776       break;
1777     case NLPID_ISO9542X25_ESIS:
1778       if (check_col(fd, COL_PROTOCOL)) {
1779         col_add_str(fd, COL_PROTOCOL, "ESIS (X.25)");
1780       }
1781       dissect_data(pd, offset, fd, tree);
1782       break;
1783     case NLPID_ISO10589_ISIS:
1784       dissect_isis(pd, offset, fd, tree);
1785       break;
1786     default:
1787       if (check_col(fd, COL_PROTOCOL)) {
1788         col_add_str(fd, COL_PROTOCOL, "ISO");
1789       }
1790       if (check_col(fd, COL_INFO)) {
1791         col_add_fstr(fd, COL_INFO, "Unknown ISO protocol (%02x)", pd[offset]);
1792       }
1793       dissect_data(pd, offset, fd, tree);
1794       break;
1795   }
1796   
1797 } /* dissect_osi */
1798
1799 void proto_register_clnp(void)
1800 {
1801   static hf_register_info hf[] = {
1802     { &hf_clnp_id,
1803       { "Protocol identifier",  "clnp.id",      FT_UINT8, BASE_HEX, VALS(nlpid_vals), 0x0,
1804         "" }},
1805
1806     { &hf_clnp_length,
1807       { "Length",               "clnp.len",     FT_UINT8, BASE_DEC, NULL, 0x0,
1808         "" }},
1809
1810     { &hf_clnp_version,
1811       { "Version",              "clnp.version", FT_UINT8, BASE_DEC, NULL, 0x0,
1812         "" }},
1813
1814     { &hf_clnp_ttl,
1815       { "TTL",                  "clnp.ttl",     FT_UINT8, BASE_DEC, NULL, 0x0,
1816         "" }},
1817
1818     { &hf_clnp_type,
1819       { "Type code",            "clnp.type",    FT_UINT8, BASE_DEC, NULL, 0x0,
1820         "" }},
1821
1822     { &hf_clnp_pdu_length,
1823       { "PDU segment length",   "clnp.pdu.len", FT_UINT16, BASE_DEC, NULL, 0x0,
1824         "" }},
1825
1826     { &hf_clnp_checksum,
1827       { "Checksum",             "clnp.checksum",FT_UINT16, BASE_DEC, NULL, 0x0,
1828         "" }},
1829
1830     { &hf_clnp_dest_length,
1831       { "Destination address length", "clnp.dsap.len", FT_UINT8, BASE_DEC, NULL, 0x0,
1832         "" }},
1833
1834     { &hf_clnp_dest,
1835       { "Destination address",  "clnp.dsap",    FT_BYTES, BASE_NONE, NULL, 0x0,
1836         "" }},
1837
1838     { &hf_clnp_src_length,
1839       { "Source address length","clnp.ssap.len",FT_UINT8, BASE_DEC, NULL, 0x0,
1840         "" }},
1841
1842     { &hf_clnp_src,
1843       { "Source address",       "clnp.ssap",    FT_BYTES, BASE_NONE, NULL, 0x0,
1844         "" }},
1845   };
1846   static gint *ett[] = {
1847     &ett_clnp,
1848   };
1849
1850   proto_clnp = proto_register_protocol("ISO CLNP", "clnp");
1851   proto_register_field_array(proto_clnp, hf, array_length(hf));
1852   proto_register_subtree_array(ett, array_length(ett));
1853 }
1854
1855 void proto_register_cotp(void)
1856 {
1857   /*        static hf_register_info hf[] = {
1858                 { &variable,
1859                 { "Name",           "cotp.abbreviation", TYPE, VALS_POINTER }},
1860         };*/
1861         static gint *ett[] = {
1862                 &ett_cotp,
1863         };
1864
1865         proto_cotp = proto_register_protocol("ISO COTP", "cotp");
1866  /*       proto_register_field_array(proto_cotp, hf, array_length(hf));*/
1867         proto_register_subtree_array(ett, array_length(ett));
1868 }