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