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