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