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