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