X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=packet-x25.c;h=3e0dfaee087246dfda5d4f7c21344c6f275dbdfa;hb=c695bcdfafb10c7646c323f3fc00a52365f3c7ee;hp=0d8fe93df1b6d96039996edf4891988943c28969;hpb=2b60eb9a61d2e2e678dfd05c604ba732cf881eea;p=obnox%2Fwireshark%2Fwip.git diff --git a/packet-x25.c b/packet-x25.c index 0d8fe93df1..3e0dfaee08 100644 --- a/packet-x25.c +++ b/packet-x25.c @@ -2,12 +2,11 @@ * Routines for x25 packet disassembly * Olivier Abad * - * $Id: packet-x25.c,v 1.33 2000/07/01 08:55:28 guy Exp $ + * $Id: packet-x25.c,v 1.64 2002/01/24 09:20:53 guy Exp $ * * Ethereal - Network traffic analyzer - * By Gerald Combs + * By Gerald Combs * Copyright 1998 - * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -36,13 +35,11 @@ #include #include #include -#include "etypes.h" -#include "packet.h" -#include "packet-x25.h" -#include "packet-ip.h" -#include "packet-osi.h" -#include "packet-clnp.h" +#include "llcsaps.h" +#include +#include "prefs.h" #include "nlpid.h" +#include "x264_prt_id.h" #define FROM_DCE 0x80 @@ -92,25 +89,22 @@ #define X25_FAC_PRIORITY 0xD2 static int proto_x25 = -1; +static int hf_x25_gfi = -1; +static int hf_x25_abit = -1; static int hf_x25_qbit = -1; static int hf_x25_dbit = -1; static int hf_x25_mod = -1; static int hf_x25_lcn = -1; static int hf_x25_type = -1; -static int hf_x25_p_r = -1; -static int hf_x25_mbit = -1; -static int hf_x25_p_s = -1; -static int proto_ex25 = -1; -static int hf_ex25_qbit = -1; -static int hf_ex25_dbit = -1; -static int hf_ex25_mod = -1; -static int hf_ex25_lcn = -1; -static int hf_ex25_type = -1; -static int hf_ex25_p_r = -1; -static int hf_ex25_mbit = -1; -static int hf_ex25_p_s = -1; +static int hf_x25_p_r_mod8 = -1; +static int hf_x25_p_r_mod128 = -1; +static int hf_x25_mbit_mod8 = -1; +static int hf_x25_mbit_mod128 = -1; +static int hf_x25_p_s_mod8 = -1; +static int hf_x25_p_s_mod128 = -1; static gint ett_x25 = -1; +static gint ett_x25_gfi = -1; static gint ett_x25_fac = -1; static gint ett_x25_fac_unknown = -1; static gint ett_x25_fac_mark = -1; @@ -132,6 +126,7 @@ static gint ett_x25_fac_ete_transit_delay = -1; static gint ett_x25_fac_calling_addr_ext = -1; static gint ett_x25_fac_call_deflect = -1; static gint ett_x25_fac_priority = -1; +static gint ett_x25_user_data = -1; static const value_string vals_modulo[] = { { 1, "8" }, @@ -160,11 +155,23 @@ static const value_string vals_x25_type[] = { { 0, NULL} }; +static dissector_handle_t ip_handle; +static dissector_handle_t ositp_handle; +static dissector_handle_t sna_handle; +static dissector_handle_t qllc_handle; +static dissector_handle_t data_handle; + +/* Preferences */ +static gboolean non_q_bit_is_sna = FALSE; + +static dissector_table_t x25_subdissector_table; +static heur_dissector_list_t x25_heur_subdissector_list; + /* * each vc_info node contains : * the time of the first frame using this dissector (secs and usecs) * the time of the last frame using this dissector (0 if it is unknown) - * a pointer to the dissector + * a handle for the dissector * * the "time of first frame" is initialized when a Call Req. is received * the "time of last frame" is initialized when a Clear, Reset, or Restart @@ -173,7 +180,7 @@ static const value_string vals_x25_type[] = { typedef struct _vc_info { guint32 first_frame_secs, first_frame_usecs; guint32 last_frame_secs, last_frame_usecs; - void (*dissect)(const u_char *, int, frame_data *, proto_tree *); + dissector_handle_t dissect; struct _vc_info *next; } vc_info; @@ -191,7 +198,7 @@ typedef struct _global_vc_info { static global_vc_info *hash_table[64]; -void +static void free_vc_info(vc_info *pt) { vc_info *vci = pt; @@ -225,10 +232,9 @@ reinit_x25_hashtable(void) } } -void +static void x25_hash_add_proto_start(guint16 vc, guint32 frame_secs, guint32 frame_usecs, - void (*dissect)(const u_char *, int, frame_data *, - proto_tree *)) + dissector_handle_t dissect) { int idx = vc % 64; global_vc_info *hash_ent; @@ -308,7 +314,7 @@ x25_hash_add_proto_start(guint16 vc, guint32 frame_secs, guint32 frame_usecs, } } -void +static void x25_hash_add_proto_end(guint16 vc, guint32 frame_secs, guint32 frame_usecs) { global_vc_info *hash_ent = hash_table[vc%64]; @@ -324,16 +330,20 @@ x25_hash_add_proto_end(guint16 vc, guint32 frame_secs, guint32 frame_usecs) vci->last_frame_usecs = frame_usecs; } -void (*x25_hash_get_dissect(guint32 frame_secs, guint32 frame_usecs, guint16 vc))(const u_char *, int, frame_data *, proto_tree *) +static dissector_handle_t +x25_hash_get_dissect(guint32 frame_secs, guint32 frame_usecs, guint16 vc) { global_vc_info *hash_ent = hash_table[vc%64]; vc_info *vci; vc_info *vci2; - if (!hash_ent) return 0; + if (!hash_ent) + return NULL; - while(hash_ent && hash_ent->vc_num != vc) hash_ent = hash_ent->next; - if (!hash_ent) return 0; + while (hash_ent && hash_ent->vc_num != vc) + hash_ent = hash_ent->next; + if (!hash_ent) + return NULL; /* a hash_ent was found for this VC number */ vci2 = vci = hash_ent->info; @@ -347,7 +357,8 @@ void (*x25_hash_get_dissect(guint32 frame_secs, guint32 frame_usecs, guint16 vc) } /* we reached last record, and previous record has a non zero * last frame time ==> no dissector */ - if (!vci && (vci2->last_frame_secs || vci2->last_frame_usecs)) return 0; + if (!vci && (vci2->last_frame_secs || vci2->last_frame_usecs)) + return NULL; /* we reached last record, and previous record has a zero last frame time * ==> dissector for previous frame has not been "stopped" by a Clear, etc */ @@ -357,16 +368,16 @@ void (*x25_hash_get_dissect(guint32 frame_secs, guint32 frame_usecs, guint16 vc) if (frame_secs < vci2->first_frame_secs || (frame_secs == vci2->first_frame_secs && frame_usecs < vci2->first_frame_usecs)) - return 0; + return NULL; else return vci2->dissect; } - /* our frame time is before vci's end. Check if it is adter vci's start */ + /* our frame time is before vci's end. Check if it is after vci's start */ if (frame_secs < vci->first_frame_secs || (frame_secs == vci->first_frame_secs && frame_usecs < vci->first_frame_usecs)) - return 0; + return NULL; else return vci->dissect; } @@ -379,10 +390,22 @@ static char *clear_code(unsigned char code) return "DTE Originated"; if (code == 0x01) return "Number Busy"; + if (code == 0x03) + return "Invalid Facility Requested"; + if (code == 0x05) + return "Network Congestion"; if (code == 0x09) return "Out Of Order"; + if (code == 0x0B) + return "Access Barred"; + if (code == 0x0D) + return "Not Obtainable"; if (code == 0x11) return "Remote Procedure Error"; + if (code == 0x13) + return "Local Procedure Error"; + if (code == 0x15) + return "RPOA Out Of Order"; if (code == 0x19) return "Reverse Charging Acceptance Not Subscribed"; if (code == 0x21) @@ -391,18 +414,6 @@ static char *clear_code(unsigned char code) return "Fast Select Acceptance Not Subscribed"; if (code == 0x39) return "Destination Absent"; - if (code == 0x03) - return "Invalid Facility Requested"; - if (code == 0x0B) - return "Access Barred"; - if (code == 0x13) - return "Local Procedure Error"; - if (code == 0x05) - return "Network Congestion"; - if (code == 0x0D) - return "Not Obtainable"; - if (code == 0x15) - return "RPOA Out Of Order"; sprintf(buffer, "Unknown %02X", code); @@ -549,6 +560,87 @@ static char *clear_diag(unsigned char code) return "Unknown called DNIC"; if (code == 122) return "Maintenance action"; + if (code == 144) + return "Timer expired or retransmission count surpassed"; + if (code == 145) + return "Timer expired or retransmission count surpassed for INTERRUPT"; + if (code == 146) + return "Timer expired or retransmission count surpassed for DATA " + "packet transmission"; + if (code == 147) + return "Timer expired or retransmission count surpassed for REJECT"; + if (code == 160) + return "DTE-specific signals"; + if (code == 161) + return "DTE operational"; + if (code == 162) + return "DTE not operational"; + if (code == 163) + return "DTE resource constraint"; + if (code == 164) + return "Fast select not subscribed"; + if (code == 165) + return "Invalid partially full DATA packet"; + if (code == 166) + return "D-bit procedure not supported"; + if (code == 167) + return "Registration/Cancellation confirmed"; + if (code == 224) + return "OSI network service problem"; + if (code == 225) + return "Disconnection (transient condition)"; + if (code == 226) + return "Disconnection (permanent condition)"; + if (code == 227) + return "Connection rejection - reason unspecified (transient " + "condition)"; + if (code == 228) + return "Connection rejection - reason unspecified (permanent " + "condition)"; + if (code == 229) + return "Connection rejection - quality of service not available " + "transient condition)"; + if (code == 230) + return "Connection rejection - quality of service not available " + "permanent condition)"; + if (code == 231) + return "Connection rejection - NSAP unreachable (transient condition)"; + if (code == 232) + return "Connection rejection - NSAP unreachable (permanent condition)"; + if (code == 233) + return "reset - reason unspecified"; + if (code == 234) + return "reset - congestion"; + if (code == 235) + return "Connection rejection - NSAP address unknown (permanent " + "condition)"; + if (code == 240) + return "Higher layer initiated"; + if (code == 241) + return "Disconnection - normal"; + if (code == 242) + return "Disconnection - abnormal"; + if (code == 243) + return "Disconnection - incompatible information in user data"; + if (code == 244) + return "Connection rejection - reason unspecified (transient " + "condition)"; + if (code == 245) + return "Connection rejection - reason unspecified (permanent " + "condition)"; + if (code == 246) + return "Connection rejection - quality of service not available " + "(transient condition)"; + if (code == 247) + return "Connection rejection - quality of service not available " + "(permanent condition)"; + if (code == 248) + return "Connection rejection - incompatible information in user data"; + if (code == 249) + return "Connection rejection - unrecognizable protocol indentifier " + "in user data"; + if (code == 250) + return "Reset - user resynchronization"; sprintf(buffer, "Unknown %d", code); @@ -621,7 +713,7 @@ static char *registration_code(unsigned char code) return buffer; } -void +static void dump_facilities(proto_tree *tree, int *offset, tvbuff_t *tvb) { guint8 fac, byte1, byte2, byte3; @@ -1200,9 +1292,9 @@ dump_facilities(proto_tree *tree, int *offset, tvbuff_t *tvb) } } -void +static void x25_ntoa(proto_tree *tree, int *offset, tvbuff_t *tvb, - frame_data *fd, gboolean toa) + packet_info *pinfo, gboolean toa) { int len1, len2; int i; @@ -1256,12 +1348,12 @@ x25_ntoa(proto_tree *tree, int *offset, tvbuff_t *tvb, if (len1) { if (toa) { - if (check_col(fd, COL_RES_DL_DST)) - col_add_str(fd, COL_RES_DL_DST, addr1); + if (check_col(pinfo->cinfo, COL_RES_DL_DST)) + col_add_str(pinfo->cinfo, COL_RES_DL_DST, addr1); } else { - if(check_col(fd, COL_RES_DL_SRC)) - col_add_str(fd, COL_RES_DL_SRC, addr1); + if(check_col(pinfo->cinfo, COL_RES_DL_SRC)) + col_add_str(pinfo->cinfo, COL_RES_DL_SRC, addr1); } if (tree) proto_tree_add_text(tree, tvb, *offset, @@ -1272,12 +1364,12 @@ x25_ntoa(proto_tree *tree, int *offset, tvbuff_t *tvb, } if (len2) { if (toa) { - if (check_col(fd, COL_RES_DL_SRC)) - col_add_str(fd, COL_RES_DL_SRC, addr2); + if (check_col(pinfo->cinfo, COL_RES_DL_SRC)) + col_add_str(pinfo->cinfo, COL_RES_DL_SRC, addr2); } else { - if(check_col(fd, COL_RES_DL_DST)) - col_add_str(fd, COL_RES_DL_DST, addr2); + if(check_col(pinfo->cinfo, COL_RES_DL_DST)) + col_add_str(pinfo->cinfo, COL_RES_DL_DST, addr2); } if (tree) proto_tree_add_text(tree, tvb, *offset + len1/2, @@ -1289,10 +1381,10 @@ x25_ntoa(proto_tree *tree, int *offset, tvbuff_t *tvb, (*offset) += ((len1 + len2 + 1) / 2); } -int +static int get_x25_pkt_len(tvbuff_t *tvb) { - int length, called_len, calling_len, dte_len, dce_len; + guint length, called_len, calling_len, dte_len, dce_len; guint8 byte2, bytex; byte2 = tvb_get_guint8(tvb, 2); @@ -1309,6 +1401,11 @@ get_x25_pkt_len(tvbuff_t *tvb) return MIN(tvb_reported_length(tvb),length); case X25_CALL_ACCEPTED: + /* The calling/called address length byte (following the packet type) + * is not mandatory, so we must check the packet length before trying + * to read it */ + if (tvb_reported_length(tvb) == 3) + return(3); bytex = tvb_get_guint8(tvb, 3); called_len = (bytex >> 0) & 0x0F; calling_len = (bytex >> 4) & 0x0F; @@ -1371,14 +1468,12 @@ get_x25_pkt_len(tvbuff_t *tvb) return 0; } -#define PRT_ID_ISO_8073 0x01 - static const value_string prt_id_vals[] = { - {PRT_ID_ISO_8073, "ISO 8073 COTP"}, - {0x02, "ISO 8602"}, - {0x03, "ISO 10732 in conjunction with ISO 8073"}, - {0x04, "ISO 10736 in conjunction with ISO 8602"}, - {0x00, NULL} + {PRT_ID_ISO_8073, "ISO 8073 COTP"}, + {PRT_ID_ISO_8602, "ISO 8602 CLTP"}, + {PRT_ID_ISO_10736_ISO_8073, "ISO 10736 in conjunction with ISO 8073 COTP"}, + {PRT_ID_ISO_10736_ISO_8602, "ISO 10736 in conjunction with ISO 8602 CLTP"}, + {0x00, NULL} }; static const value_string sharing_strategy_vals[] = { @@ -1386,26 +1481,24 @@ static const value_string sharing_strategy_vals[] = { {0x00, NULL} }; -void +static void dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - proto_tree *x25_tree=0, *ti; - int localoffset=0; - int x25_pkt_len; + proto_tree *x25_tree=0, *gfi_tree=0, *userdata_tree=0; + proto_item *ti; + guint localoffset=0; + guint x25_pkt_len; int modulo; guint16 vc; - void (*dissect)(const u_char *, int, frame_data *, proto_tree *); + dissector_handle_t dissect; gboolean toa; /* TOA/NPI address format */ guint16 bytes0_1; guint8 pkt_type; tvbuff_t *next_tvb; - const guint8 *next_pd; - int next_offset; + gboolean q_bit_set = FALSE; - pinfo->current_proto = "X.25"; - - if (check_col(pinfo->fd, COL_PROTOCOL)) - col_add_str(pinfo->fd, COL_PROTOCOL, "X.25"); + if (check_col(pinfo->cinfo, COL_PROTOCOL)) + col_set_str(pinfo->cinfo, COL_PROTOCOL, "X.25"); bytes0_1 = tvb_get_ntohs(tvb, 0); @@ -1418,52 +1511,63 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) x25_pkt_len = get_x25_pkt_len(tvb); if (x25_pkt_len < 3) /* packet too short */ { - if (check_col(pinfo->fd, COL_INFO)) - col_add_str(pinfo->fd, COL_INFO, "Invalid/short X.25 packet"); + if (check_col(pinfo->cinfo, COL_INFO)) + col_set_str(pinfo->cinfo, COL_INFO, "Invalid/short X.25 packet"); if (tree) - proto_tree_add_protocol_format(tree, - (modulo == 8 ? proto_x25 : proto_ex25), tvb, 0, - tvb_length(tvb), "Invalid/short X.25 packet"); + proto_tree_add_protocol_format(tree, proto_x25, tvb, 0, -1, + "Invalid/short X.25 packet"); return; } + + pkt_type = tvb_get_guint8(tvb, 2); + if (tree) { - ti = proto_tree_add_protocol_format(tree, - (modulo == 8) ? proto_x25 : proto_ex25, tvb, 0, x25_pkt_len, - "X.25"); - x25_tree = proto_item_add_subtree(ti, ett_x25); - if (bytes0_1 & 0x8000) - proto_tree_add_boolean(x25_tree, - (modulo == 8) ? hf_x25_qbit : hf_ex25_qbit, tvb, 0, 2, - bytes0_1); - if (bytes0_1 & 0x4000) - proto_tree_add_boolean(x25_tree, - (modulo == 8) ? hf_x25_dbit : hf_ex25_dbit, tvb, 0, 2, - bytes0_1); - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_mod : hf_ex25_mod, - tvb, 0, 2, bytes0_1); + ti = proto_tree_add_item(tree, proto_x25, tvb, 0, x25_pkt_len, FALSE); + x25_tree = proto_item_add_subtree(ti, ett_x25); + ti = proto_tree_add_item(x25_tree, hf_x25_gfi, tvb, 0, 2, FALSE); + gfi_tree = proto_item_add_subtree(ti, ett_x25_gfi); + + if ((pkt_type & 0x01) == X25_DATA) { + proto_tree_add_boolean(gfi_tree, hf_x25_qbit, tvb, 0, 2, + bytes0_1); + if (bytes0_1 & 0x8000) { + q_bit_set = TRUE; + } + } + else if (pkt_type == X25_CALL_REQUEST || + pkt_type == X25_CALL_ACCEPTED || + pkt_type == X25_CLEAR_REQUEST || + pkt_type == X25_CLEAR_CONFIRMATION) { + proto_tree_add_boolean(gfi_tree, hf_x25_abit, tvb, 0, 2, + bytes0_1); + } + + if (pkt_type == X25_CALL_REQUEST || pkt_type == X25_CALL_ACCEPTED || + (pkt_type & 0x01) == X25_DATA) { + proto_tree_add_boolean(gfi_tree, hf_x25_dbit, tvb, 0, 2, + bytes0_1); + } + proto_tree_add_uint(gfi_tree, hf_x25_mod, tvb, 0, 2, bytes0_1); } - pkt_type = tvb_get_guint8(tvb, 2); switch (pkt_type) { case X25_CALL_REQUEST: - if (check_col(pinfo->fd, COL_INFO)) - col_add_fstr(pinfo->fd, COL_INFO, "%s VC:%d", + if (check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "%s VC:%d", (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Inc. call" : "Call req." , vc); if (x25_tree) { - proto_tree_add_uint(x25_tree, - (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, tvb, + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, 0, 2, bytes0_1); - proto_tree_add_uint_format(x25_tree, - (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, 2, 1, + proto_tree_add_uint_format(x25_tree, hf_x25_type, tvb, 2, 1, X25_CALL_REQUEST, (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Incoming call" : "Call request"); } localoffset = 3; if (localoffset < x25_pkt_len) /* calling/called addresses */ - x25_ntoa(x25_tree, &localoffset, tvb, pinfo->fd, toa); + x25_ntoa(x25_tree, &localoffset, tvb, pinfo, toa); if (localoffset < x25_pkt_len) /* facilities */ dump_facilities(x25_tree, &localoffset, tvb); @@ -1471,112 +1575,235 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) if (localoffset < tvb_reported_length(tvb)) /* user data */ { guint8 spi; + int is_x_264; guint8 prt_id; - /* Compare the first octet of the CALL REQUEST packet with - various ISO 9577 NLPIDs, as per Annex A of ISO 9577. */ - spi = tvb_get_guint8(tvb, localoffset); - switch (spi) { - - /* XXX - handle other NLPIDs, e.g. PPP? */ - - case NLPID_IP: - x25_hash_add_proto_start(vc, pinfo->fd->abs_secs, - pinfo->fd->abs_usecs, dissect_ip); - if (x25_tree) - proto_tree_add_text(x25_tree, tvb, localoffset, 1, - "X.224 secondary protocol ID: IP"); - localoffset++; - break; + if (x25_tree) { + ti = proto_tree_add_text(x25_tree, tvb, localoffset, -1, + "User data"); + userdata_tree = proto_item_add_subtree(ti, ett_x25_user_data); + } - default: - if ((spi >= 0x03 && spi <= 0x82) - && tvb_get_guint8(tvb, localoffset+1) == 0x01) { - /* ISO 9577 claims that a SPI in that range is a - length field for X.224/ISO 8073 or X.264/ISO 11570; - however, some of them collide with NLPIDs such - as 0x81 for ISO 8473 CLNP or ISO 8542 ESIS, so - I don't know how you run those over X.25, assuming - you do. - - I'm also not sure what the "or" means there; it - looks as if X.264 specifies the layout of a - "UN TPDU" ("Use of network connection TPDU"), - which specifies the transport protocol to use - over this network connection, and 0x03 0x01 0x01 - 0x00 is such a TPDU, with a length of 3, a UN - field of 1 (as is required), a PRT-ID ("protocol - identifier") field of 1 (X.224/ISO 8073, a/k/a - COTP service), and a SHARE ("sharing strategy") - field of 0 ("no sharing", which is the only one - allowed). - - So we'll assume that's what it is, as the SPI - is in the right range for a length, and the UN - field is 0x01. */ - prt_id = tvb_get_guint8(tvb, localoffset+2); - if (x25_tree) { - proto_tree_add_text(x25_tree, tvb, localoffset, 1, + /* X.263/ISO 9577 says that: + + When CLNP or ESIS are run over X.25, the SPI + is 0x81 or 0x82, respectively; those are the + NLPIDs for those protocol. + + When X.224/ISO 8073 COTP is run over X.25, and + when ISO 11570 explicit identification is being + used, the first octet of the user data field is + a TPDU length field, and the rest is "as defined + in ITU-T Rec. X.225 | ISO/IEC 8073, Annex B, + or ITU-T Rec. X.264 and ISO/IEC 11570". + + When X.264/ISO 11570 default identification is + being used, there is no user data field in the + CALL REQUEST packet. This is for X.225/ISO 8073 + COTP. + + It also says that SPI values from 0x03 through 0x3f are + reserved and are in use by X.224/ISO 8073 Annex B and + X.264/ISO 11570. The note says that those values are + not NLPIDs, they're "used by the respective higher layer + protocol" and "not used for higher layer protocol + identification". I infer from this and from what + X.264/ISO 11570 says that this means that values in those + range are valid values for the first octet of an + X.224/ISO 8073 packet or for X.264/ISO 11570. + + Annex B of X.225/ISO 8073 mentions some additional TPDU + types that can be put in what I presume is the user + data of connect requests. It says that: + + The sending transport entity shall: + + a) either not transmit any TPDU in the NS-user data + parameter of the N-CONNECT request primitive; or + + b) transmit the UN-TPDU (see ITU-T Rec. X.264 and + ISO/IEC 11570) followed by the NCM-TPDU in the + NS-user data parameter of the N-CONNECT request + primitive. + + I don't know if this means that the user data field + will contain a UN TPDU followed by an NCM TPDU or not. + + X.264/ISO 11570 says that: + + When default identification is being used, + X.225/ISO 8073 COTP is identified. No user data + is sent in the network-layer connection request. + + When explicit identification is being used, + the user data is a UN TPDU ("Use of network + connection TPDU"), which specifies the transport + protocol to use over this network connection. + It also says that the length of a UN TPDU shall + not exceed 32 octets, i.e. shall not exceed 0x20; + it says this is "due to the desire not to conflict + with the protocol identifier field carried by X.25 + CALL REQUEST/INCOMING CALL packets", and says that + field has values specified in X.244. X.244 has been + superseded by X.263/ISO 9577, so that presumably + means the goal is to allow a UN TPDU's length + field to be distinguished from an NLPID, allowing + you to tell whether X.264/ISO 11570 explicit + identification is being used or an NLPID is + being used as the SPI. + + I read this as meaning that, if the ISO mechanisms are + used to identify the protocol being carried over X.25: + + if there's no user data in the CALL REQUEST/ + INCOMING CALL packet, it's COTP; + + if there is user data, then: + + if the first octet is less than or equal to + 32, it might be a UN TPDU, and that identifies + the transport protocol being used, and + it may be followed by more data, such + as a COTP NCM TPDU if it's COTP; + + if the first octet is greater than 32, it's + an NLPID, *not* a TPDU length, and the + stuff following it is *not* a TPDU. + + Figure A.2 of X.263/ISO 9577 seems to say that the + first octet of the user data is a TPDU length field, + in the range 0x03 through 0x82, and says they are + for X.225/ISO 8073 Annex B or X.264/ISO 11570. + + However, X.264/ISO 11570 seems to imply that the length + field would be that of a UN TPDU, which must be less + than or equal to 0x20, and X.225/ISO 8073 Annex B seems + to indicate that the user data must begin with + an X.264/ISO 11570 UN TPDU, so I'd say that A.2 should + have said "in the range 0x03 through 0x20", instead + (the length value doesn't include the length field, + and the minimum UN TPDU has length, type, PRT-ID, + and SHARE, so that's 3 bytes without the length). */ + spi = tvb_get_guint8(tvb, localoffset); + if (spi > 32 || spi < 3) { + /* First octet is > 32, or < 3, so the user data isn't an + X.264/ISO 11570 UN TPDU */ + is_x_264 = FALSE; + } else { + /* First octet is >= 3 and <= 32, so the user data *might* + be an X.264/ISO 11570 UN TPDU. Check whether we have + enough data to see if it is. */ + if (tvb_bytes_exist(tvb, localoffset+1, 1)) { + /* We do; check whether the second octet is 1. */ + if (tvb_get_guint8(tvb, localoffset+1) == 0x01) { + /* Yes, the second byte is 1, so it looks like + a UN TPDU. */ + is_x_264 = TRUE; + } else { + /* No, the second byte is not 1, so it's not a + UN TPDU. */ + is_x_264 = FALSE; + } + } else { + /* We can't see the second byte of the putative UN + TPDU, so we don't know if that's what it is. */ + is_x_264 = -1; + } + } + if (is_x_264 == -1) { + /* + * We don't know what it is; just skip it. + */ + localoffset = tvb_length(tvb); + } else if (is_x_264) { + /* It looks like an X.264 UN TPDU, so show it as such. */ + if (userdata_tree) { + proto_tree_add_text(userdata_tree, tvb, localoffset, 1, "X.264 length indicator: %u", spi); - proto_tree_add_text(x25_tree, tvb, localoffset+1, 1, - "X.264 UN TPDU identifier: 0x%02X", - tvb_get_guint8(tvb, localoffset+1)); - proto_tree_add_text(x25_tree, tvb, localoffset+2, 1, - "X.264 protocol identifier: %s", + proto_tree_add_text(userdata_tree, tvb, localoffset+1, 1, + "X.264 UN TPDU identifier: 0x%02X", + tvb_get_guint8(tvb, localoffset+1)); + } + prt_id = tvb_get_guint8(tvb, localoffset+2); + if (userdata_tree) { + proto_tree_add_text(x25_tree, tvb, localoffset+2, 1, + "X.264 protocol identifier: %s", val_to_str(prt_id, prt_id_vals, - "Unknown (0x%02X)")); - proto_tree_add_text(x25_tree, tvb, localoffset+3, 1, - "X.264 sharing strategy: %s", + "Unknown (0x%02X)")); + proto_tree_add_text(x25_tree, tvb, localoffset+3, 1, + "X.264 sharing strategy: %s", val_to_str(tvb_get_guint8(tvb, localoffset+3), - sharing_strategy_vals, "Unknown (0x%02X)")); - } + sharing_strategy_vals, "Unknown (0x%02X)")); + } - /* XXX - dissect the variable part? */ + /* XXX - dissect the variable part? */ - /* The length doesn't include the length octet itself. */ - localoffset += spi + 1; + /* The length doesn't include the length octet itself. */ + localoffset += spi + 1; - switch (prt_id) { + switch (prt_id) { - case PRT_ID_ISO_8073: - /* ISO 8073 COTP */ - x25_hash_add_proto_start(vc, pinfo->fd->abs_secs, - pinfo->fd->abs_usecs, dissect_ositp); - break; + case PRT_ID_ISO_8073: + /* ISO 8073 COTP */ + x25_hash_add_proto_start(vc, pinfo->fd->abs_secs, + pinfo->fd->abs_usecs, + ositp_handle); + /* XXX - disssect the rest of the user data as COTP? + That needs support for NCM TPDUs, etc. */ + break; - default: - goto unknown; - } - } else { - unknown: - if (x25_tree) { - proto_tree_add_text(x25_tree, tvb, localoffset, - tvb_reported_length(tvb)-localoffset, "Data"); - } - localoffset = tvb_reported_length(tvb); + case PRT_ID_ISO_8602: + /* ISO 8602 CLTP */ + x25_hash_add_proto_start(vc, pinfo->fd->abs_secs, + pinfo->fd->abs_usecs, + ositp_handle); + break; + } + } else if (is_x_264 == 0) { + /* It doesn't look like a UN TPDU, so compare the first + octet of the CALL REQUEST packet with various X.263/ + ISO 9577 NLPIDs, as per Annex A of X.263/ISO 9577. */ + + if (userdata_tree) { + proto_tree_add_text(userdata_tree, tvb, localoffset, 1, + "X.263 secondary protocol ID: %s", + val_to_str(spi, nlpid_vals, "Unknown (0x%02x)")); + } + localoffset++; + + /* + * What's the dissector handle for this SPI? + */ + dissect = dissector_get_port_handle(x25_subdissector_table, spi); + x25_hash_add_proto_start(vc, pinfo->fd->abs_secs, + pinfo->fd->abs_usecs, dissect); + } + if (localoffset < tvb_length(tvb)) { + if (userdata_tree) { + proto_tree_add_text(userdata_tree, tvb, localoffset, -1, + "Data"); } + localoffset = tvb_length(tvb); } } break; case X25_CALL_ACCEPTED: - if(check_col(pinfo->fd, COL_INFO)) - col_add_fstr(pinfo->fd, COL_INFO, "%s VC:%d", + if(check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "%s VC:%d", (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Call conn." : "Call acc." , vc); if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, - tvb, 0, 2, bytes0_1); - proto_tree_add_uint_format(x25_tree, - (modulo == 8) ? hf_x25_type : hf_ex25_type, - tvb, 2, 1, X25_CALL_ACCEPTED, + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, 0, 2, bytes0_1); + proto_tree_add_uint_format(x25_tree, hf_x25_type, tvb, 2, 1, + X25_CALL_ACCEPTED, (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Call connected" : "Call accepted"); } localoffset = 3; if (localoffset < x25_pkt_len) /* calling/called addresses */ - x25_ntoa(x25_tree, &localoffset, tvb, pinfo->fd, toa); + x25_ntoa(x25_tree, &localoffset, tvb, pinfo, toa); if (localoffset < x25_pkt_len) /* facilities */ dump_facilities(x25_tree, &localoffset, tvb); @@ -1589,8 +1816,8 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } break; case X25_CLEAR_REQUEST: - if(check_col(pinfo->fd, COL_INFO)) { - col_add_fstr(pinfo->fd, COL_INFO, "%s VC:%d %s - %s", + if(check_col(pinfo->cinfo, COL_INFO)) { + col_add_fstr(pinfo->cinfo, COL_INFO, "%s VC:%d %s - %s", (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Clear ind." : "Clear req." , vc, clear_code(tvb_get_guint8(tvb, 3)), @@ -1598,11 +1825,9 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } x25_hash_add_proto_end(vc, pinfo->fd->abs_secs, pinfo->fd->abs_usecs); if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, tvb, - 0, 2, bytes0_1); - proto_tree_add_uint_format(x25_tree, - (modulo == 8) ? hf_x25_type : hf_ex25_type, - tvb, localoffset+2, 1, X25_CLEAR_REQUEST, + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, 0, 2, bytes0_1); + proto_tree_add_uint_format(x25_tree, hf_x25_type, tvb, + localoffset+2, 1, X25_CLEAR_REQUEST, (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Clear indication" : "Clear request"); proto_tree_add_text(x25_tree, tvb, 3, 1, @@ -1613,60 +1838,57 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) localoffset = x25_pkt_len; break; case X25_CLEAR_CONFIRMATION: - if(check_col(pinfo->fd, COL_INFO)) - col_add_fstr(pinfo->fd, COL_INFO, "Clear Conf. VC:%d", vc); + if(check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "Clear Conf. VC:%d", vc); if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, tvb, - 0, 2, bytes0_1); - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, - 2, 1, X25_CLEAR_CONFIRMATION); + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, 0, 2, bytes0_1); + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, 2, 1, + X25_CLEAR_CONFIRMATION); } localoffset = x25_pkt_len; if (localoffset < tvb_reported_length(tvb)) /* extended clear conf format */ - x25_ntoa(x25_tree, &localoffset, tvb, pinfo->fd, toa); + x25_ntoa(x25_tree, &localoffset, tvb, pinfo, toa); if (localoffset < tvb_reported_length(tvb)) /* facilities */ dump_facilities(x25_tree, &localoffset, tvb); break; case X25_DIAGNOSTIC: - if(check_col(pinfo->fd, COL_INFO)) { - col_add_fstr(pinfo->fd, COL_INFO, "Diag. %d", + if(check_col(pinfo->cinfo, COL_INFO)) { + col_add_fstr(pinfo->cinfo, COL_INFO, "Diag. %d", (int)tvb_get_guint8(tvb, 3)); } if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, - 2, 1, X25_DIAGNOSTIC); + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, 2, 1, + X25_DIAGNOSTIC); proto_tree_add_text(x25_tree, tvb, 3, 1, "Diagnostic : %d", (int)tvb_get_guint8(tvb, 3)); } localoffset = x25_pkt_len; break; case X25_INTERRUPT: - if(check_col(pinfo->fd, COL_INFO)) - col_add_fstr(pinfo->fd, COL_INFO, "Interrupt VC:%d", vc); + if(check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "Interrupt VC:%d", vc); if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, tvb, - 0, 2, bytes0_1); - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, - 2, 1, X25_INTERRUPT); + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, 0, 2, bytes0_1); + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, 2, 1, + X25_INTERRUPT); } localoffset = x25_pkt_len; break; case X25_INTERRUPT_CONFIRMATION: - if(check_col(pinfo->fd, COL_INFO)) - col_add_fstr(pinfo->fd, COL_INFO, "Interrupt Conf. VC:%d", vc); + if(check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "Interrupt Conf. VC:%d", vc); if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, tvb, - 0, 2, bytes0_1); - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, - 2, 1, X25_INTERRUPT_CONFIRMATION); + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, 0, 2, bytes0_1); + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, 2, 1, + X25_INTERRUPT_CONFIRMATION); } localoffset = x25_pkt_len; break; case X25_RESET_REQUEST: - if(check_col(pinfo->fd, COL_INFO)) { - col_add_fstr(pinfo->fd, COL_INFO, "%s VC:%d %s - Diag.:%d", + if(check_col(pinfo->cinfo, COL_INFO)) { + col_add_fstr(pinfo->cinfo, COL_INFO, "%s VC:%d %s - Diag.:%d", (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Reset ind." : "Reset req.", vc, reset_code(tvb_get_guint8(tvb, 3)), @@ -1674,10 +1896,8 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } x25_hash_add_proto_end(vc, pinfo->fd->abs_secs, pinfo->fd->abs_usecs); if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, tvb, - 0, 2, bytes0_1); - proto_tree_add_uint_format(x25_tree, - (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, 2, 1, + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, 0, 2, bytes0_1); + proto_tree_add_uint_format(x25_tree, hf_x25_type, tvb, 2, 1, X25_RESET_REQUEST, (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Reset indication" : "Reset request"); @@ -1689,27 +1909,25 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) localoffset = x25_pkt_len; break; case X25_RESET_CONFIRMATION: - if(check_col(pinfo->fd, COL_INFO)) - col_add_fstr(pinfo->fd, COL_INFO, "Reset conf. VC:%d", vc); + if(check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "Reset conf. VC:%d", vc); if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, tvb, - 0, 2, bytes0_1); - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, - 2, 1, X25_RESET_CONFIRMATION); + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, 0, 2, bytes0_1); + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, 2, 1, + X25_RESET_CONFIRMATION); } localoffset = x25_pkt_len; break; case X25_RESTART_REQUEST: - if(check_col(pinfo->fd, COL_INFO)) { - col_add_fstr(pinfo->fd, COL_INFO, "%s %s - Diag.:%d", + if(check_col(pinfo->cinfo, COL_INFO)) { + col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s - Diag.:%d", (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Restart ind." : "Restart req.", restart_code(tvb_get_guint8(tvb, 3)), (int)tvb_get_guint8(tvb, 3)); } if (x25_tree) { - proto_tree_add_uint_format(x25_tree, - (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, 2, 1, + proto_tree_add_uint_format(x25_tree, hf_x25_type, tvb, 2, 1, X25_RESTART_REQUEST, (pinfo->pseudo_header->x25.flags & FROM_DCE) ? "Restart indication" : "Restart request"); @@ -1721,22 +1939,22 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) localoffset = x25_pkt_len; break; case X25_RESTART_CONFIRMATION: - if(check_col(pinfo->fd, COL_INFO)) - col_add_str(pinfo->fd, COL_INFO, "Restart conf."); + if(check_col(pinfo->cinfo, COL_INFO)) + col_set_str(pinfo->cinfo, COL_INFO, "Restart conf."); if (x25_tree) - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, - 2, 1, X25_RESTART_CONFIRMATION); + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, 2, 1, + X25_RESTART_CONFIRMATION); localoffset = x25_pkt_len; break; case X25_REGISTRATION_REQUEST: - if(check_col(pinfo->fd, COL_INFO)) - col_add_str(pinfo->fd, COL_INFO, "Registration req."); + if(check_col(pinfo->cinfo, COL_INFO)) + col_set_str(pinfo->cinfo, COL_INFO, "Registration req."); if (x25_tree) - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, - 2, 1, X25_REGISTRATION_REQUEST); + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, 2, 1, + X25_REGISTRATION_REQUEST); localoffset = 3; if (localoffset < x25_pkt_len) - x25_ntoa(x25_tree, &localoffset, tvb, pinfo->fd, FALSE); + x25_ntoa(x25_tree, &localoffset, tvb, pinfo, FALSE); if (x25_tree) { if (localoffset < x25_pkt_len) @@ -1751,11 +1969,11 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) localoffset = tvb_reported_length(tvb); break; case X25_REGISTRATION_CONFIRMATION: - if(check_col(pinfo->fd, COL_INFO)) - col_add_str(pinfo->fd, COL_INFO, "Registration conf."); + if(check_col(pinfo->cinfo, COL_INFO)) + col_set_str(pinfo->cinfo, COL_INFO, "Registration conf."); if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_type : hf_ex25_type, tvb, - 2, 1, X25_REGISTRATION_CONFIRMATION); + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, 2, 1, + X25_REGISTRATION_CONFIRMATION); proto_tree_add_text(x25_tree, tvb, 3, 1, "Cause: %s", registration_code(tvb_get_guint8(tvb, 3))); proto_tree_add_text(x25_tree, tvb, 4, 1, @@ -1763,7 +1981,7 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) } localoffset = 5; if (localoffset < x25_pkt_len) - x25_ntoa(x25_tree, &localoffset, tvb, pinfo->fd, TRUE); + x25_ntoa(x25_tree, &localoffset, tvb, pinfo, TRUE); if (x25_tree) { if (localoffset < x25_pkt_len) @@ -1781,47 +1999,47 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) localoffset = 2; if ((pkt_type & 0x01) == X25_DATA) { - if(check_col(pinfo->fd, COL_INFO)) { + if(check_col(pinfo->cinfo, COL_INFO)) { if (modulo == 8) - col_add_fstr(pinfo->fd, COL_INFO, + col_add_fstr(pinfo->cinfo, COL_INFO, "Data VC:%d P(S):%d P(R):%d %s", vc, (pkt_type >> 1) & 0x07, (pkt_type >> 5) & 0x07, ((pkt_type >> 4) & 0x01) ? " M" : ""); else - col_add_fstr(pinfo->fd, COL_INFO, + col_add_fstr(pinfo->cinfo, COL_INFO, "Data VC:%d P(S):%d P(R):%d %s", vc, tvb_get_guint8(tvb, localoffset+1) >> 1, pkt_type >> 1, (tvb_get_guint8(tvb, localoffset+1) & 0x01) ? " M" : ""); } if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, - tvb, localoffset-2, 2, bytes0_1); + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, localoffset-2, + 2, bytes0_1); + proto_tree_add_uint_hidden(x25_tree, hf_x25_type, tvb, + localoffset, 1, X25_DATA); if (modulo == 8) { - proto_tree_add_uint_hidden(x25_tree, hf_x25_type, tvb, - localoffset, 1, X25_DATA); - proto_tree_add_uint(x25_tree, hf_x25_p_r, tvb, + proto_tree_add_uint(x25_tree, hf_x25_p_r_mod8, tvb, localoffset, 1, pkt_type); if (pkt_type & 0x10) - proto_tree_add_boolean(x25_tree, hf_x25_mbit, tvb, localoffset, 1, - pkt_type); - proto_tree_add_uint(x25_tree, hf_x25_p_s, tvb, localoffset, 1, - pkt_type); + proto_tree_add_boolean(x25_tree, hf_x25_mbit_mod8, tvb, + localoffset, 1, pkt_type); + proto_tree_add_uint(x25_tree, hf_x25_p_s_mod8, tvb, + localoffset, 1, pkt_type); proto_tree_add_text(x25_tree, tvb, localoffset, 1, decode_boolean_bitfield(pkt_type, 0x01, 1*8, NULL, "DATA")); } else { - proto_tree_add_uint_hidden(x25_tree, hf_ex25_type, tvb, - localoffset, 1, X25_DATA); - proto_tree_add_uint(x25_tree, hf_x25_p_r, tvb, + proto_tree_add_uint(x25_tree, hf_x25_p_r_mod128, tvb, localoffset, 1, pkt_type); - proto_tree_add_uint(x25_tree, hf_x25_p_s, tvb, - localoffset+1, 1, tvb_get_guint8(tvb, localoffset+1)); + proto_tree_add_uint(x25_tree, hf_x25_p_s_mod128, tvb, + localoffset+1, 1, + tvb_get_guint8(tvb, localoffset+1)); if (tvb_get_guint8(tvb, localoffset+1) & 0x01) - proto_tree_add_boolean(x25_tree, hf_ex25_mbit, tvb, - localoffset+1, 1, tvb_get_guint8(tvb, localoffset+1)); + proto_tree_add_boolean(x25_tree, hf_x25_mbit_mod128, tvb, + localoffset+1, 1, + tvb_get_guint8(tvb, localoffset+1)); } } localoffset += (modulo == 8) ? 1 : 2; @@ -1830,81 +2048,81 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) switch (pkt_type & 0x1F) { case X25_RR: - if(check_col(pinfo->fd, COL_INFO)) { + if(check_col(pinfo->cinfo, COL_INFO)) { if (modulo == 8) - col_add_fstr(pinfo->fd, COL_INFO, "RR VC:%d P(R):%d", + col_add_fstr(pinfo->cinfo, COL_INFO, "RR VC:%d P(R):%d", vc, (pkt_type >> 5) & 0x07); else - col_add_fstr(pinfo->fd, COL_INFO, "RR VC:%d P(R):%d", + col_add_fstr(pinfo->cinfo, COL_INFO, "RR VC:%d P(R):%d", vc, tvb_get_guint8(tvb, localoffset+1) >> 1); } if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, - tvb, localoffset-2, 2, bytes0_1); + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, localoffset-2, + 2, bytes0_1); if (modulo == 8) { - proto_tree_add_uint(x25_tree, hf_x25_p_r, tvb, + proto_tree_add_uint(x25_tree, hf_x25_p_r_mod8, tvb, localoffset, 1, pkt_type); proto_tree_add_uint(x25_tree, hf_x25_type, tvb, localoffset, 1, X25_RR); } else { - proto_tree_add_uint(x25_tree, hf_ex25_type, tvb, + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, localoffset, 1, X25_RR); - proto_tree_add_item(x25_tree, hf_ex25_p_r, tvb, + proto_tree_add_item(x25_tree, hf_x25_p_r_mod128, tvb, localoffset+1, 1, FALSE); } } break; case X25_RNR: - if(check_col(pinfo->fd, COL_INFO)) { + if(check_col(pinfo->cinfo, COL_INFO)) { if (modulo == 8) - col_add_fstr(pinfo->fd, COL_INFO, "RNR VC:%d P(R):%d", + col_add_fstr(pinfo->cinfo, COL_INFO, "RNR VC:%d P(R):%d", vc, (pkt_type >> 5) & 0x07); else - col_add_fstr(pinfo->fd, COL_INFO, "RNR VC:%d P(R):%d", + col_add_fstr(pinfo->cinfo, COL_INFO, "RNR VC:%d P(R):%d", vc, tvb_get_guint8(tvb, localoffset+1) >> 1); } if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, - tvb, localoffset-2, 2, bytes0_1); + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, localoffset-2, + 2, bytes0_1); if (modulo == 8) { - proto_tree_add_uint(x25_tree, hf_x25_p_r, tvb, + proto_tree_add_uint(x25_tree, hf_x25_p_r_mod8, tvb, localoffset, 1, pkt_type); proto_tree_add_uint(x25_tree, hf_x25_type, tvb, localoffset, 1, X25_RNR); } else { - proto_tree_add_uint(x25_tree, hf_ex25_type, tvb, + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, localoffset, 1, X25_RNR); - proto_tree_add_item(x25_tree, hf_ex25_p_r, tvb, + proto_tree_add_item(x25_tree, hf_x25_p_r_mod128, tvb, localoffset+1, 1, FALSE); } } break; case X25_REJ: - if(check_col(pinfo->fd, COL_INFO)) { + if(check_col(pinfo->cinfo, COL_INFO)) { if (modulo == 8) - col_add_fstr(pinfo->fd, COL_INFO, "REJ VC:%d P(R):%d", + col_add_fstr(pinfo->cinfo, COL_INFO, "REJ VC:%d P(R):%d", vc, (pkt_type >> 5) & 0x07); else - col_add_fstr(pinfo->fd, COL_INFO, "REJ VC:%d P(R):%d", + col_add_fstr(pinfo->cinfo, COL_INFO, "REJ VC:%d P(R):%d", vc, tvb_get_guint8(tvb, localoffset+1) >> 1); } if (x25_tree) { - proto_tree_add_uint(x25_tree, (modulo == 8) ? hf_x25_lcn : hf_ex25_lcn, - tvb, localoffset-2, 2, bytes0_1); + proto_tree_add_uint(x25_tree, hf_x25_lcn, tvb, localoffset-2, + 2, bytes0_1); if (modulo == 8) { - proto_tree_add_uint(x25_tree, hf_x25_p_r, tvb, + proto_tree_add_uint(x25_tree, hf_x25_p_r_mod8, tvb, localoffset, 1, pkt_type); proto_tree_add_uint(x25_tree, hf_x25_type, tvb, localoffset, 1, X25_REJ); } else { - proto_tree_add_uint(x25_tree, hf_ex25_type, tvb, + proto_tree_add_uint(x25_tree, hf_x25_type, tvb, localoffset, 1, X25_REJ); - proto_tree_add_item(x25_tree, hf_ex25_p_r, tvb, + proto_tree_add_item(x25_tree, hf_x25_p_r_mod128, tvb, localoffset+1, 1, FALSE); } } @@ -1915,81 +2133,95 @@ dissect_x25(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) if (localoffset >= tvb_reported_length(tvb)) return; next_tvb = tvb_new_subset(tvb, localoffset, -1, -1); - tvb_compat(next_tvb, &next_pd, &next_offset); + + /* QLLC ? */ + if (q_bit_set) { + call_dissector(qllc_handle, next_tvb, pinfo, tree); + return; + } + /* search the dissector in the hash table */ - if ((dissect = x25_hash_get_dissect(pinfo->fd->abs_secs, pinfo->fd->abs_usecs, vc))) - (*dissect)(next_pd, next_offset, pinfo->fd, tree); - else { - /* If the Call Req. has not been captured, assume these packets carry IP */ - if (tvb_get_guint8(tvb, localoffset) == 0x45) { - x25_hash_add_proto_start(vc, pinfo->fd->abs_secs, - pinfo->fd->abs_usecs, dissect_ip); - dissect_ip(next_pd, next_offset, pinfo->fd, tree); - } - else { - dissect_data(next_pd, next_offset, pinfo->fd, tree); - } + if ((dissect = x25_hash_get_dissect(pinfo->fd->abs_secs, pinfo->fd->abs_usecs, vc))) { + /* Found it in the hash table; use it. */ + call_dissector(dissect, next_tvb, pinfo, tree); + return; + } + + /* Did the user suggest SNA-over-X.25? */ + if (non_q_bit_is_sna) { + /* Yes - dissect it as SNA. */ + x25_hash_add_proto_start(vc, pinfo->fd->abs_secs, + pinfo->fd->abs_usecs, sna_handle); + call_dissector(sna_handle, next_tvb, pinfo, tree); + return; + } + + /* If the Call Req. has not been captured, and the payload begins + with what appears to be an IP header, assume these packets carry + IP */ + if (tvb_get_guint8(tvb, localoffset) == 0x45) { + x25_hash_add_proto_start(vc, pinfo->fd->abs_secs, + pinfo->fd->abs_usecs, ip_handle); + call_dissector(ip_handle, next_tvb, pinfo, tree); + return; } + + /* Try the heuristic dissectors. */ + if (dissector_try_heuristic(x25_heur_subdissector_list, next_tvb, pinfo, + tree)) + return; + + /* All else failed; dissect it as raw data */ + call_dissector(data_handle, next_tvb, pinfo, tree); } void proto_register_x25(void) { - static hf_register_info hf8[] = { + static hf_register_info hf[] = { + { &hf_x25_gfi, + { "GFI", "x.25.gfi", FT_UINT16, BASE_BIN, NULL, 0xF000, + "General format identifier", HFILL }}, + { &hf_x25_abit, + { "A Bit", "x.25.a", FT_BOOLEAN, 16, NULL, 0x8000, + "Address Bit", HFILL }}, { &hf_x25_qbit, - { "Q Bit", "x25.q", FT_BOOLEAN, 2, NULL, 0x8000, - "Qualifier Bit" } }, + { "Q Bit", "x.25.q", FT_BOOLEAN, 16, NULL, 0x8000, + "Qualifier Bit", HFILL }}, { &hf_x25_dbit, - { "D Bit", "x25.d", FT_BOOLEAN, 2, NULL, 0x4000, - "Delivery Confirmation Bit" } }, + { "D Bit", "x.25.d", FT_BOOLEAN, 16, NULL, 0x4000, + "Delivery Confirmation Bit", HFILL }}, { &hf_x25_mod, - { "Modulo", "x25.mod", FT_UINT16, BASE_DEC, VALS(vals_modulo), 0x3000, - "Specifies whether the frame is modulo 8 or 128" } }, + { "Modulo", "x.25.mod", FT_UINT16, BASE_DEC, VALS(vals_modulo), 0x3000, + "Specifies whether the frame is modulo 8 or 128", HFILL }}, { &hf_x25_lcn, - { "Logical Channel", "x25.lcn", FT_UINT16, BASE_DEC, NULL, 0x0FFF, - "Logical Channel Number" } }, + { "Logical Channel", "x.25.lcn", FT_UINT16, BASE_DEC, NULL, 0x0FFF, + "Logical Channel Number", HFILL }}, { &hf_x25_type, - { "Packet Type", "x25.type", FT_UINT8, BASE_HEX, VALS(vals_x25_type), 0x0, - "Packet Type" } }, - { &hf_x25_p_r, - { "P(R)", "x25.p_r", FT_UINT8, BASE_HEX, NULL, 0xE0, - "Packet Receive Sequence Number" } }, - { &hf_x25_mbit, - { "M Bit", "x25.m", FT_BOOLEAN, 1, NULL, 0x10, - "More Bit" } }, - { &hf_x25_p_s, - { "P(S)", "x25.p_s", FT_UINT8, BASE_HEX, NULL, 0x0E, - "Packet Send Sequence Number" } }, - }; - - static hf_register_info hf128[] = { - { &hf_ex25_qbit, - { "Q Bit", "ex25.q", FT_BOOLEAN, 2, NULL, 0x8000, - "Qualifier Bit" } }, - { &hf_ex25_dbit, - { "D Bit", "ex25.d", FT_BOOLEAN, 2, NULL, 0x4000, - "Delivery Confirmation Bit" } }, - { &hf_ex25_mod, - { "Modulo", "ex25.mod", FT_UINT16, BASE_DEC, VALS(vals_modulo), 0x3000, - "Specifies whether the frame is modulo 8 or 128" } }, - { &hf_ex25_lcn, - { "Logical Channel", "ex25.lcn", FT_UINT16, BASE_HEX, NULL, 0x0FFF, - "Logical Channel Number" } }, - { &hf_ex25_type, - { "Packet Type", "ex25.type", FT_UINT8, BASE_HEX, VALS(vals_x25_type), 0x0, - "Packet Type" } }, - { &hf_ex25_p_r, - { "P(R)", "ex25.p_r", FT_UINT8, BASE_HEX, NULL, 0xFE, - "Packet Receive Sequence Number" } }, - { &hf_ex25_mbit, - { "M Bit", "ex25.m", FT_BOOLEAN, 1, NULL, 0x01, - "More Bit" } }, - { &hf_ex25_p_s, - { "P(S)", "ex25.p_s", FT_UINT8, BASE_HEX, NULL, 0xFE, - "Packet Send Sequence Number" } }, + { "Packet Type", "x.25.type", FT_UINT8, BASE_HEX, VALS(vals_x25_type), 0x0, + "Packet Type", HFILL }}, + { &hf_x25_p_r_mod8, + { "P(R)", "x.25.p_r", FT_UINT8, BASE_HEX, NULL, 0xE0, + "Packet Receive Sequence Number", HFILL }}, + { &hf_x25_p_r_mod128, + { "P(R)", "x.25.p_r", FT_UINT8, BASE_HEX, NULL, 0xFE, + "Packet Receive Sequence Number", HFILL }}, + { &hf_x25_mbit_mod8, + { "M Bit", "x.25.m", FT_BOOLEAN, 8, NULL, 0x10, + "More Bit", HFILL }}, + { &hf_x25_mbit_mod128, + { "M Bit", "x.25.m", FT_BOOLEAN, 8, NULL, 0x01, + "More Bit", HFILL }}, + { &hf_x25_p_s_mod8, + { "P(S)", "x.25.p_s", FT_UINT8, BASE_HEX, NULL, 0x0E, + "Packet Send Sequence Number", HFILL }}, + { &hf_x25_p_s_mod128, + { "P(S)", "x.25.p_s", FT_UINT8, BASE_HEX, NULL, 0xFE, + "Packet Send Sequence Number", HFILL }}, }; static gint *ett[] = { &ett_x25, + &ett_x25_gfi, &ett_x25_fac, &ett_x25_fac_unknown, &ett_x25_fac_mark, @@ -2010,13 +2242,43 @@ proto_register_x25(void) &ett_x25_fac_ete_transit_delay, &ett_x25_fac_calling_addr_ext, &ett_x25_fac_call_deflect, - &ett_x25_fac_priority + &ett_x25_fac_priority, + &ett_x25_user_data }; + module_t *x25_module; - proto_x25 = proto_register_protocol ("X.25", "x25"); - proto_ex25 = proto_register_protocol ("Extended X.25 (modulo 128)", "ex25"); - proto_register_field_array (proto_x25, hf8, array_length(hf8)); - proto_register_field_array (proto_ex25, hf128, array_length(hf128)); + proto_x25 = proto_register_protocol ("X.25", "X.25", "x.25"); + proto_register_field_array (proto_x25, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); register_init_routine(&reinit_x25_hashtable); + + x25_subdissector_table = register_dissector_table("x.25.spi", + "X.25 secondary protocol identifier", FT_UINT8, BASE_HEX); + register_heur_dissector_list("x.25", &x25_heur_subdissector_list); + + register_dissector("x.25", dissect_x25, proto_x25); + + /* Preferences */ + x25_module = prefs_register_protocol(proto_x25, NULL); + prefs_register_bool_preference(x25_module, "non_q_bit_is_sna", + "When Q-bit is 0, payload is SNA", "When Q-bit is 0, payload is SNA", + &non_q_bit_is_sna); +} + +void +proto_reg_handoff_x25(void) +{ + dissector_handle_t x25_handle; + + /* + * Get handles for various dissectors. + */ + ip_handle = find_dissector("ip"); + ositp_handle = find_dissector("ositp"); + sna_handle = find_dissector("sna"); + qllc_handle = find_dissector("qllc"); + data_handle = find_dissector("data"); + + x25_handle = find_dissector("x.25"); + dissector_add("llc.dsap", SAP_X25, x25_handle); }