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