1 /* packet-osi-options.c
2 * Routines for the decode of ISO/OSI option part
4 * ISO 8473 CLNP (ConnectionLess Mode Network Service Protocol)
5 * ISO 10589 ISIS (Intradomain Routeing Information Exchange Protocol)
6 * ISO 9542 ESIS (End System To Intermediate System Routeing Exchange Protocol)
8 * $Id: packet-osi-options.c,v 1.3 2000/11/18 10:38:24 guy Exp $
9 * Ralf Schneider <Ralf.Schneider@t-online.de>
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@zing.org>
13 * Copyright 1998 Gerald Combs
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
46 #include "packet-osi.h"
47 #include "packet-isis.h"
48 #include "packet-isis-clv.h"
49 #include "packet-isis-hello.h"
50 #include "packet-isis-lsp.h"
51 #include "packet-isis-snp.h"
52 #include "packet-esis.h"
53 #include "packet-clnp.h"
54 #include "packet-osi-options.h"
56 #define OSI_OPT_SECURITY 0xc5
57 #define OSI_OPT_QOS_MAINTANANCE 0xc3
58 #define OSI_OPT_PRIORITY 0xcd
59 #define OSI_OPT_ADDRESS_MASK 0xe1
60 #define OSI_OPT_SNPA_MASK 0xe2
61 #define OSI_OPT_ES_CONFIG_TIMER 0xc6
63 #define OSI_OPT_MAX_PRIORITY 0x0e
65 #define OSI_OPT_PADDING 0xcc
66 #define OSI_OPT_SOURCE_ROUTING 0xc8
67 #define OSI_OPT_RECORD_OF_ROUTE 0xcb
68 #define OSI_OPT_REASON_OF_DISCARD 0xc1
70 #define OSI_OPT_SEC_MASK 0xc0
71 #define OSI_OPT_SEC_RESERVED 0x00
72 #define OSI_OPT_SEC_SRC_ADR_SPEC 0x40
73 #define OSI_OPT_SEC_DST_ADR_SPEC 0x80
74 #define OSI_OPT_SEC_GLOBAL_UNIQUE 0xc0
76 #define OSI_OPT_QOS_MASK 0xc0
77 #define OSI_OPT_QOS_RESERVED 0x00
78 #define OSI_OPT_QOS_SRC_ADR_SPEC 0x40
79 #define OSI_OPT_QOS_DST_ADR_SPEC 0x80
80 #define OSI_OPT_QOS_GLOBAL_UNIQUE 0xc0
82 #define OSI_OPT_QOS_SUB_MASK 0x3f
83 #define OSI_OPT_QOS_SUB_RSVD 0x20
84 #define OSI_OPT_QOS_SUB_SEQ_VS_TRS 0x10
85 #define OSI_OPT_QOS_SUB_CONG_EXPED 0x08
86 #define OSI_OPT_QOS_SUB_TSD_VS_COST 0x04
87 #define OSI_OPT_QOS_SUB_RESERR_TRS 0x02
88 #define OSI_OPT_QOS_SUB_RESERR_COST 0x01
90 #define OSI_OPT_RFD_GENERAL 0x00
91 #define OSI_OPT_RFD_ADDRESS 0x80
92 #define OSI_OPT_RFD_SOURCE_ROUTEING 0x90
93 #define OSI_OPT_RFD_LIFETIME 0xa0
94 #define OSI_OPT_RFD_PDU_DISCARDED 0xb0
95 #define OSI_OPT_RFD_REASSEMBLY 0xc0
97 #define OSI_OPT_RFD_MASK 0xf0
98 #define OSI_OPT_RFD_SUB_MASK 0x0f
103 static gint ott_osi_options = -1;
104 static gint ott_osi_qos = -1;
105 static gint ott_osi_route = -1;
106 static gint ott_osi_redirect = -1;
108 static const value_string osi_opt_sec_vals[] = {
109 { OSI_OPT_SEC_RESERVED, "Reserved"},
110 { OSI_OPT_SEC_SRC_ADR_SPEC, "Source Address Specific"},
111 { OSI_OPT_SEC_DST_ADR_SPEC, "Destination Address Specific"},
112 { OSI_OPT_SEC_GLOBAL_UNIQUE, "Globally Unique"},
115 static const value_string osi_opt_qos_vals[] = {
116 { OSI_OPT_QOS_RESERVED, "Reserved"},
117 { OSI_OPT_QOS_SRC_ADR_SPEC, "Source Address Specific"},
118 { OSI_OPT_QOS_DST_ADR_SPEC, "Destination Address Specific"},
119 { OSI_OPT_QOS_GLOBAL_UNIQUE, "Globally Unique"},
122 static const value_string osi_opt_qos_sub_vals[] = {
123 { 0x20, " xx10 0000 Reserved"},
124 { 0x10, " xx01 0000 Sequencing versus transit delay"},
125 { 0x08, " xx00 1000 Congestion experienced"},
126 { 0x04, " xx00 0100 Transit delay versus cost"},
127 { 0x02, " xx00 0010 Residual error probability versus transit delay"},
128 { 0x01, " xx00 0001 Residual error probability versus cost"},
131 static const value_string osi_opt_rfd_general[] = {
132 { 0x00, "Reason not specified"},
133 { 0x01, "Protocol procedure error"},
134 { 0x02, "Incorrect checksum"},
135 { 0x03, "PDU discarded due to congestion"},
136 { 0x04, "Header syntax error ( cannot be parsed )"},
137 { 0x05, "Segmentation needed but not permitted"},
138 { 0x06, "Incomplete PDU received"},
139 { 0x07, "Duplicate option"},
142 static const value_string osi_opt_rfd_address[] = {
143 { 0x00, "Destination Address unreachable"},
144 { 0x01, "Destination Address unknown"},
147 static const value_string osi_opt_rfd_src_route[] = {
148 { 0x00, "Unspecified source routeing error"},
149 { 0x01, "Syntax error in source routeing field"},
150 { 0x02, "Unknown address in source routeing field"},
151 { 0x03, "Path not acceptable"},
154 static const value_string osi_opt_rfd_lifetime[] = {
155 { 0x00, "Lifetime expired while data unit in transit"},
156 { 0x01, "Lifetime expired during reassembly"},
159 static const value_string osi_opt_rfd_discarded[] = {
160 { 0x00, "Unsupported option not specified"},
161 { 0x01, "Unsupported protocol version"},
162 { 0x02, "Unsupported security option"},
163 { 0x03, "Unsupported source routeing option"},
164 { 0x04, "Unsupported recording of route option"},
167 static const value_string osi_opt_rfd_reassembly[] = {
168 { 0x00, "Reassembly interference"},
173 dissect_option_qos( const u_char type, const u_char sub_type, u_char offset,
174 u_char len, tvbuff_t *tvb, proto_tree *tree ) {
178 proto_tree *osi_qos_tree = NULL;
181 ti = proto_tree_add_text( tree, NullTVB, offset, len,
182 "Quality of service maintenance: %s",
183 val_to_str( type, osi_opt_qos_vals, "Unknown (0x%x)") );
185 osi_qos_tree = proto_item_add_subtree( ti, ott_osi_qos );
187 if ( OSI_OPT_SEC_MASK == type ) { /* Analye BIT field to get all Values */
189 tmp_type = sub_type & OSI_OPT_QOS_SUB_RSVD;
191 proto_tree_add_text( osi_qos_tree, NullTVB, offset, len,
192 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
194 tmp_type = sub_type & OSI_OPT_QOS_SUB_SEQ_VS_TRS;
196 proto_tree_add_text( osi_qos_tree, NullTVB, offset, len,
197 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
199 tmp_type = sub_type &OSI_OPT_QOS_SUB_CONG_EXPED;
201 proto_tree_add_text( osi_qos_tree, NullTVB, offset, len,
202 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
204 tmp_type = sub_type & OSI_OPT_QOS_SUB_TSD_VS_COST;
207 proto_tree_add_text( osi_qos_tree, NullTVB, offset, len,
208 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
210 tmp_type = sub_type & OSI_OPT_QOS_SUB_RESERR_TRS;
212 proto_tree_add_text( osi_qos_tree, NullTVB, offset, len,
213 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
215 tmp_type = sub_type & OSI_OPT_QOS_SUB_RESERR_COST;
217 proto_tree_add_text( osi_qos_tree, NullTVB, offset, len,
218 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
223 dissect_option_route( u_char parm_type, u_char offset, u_char parm_len,
224 tvbuff_t *tvb, proto_tree *tree ) {
233 proto_tree *osi_route_tree = NULL;
235 static const value_string osi_opt_route[] = {
236 { 0x03, "No Network Entity Titles Recorded Yet"},
237 { 0xff, "Recording Terminated !"},
240 if ( parm_type == OSI_OPT_SOURCE_ROUTING ) {
241 next_hop = tvb_get_guint8(tvb, offset + 1 );
242 netl = tvb_get_guint8(tvb, next_hop + 2 );
243 this_hop = offset + 3; /* points to first netl */
245 ti = proto_tree_add_text( tree, tvb, offset + next_hop, netl,
246 "Source Routing: %s ( Next Hop Highlighted In Data Buffer )",
247 (tvb_get_guint8(tvb, offset) == 0) ? "Partial Source Routeing" :
248 "Complete Source Routeing" );
251 last_hop = tvb_get_guint8(tvb, offset + 1 );
252 /* points to the end of the list */
253 netl = tvb_get_guint8(tvb, last_hop );
254 /* mis-used to highlight buffer */
256 ti = proto_tree_add_text( tree, tvb, offset + next_hop, netl,
257 "Record of Route: %s : %s",
258 (tvb_get_guint8(tvb, offset) == 0) ? "Partial Source Routeing" :
259 "Complete Source Routeing" ,
260 val_to_str( last_hop, osi_opt_route, "Unknown (0x%x" ) );
261 if ( 255 == last_hop )
262 this_hop = parm_len + 1; /* recording terminated, nothing to show */
264 this_hop = offset + 3;
266 osi_route_tree = proto_item_add_subtree( ti, ott_osi_route );
268 while ( this_hop < parm_len ) {
269 netl = tvb_get_guint8(tvb, this_hop + 1);
270 proto_tree_add_text( osi_route_tree, tvb, offset + this_hop, netl,
271 "Hop #%3u NETL: %2u, NET: %s",
274 print_nsap_net( tvb_get_ptr(tvb, this_hop + 1, netl), netl ) );
275 this_hop += 1 + netl;
284 dissect_option_rfd( const u_char error, const u_char field, u_char offset,
285 u_char len, tvbuff_t *tvb, proto_tree *tree ) {
286 u_char error_class = 0;
287 char *format_string[] =
288 { "Reason for discard {General} : %s, in field %u",
289 "Reason for discard {Address} : %s, in field %u",
290 "Reason for discard {Source Routeing}: %s, in field %u",
291 "Reason for discard {Lifetime} : %s, in field %u",
292 "Reason for discard {PDU discarded} : %s, in field %u",
293 "Reason for discard {Reassembly} : %s, in field %u"
296 error_class = error & OSI_OPT_RFD_MASK;
298 if ( OSI_OPT_RFD_GENERAL == error_class ) {
299 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[0],
300 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
301 osi_opt_rfd_general, "Unknown (0x%x)"), field );
303 else if ( OSI_OPT_RFD_ADDRESS == error_class ) {
304 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[1],
305 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
306 osi_opt_rfd_address, "Unknown (0x%x)"), field );
308 else if ( OSI_OPT_RFD_SOURCE_ROUTEING == error_class ) {
309 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[2],
310 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
311 osi_opt_rfd_src_route, "Unknown (0x%x)"), field );
313 else if ( OSI_OPT_RFD_LIFETIME == error_class ) {
314 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[3],
315 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
316 osi_opt_rfd_lifetime, "Unknown (0x%x)"), field );
318 else if ( OSI_OPT_RFD_PDU_DISCARDED == error_class ) {
319 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[4],
320 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
321 osi_opt_rfd_discarded, "Unknown (0x%x)"), field );
323 else if ( OSI_OPT_RFD_REASSEMBLY == error_class ) {
324 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[5],
325 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
326 osi_opt_rfd_reassembly, "Unknown (0x%x)"), field );
329 proto_tree_add_text( tree, tvb, offset, len,
330 "Reason for discard: UNKNOWN Error Class" );
334 /* ############################## Dissection Functions ###################### */
337 * Name: dissect_osi_options()
340 * Main entry area for esis de-mangling. This will build the
341 * main esis tree data and call the sub-protocols as needed.
344 * u_char : PDU type to check if option is allowed or not
345 * u_char : length of option section
346 * u_char * : packet data
347 * int : offset into packet where we are (packet_data[offset]== start
348 * of what we care about)
349 * frame_data * : frame data (whole packet with extra info)
350 * proto_tree * : tree of display data. May be NULL.
353 * void, but we will add to the proto_tree if it is not NULL.
356 dissect_osi_options( u_char pdu_type, u_char opt_len, tvbuff_t *tvb,
357 int offset, packet_info *pinfo, proto_tree *tree) {
359 proto_tree *osi_option_tree = NULL;
361 u_char parm_type = 0;
365 if ( 0 == opt_len ) {
366 proto_tree_add_text( tree, tvb, offset, 0,
367 "### No Options for this PDU ###" );
371 if ( opt_len > END_OF_FRAME ) {
372 proto_tree_add_text( tree, tvb, offset, END_OF_FRAME,
373 "### Options go past the end of the captured data in this PDU ###" );
377 ti = proto_tree_add_text( tree, tvb, offset, opt_len,
378 "### Option Section ###" );
379 osi_option_tree = proto_item_add_subtree( ti, ott_osi_options );
381 while ( 0 < opt_len ) {
382 parm_type = (int) tvb_get_guint8(tvb, offset);
384 parm_len = (int) tvb_get_guint8(tvb, offset);
387 switch ( parm_type ) {
388 case OSI_OPT_QOS_MAINTANANCE:
389 octet = tvb_get_guint8(tvb, offset);
390 dissect_option_qos( octet&OSI_OPT_QOS_MASK,
391 octet&OSI_OPT_QOS_SUB_MASK,
392 offset, parm_len, tvb, osi_option_tree );
394 case OSI_OPT_SECURITY:
395 octet = tvb_get_guint8(tvb, offset);
396 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
398 val_to_str( octet&OSI_OPT_SEC_MASK,
399 osi_opt_sec_vals, "Unknown (0x%x)") );
401 case OSI_OPT_PRIORITY:
402 octet = tvb_get_guint8(tvb, offset);
403 if ( OSI_OPT_MAX_PRIORITY >= octet ) {
404 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
405 "Priority : %u", octet );
408 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
409 "Priority : %u ( Invalid )",
413 case OSI_OPT_ADDRESS_MASK:
414 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
416 print_area( tvb_get_ptr(tvb, offset, parm_len), parm_len ) );
418 case OSI_OPT_SNPA_MASK:
419 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
421 print_system_id( tvb_get_ptr(tvb, offset, parm_len), parm_len ));
423 case OSI_OPT_ES_CONFIG_TIMER:
424 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
425 "ESCT : %u seconds", tvb_get_ntohs( tvb, offset ) );
427 case OSI_OPT_PADDING:
428 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
429 "Padding : %u Octets", parm_len ) ;
431 case OSI_OPT_SOURCE_ROUTING:
432 case OSI_OPT_RECORD_OF_ROUTE:
433 dissect_option_route( parm_type,
434 offset, parm_len, tvb, osi_option_tree );
436 case OSI_OPT_REASON_OF_DISCARD:
437 dissect_option_rfd( tvb_get_guint8(tvb, offset),
438 tvb_get_guint8(tvb, offset + 1),
439 offset, parm_len, tvb, osi_option_tree );
442 opt_len -= parm_len + 2;
446 }; /* dissect-osi-options */
450 * Name: proto_register_osi_options()
453 * main register for esis protocol set. We register some display
454 * formats and the protocol module variables.
456 * NOTE: this procedure to autolinked by the makefile process that
467 proto_register_osi_options(void) {
468 static gint *ott[] = {
474 proto_register_subtree_array( ott, array_length(ott));