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 Routing Information Exchange Protocol)
6 * ISO 9542 ESIS (End System To Intermediate System Routing Exchange Protocol)
8 * $Id: packet-osi-options.c,v 1.14 2002/08/28 21:00:24 jmayer Exp $
9 * Ralf Schneider <Ralf.Schneider@t-online.de>
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@ethereal.com>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 #include <epan/packet.h>
39 #include "packet-osi.h"
40 #include "packet-isis.h"
41 #include "packet-isis-clv.h"
42 #include "packet-isis-hello.h"
43 #include "packet-isis-lsp.h"
44 #include "packet-isis-snp.h"
45 #include "packet-esis.h"
46 #include "packet-osi-options.h"
48 #define OSI_OPT_SECURITY 0xc5
49 #define OSI_OPT_QOS_MAINTANANCE 0xc3
50 #define OSI_OPT_PRIORITY 0xcd
51 #define OSI_OPT_ADDRESS_MASK 0xe1
52 #define OSI_OPT_SNPA_MASK 0xe2
53 #define OSI_OPT_ES_CONFIG_TIMER 0xc6
55 #define OSI_OPT_MAX_PRIORITY 0x0e
57 #define OSI_OPT_PADDING 0xcc
58 #define OSI_OPT_SOURCE_ROUTING 0xc8
59 #define OSI_OPT_RECORD_OF_ROUTE 0xcb
60 #define OSI_OPT_REASON_OF_DISCARD 0xc1
62 #define OSI_OPT_SEC_MASK 0xc0
63 #define OSI_OPT_SEC_RESERVED 0x00
64 #define OSI_OPT_SEC_SRC_ADR_SPEC 0x40
65 #define OSI_OPT_SEC_DST_ADR_SPEC 0x80
66 #define OSI_OPT_SEC_GLOBAL_UNIQUE 0xc0
68 #define OSI_OPT_QOS_MASK 0xc0
69 #define OSI_OPT_QOS_RESERVED 0x00
70 #define OSI_OPT_QOS_SRC_ADR_SPEC 0x40
71 #define OSI_OPT_QOS_DST_ADR_SPEC 0x80
72 #define OSI_OPT_QOS_GLOBAL_UNIQUE 0xc0
74 #define OSI_OPT_QOS_SUB_MASK 0x3f
75 #define OSI_OPT_QOS_SUB_RSVD 0x20
76 #define OSI_OPT_QOS_SUB_SEQ_VS_TRS 0x10
77 #define OSI_OPT_QOS_SUB_CONG_EXPED 0x08
78 #define OSI_OPT_QOS_SUB_TSD_VS_COST 0x04
79 #define OSI_OPT_QOS_SUB_RESERR_TRS 0x02
80 #define OSI_OPT_QOS_SUB_RESERR_COST 0x01
82 #define OSI_OPT_RFD_GENERAL 0x00
83 #define OSI_OPT_RFD_ADDRESS 0x80
84 #define OSI_OPT_RFD_SOURCE_ROUTING 0x90
85 #define OSI_OPT_RFD_LIFETIME 0xa0
86 #define OSI_OPT_RFD_PDU_DISCARDED 0xb0
87 #define OSI_OPT_RFD_REASSEMBLY 0xc0
89 #define OSI_OPT_RFD_MASK 0xf0
90 #define OSI_OPT_RFD_SUB_MASK 0x0f
95 static gint ott_osi_options = -1;
96 static gint ott_osi_qos = -1;
97 static gint ott_osi_route = -1;
98 static gint ott_osi_redirect = -1;
100 static const value_string osi_opt_sec_vals[] = {
101 { OSI_OPT_SEC_RESERVED, "Reserved"},
102 { OSI_OPT_SEC_SRC_ADR_SPEC, "Source Address Specific"},
103 { OSI_OPT_SEC_DST_ADR_SPEC, "Destination Address Specific"},
104 { OSI_OPT_SEC_GLOBAL_UNIQUE, "Globally Unique"},
107 static const value_string osi_opt_qos_vals[] = {
108 { OSI_OPT_QOS_RESERVED, "Reserved"},
109 { OSI_OPT_QOS_SRC_ADR_SPEC, "Source Address Specific"},
110 { OSI_OPT_QOS_DST_ADR_SPEC, "Destination Address Specific"},
111 { OSI_OPT_QOS_GLOBAL_UNIQUE, "Globally Unique"},
114 static const value_string osi_opt_qos_sub_vals[] = {
115 { 0x20, " xx10 0000 Reserved"},
116 { 0x10, " xx01 0000 Sequencing versus transit delay"},
117 { 0x08, " xx00 1000 Congestion experienced"},
118 { 0x04, " xx00 0100 Transit delay versus cost"},
119 { 0x02, " xx00 0010 Residual error probability versus transit delay"},
120 { 0x01, " xx00 0001 Residual error probability versus cost"},
123 static const value_string osi_opt_rfd_general[] = {
124 { 0x00, "Reason not specified"},
125 { 0x01, "Protocol procedure error"},
126 { 0x02, "Incorrect checksum"},
127 { 0x03, "PDU discarded due to congestion"},
128 { 0x04, "Header syntax error ( cannot be parsed )"},
129 { 0x05, "Segmentation needed but not permitted"},
130 { 0x06, "Incomplete PDU received"},
131 { 0x07, "Duplicate option"},
134 static const value_string osi_opt_rfd_address[] = {
135 { 0x00, "Destination Address unreachable"},
136 { 0x01, "Destination Address unknown"},
139 static const value_string osi_opt_rfd_src_route[] = {
140 { 0x00, "Unspecified source routing error"},
141 { 0x01, "Syntax error in source routing field"},
142 { 0x02, "Unknown address in source routing field"},
143 { 0x03, "Path not acceptable"},
146 static const value_string osi_opt_rfd_lifetime[] = {
147 { 0x00, "Lifetime expired while data unit in transit"},
148 { 0x01, "Lifetime expired during reassembly"},
151 static const value_string osi_opt_rfd_discarded[] = {
152 { 0x00, "Unsupported option not specified"},
153 { 0x01, "Unsupported protocol version"},
154 { 0x02, "Unsupported security option"},
155 { 0x03, "Unsupported source routing option"},
156 { 0x04, "Unsupported recording of route option"},
159 static const value_string osi_opt_rfd_reassembly[] = {
160 { 0x00, "Reassembly interference"},
165 dissect_option_qos( const guchar type, const guchar sub_type, int offset,
166 guchar len, tvbuff_t *tvb, proto_tree *tree ) {
170 proto_tree *osi_qos_tree = NULL;
173 ti = proto_tree_add_text( tree, tvb, offset, len,
174 "Quality of service maintenance: %s",
175 val_to_str( type, osi_opt_qos_vals, "Unknown (0x%x)") );
177 osi_qos_tree = proto_item_add_subtree( ti, ott_osi_qos );
179 if ( OSI_OPT_SEC_MASK == type ) { /* Analye BIT field to get all Values */
181 tmp_type = sub_type & OSI_OPT_QOS_SUB_RSVD;
183 proto_tree_add_text( osi_qos_tree, tvb, offset, len,
184 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
186 tmp_type = sub_type & OSI_OPT_QOS_SUB_SEQ_VS_TRS;
188 proto_tree_add_text( osi_qos_tree, tvb, offset, len,
189 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
191 tmp_type = sub_type &OSI_OPT_QOS_SUB_CONG_EXPED;
193 proto_tree_add_text( osi_qos_tree, tvb, offset, len,
194 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
196 tmp_type = sub_type & OSI_OPT_QOS_SUB_TSD_VS_COST;
199 proto_tree_add_text( osi_qos_tree, tvb, offset, len,
200 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
202 tmp_type = sub_type & OSI_OPT_QOS_SUB_RESERR_TRS;
204 proto_tree_add_text( osi_qos_tree, tvb, offset, len,
205 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
207 tmp_type = sub_type & OSI_OPT_QOS_SUB_RESERR_COST;
209 proto_tree_add_text( osi_qos_tree, tvb, offset, len,
210 val_to_str( tmp_type, osi_opt_qos_sub_vals, "Unknown (0x%x)") );
216 dissect_option_route( guchar parm_type, guchar offset, guchar parm_len,
217 tvbuff_t *tvb, proto_tree *tree ) {
226 proto_tree *osi_route_tree = NULL;
228 static const value_string osi_opt_route[] = {
229 { 0x03, "No Network Entity Titles Recorded Yet"},
230 { 0xff, "Recording Terminated !"},
233 if ( parm_type == OSI_OPT_SOURCE_ROUTING ) {
234 next_hop = tvb_get_guint8(tvb, offset + 1 );
235 netl = tvb_get_guint8(tvb, next_hop + 2 );
236 this_hop = offset + 3; /* points to first netl */
238 ti = proto_tree_add_text( tree, tvb, offset + next_hop, netl,
239 "Source Routing: %s ( Next Hop Highlighted In Data Buffer )",
240 (tvb_get_guint8(tvb, offset) == 0) ? "Partial Source Routing" :
241 "Complete Source Routing" );
244 last_hop = tvb_get_guint8(tvb, offset + 1 );
245 /* points to the end of the list */
246 netl = tvb_get_guint8(tvb, last_hop );
247 /* mis-used to highlight buffer */
249 ti = proto_tree_add_text( tree, tvb, offset + next_hop, netl,
250 "Record of Route: %s : %s",
251 (tvb_get_guint8(tvb, offset) == 0) ? "Partial Source Routing" :
252 "Complete Source Routing" ,
253 val_to_str( last_hop, osi_opt_route, "Unknown (0x%x" ) );
254 if ( 255 == last_hop )
255 this_hop = parm_len + 1; /* recording terminated, nothing to show */
257 this_hop = offset + 3;
259 osi_route_tree = proto_item_add_subtree( ti, ott_osi_route );
261 while ( this_hop < parm_len ) {
262 netl = tvb_get_guint8(tvb, this_hop + 1);
263 proto_tree_add_text( osi_route_tree, tvb, offset + this_hop, netl,
264 "Hop #%3u NETL: %2u, NET: %s",
267 print_nsap_net( tvb_get_ptr(tvb, this_hop + 1, netl), netl ) );
268 this_hop += 1 + netl;
277 dissect_option_rfd( const guchar error, const guchar field, guchar offset,
278 guchar len, tvbuff_t *tvb, proto_tree *tree ) {
279 guchar error_class = 0;
280 char *format_string[] =
281 { "Reason for discard {General} : %s, in field %u",
282 "Reason for discard {Address} : %s, in field %u",
283 "Reason for discard {Source Routing}: %s, in field %u",
284 "Reason for discard {Lifetime} : %s, in field %u",
285 "Reason for discard {PDU discarded} : %s, in field %u",
286 "Reason for discard {Reassembly} : %s, in field %u"
289 error_class = error & OSI_OPT_RFD_MASK;
291 if ( OSI_OPT_RFD_GENERAL == error_class ) {
292 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[0],
293 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
294 osi_opt_rfd_general, "Unknown (0x%x)"), field );
296 else if ( OSI_OPT_RFD_ADDRESS == error_class ) {
297 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[1],
298 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
299 osi_opt_rfd_address, "Unknown (0x%x)"), field );
301 else if ( OSI_OPT_RFD_SOURCE_ROUTING == error_class ) {
302 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[2],
303 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
304 osi_opt_rfd_src_route, "Unknown (0x%x)"), field );
306 else if ( OSI_OPT_RFD_LIFETIME == error_class ) {
307 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[3],
308 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
309 osi_opt_rfd_lifetime, "Unknown (0x%x)"), field );
311 else if ( OSI_OPT_RFD_PDU_DISCARDED == error_class ) {
312 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[4],
313 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
314 osi_opt_rfd_discarded, "Unknown (0x%x)"), field );
316 else if ( OSI_OPT_RFD_REASSEMBLY == error_class ) {
317 proto_tree_add_text( tree, tvb, offset + field, 1, format_string[5],
318 val_to_str( error & OSI_OPT_RFD_SUB_MASK,
319 osi_opt_rfd_reassembly, "Unknown (0x%x)"), field );
322 proto_tree_add_text( tree, tvb, offset, len,
323 "Reason for discard: UNKNOWN Error Class" );
327 /* ############################## Dissection Functions ###################### */
330 * Name: dissect_osi_options()
333 * Main entry area for esis de-mangling. This will build the
334 * main esis tree data and call the sub-protocols as needed.
337 * guchar : length of option section
338 * tvbuff_t * : tvbuff containing packet data
339 * int : offset into packet where we are (packet_data[offset]== start
340 * of what we care about)
341 * proto_tree * : tree of display data. May be NULL.
344 * void, but we will add to the proto_tree if it is not NULL.
347 dissect_osi_options( guchar opt_len, tvbuff_t *tvb,
348 int offset, proto_tree *tree) {
350 proto_tree *osi_option_tree = NULL;
352 guchar parm_type = 0;
356 if ( 0 == opt_len ) {
357 proto_tree_add_text( tree, tvb, offset, 0,
358 "### No Options for this PDU ###" );
362 ti = proto_tree_add_text( tree, tvb, offset, opt_len,
363 "### Option Section ###" );
364 osi_option_tree = proto_item_add_subtree( ti, ott_osi_options );
366 while ( 0 < opt_len ) {
367 parm_type = (int) tvb_get_guint8(tvb, offset);
369 parm_len = (int) tvb_get_guint8(tvb, offset);
372 switch ( parm_type ) {
373 case OSI_OPT_QOS_MAINTANANCE:
374 octet = tvb_get_guint8(tvb, offset);
375 dissect_option_qos( octet&OSI_OPT_QOS_MASK,
376 octet&OSI_OPT_QOS_SUB_MASK,
377 offset, parm_len, tvb, osi_option_tree );
379 case OSI_OPT_SECURITY:
380 octet = tvb_get_guint8(tvb, offset);
381 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
383 val_to_str( octet&OSI_OPT_SEC_MASK,
384 osi_opt_sec_vals, "Unknown (0x%x)") );
386 case OSI_OPT_PRIORITY:
387 octet = tvb_get_guint8(tvb, offset);
388 if ( OSI_OPT_MAX_PRIORITY >= octet ) {
389 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
390 "Priority : %u", octet );
393 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
394 "Priority : %u ( Invalid )",
398 case OSI_OPT_ADDRESS_MASK:
399 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
401 print_area( tvb_get_ptr(tvb, offset, parm_len), parm_len ) );
403 case OSI_OPT_SNPA_MASK:
404 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
406 print_system_id( tvb_get_ptr(tvb, offset, parm_len), parm_len ));
408 case OSI_OPT_ES_CONFIG_TIMER:
409 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
410 "ESCT : %u seconds", tvb_get_ntohs( tvb, offset ) );
412 case OSI_OPT_PADDING:
413 proto_tree_add_text( osi_option_tree, tvb, offset, parm_len,
414 "Padding : %u Octets", parm_len ) ;
416 case OSI_OPT_SOURCE_ROUTING:
417 case OSI_OPT_RECORD_OF_ROUTE:
418 dissect_option_route( parm_type,
419 offset, parm_len, tvb, osi_option_tree );
421 case OSI_OPT_REASON_OF_DISCARD:
422 dissect_option_rfd( tvb_get_guint8(tvb, offset),
423 tvb_get_guint8(tvb, offset + 1),
424 offset, parm_len, tvb, osi_option_tree );
427 opt_len -= parm_len + 2;
431 } /* dissect-osi-options */
435 * Name: proto_register_osi_options()
438 * main register for esis protocol set. We register some display
439 * formats and the protocol module variables.
441 * NOTE: this procedure to autolinked by the makefile process that
452 proto_register_osi_options(void) {
453 static gint *ott[] = {
459 proto_register_subtree_array( ott, array_length(ott));