diff options
Diffstat (limited to 'epan/dissectors/packet-3g-a11.c')
-rw-r--r-- | epan/dissectors/packet-3g-a11.c | 2748 |
1 files changed, 2748 insertions, 0 deletions
diff --git a/epan/dissectors/packet-3g-a11.c b/epan/dissectors/packet-3g-a11.c new file mode 100644 index 00000000..27080c46 --- /dev/null +++ b/epan/dissectors/packet-3g-a11.c @@ -0,0 +1,2748 @@ +/* + * packet-3g-a11.c + * Routines for CDMA2000 A11 packet trace + * Copyright 2002, Ryuji Somegawa <somegawa@wide.ad.jp> + * packet-3g-a11.c was written based on 'packet-mip.c'. + * + * packet-3g-a11.c updated by Ravi Valmikam for 3GPP2 TIA-878-A + * Copyright 2005, Ravi Valmikam <rvalmikam@airvananet.com> + * + * packet-mip.c + * Routines for Mobile IP dissection + * Copyright 2000, Stefan Raab <sraab@cisco.com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + * + *Ref: + * https://www.3gpp2.org/Public_html/Specs/A.S0009-C_v3.0_100621.pdf + * https://www.3gpp2.org/Public_html/Specs/A.S0017-D_v1.0_070624.pdf (IOS 5.1) + * https://www.3gpp2.org/Public_html/Specs/A.S0017-D_v2.0_090825.pdf + * https://www.3gpp2.org/Public_html/Specs/A.S0017-D%20v3.0_Interoperability%20Specification%20%28IOS%29%20for%20cdma2000%20Access%20Network%20Interfaces%20-%20Part%207%20%28A10%20and%20A11%20Interfaces%29_20110701.pdf + * https://www.3gpp2.org/Public_html/Specs/A00-20110419-002Er0%20A.S0008-C%20v4.0%20HRPD%20IOS-Pub_20110513.pdf + * https://www.3gpp2.org/Public_html/Specs/A.S0022-0_v2.0_100426.pdf + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/expert.h> +/* Include vendor id translation */ +#include <epan/sminmpec.h> +#include <epan/addr_resolv.h> + +#include "packet-radius.h" + +/* Forward declarations */ +void proto_register_a11(void); +void proto_reg_handoff_a11(void); + +static int registration_request_msg =0; + +/* Initialize the protocol and registered fields */ +static int proto_a11 = -1; +static int hf_a11_type = -1; +static int hf_a11_flags = -1; +static int hf_a11_s = -1; +static int hf_a11_b = -1; +static int hf_a11_d = -1; +static int hf_a11_m = -1; +static int hf_a11_g = -1; +static int hf_a11_v = -1; +static int hf_a11_t = -1; +static int hf_a11_code = -1; +static int hf_a11_status = -1; +static int hf_a11_life = -1; +static int hf_a11_homeaddr = -1; +static int hf_a11_haaddr = -1; +static int hf_a11_coa = -1; +static int hf_a11_ident = -1; +static int hf_a11_ext_type = -1; +static int hf_a11_ext_stype = -1; +static int hf_a11_ext_len = -1; +static int hf_a11_ext = -1; +static int hf_a11_aext_spi = -1; +static int hf_a11_aext_auth = -1; +static int hf_a11_next_nai = -1; + +static int hf_a11_ses_key = -1; +static int hf_a11_ses_mnsrid = -1; +static int hf_a11_ses_sidver = -1; +static int hf_a11_ses_msid_type = -1; +static int hf_a11_ses_msid_len = -1; +static int hf_a11_ses_msid = -1; +static int hf_a11_ses_ptype = -1; + +static int hf_a11_vse_vid = -1; +static int hf_a11_vse_apptype = -1; +static int hf_a11_vse_canid = -1; +static int hf_a11_vse_panid = -1; +static int hf_a11_vse_srvopt = -1; +static int hf_a11_vse_qosmode = -1; +static int hf_a11_vse_pdit = -1; +static int hf_a11_vse_session_parameter = -1; +static int hf_a11_vse_code = -1; +static int hf_a11_vse_dormant = -1; +static int hf_a11_vse_ehrpd_mode = -1; +static int hf_a11_vse_ehrpd_pmk = -1; +static int hf_a11_vse_ehrpd_handoff_info = -1; +static int hf_a11_vse_ehrpd_tunnel_mode = -1; +static int hf_a11_vse_ppaddr = -1; + +/* Additional Session Information */ +static int hf_a11_ase_len_type = -1; +static int hf_a11_ase_srid_type = -1; +static int hf_a11_ase_servopt_type = -1; +static int hf_a11_ase_gre_proto_type = -1; +static int hf_a11_ase_gre_key = -1; +static int hf_a11_ase_pcf_addr_key = -1; + +static int hf_a11_ase_forward_rohc_info_len = -1; +static int hf_a11_ase_forward_maxcid = -1; +static int hf_a11_ase_forward_mrru = -1; +static int hf_a11_ase_forward_large_cids = -1; +static int hf_a11_ase_forward_profile_count = -1; +static int hf_a11_ase_forward_profile = -1; + +static int hf_a11_ase_reverse_rohc_info_len = -1; +static int hf_a11_ase_reverse_maxcid = -1; +static int hf_a11_ase_reverse_mrru = -1; +static int hf_a11_ase_reverse_large_cids = -1; +static int hf_a11_ase_reverse_profile_count = -1; +static int hf_a11_ase_reverse_profile = -1; +static int hf_a11_aut_flow_prof_sub_type = -1; +static int hf_a11_aut_flow_prof_sub_type_len = -1; +static int hf_a11_aut_flow_prof_sub_type_value = -1; +static int hf_a11_serv_opt_prof_max_serv = -1; +static int hf_a11_sub_type = -1; +static int hf_a11_sub_type_length = -1; +static int hf_a11_serv_opt = -1; +static int hf_a11_max_num_serv_opt = -1; +static int hf_a11_bcmcs_stype = -1; +static int hf_a11_bcmcs_entry_len = -1; + +/* Forward QoS Information */ +static int hf_a11_fqi_srid = -1; +static int hf_a11_fqi_flags = -1; +static int hf_a11_fqi_flags_ip_flow = -1; +static int hf_a11_fqi_flags_dscp = -1; +static int hf_a11_fqi_entry_flag = -1; +static int hf_a11_fqi_entry_flag_dscp = -1; +static int hf_a11_fqi_entry_flag_flow_state = -1; +static int hf_a11_fqi_flowcount = -1; +static int hf_a11_fqi_flowid = -1; +static int hf_a11_fqi_entrylen = -1; +/* static int hf_a11_fqi_flowstate = -1; */ +static int hf_a11_fqi_requested_qoslen = -1; +static int hf_a11_fqi_flow_priority = -1; +static int hf_a11_fqi_num_qos_attribute_set = -1; +static int hf_a11_fqi_qos_attribute_setlen = -1; +static int hf_a11_fqi_qos_attribute_setid = -1; +static int hf_a11_fqi_qos_granted_attribute_setid = -1; +static int hf_a11_fqi_verbose = -1; +static int hf_a11_fqi_flow_profileid = -1; +static int hf_a11_fqi_granted_qoslen = -1; + +/* Reverse QoS Information */ +static int hf_a11_rqi_srid = -1; +static int hf_a11_rqi_flowcount = -1; +static int hf_a11_rqi_flowid = -1; +static int hf_a11_rqi_entrylen = -1; +static int hf_a11_rqi_entry_flag = -1; +static int hf_a11_rqi_entry_flag_flow_state = -1; +/* static int hf_a11_rqi_flowstate = -1; */ +static int hf_a11_rqi_requested_qoslen = -1; +static int hf_a11_rqi_flow_priority = -1; +static int hf_a11_rqi_num_qos_attribute_set = -1; +static int hf_a11_rqi_qos_attribute_setlen = -1; +static int hf_a11_rqi_qos_attribute_setid = -1; +static int hf_a11_rqi_qos_granted_attribute_setid = -1; +static int hf_a11_rqi_verbose = -1; +static int hf_a11_rqi_flow_profileid = -1; +/* static int hf_a11_rqi_requested_qos = -1; */ +static int hf_a11_rqi_granted_qoslen = -1; +/* static int hf_a11_rqi_granted_qos = -1; */ + +/* QoS Update Information */ +static int hf_a11_fqui_flowcount = -1; +static int hf_a11_rqui_flowcount = -1; +static int hf_a11_fqui_updated_qoslen = -1; +static int hf_a11_fqui_updated_qos = -1; +static int hf_a11_rqui_updated_qoslen = -1; +static int hf_a11_rqui_updated_qos = -1; +static int hf_a11_subsciber_profile = -1; +/* static int hf_a11_subsciber_profile_len = -1; */ + +/* Initialize the subtree pointers */ +static gint ett_a11 = -1; +static gint ett_a11_flags = -1; +static gint ett_a11_ext = -1; +static gint ett_a11_exts = -1; +static gint ett_a11_radius = -1; +static gint ett_a11_radiuses = -1; +static gint ett_a11_ase = -1; +static gint ett_a11_fqi_flowentry = -1; +static gint ett_a11_fqi_requestedqos = -1; +static gint ett_a11_fqi_qos_attribute_set = -1; +static gint ett_a11_fqi_grantedqos = -1; +static gint ett_a11_rqi_flowentry = -1; +static gint ett_a11_rqi_requestedqos = -1; +static gint ett_a11_rqi_qos_attribute_set = -1; +static gint ett_a11_rqi_grantedqos = -1; +static gint ett_a11_fqi_flags = -1; +static gint ett_a11_fqi_entry_flags = -1; +static gint ett_a11_rqi_entry_flags = -1; +static gint ett_a11_fqui_flowentry = -1; +static gint ett_a11_rqui_flowentry = -1; +static gint ett_a11_subscriber_profile = -1; +static gint ett_a11_forward_rohc = -1; +static gint ett_a11_reverse_rohc = -1; +static gint ett_a11_forward_profile = -1; +static gint ett_a11_reverse_profile = -1; +static gint ett_a11_aut_flow_profile_ids = -1; +static gint ett_a11_bcmcs_entry = -1; + +static expert_field ei_a11_sub_type_length_not2 = EI_INIT; +static expert_field ei_a11_sse_too_short = EI_INIT; +static expert_field ei_a11_bcmcs_too_short = EI_INIT; +static expert_field ei_a11_entry_data_not_dissected = EI_INIT; +static expert_field ei_a11_session_data_not_dissected = EI_INIT; + +static dissector_handle_t a11_handle = NULL; + +/* Port used for Mobile IP based Tunneling Protocol (A11) */ +#define UDP_PORT_3GA11 699 /* Not IANA registered */ + +typedef enum { + REGISTRATION_REQUEST = 1, + REGISTRATION_REPLY = 3, + REGISTRATION_UPDATE = 20, + REGISTRATION_ACK = 21, + SESSION_UPDATE = 22, + SESSION_ACK = 23, + CAPABILITIES_INFO = 24, + CAPABILITIES_INFO_ACK = 25, + BC_SERVICE_REQUEST = 0xb0, /* 3GPP2 A.S0019-A v2.0 */ + BC_SERVICE_REPLY = 0xb1, + BC_REGISTRATION_REQUEST = 0xb2, + BC_REGISTRATION_REPLY = 0xb3, + BC_REGISTRATION_UPDATE = 0xb4, + BC_REGISTRATION_ACK = 0xb5 + +} a11MessageTypes; + +static const value_string a11_types[] = { + {REGISTRATION_REQUEST, "Registration Request"}, + {REGISTRATION_REPLY, "Registration Reply"}, + {REGISTRATION_UPDATE, "Registration Update"}, + {REGISTRATION_ACK, "Registration Ack"}, + {SESSION_UPDATE, "Session Update"}, + {SESSION_ACK, "Session Update Ack"}, + {CAPABILITIES_INFO, "Capabilities Info"}, + {CAPABILITIES_INFO_ACK, "Capabilities Info Ack"}, + {BC_SERVICE_REQUEST, "BC Service Request"}, + {BC_SERVICE_REPLY, "BC Service Response"}, + {BC_REGISTRATION_REQUEST, "BC Registration RequestT"}, + {BC_REGISTRATION_REPLY, "BC Registration Reply"}, + {BC_REGISTRATION_UPDATE, "BC Registration Update"}, + {BC_REGISTRATION_ACK, "BC Registration Acknowledge"}, + + {0, NULL}, +}; +static value_string_ext a11_types_ext = VALUE_STRING_EXT_INIT(a11_types); + +static const value_string a11_ses_ptype_vals[] = { + {0x8881, "Unstructured Byte Stream"}, + {0x88D2, "3GPP2 Packet"}, + {0, NULL}, +}; + +static const value_string a11_reply_codes[]= { + {0, "Reg Accepted"}, + {9, "Connection Update"}, +#if 0 + {1, "Reg Accepted, but Simultaneous Bindings Unsupported."}, + {64, "Reg Deny (FA)- Unspecified Reason"}, + {65, "Reg Deny (FA)- Administratively Prohibited"}, + {66, "Reg Deny (FA)- Insufficient Resources"}, + {67, "Reg Deny (FA)- MN failed Authentication"}, + {68, "Reg Deny (FA)- HA failed Authentication"}, + {69, "Reg Deny (FA)- Requested Lifetime too Long"}, + {70, "Reg Deny (FA)- Poorly Formed Request"}, + {71, "Reg Deny (FA)- Poorly Formed Reply"}, + {72, "Reg Deny (FA)- Requested Encapsulation Unavailable"}, + {73, "Reg Deny (FA)- VJ Compression Unavailable"}, + {74, "Reg Deny (FA)- Requested Reverse Tunnel Unavailable"}, + {75, "Reg Deny (FA)- Reverse Tunnel is Mandatory and 'T' Bit Not Set"}, + {76, "Reg Deny (FA)- Mobile Node Too Distant"}, + {79, "Reg Deny (FA)- Delivery Style Not Supported"}, + {80, "Reg Deny (FA)- Home Network Unreachable"}, + {81, "Reg Deny (FA)- HA Host Unreachable"}, + {82, "Reg Deny (FA)- HA Port Unreachable"}, + {88, "Reg Deny (FA)- HA Unreachable"}, + {96, "Reg Deny (FA)(NAI) - Non Zero Home Address Required"}, + {97, "Reg Deny (FA)(NAI) - Missing NAI"}, + {98, "Reg Deny (FA)(NAI) - Missing Home Agent"}, + {99, "Reg Deny (FA)(NAI) - Missing Home Address"}, +#endif + {128, "Registration Denied - Unspecified"}, /* 3GPP2 A.S0017-D v4.0 */ + {129, "Registration Denied - Administratively Prohibited"}, + {130, "Registration Denied - Insufficient Resources"}, + {131, "Registration Denied - PCF Failed Authentication"}, + /* {132, "Reg Deny (HA)- FA Failed Authentication"}, */ + {133, "Registration Denied - Identification Mismatch"}, + {134, "Registration Denied - Poorly Formed Request"}, + /* {135, "Reg Deny (HA)- Too Many Simultaneous Bindings"}, */ + {136, "Registration Denied - Unknown PDSN Address"}, + {137, "Registration Denied - Requested Reverse Tunnel Unavailable"}, + {138, "Registration Denied - Reverse Tunnel is Mandatory and 'T' Bit Not Set"}, + {139, "Registration Denied - service option not supported"}, + {140, "Registration Denied - no CID available"}, + {141, "Registration Denied - unsupported Vendor ID / Application Type in CVSE"}, + {142, "Registration Denied - nonexistent A10 or IP flow"}, + {0, NULL}, +}; +static value_string_ext a11_reply_codes_ext = VALUE_STRING_EXT_INIT(a11_reply_codes); + +static const value_string a11_ack_status[]= { + {0x00, "Update Accepted"}, + {0x01, "Partial QoS updated"}, + {0x80, "Update Denied - reason unspecified"}, + {0x83, "Update Denied - sending node failed authentication"}, + {0x85, "Update Denied - identification mismatch)"}, + {0x86, "Update Denied - poorly formed registration update"}, + {0xc9, "Update Denied - Session Parameter Not Updated"}, + {0xca, "Update Denied - PMK not requested"}, + {0xfd, "Update Denied - QoS profileID not supported"}, + {0xfe, "Update Denied - insufficient resources"}, + {0xff, "Update Denied - handoff in progress"}, + {0, NULL}, +}; +static value_string_ext a11_ack_status_ext = VALUE_STRING_EXT_INIT(a11_ack_status); + +typedef enum { + MH_AUTH_EXT = 32, + MF_AUTH_EXT = 33, + FH_AUTH_EXT = 34, + GEN_AUTH_EXT = 36, /* RFC 3012 */ + OLD_CVSE_EXT = 37, /* RFC 3115 */ + CVSE_EXT = 38, /* RFC 3115 */ + SS_EXT = 39, /* 3GPP2 IOS4.2 */ + RU_AUTH_EXT = 40, /* 3GPP2 IOS4.2 */ + MN_NAI_EXT = 131, + MF_CHALLENGE_EXT = 132, /* RFC 3012 */ + OLD_NVSE_EXT = 133, /* RFC 3115 */ + NVSE_EXT = 134, /* RFC 3115 */ + BCMCS_EXT = 0xb0 /* 3GPP2 A.S0019-A v2.0 */ +} MIP_EXTS; + + +static const value_string a11_ext_types[]= { + {MH_AUTH_EXT, "Mobile-Home Authentication Extension"}, + {MF_AUTH_EXT, "Mobile-Foreign Authentication Extension"}, + {FH_AUTH_EXT, "Foreign-Home Authentication Extension"}, + {GEN_AUTH_EXT, "Generalized Mobile-IP Authentication Extension"}, + {OLD_CVSE_EXT, "Critical Vendor/Organization Specific Extension (OLD)"}, + {CVSE_EXT, "Critical Vendor/Organization Specific Extension"}, + {SS_EXT, "Session Specific Extension"}, + {RU_AUTH_EXT, "Registration Update Authentication Extension"}, + {MN_NAI_EXT, "Mobile Node NAI Extension"}, + {MF_CHALLENGE_EXT, "MN-FA Challenge Extension"}, + {OLD_NVSE_EXT, "Normal Vendor/Organization Specific Extension (OLD)"}, + {NVSE_EXT, "Normal Vendor/Organization Specific Extension"}, + {BCMCS_EXT, "BCMCS Session Extension"}, + {0, NULL}, +}; +static value_string_ext a11_ext_types_ext = VALUE_STRING_EXT_INIT(a11_ext_types); + +static const value_string a11_ext_stypes[]= { + {1, "MN AAA Extension"}, + {0, NULL}, +}; + +static const value_string a11_ext_nvose_qosmode[]= { + {0x00, "QoS Disabled"}, + {0x01, "QoS Enabled"}, + {0, NULL}, +}; + +static const value_string a11_ext_nvose_srvopt[]= { + {0x0021, "3G High Speed Packet Data"}, + {0x003B, "HRPD Main Service Connection"}, + {0x003C, "Link Layer Assisted Header Removal"}, + {0x003D, "Link Layer Assisted Robust Header Compression"}, + {0x0040, "HRPD Accounting Records Identifier"}, /* 3GPP2 A.S0009-C v4.0 */ + {0x0043, "HRPD Packet Data IP Service where Higher Layer Protocol is IP or ROHC"}, /* 3GPP2 A.S0009-C v4.0 */ + {0x0047, "HRPD AltPPP operation"}, /* 3GPP2 A.S0009-C v4.0 */ + {0, NULL}, +}; + +static const value_string a11_ext_nvose_pdsn_code[]= { + {0xc1, "Connection Release - reason unspecified"}, + {0xc2, "Connection Release - PPP time-out"}, + {0xc3, "Connection Release - registration time-out"}, + {0xc4, "Connection Release - PDSN error"}, + {0xc5, "Connection Release - inter-PCF handoff"}, + {0xc6, "Connection Release - inter-PDSN handoff"}, + {0xc7, "Connection Release - PDSN OAM&P intervention"}, + {0xc8, "Connection Release - accounting error"}, + {0xca, "Connection Release - user (NAI) failed authentication"}, + {0x00, NULL}, +}; + +static const value_string a11_ext_dormant[]= { + {0x0000, "all MS packet data service instances are dormant"}, + {0, NULL}, +}; + + +static const true_false_string a11_tfs_ehrpd_mode = { + "eAT is operating in evolved mode", + "eAT is operating in legacy mode" +}; + +/* 3GPP2 A.S0022-0 v2.0, section 4.2.14 */ +static const true_false_string a11_tfs_ehrpd_pmk = { + "eAT is requesting PMK information", + "eAT is not requesting PMK information", +}; + +/* 3GPP2 A.S0022-0 v2.0, section 4.2.14 */ +static const true_false_string a11_tfs_ehrpd_handoff_info = { + "eAT is requesting information for E-UTRAN handoff", + "eAT is not requesting information for E-UTRAN handoff", +}; + +/* 3GPP2 A.S0022-0 v2.0, section 4.2.14 */ +static const true_false_string a11_tfs_ehrpd_tunnel_mode = { + "eAT is communicating via tunnel from non-eHRPD", + "eAT is communicating directly via eHRPD", +}; + +static const value_string a11_ext_app[]= { + {0x0101, "Accounting (RADIUS)"}, + {0x0102, "Accounting (DIAMETER)"}, + {0x0201, "Mobility Event Indicator (Mobility)"}, + {0x0301, "Data Available Indicator (Data Ready to Send)"}, + {0x0401, "Access Network Identifiers (ANID)"}, + {0x0501, "PDSN Identifiers (Anchor P-P Address)"}, + {0x0601, "Indicators (All Dormant Indicator)"}, + {0x0602, "Indicators (eHRPD Mode)"}, /* 3GPP2 A.S0022-B v1.0 */ + {0x0603, "Indicators (eHRPD Indicators)"}, /* 3GPP2 A.S0009-C v4.0 */ + {0x0701, "PDSN Code (PDSN Code)"}, + {0x0801, "Session Parameter (RN-PDIT:Radio Network Packet Data Inactivity Timer)"}, + {0x0802, "Session Parameter (Always On)"}, + {0x0803, "Session Parameter (QoS Mode)"}, + {0x0901, "Service Option (Service Option Value)"}, + {0x0A01, "PDSN Enabled Features (Flow Control Enabled)"}, + {0x0A02, "PDSN Enabled Features (Packet Boundary Enabled)"}, + {0x0A03, "PDSN Enabled Features (GRE Segmentation Enabled)"}, + {0x0B01, "PCF Enabled Features (Short Data Indication Supported)"}, + {0x0B02, "PCF Enabled Features (GRE Segmentation Enabled)"}, + {0x0C01, "Additional Session Info"}, + {0x0D01, "QoS Information (Forward QoS Information)"}, + {0x0D02, "QoS Information (Reverse QoS Information)"}, + {0x0D03, "QoS Information (Subscriber QoS Profile)"}, + {0x0D04, "QoS Information (Forward Flow Priority Update Information)"}, + {0x0D05, "QoS Information (Reverse Flow Priority Update Information)"}, + {0x0DFE, "QoS Information (Forward QoS Update Information)"}, + {0x0DFF, "QoS Information (Reverse QoS Update Information)"}, + {0x0E01, "Header Compression (ROHC Configuration Parameters)"}, + {0x0F01, "Information (Cause Code)"}, + {0x0F04, "Information (Additional HSGW Information)"}, + {0x1001, "HRPD Indicators (Emergency Services)"}, + {0xB001, "System Identifiers (BSID / HRPD Subnet)"}, + {0, NULL}, +}; +static value_string_ext a11_ext_app_ext = VALUE_STRING_EXT_INIT(a11_ext_app); + +#if 0 +static const value_string a11_airlink_types[]= { + {1, "Session Setup (Y=1)"}, + {2, "Active Start (Y=2)"}, + {3, "Active Stop (Y=3)"}, + {4, "Short Data Burst (Y=4)"}, + {0, NULL}, +}; +#endif + +static const value_string a11_bcmcs_stype_vals[] = { + {1, "BCMCS Flow and Registration Information"}, + {2, "Session Information"}, + {3, "BCMCS Registration Result"}, + {4, "Enhanced Session Information"}, + {0, NULL}, +}; + +#define A11_MSG_MSID_ELEM_LEN_MAX 8 +#define A11_MSG_MSID_LEN_MAX 15 + + + +/* XXXX ToDo This should be imported from packet-rohc.h */ +static const value_string a11_rohc_profile_vals[] = +{ + { 0x0000, "ROHC uncompressed" }, /*RFC 5795*/ + { 0x0001, "ROHC RTP" }, /*RFC 3095*/ + { 0x0002, "ROHC UDP" }, /*RFC 3095*/ + { 0x0003, "ROHC ESP" }, /*RFC 3095*/ + { 0x0004, "ROHC IP" }, /*RFC 3843*/ + { 0x0005, "ROHC LLA" }, /*RFC 3242*/ + { 0x0006, "ROHC TCP" }, /*RFC 4996*/ + { 0x0007, "ROHC RTP/UDP-Lite" }, /*RFC 4019*/ + { 0x0008, "ROHC UDP-Lite" }, /*RFC 4019*/ + { 0x0101, "ROHCv2 RTP" }, /*RFC 5225*/ + { 0x0102, "ROHCv2 UDP" }, /*RFC 5225*/ + { 0x0103, "ROHCv2 ESP" }, /*RFC 5225*/ + { 0x0104, "ROHCv2 IP" }, /*RFC 5225*/ + { 0x0105, "ROHC LLA with R-mode" }, /*RFC 3408*/ + { 0x0107, "ROHCv2 RTP/UDP-Lite" }, /*RFC 5225*/ + { 0x0108, "ROHCv2 UDP-Lite" }, /*RFC 5225*/ + { 0, NULL }, +}; +static value_string_ext a11_rohc_profile_vals_ext = VALUE_STRING_EXT_INIT(a11_rohc_profile_vals); + +#define NUM_ATTR (sizeof(attrs)/sizeof(struct radius_attribute)) + +#define RADIUS_VENDOR_SPECIFIC 26 +#define SKIP_HDR_LEN 6 + +/* decode MSID from SSE */ + +/* MSID is encoded in Binary Coded Decimal format + First Byte: [odd-indicator] [Digit 1] + Second Byte: [Digit 3] [Digit 2] + .. + if[odd] + Last Byte: [Digit N] [Digit N-1] + else + Last Byte: [F] [Digit N] +*/ + + +/* 3GPP2 A.S0008-C v4.0, 3GPP2 A.S0019-A v2.0 */ +static const value_string a11_ses_msid_type_vals[] = +{ + { 0x0000, "No Identity Code" }, + { 0x0001, "MEID" }, + { 0x0005, "ESN" }, + { 0x0006, "IMSI" }, + { 0x0008, "BCMCS Flow ID" }, + { 0, NULL }, +}; + +static int * const a11_flags[] = { + &hf_a11_s, + &hf_a11_b, + &hf_a11_d, + &hf_a11_m, + &hf_a11_g, + &hf_a11_v, + &hf_a11_t, + NULL +}; + +static void +decode_sse(proto_tree *ext_tree, packet_info *pinfo, tvbuff_t *tvb, int offset, guint ext_len, proto_item *ext_len_item) +{ + guint8 msid_len; + guint8 msid_start_offset; + guint8 msid_num_digits; + guint8 msid_index; + char *msid_digits; + const char *p_msid; + gboolean odd_even_ind; + + /* Decode Protocol Type */ + if (ext_len < 2) { + expert_add_info_format(pinfo, ext_len_item, &ei_a11_sse_too_short, + "Cannot decode Protocol Type - SSE too short"); + return; + } + proto_tree_add_item(ext_tree, hf_a11_ses_ptype, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + ext_len -= 2; + + /* Decode Session Key */ + if (ext_len < 4) { + expert_add_info_format(pinfo, ext_len_item, &ei_a11_sse_too_short, + "Cannot decode Session Key - SSE too short"); + return; + } + proto_tree_add_item(ext_tree, hf_a11_ses_key, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + ext_len -= 4; + + + /* Decode Session Id Version */ + if (ext_len < 2) { + expert_add_info_format(pinfo, ext_len_item, &ei_a11_sse_too_short, + "Cannot decode Session Id Version - SSE too short"); + return; + } + proto_tree_add_item(ext_tree, hf_a11_ses_sidver, tvb, offset+1, 1, ENC_BIG_ENDIAN); + offset += 2; + ext_len -= 2; + + + /* Decode SRID */ + if (ext_len < 2) { + expert_add_info_format(pinfo, ext_len_item, &ei_a11_sse_too_short, + "Cannot decode SRID - SSE too short"); + return; + } + proto_tree_add_item(ext_tree, hf_a11_ses_mnsrid, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + ext_len -= 2; + + /* MSID Type */ + if (ext_len < 2) { + expert_add_info_format(pinfo, ext_len_item, &ei_a11_sse_too_short, + "Cannot decode MSID Type - SSE too short"); + return; + } + proto_tree_add_item(ext_tree, hf_a11_ses_msid_type, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + ext_len -= 2; + + + /* MSID Len */ + if (ext_len < 1) { + expert_add_info_format(pinfo, ext_len_item, &ei_a11_sse_too_short, + "Cannot decode MSID Length - SSE too short"); + return; + } + msid_len = tvb_get_guint8(tvb, offset); + proto_tree_add_item(ext_tree, hf_a11_ses_msid_len, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + ext_len -= 1; + + /* Decode MSID */ + if (ext_len < msid_len) { + expert_add_info_format(pinfo, ext_len_item, &ei_a11_sse_too_short, + "Cannot decode MSID - SSE too short"); + return; + } + + msid_digits = (char *)wmem_alloc(pinfo->pool, A11_MSG_MSID_LEN_MAX+2); + msid_start_offset = offset; + + if (msid_len > A11_MSG_MSID_ELEM_LEN_MAX) { + p_msid = "MSID is too long"; + } else if (msid_len == 0) { + p_msid = "MSID is too short"; + } else { + /* Decode the BCD digits */ + for (msid_index=0; msid_index<msid_len; msid_index++) { + guint8 msid_digit = tvb_get_guint8(tvb, offset); + offset += 1; + ext_len -= 1; + + msid_digits[msid_index*2] = (msid_digit & 0x0F) + '0'; + msid_digits[(msid_index*2) + 1] = ((msid_digit & 0xF0) >> 4) + '0'; + } + + odd_even_ind = (msid_digits[0] == '1'); + + if (odd_even_ind) { + msid_num_digits = ((msid_len-1) * 2) + 1; + } else { + msid_num_digits = (msid_len-1) * 2; + } + + msid_digits[msid_num_digits + 1] = '\0'; + p_msid = msid_digits + 1; + } + + proto_tree_add_string(ext_tree, hf_a11_ses_msid, tvb, msid_start_offset, msid_len, p_msid); +} + +static void +decode_bcmcs(proto_tree* ext_tree, packet_info *pinfo, tvbuff_t* tvb, int offset, guint ext_len, proto_item *ext_len_item) +{ + + guint8 bc_stype, entry_len; + + /* Decode Protocol Type */ + if (ext_len < 2) { + expert_add_info_format(pinfo, ext_len_item, &ei_a11_bcmcs_too_short, + "Cannot decode Protocol Type - BCMCS too short"); + return; + } + + bc_stype=tvb_get_guint8(tvb, offset); + proto_tree_add_item(ext_tree, hf_a11_bcmcs_stype, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + ext_len -= 1; + + switch (bc_stype) { + case 1: + { + int i = 0; + proto_tree *entry_tree; + while (ext_len > 0) { + i++; + entry_len = tvb_get_guint8(tvb, offset); + if (entry_len == 0) { + ext_len -= 1; + entry_len = 1; + } else { + ext_len = ext_len - entry_len; + } + entry_tree = proto_tree_add_subtree_format(ext_tree, tvb, offset, entry_len, + ett_a11_bcmcs_entry, NULL, "BCMCS Information Entry %u", i); + proto_tree_add_item(entry_tree, hf_a11_bcmcs_entry_len, tvb, offset, 1, ENC_BIG_ENDIAN); + + proto_tree_add_expert(ext_tree, pinfo, &ei_a11_entry_data_not_dissected, tvb, offset, entry_len -1); + offset = offset+entry_len; + } + } + break; + default: + proto_tree_add_expert_format(ext_tree, pinfo, &ei_a11_session_data_not_dissected, tvb, offset, -1, "Session Data Type %u Not dissected yet", bc_stype); + return; + break; + } + + +} + +/* RADIUS attributed */ +static void +dissect_a11_radius( tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree, int app_len) +{ + proto_tree *radius_tree; + + /* None of this really matters if we don't have a tree */ + if (!tree) + return; + + /* return if length of extension is not valid */ + if (tvb_reported_length_remaining(tvb, offset) < 12) { + return; + } + + radius_tree = proto_tree_add_subtree(tree, tvb, offset - 2, app_len, ett_a11_radiuses, NULL, "Airlink Record"); + + dissect_attribute_value_pairs(radius_tree, pinfo, tvb, offset, app_len-2); + + +} + +/* X.S0011-005-D v2.0 Service Option Profile */ +static const gchar * +dissect_3gpp2_service_option_profile(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo) +{ + int offset = 0; + guint8 sub_type, sub_type_length; + proto_item *pi; + + /* Maximum service connections/Link Flows total 32 bit*/ + proto_tree_add_item(tree, hf_a11_serv_opt_prof_max_serv, tvb, offset, 4, ENC_BIG_ENDIAN); + offset+=4; + + while (tvb_reported_length_remaining(tvb,offset) > 0) { + sub_type_length = tvb_get_guint8(tvb,offset+1); + + sub_type = tvb_get_guint8(tvb,offset); + proto_tree_add_item(tree, hf_a11_sub_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + pi = proto_tree_add_item(tree, hf_a11_sub_type_length, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + if (sub_type_length < 2) { + expert_add_info(pinfo, pi, &ei_a11_sub_type_length_not2); + sub_type_length = 2; + } + if (sub_type == 1) { + proto_tree_add_item(tree, hf_a11_serv_opt, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + /* Max number of service instances of Service Option n */ + proto_tree_add_item(tree, hf_a11_max_num_serv_opt, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + } + + offset = offset + sub_type_length-2; + } + + return ""; + +} + +static const value_string a11_aut_flow_prof_subtype_vals[] = { + {0x1, "ProfileID-Forward"}, + {0x2, "ProfileID-Reverse"}, + {0x3, "ProfileID-Bi-direction"}, + {0, NULL}, +}; + +/* X.S0011-005-D v2.0 Authorized Flow Profile IDs for the User */ +static const gchar * +dissect_3gpp2_radius_aut_flow_profile_ids(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo) +{ + proto_tree *sub_tree; + int offset = 0; + proto_item *item; + guint8 sub_type, sub_type_length; + guint32 value; + + while (tvb_reported_length_remaining(tvb,offset) > 0) { + sub_type = tvb_get_guint8(tvb,offset); + sub_type_length = tvb_get_guint8(tvb,offset+1); + /* value is 2 octets */ + value = tvb_get_ntohs(tvb,offset+2); + sub_tree = proto_tree_add_subtree_format(tree, tvb, offset, sub_type_length, ett_a11_aut_flow_profile_ids, &item, + "%s = %u", val_to_str_const(sub_type, a11_aut_flow_prof_subtype_vals, "Unknown"), value); + + proto_tree_add_item(sub_tree, hf_a11_aut_flow_prof_sub_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + item = proto_tree_add_item(sub_tree, hf_a11_aut_flow_prof_sub_type_len, tvb, offset, 1, ENC_BIG_ENDIAN); + if (sub_type_length < 2) { + expert_add_info(pinfo, item, &ei_a11_sub_type_length_not2); + sub_type_length = 2; + } + offset += 1; + proto_tree_add_item(sub_tree, hf_a11_aut_flow_prof_sub_type_value, tvb, offset, 2, ENC_BIG_ENDIAN); + + offset = offset+sub_type_length - 2; + } + + return ""; +} + +/* Code to dissect Additional Session Info */ +static void +dissect_ase(tvbuff_t *tvb, int offset, guint ase_len, proto_tree *ext_tree) +{ + guint clen = 0; /* consumed length */ + + while (clen < ase_len) { + proto_tree *exts_tree; + guint8 srid = tvb_get_guint8(tvb, offset+1); + guint16 service_option = tvb_get_ntohs(tvb, offset+2); + guint8 entry_length; + int entry_start_offset; + + /* Entry Length */ + entry_start_offset = offset; + entry_length = tvb_get_guint8(tvb, offset); + + if (registration_request_msg && ((service_option == 64) || (service_option == 67))) + exts_tree = proto_tree_add_subtree_format(ext_tree, tvb, offset, entry_length+1, + ett_a11_ase, NULL, "GRE Key Entry (SRID: %d)", srid); + else + exts_tree = proto_tree_add_subtree_format(ext_tree, tvb, offset, entry_length, + ett_a11_ase, NULL, "GRE Key Entry (SRID: %d)", srid); + + proto_tree_add_item(exts_tree, hf_a11_ase_len_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* SRID */ + proto_tree_add_item(exts_tree, hf_a11_ase_srid_type, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Service Option */ + proto_tree_add_item(exts_tree, hf_a11_ase_servopt_type, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* GRE Protocol Type*/ + proto_tree_add_item(exts_tree, hf_a11_ase_gre_proto_type, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* GRE Key */ + proto_tree_add_item(exts_tree, hf_a11_ase_gre_key, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* PCF IP Address */ + proto_tree_add_item(exts_tree, hf_a11_ase_pcf_addr_key, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + if ((entry_length>14)&&(registration_request_msg)) { + if (service_option == 0x0043) { + proto_tree *extv_tree; + guint8 profile_count = tvb_get_guint8(tvb, offset+6); + guint8 profile_index = 0; + guint8 reverse_profile_count; + + proto_tree *extt_tree = proto_tree_add_subtree(exts_tree, tvb, offset,6+(profile_count*2)+1, + ett_a11_forward_rohc, NULL, "Forward ROHC Info"); + + proto_tree_add_item(extt_tree, hf_a11_ase_forward_rohc_info_len, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + proto_tree_add_item(extt_tree, hf_a11_ase_forward_maxcid, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(extt_tree, hf_a11_ase_forward_mrru, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(extt_tree, hf_a11_ase_forward_large_cids, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + profile_count=tvb_get_guint8(tvb, offset); + + proto_tree_add_item(extt_tree, hf_a11_ase_forward_profile_count, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + + for (profile_index=0; profile_index<profile_count; profile_index++) { + proto_tree *extu_tree = proto_tree_add_subtree_format(extt_tree, tvb, offset, (2*profile_count), + ett_a11_forward_profile, NULL, "Forward Profile : %d", profile_index); + proto_tree_add_item(extu_tree, hf_a11_ase_forward_profile, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + }/*for*/ + + + reverse_profile_count=tvb_get_guint8(tvb, offset+6); + + extv_tree = proto_tree_add_subtree(exts_tree, tvb, offset,6+(reverse_profile_count*2)+1, + ett_a11_reverse_rohc, NULL, "Reverse ROHC Info"); + + proto_tree_add_item(extv_tree, hf_a11_ase_reverse_rohc_info_len, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + + proto_tree_add_item(extv_tree, hf_a11_ase_reverse_maxcid, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(extv_tree, hf_a11_ase_reverse_mrru, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + proto_tree_add_item(extv_tree, hf_a11_ase_reverse_large_cids, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + profile_count=tvb_get_guint8(tvb, offset); + + proto_tree_add_item(extv_tree, hf_a11_ase_reverse_profile_count, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + + for (profile_index=0; profile_index<reverse_profile_count; profile_index++) { + proto_tree *extw_tree = proto_tree_add_subtree_format(extv_tree, tvb, offset, (2*profile_count), + ett_a11_reverse_profile, NULL, "Reverse Profile : %d", profile_index); + + proto_tree_add_item(extw_tree, hf_a11_ase_reverse_profile, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + }/*for*/ + }/* Service option */ + + }/* if */ + clen += entry_length + 1; + /* Set offset = start of next entry in case of padding */ + offset = entry_start_offset + entry_length+1; + + } /* while */ + + registration_request_msg =0; +} + + +#define A11_FQI_IPFLOW_DISC_ENABLED 0x80 +#define A11_FQI_DSCP_INCLUDED 0x40 + +static void +dissect_fwd_qosinfo_flags(tvbuff_t *tvb, int offset, proto_tree *ext_tree, guint8 *p_dscp_included) +{ + guint8 flags = tvb_get_guint8(tvb, offset); + + proto_item *ti = proto_tree_add_item(ext_tree, hf_a11_fqi_flags, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree *flags_tree = proto_item_add_subtree(ti, ett_a11_fqi_flags); + + proto_tree_add_item(flags_tree, hf_a11_fqi_flags_ip_flow, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(flags_tree, hf_a11_fqi_flags_dscp, tvb, offset, 1, ENC_BIG_ENDIAN); + + if (flags & A11_FQI_DSCP_INCLUDED) { + *p_dscp_included = 1; + } else { + *p_dscp_included = 0; + } +} + +static void +dissect_fqi_entry_flags(tvbuff_t *tvb, int offset, proto_tree *ext_tree, guint8 dscp_enabled) +{ + proto_item *ti = proto_tree_add_item(ext_tree, hf_a11_fqi_entry_flag, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree *flags_tree = proto_item_add_subtree(ti, ett_a11_fqi_entry_flags); + + if (dscp_enabled) { + proto_tree_add_item(flags_tree, hf_a11_fqi_entry_flag_dscp, tvb, offset, 1, ENC_BIG_ENDIAN); + } + + proto_tree_add_item(flags_tree, hf_a11_fqi_entry_flag_flow_state, tvb, offset, 1, ENC_BIG_ENDIAN); +} + +static void +dissect_rqi_entry_flags(tvbuff_t *tvb, int offset, proto_tree *ext_tree) +{ + proto_item *ti = proto_tree_add_item(ext_tree, hf_a11_rqi_entry_flag, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree *flags_tree = proto_item_add_subtree(ti, ett_a11_rqi_entry_flags); + + proto_tree_add_item(flags_tree, hf_a11_rqi_entry_flag_flow_state, tvb, offset, 1, ENC_BIG_ENDIAN); +} + +/* Code to dissect Forward QoS Info */ +static void +dissect_fwd_qosinfo(tvbuff_t *tvb, int offset, proto_tree *ext_tree) +{ + int clen = 0; /* consumed length */ + guint8 flow_count; + guint8 flow_index; + guint8 dscp_enabled = 0; + + /* SR Id */ + proto_tree_add_item(ext_tree, hf_a11_fqi_srid, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Flags */ + dissect_fwd_qosinfo_flags(tvb, offset+clen, ext_tree, &dscp_enabled); + clen++; + + /* Flow Count */ + flow_count = tvb_get_guint8(tvb, offset+clen); + flow_count &= 0x1F; + proto_tree_add_item(ext_tree, hf_a11_fqi_flowcount, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + for (flow_index=0; flow_index<flow_count; flow_index++) { + guint8 requested_qos_len = 0; + guint8 granted_qos_len = 0; + + guint8 entry_len = tvb_get_guint8(tvb, offset+clen); + guint8 flow_id = tvb_get_guint8(tvb, offset+clen+1); + + proto_tree *flow_tree = proto_tree_add_subtree_format(ext_tree, tvb, offset+clen, + entry_len+1, ett_a11_fqi_flowentry, NULL, "Forward Flow Entry (Flow Id: %d)", flow_id); + + /* Entry Length */ + proto_tree_add_item(flow_tree, hf_a11_fqi_entrylen, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Flow Id */ + proto_tree_add_item(flow_tree, hf_a11_fqi_flowid, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* DSCP and Flow State*/ + dissect_fqi_entry_flags(tvb, offset+clen, flow_tree, dscp_enabled); + clen++; + + + /* Requested QoS Length */ + requested_qos_len = tvb_get_guint8(tvb, offset+clen); + proto_tree_add_item(flow_tree, hf_a11_fqi_requested_qoslen, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Requested QoS Blob */ + if (requested_qos_len) { + proto_tree *exts_tree2; + + proto_tree *exts_tree1 = proto_tree_add_subtree(flow_tree, tvb, offset+clen,requested_qos_len, + ett_a11_fqi_requestedqos, NULL, "Forward Requested QoS "); + + /* Flow Priority */ + proto_tree_add_item(exts_tree1, hf_a11_fqi_flow_priority, tvb,offset+clen , 1, ENC_BIG_ENDIAN); + + /* Num of QoS attribute sets */ + proto_tree_add_item(exts_tree1, hf_a11_fqi_num_qos_attribute_set, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + + /* QoS attribute set length */ + proto_tree_add_item(exts_tree1, hf_a11_fqi_qos_attribute_setlen, tvb, offset+clen, 2, ENC_BIG_ENDIAN); + clen++; + + /* QoS attribute set */ + exts_tree2 = proto_tree_add_subtree(exts_tree1, tvb, offset+clen, 4, ett_a11_fqi_qos_attribute_set, + NULL, "QoS Attribute Set"); + + /* QoS attribute setid */ + proto_tree_add_item(exts_tree2, hf_a11_fqi_qos_attribute_setid, tvb, offset+clen, 2, ENC_BIG_ENDIAN); + clen++; + + /* verbose */ + proto_tree_add_item(exts_tree2, hf_a11_fqi_verbose, tvb,offset+clen, 1, ENC_BIG_ENDIAN); + + /* Flow profile id */ + proto_tree_add_item(exts_tree2, hf_a11_fqi_flow_profileid, tvb, offset+clen, 3, ENC_BIG_ENDIAN); + clen += 3; + + } + + /* Granted QoS Length */ + granted_qos_len = tvb_get_guint8(tvb, offset+clen); + proto_tree_add_item(flow_tree, hf_a11_fqi_granted_qoslen, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Granted QoS Blob */ + if (granted_qos_len) { + proto_tree *exts_tree3; + + exts_tree3 = proto_tree_add_subtree(flow_tree, tvb, offset+clen, granted_qos_len, + ett_a11_fqi_grantedqos, NULL, "Forward Granted QoS "); + + /* QoS attribute setid */ + proto_tree_add_item(exts_tree3, hf_a11_fqi_qos_granted_attribute_setid, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + } + } /* for (flow_index...) */ +} + +/* Code to dissect Reverse QoS Info */ +static void +dissect_rev_qosinfo(tvbuff_t *tvb, int offset, proto_tree *ext_tree) +{ + int clen = 0; /* consumed length */ + guint8 flow_count; + guint8 flow_index; + + /* SR Id */ + proto_tree_add_item(ext_tree, hf_a11_rqi_srid, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Flow Count */ + flow_count = tvb_get_guint8(tvb, offset+clen); + flow_count &= 0x1F; + proto_tree_add_item(ext_tree, hf_a11_rqi_flowcount, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + for (flow_index=0; flow_index<flow_count; flow_index++) { + guint8 requested_qos_len; + guint8 granted_qos_len; + + guint8 entry_len = tvb_get_guint8(tvb, offset+clen); + guint8 flow_id = tvb_get_guint8(tvb, offset+clen+1); + + proto_tree *flow_tree = proto_tree_add_subtree_format + (ext_tree, tvb, offset+clen, entry_len+1, ett_a11_rqi_flowentry, NULL, + "Reverse Flow Entry (Flow Id: %d)", flow_id); + + /* Entry Length */ + proto_tree_add_item(flow_tree, hf_a11_rqi_entrylen, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Flow Id */ + proto_tree_add_item(flow_tree, hf_a11_rqi_flowid, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Flags */ + dissect_rqi_entry_flags(tvb, offset+clen, flow_tree); + clen++; + + /* Requested QoS Length */ + requested_qos_len = tvb_get_guint8(tvb, offset+clen); + proto_tree_add_item(flow_tree, hf_a11_rqi_requested_qoslen, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Requested QoS Blob */ + if (requested_qos_len) { + proto_tree *exts_tree1, *exts_tree2; + + exts_tree1 = proto_tree_add_subtree(flow_tree, tvb, offset+clen,requested_qos_len, + ett_a11_rqi_requestedqos, NULL, "Reverse Requested QoS "); + + /* Flow Priority */ + proto_tree_add_item(exts_tree1, hf_a11_rqi_flow_priority, tvb,offset+clen , 1, ENC_BIG_ENDIAN); + + /* Num of QoS attribute sets */ + proto_tree_add_item(exts_tree1, hf_a11_rqi_num_qos_attribute_set, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + + /* QoS attribute set length */ + proto_tree_add_item(exts_tree1, hf_a11_rqi_qos_attribute_setlen, tvb, offset+clen, 2, ENC_BIG_ENDIAN); + clen++; + + /* QoS attribute set */ + exts_tree2 = proto_tree_add_subtree(exts_tree1, tvb, offset+clen, 4, + ett_a11_rqi_qos_attribute_set, NULL, "QoS Attribute Set"); + + /* QoS attribute setid */ + proto_tree_add_item(exts_tree2, hf_a11_rqi_qos_attribute_setid, tvb, offset+clen, 2, ENC_BIG_ENDIAN); + clen++; + + /* verbose */ + proto_tree_add_item(exts_tree2, hf_a11_rqi_verbose, tvb,offset+clen, 1, ENC_BIG_ENDIAN); + + /* Flow profile id */ + proto_tree_add_item(exts_tree2, hf_a11_rqi_flow_profileid, tvb, offset+clen, 3, ENC_BIG_ENDIAN); + clen += 3; + } + + /* Granted QoS Length */ + granted_qos_len = tvb_get_guint8(tvb, offset+clen); + proto_tree_add_item(flow_tree, hf_a11_rqi_granted_qoslen, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Granted QoS Blob */ + if (granted_qos_len) { + proto_tree *exts_tree3; + + exts_tree3 = proto_tree_add_subtree(flow_tree, tvb, offset+clen,granted_qos_len, + ett_a11_rqi_grantedqos, NULL, "Reverse Granted QoS "); + + /* QoS attribute setid */ + proto_tree_add_item(exts_tree3, hf_a11_rqi_qos_granted_attribute_setid, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + } + } +} + + +/* Code to dissect Subscriber QoS Profile */ +static void +dissect_subscriber_qos_profile(tvbuff_t *tvb, packet_info *pinfo, int offset, int ext_len, proto_tree *ext_tree) +{ + proto_tree *exts_tree; + + int qos_profile_len = ext_len; + + exts_tree = + proto_tree_add_subtree_format(ext_tree, tvb, offset, 0, ett_a11_subscriber_profile, NULL, + "Subscriber Qos Profile (%d bytes)", + qos_profile_len); + + /* Subscriber QoS profile */ + if (qos_profile_len) { + proto_tree_add_item + (exts_tree, hf_a11_subsciber_profile, tvb, offset, + qos_profile_len, ENC_NA); + + dissect_attribute_value_pairs(exts_tree, pinfo, tvb, offset, qos_profile_len); + } +} + +/* Code to dissect Forward QoS Update Info */ +static void +dissect_fwd_qosupdate_info(tvbuff_t *tvb, int offset, proto_tree *ext_tree) +{ + int clen = 0; /* consumed length */ + guint8 flow_count; + guint8 flow_index; + + /* Flow Count */ + flow_count = tvb_get_guint8(tvb, offset+clen); + proto_tree_add_item(ext_tree, hf_a11_fqui_flowcount, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + for (flow_index=0; flow_index<flow_count; flow_index++) { + proto_tree *exts_tree; + guint8 granted_qos_len; + + guint8 flow_id = tvb_get_guint8(tvb, offset+clen); + + exts_tree = proto_tree_add_subtree_format + (ext_tree, tvb, offset+clen, 1, ett_a11_fqui_flowentry, NULL, + "Forward Flow Entry (Flow Id: %d)", flow_id); + + clen++; + + /* Forward QoS Sub Blob Length */ + granted_qos_len = tvb_get_guint8(tvb, offset+clen); + proto_tree_add_item + (exts_tree, hf_a11_fqui_updated_qoslen, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Forward QoS Sub Blob */ + if (granted_qos_len) { + proto_tree_add_item + (exts_tree, hf_a11_fqui_updated_qos, tvb, offset+clen, + granted_qos_len, ENC_NA); + clen += granted_qos_len; + } + } +} + + +/* Code to dissect Reverse QoS Update Info */ +static void +dissect_rev_qosupdate_info(tvbuff_t *tvb, int offset, proto_tree *ext_tree) +{ + int clen = 0; /* consumed length */ + guint8 flow_count; + guint8 flow_index; + + /* Flow Count */ + flow_count = tvb_get_guint8(tvb, offset+clen); + proto_tree_add_item(ext_tree, hf_a11_rqui_flowcount, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + for (flow_index=0; flow_index<flow_count; flow_index++) { + proto_tree *exts_tree; + guint8 granted_qos_len; + + guint8 flow_id = tvb_get_guint8(tvb, offset+clen); + + exts_tree = proto_tree_add_subtree_format + (ext_tree, tvb, offset+clen, 1, ett_a11_rqui_flowentry, NULL, + "Reverse Flow Entry (Flow Id: %d)", flow_id); + clen++; + + /* Reverse QoS Sub Blob Length */ + granted_qos_len = tvb_get_guint8(tvb, offset+clen); + proto_tree_add_item + (exts_tree, hf_a11_rqui_updated_qoslen, tvb, offset+clen, 1, ENC_BIG_ENDIAN); + clen++; + + /* Reverse QoS Sub Blob */ + if (granted_qos_len) { + proto_tree_add_item + (exts_tree, hf_a11_rqui_updated_qos, tvb, offset+clen, + granted_qos_len, ENC_NA); + clen += granted_qos_len; + } + } +} + +/* Code to dissect extensions */ +static void +dissect_a11_extensions( tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree) +{ + proto_tree *exts_tree; + proto_tree *ext_tree; + proto_item *ext_len_item = NULL; + guint ext_len; + guint8 ext_type; + guint8 ext_subtype = 0; + guint hdrLen; + + gint16 apptype = -1; + + /* Add our tree, if we have extensions */ + exts_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_a11_exts, NULL, "Extensions"); + + /* And, handle each extension */ + while (tvb_reported_length_remaining(tvb, offset) > 0) { + + /* Get our extension info */ + ext_type = tvb_get_guint8(tvb, offset); + if (ext_type == GEN_AUTH_EXT) { + /* + * Very nasty . . breaks normal extensions, since the length is + * in the wrong place :( + */ + ext_subtype = tvb_get_guint8(tvb, offset + 1); + ext_len = tvb_get_ntohs(tvb, offset + 2); + hdrLen = 4; + } else if ((ext_type == CVSE_EXT) || (ext_type == OLD_CVSE_EXT)) { + ext_len = tvb_get_ntohs(tvb, offset + 2); + ext_subtype = tvb_get_guint8(tvb, offset + 8); + hdrLen = 4; + } else { + ext_len = tvb_get_guint8(tvb, offset + 1); + hdrLen = 2; + } + + ext_tree = proto_tree_add_subtree_format(exts_tree, tvb, offset, ext_len + hdrLen, + ett_a11_ext, NULL, "Extension: %s", + val_to_str_ext(ext_type, &a11_ext_types_ext, + "Unknown Extension %u")); + + proto_tree_add_uint(ext_tree, hf_a11_ext_type, tvb, offset, 1, ext_type); + offset += 1; + + if (ext_type == SS_EXT) { + ext_len_item = proto_tree_add_uint(ext_tree, hf_a11_ext_len, tvb, offset, 1, ext_len); + offset += 1; + } + else if ((ext_type == CVSE_EXT) || (ext_type == OLD_CVSE_EXT)) { + offset += 1; + ext_len_item = proto_tree_add_uint(ext_tree, hf_a11_ext_len, tvb, offset, 2, ext_len); + offset += 2; + } + else if (ext_type != GEN_AUTH_EXT) { + /* Another nasty hack since GEN_AUTH_EXT broke everything */ + ext_len_item = proto_tree_add_uint(ext_tree, hf_a11_ext_len, tvb, offset, 1, ext_len); + offset += 1; + } + + switch (ext_type) { + case SS_EXT: + decode_sse(ext_tree, pinfo, tvb, offset, ext_len, ext_len_item); + offset += ext_len; + ext_len = 0; + break; + + case MH_AUTH_EXT: + case MF_AUTH_EXT: + case FH_AUTH_EXT: + case RU_AUTH_EXT: + /* All these extensions look the same. 4 byte SPI followed by a key */ + if (ext_len < 4) + break; + proto_tree_add_item(ext_tree, hf_a11_aext_spi, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + ext_len -= 4; + if (ext_len == 0) + break; + proto_tree_add_item(ext_tree, hf_a11_aext_auth, tvb, offset, ext_len, + ENC_NA); + break; + case MN_NAI_EXT: + if (ext_len == 0) + break; + /* + * RFC 2486 speaks only of ASCII; RFC 4282 expands that to + * UTF-8. + */ + proto_tree_add_item(ext_tree, hf_a11_next_nai, tvb, offset, + ext_len, ENC_UTF_8); + break; + + case GEN_AUTH_EXT: /* RFC 3012 */ + /* + * Very nasty . . breaks normal extensions, since the length is + * in the wrong place :( + */ + proto_tree_add_uint(ext_tree, hf_a11_ext_stype, tvb, offset, 1, ext_subtype); + offset += 1; + proto_tree_add_uint(ext_tree, hf_a11_ext_len, tvb, offset, 2, ext_len); + offset += 2; + /* SPI */ + if (ext_len < 4) + break; + proto_tree_add_item(ext_tree, hf_a11_aext_spi, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + ext_len -= 4; + /* Key */ + if (ext_len == 0) + break; + proto_tree_add_item(ext_tree, hf_a11_aext_auth, tvb, offset, + ext_len, ENC_NA); + + break; + case OLD_CVSE_EXT: /* RFC 3115 */ + case CVSE_EXT: /* RFC 3115 */ + if (ext_len < 4) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_vid, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + ext_len -= 4; + if (ext_len < 2) + break; + apptype = tvb_get_ntohs(tvb, offset); + proto_tree_add_uint(ext_tree, hf_a11_vse_apptype, tvb, offset, 2, apptype); + offset += 2; + ext_len -= 2; + if (apptype == 0x0101) { + if (tvb_reported_length_remaining(tvb, offset) > 0) { + dissect_a11_radius(tvb, pinfo, offset, ext_tree, ext_len + 2); + } + } + break; + case OLD_NVSE_EXT: /* RFC 3115 */ + case NVSE_EXT: /* RFC 3115 */ + if (ext_len < 6) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_vid, tvb, offset+2, 4, ENC_BIG_ENDIAN); + offset += 6; + ext_len -= 6; + proto_tree_add_item(ext_tree, hf_a11_vse_apptype, tvb, offset, 2, ENC_BIG_ENDIAN); + + if (ext_len < 2) + break; + apptype = tvb_get_ntohs(tvb, offset); + offset += 2; + ext_len -= 2; + switch (apptype) { + case 0x0401: + if (ext_len < 5) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_panid, tvb, offset, 5, ENC_NA); + offset += 5; + ext_len -= 5; + if (ext_len < 5) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_canid, tvb, offset, 5, ENC_NA); + break; + case 0x0501: + if (ext_len < 4) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_ppaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + break; + case 0x0601: + if (ext_len < 2) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_dormant, tvb, offset, 2, ENC_BIG_ENDIAN); + break; + case 0x0602: + /* eHRPD Mode */ + if (ext_len < 1) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_ehrpd_mode, tvb, offset, 1, ENC_BIG_ENDIAN); + break; + case 0x0603: + /* eHRPD Indicators */ + if (ext_len < 1) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_ehrpd_pmk, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(ext_tree, hf_a11_vse_ehrpd_handoff_info, tvb, offset, 1, ENC_BIG_ENDIAN); + proto_tree_add_item(ext_tree, hf_a11_vse_ehrpd_tunnel_mode, tvb, offset, 1, ENC_BIG_ENDIAN); + break; + case 0x0701: + if (ext_len < 1) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_code, tvb, offset, 1, ENC_BIG_ENDIAN); + break; + case 0x0801: + if (ext_len < 1) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_pdit, tvb, offset, 1, ENC_BIG_ENDIAN); + break; + case 0x0802: + proto_tree_add_item(ext_tree, hf_a11_vse_session_parameter, tvb, offset, -1, ENC_NA); + break; + case 0x0803: + proto_tree_add_item(ext_tree, hf_a11_vse_qosmode, tvb, offset, 1, ENC_BIG_ENDIAN); + break; + case 0x0901: + if (ext_len < 2) + break; + proto_tree_add_item(ext_tree, hf_a11_vse_srvopt, tvb, offset, 2, ENC_BIG_ENDIAN); + break; + case 0x0C01: + dissect_ase(tvb, offset, ext_len, ext_tree); + break; + case 0x0D01: + dissect_fwd_qosinfo(tvb, offset, ext_tree); + break; + case 0x0D02: + dissect_rev_qosinfo(tvb, offset, ext_tree); + break; + case 0x0D03: + dissect_subscriber_qos_profile(tvb, pinfo, offset, ext_len, ext_tree); + break; + case 0x0DFE: + dissect_fwd_qosupdate_info(tvb, offset, ext_tree); + break; + case 0x0DFF: + dissect_rev_qosupdate_info(tvb, offset, ext_tree); + break; + } + + break; + case BCMCS_EXT: + decode_bcmcs(ext_tree, pinfo, tvb, offset, ext_len, ext_len_item); + offset += ext_len; + ext_len = 0; + break; + case MF_CHALLENGE_EXT: /* RFC 3012 */ + /* The default dissector is good here. The challenge is all hex anyway. */ + default: + proto_tree_add_item(ext_tree, hf_a11_ext, tvb, offset, ext_len, ENC_NA); + break; + } /* ext type */ + + offset += ext_len; + } /* while data remaining */ + +} /* dissect_a11_extensions */ + +/* Code to actually dissect the packets */ +static int +dissect_a11( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) +{ + /* Set up structures we will need to add the protocol subtree and manage it */ + proto_item *ti; + proto_tree *a11_tree = NULL; + guint8 type; + guint offset = 0; + + if (!tvb_bytes_exist(tvb, offset, 1)) + return 0; /* not enough data to check message type */ + + type = tvb_get_guint8(tvb, offset); + if (try_val_to_str_ext(type, &a11_types_ext) == NULL) + return 0; /* not a known message type */ + + /* Make entries in Protocol column and Info column on summary display */ + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "3GPP2 A11"); + col_clear(pinfo->cinfo, COL_INFO); + + if (type == REGISTRATION_REQUEST) + registration_request_msg =1; + else + registration_request_msg =0; + + + switch (type) { + case REGISTRATION_REQUEST: + + registration_request_msg = 1; + col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Request: PDSN=%s PCF=%s", + tvb_ip_to_str(pinfo->pool, tvb, 8), + tvb_ip_to_str(pinfo->pool, tvb, 12)); + + if (tree) { + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* flags */ + proto_tree_add_bitmask(a11_tree, tvb, offset, hf_a11_flags, + ett_a11_flags, a11_flags, ENC_NA); + offset += 1; + + /* lifetime */ + proto_tree_add_item(a11_tree, hf_a11_life, tvb, offset, 2, ENC_BIG_ENDIAN); + offset +=2; + + /* home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* home agent address */ + proto_tree_add_item(a11_tree, hf_a11_haaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Care of Address */ + proto_tree_add_item(a11_tree, hf_a11_coa, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + case REGISTRATION_REPLY: + col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Reply: PDSN=%s, Code=%u", + tvb_ip_to_str(pinfo->pool, tvb, 8), tvb_get_guint8(tvb,1)); + + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reply Code */ + proto_tree_add_item(a11_tree, hf_a11_code, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Registration Lifetime */ + proto_tree_add_item(a11_tree, hf_a11_life, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Home Agent Address */ + proto_tree_add_item(a11_tree, hf_a11_haaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + } /* if tree */ + + break; + case REGISTRATION_UPDATE: + col_add_fstr(pinfo->cinfo, COL_INFO,"Reg Update: PDSN=%s", + tvb_ip_to_str(pinfo->pool, tvb, 8)); + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reserved */ + offset += 3; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Home Agent Address */ + proto_tree_add_item(a11_tree, hf_a11_haaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + case REGISTRATION_ACK: + col_add_fstr(pinfo->cinfo, COL_INFO, "Reg Ack: PCF=%s Status=%u", + tvb_ip_to_str(pinfo->pool, tvb, 8), + tvb_get_guint8(tvb,3)); + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reserved */ + offset += 2; + + /* Ack Status */ + proto_tree_add_item(a11_tree, hf_a11_status, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Care of Address */ + proto_tree_add_item(a11_tree, hf_a11_coa, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + case SESSION_UPDATE: /* IOS4.3 */ + col_add_fstr(pinfo->cinfo, COL_INFO,"Ses Update: PDSN=%s", + tvb_ip_to_str(pinfo->pool, tvb, 8)); + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reserved */ + offset += 3; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Home Agent Address */ + proto_tree_add_item(a11_tree, hf_a11_haaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + case SESSION_ACK: /* IOS4.3 */ + col_add_fstr(pinfo->cinfo, COL_INFO, "Ses Upd Ack: PCF=%s, Status=%u", + tvb_ip_to_str(pinfo->pool, tvb, 8), + tvb_get_guint8(tvb,3)); + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reserved */ + offset += 2; + + /* Ack Status */ + proto_tree_add_item(a11_tree, hf_a11_status, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Care of Address */ + proto_tree_add_item(a11_tree, hf_a11_coa, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + case CAPABILITIES_INFO: /* IOS5.1 */ + col_add_fstr(pinfo->cinfo, COL_INFO, "Cap Info: PDSN=%s, PCF=%s", + tvb_ip_to_str(pinfo->pool, tvb, 8), + tvb_ip_to_str(pinfo->pool, tvb, 12)); + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reserved */ + offset += 3; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Home Agent Address */ + proto_tree_add_item(a11_tree, hf_a11_haaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Care of Address */ + proto_tree_add_item(a11_tree, hf_a11_coa, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + case CAPABILITIES_INFO_ACK: /* IOS5.1 */ + col_add_fstr(pinfo->cinfo, COL_INFO, "Cap Info Ack: PCF=%s", + tvb_ip_to_str(pinfo->pool, tvb, 8)); + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reserved */ + offset += 3; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Care of Address */ + proto_tree_add_item(a11_tree, hf_a11_coa, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + case BC_SERVICE_REQUEST: + col_add_fstr(pinfo->cinfo, COL_INFO, "Service Request: PCF=%s ", + tvb_ip_to_str(pinfo->pool, tvb, offset + 8)); + + if (tree) { + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 4; + + /* home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Care-of-Address */ + proto_tree_add_item(a11_tree, hf_a11_coa, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + + case BC_SERVICE_REPLY: + col_add_fstr(pinfo->cinfo, COL_INFO, "Service Response: BSN=%s ", + tvb_ip_to_str(pinfo->pool, tvb, offset + 8)); + + if (tree) { + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 3; + + /* Reply Code */ + proto_tree_add_item(a11_tree, hf_a11_code, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Home Agent */ + proto_tree_add_item(a11_tree, hf_a11_haaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + case BC_REGISTRATION_REQUEST: + col_add_fstr(pinfo->cinfo, COL_INFO, "BC Reg Request: BSN=%s ", + tvb_ip_to_str(pinfo->pool, tvb, offset + 8)); + + if (tree) { + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* flags */ + proto_tree_add_bitmask(a11_tree, tvb, offset, hf_a11_flags, + ett_a11_flags, a11_flags, ENC_NA); + offset += 1; + + /* lifetime */ + proto_tree_add_item(a11_tree, hf_a11_life, tvb, offset, 2, ENC_BIG_ENDIAN); + offset +=2; + + /* home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Home Agent */ + proto_tree_add_item(a11_tree, hf_a11_haaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Care-of-Address */ + proto_tree_add_item(a11_tree, hf_a11_coa, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + + offset += 8; + + } /* if tree */ + break; + + + case BC_REGISTRATION_REPLY: + col_add_fstr(pinfo->cinfo, COL_INFO, "BC Reg Reply: BSN=%s, Code=%u", + tvb_ip_to_str(pinfo->pool, tvb, offset + 8), + tvb_get_guint8(tvb, offset + 1)); + + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reply Code */ + proto_tree_add_item(a11_tree, hf_a11_code, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Registration Lifetime */ + proto_tree_add_item(a11_tree, hf_a11_life, tvb, offset, 2, ENC_BIG_ENDIAN); + offset += 2; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Home Agent */ + proto_tree_add_item(a11_tree, hf_a11_haaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + + offset += 8; + } /* if tree */ + + break; + case BC_REGISTRATION_UPDATE: + col_add_fstr(pinfo->cinfo, COL_INFO,"BC Reg Update: BSN=%s", + tvb_ip_to_str(pinfo->pool, tvb, offset + 8)); + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reserved */ + offset += 3; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Home Agent */ + proto_tree_add_item(a11_tree, hf_a11_haaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + offset += 8; + + } /* if tree */ + break; + case BC_REGISTRATION_ACK: + col_add_fstr(pinfo->cinfo, COL_INFO, "BC Reg Acknowledge: PCF=%s Status=%u", + tvb_ip_to_str(pinfo->pool, tvb, offset + 8), + tvb_get_guint8(tvb, offset + 3)); + if (tree) { + /* Add Subtree */ + ti = proto_tree_add_item(tree, proto_a11, tvb, offset, -1, ENC_NA); + a11_tree = proto_item_add_subtree(ti, ett_a11); + + /* Type */ + proto_tree_add_uint(a11_tree, hf_a11_type, tvb, offset, 1, type); + offset += 1; + + /* Reserved */ + offset += 2; + + /* Ack Status */ + proto_tree_add_item(a11_tree, hf_a11_status, tvb, offset, 1, ENC_BIG_ENDIAN); + offset += 1; + + /* Home address */ + proto_tree_add_item(a11_tree, hf_a11_homeaddr, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Care-of-Address */ + proto_tree_add_item(a11_tree, hf_a11_coa, tvb, offset, 4, ENC_BIG_ENDIAN); + offset += 4; + + /* Identifier - assumed to be an NTP time here */ + proto_tree_add_item(a11_tree, hf_a11_ident, tvb, offset, 8, ENC_TIME_NTP|ENC_BIG_ENDIAN); + + offset += 8; + + } /* if tree */ + break; + + default: + DISSECTOR_ASSERT_NOT_REACHED(); + break; + } /* End switch */ + + if (tree && a11_tree) { + if (tvb_reported_length_remaining(tvb, offset) > 0) + dissect_a11_extensions(tvb, pinfo, offset, a11_tree); + } + return tvb_reported_length(tvb); +} /* dissect_a11 */ + +/* Register the protocol with Wireshark */ +void +proto_register_a11(void) +{ + +/* Setup list of header fields */ + static hf_register_info hf[] = { + { &hf_a11_type, + { "Message Type", "a11.type", + FT_UINT8, BASE_DEC | BASE_EXT_STRING, &a11_types_ext, 0, + "A11 Message Type", HFILL } + }, + { &hf_a11_flags, + { "Flags", "a11.flags", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL} + }, + { &hf_a11_s, + { "Simultaneous Bindings", "a11.s", + FT_BOOLEAN, 8, NULL, 128, + "Simultaneous Bindings Allowed", HFILL } + }, + { &hf_a11_b, + { "Broadcast Datagrams", "a11.b", + FT_BOOLEAN, 8, NULL, 64, + "Broadcast Datagrams requested", HFILL } + }, + { &hf_a11_d, + { "Co-located Care-of Address", "a11.d", + FT_BOOLEAN, 8, NULL, 32, + "MN using Co-located Care-of address", HFILL } + }, + { &hf_a11_m, + { "Minimal Encapsulation", "a11.m", + FT_BOOLEAN, 8, NULL, 16, + "MN wants Minimal encapsulation", HFILL } + }, + { &hf_a11_g, + { "GRE", "a11.g", + FT_BOOLEAN, 8, NULL, 8, + "MN wants GRE encapsulation", HFILL } + }, + { &hf_a11_v, + { "Van Jacobson", "a11.v", + FT_BOOLEAN, 8, NULL, 4, + NULL, HFILL } + }, + { &hf_a11_t, + { "Reverse Tunneling", "a11.t", + FT_BOOLEAN, 8, NULL, 2, + "Reverse tunneling requested", HFILL } + }, + { &hf_a11_code, + { "Reply Code", "a11.code", + FT_UINT8, BASE_DEC | BASE_EXT_STRING, &a11_reply_codes_ext, 0, + "A11 Registration Reply code", HFILL } + }, + { &hf_a11_status, + { "Reply Status", "a11.ackstat", + FT_UINT8, BASE_DEC | BASE_EXT_STRING, &a11_ack_status_ext, 0, + "A11 Registration Ack Status", HFILL } + }, + { &hf_a11_life, + { "Lifetime", "a11.life", + FT_UINT16, BASE_DEC, NULL, 0, + "A11 Registration Lifetime", HFILL } + }, + { &hf_a11_homeaddr, + { "Home Address", "a11.homeaddr", + FT_IPv4, BASE_NONE, NULL, 0, + "Mobile Node's home address", HFILL } + }, + + { &hf_a11_haaddr, + { "Home Agent", "a11.haaddr", + FT_IPv4, BASE_NONE, NULL, 0, + "Home agent IP Address", HFILL } + }, + { &hf_a11_coa, + { "Care of Address", "a11.coa", + FT_IPv4, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_ident, + { "Identification", "a11.ident", + FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0, + "MN Identification", HFILL } + }, + { &hf_a11_ext_type, + { "Extension Type", "a11.ext.type", + FT_UINT8, BASE_DEC | BASE_EXT_STRING, &a11_ext_types_ext, 0, + "Mobile IP Extension Type", HFILL } + }, + { &hf_a11_ext_stype, + { "Gen Auth Ext SubType", "a11.ext.auth.subtype", + FT_UINT8, BASE_DEC, VALS(a11_ext_stypes), 0, + "Mobile IP Auth Extension Sub Type", HFILL } + }, + { &hf_a11_ext_len, + { "Extension Length", "a11.ext.len", + FT_UINT16, BASE_DEC, NULL, 0, + "Mobile IP Extension Length", HFILL } + }, + { &hf_a11_ext, + { "Extension", "a11.extension", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_aext_spi, + { "SPI", "a11.auth.spi", + FT_UINT32, BASE_HEX, NULL, 0, + "Authentication Header Security Parameter Index", HFILL } + }, + { &hf_a11_aext_auth, + { "Authenticator", "a11.auth.auth", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_next_nai, + { "NAI", "a11.nai", + FT_STRING, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_ses_key, + { "Key", "a11.ext.key", + FT_UINT32, BASE_HEX, NULL, 0, + "Session Key", HFILL } + }, + { &hf_a11_ses_sidver, + { "Session ID Version", "a11.ext.sidver", + FT_UINT8, BASE_DEC, NULL, 3, + NULL, HFILL} + }, + { &hf_a11_ses_mnsrid, + { "MNSR-ID", "a11.ext.mnsrid", + FT_UINT16, BASE_HEX, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_ses_msid_type, + { "MSID Type", "a11.ext.msid_type", + FT_UINT16, BASE_DEC, VALS(a11_ses_msid_type_vals), 0, + NULL, HFILL } + }, + { &hf_a11_ses_msid_len, + { "MSID Length", "a11.ext.msid_len", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_ses_msid, + { "MSID(BCD)", "a11.ext.msid", + FT_STRING, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_ses_ptype, + { "Protocol Type", "a11.ext.ptype", + FT_UINT16, BASE_HEX, VALS(a11_ses_ptype_vals), 0, + NULL, HFILL } + }, + { &hf_a11_vse_vid, + { "Vendor ID", "a11.ext.vid", + FT_UINT32, BASE_ENTERPRISES, STRINGS_ENTERPRISES, 0, + NULL, HFILL } + }, + { &hf_a11_vse_apptype, + { "Application Type", "a11.ext.apptype", + FT_UINT16, BASE_HEX | BASE_EXT_STRING, &a11_ext_app_ext, 0, + NULL, HFILL } + }, + { &hf_a11_vse_ppaddr, + { "Anchor P-P Address", "a11.ext.ppaddr", + FT_IPv4, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_vse_dormant, + { "All Dormant Indicator", "a11.ext.dormant", + FT_UINT16, BASE_HEX, VALS(a11_ext_dormant), 0, + NULL, HFILL } + }, + { &hf_a11_vse_ehrpd_mode, + { "eHRPD Mode", "a11.ext.ehrpd.mode", + FT_BOOLEAN, 8, TFS(&a11_tfs_ehrpd_mode), 0, + NULL, HFILL } + }, + { &hf_a11_vse_ehrpd_pmk, + { "PMK", "a11.ext.ehrpd.pmk", + FT_BOOLEAN, 8, TFS(&a11_tfs_ehrpd_pmk), 0x04, + NULL, HFILL } + }, + { &hf_a11_vse_ehrpd_handoff_info, + { "E-UTRAN Handoff Info", "a11.ext.ehrpd.handoff_info", + FT_BOOLEAN, 8, TFS(&a11_tfs_ehrpd_handoff_info), 0x02, + NULL, HFILL } + }, + { &hf_a11_vse_ehrpd_tunnel_mode, + { "Tunnel Mode", "a11.ext.ehrpd.tunnel_mode", + FT_BOOLEAN, 8, TFS(&a11_tfs_ehrpd_tunnel_mode), 0x01, + NULL, HFILL } + }, + { &hf_a11_vse_code, + { "Reply Code", "a11.ext.code", + FT_UINT8, BASE_DEC | BASE_EXT_STRING, &a11_reply_codes_ext, 0, + NULL, HFILL } + }, + /* XXX: Is this the correct filter name ?? */ + { &hf_a11_vse_pdit, + { "PDSN Code", "a11.ext.code", + FT_UINT8, BASE_HEX, VALS(a11_ext_nvose_pdsn_code), 0, + NULL, HFILL } + }, + { &hf_a11_vse_session_parameter, + { "Session Parameter - Always On", "a11.ext.session_parameter", + FT_NONE, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_vse_srvopt, + { "Service Option", "a11.ext.srvopt", + FT_UINT16, BASE_HEX, VALS(a11_ext_nvose_srvopt), 0, + NULL, HFILL } + }, + { &hf_a11_vse_panid, + { "PANID", "a11.ext.panid", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_vse_canid, + { "CANID", "a11.ext.canid", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_vse_qosmode, + { "QoS Mode", "a11.ext.qosmode", + FT_UINT8, BASE_HEX, VALS(a11_ext_nvose_qosmode), 0, + NULL, HFILL } + }, + { &hf_a11_ase_len_type, + { "Entry Length", "a11.ext.ase.len", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_ase_srid_type, + { "Service Reference ID (SRID)", "a11.ext.ase.srid", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_ase_servopt_type, + { "Service Option", "a11.ext.ase.srvopt", + FT_UINT16, BASE_HEX, VALS(a11_ext_nvose_srvopt), 0, + NULL, HFILL } + }, + { &hf_a11_ase_gre_proto_type, + { "GRE Protocol Type", "a11.ext.ase.ptype", + FT_UINT16, BASE_HEX, VALS(a11_ses_ptype_vals), 0, + NULL, HFILL } + }, + { &hf_a11_ase_gre_key, + { "GRE Key", "a11.ext.ase.key", + FT_UINT32, BASE_HEX, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_ase_pcf_addr_key, + { "PCF IP Address", "a11.ext.ase.pcfip", + FT_IPv4, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_fqi_srid, + { "SRID", "a11.ext.fqi.srid", + FT_UINT8, BASE_DEC, NULL, 0, + "Forward Flow Entry SRID", HFILL } + }, + { &hf_a11_fqi_flags, + { "Flags", "a11.ext.fqi.flags", + FT_UINT8, BASE_HEX, NULL, 0, + "Forward Flow Entry Flags", HFILL } + }, + { &hf_a11_fqi_flags_ip_flow, + { "IP Flow Discriminator", "a11.ext.fqi.flags.ip_flow", + FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), A11_FQI_IPFLOW_DISC_ENABLED, + NULL, HFILL } + }, + { &hf_a11_fqi_flags_dscp, + { "DSCP", "a11.ext.fqi.flags.dscp", + FT_BOOLEAN, 8, TFS(&tfs_included_not_included), A11_FQI_DSCP_INCLUDED, + NULL, HFILL } + }, + { &hf_a11_fqi_entry_flag, + { "DSCP and Flow State", "a11.ext.fqi.entry_flag", + FT_UINT8, BASE_HEX, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_fqi_entry_flag_dscp, + { "DSCP", "a11.ext.fqi.entry_flag.dscp", + FT_UINT8, BASE_HEX, NULL, 0x7E, + NULL, HFILL } + }, + { &hf_a11_fqi_entry_flag_flow_state, + { "Flow State", "a11.ext.fqi.entry_flag.flow_state", + FT_BOOLEAN, 8, TFS(&tfs_active_inactive), 0x01, + NULL, HFILL } + }, + { &hf_a11_fqi_flowcount, + { "Forward Flow Count", "a11.ext.fqi.flowcount", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_fqi_flowid, + { "Forward Flow Id", "a11.ext.fqi.flowid", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_fqi_entrylen, + { "Entry Length", "a11.ext.fqi.entrylen", + FT_UINT8, BASE_DEC, NULL, 0, + "Forward Entry Length", HFILL } + }, +#if 0 + { &hf_a11_fqi_flowstate, + { "Forward Flow State", "a11.ext.fqi.flowstate", + FT_UINT8, BASE_HEX, NULL, 0, + NULL, HFILL } + }, +#endif + { &hf_a11_fqi_requested_qoslen, + { "Requested QoS Length", "a11.ext.fqi.reqqoslen", + FT_UINT8, BASE_DEC, NULL, 0, + "Forward Requested QoS Length", HFILL } + }, + { &hf_a11_fqi_flow_priority, + { "Flow Priority", "a11.ext.fqi.flow_priority", + FT_UINT8, BASE_DEC, NULL, 0xF0, + NULL, HFILL } + }, + { &hf_a11_fqi_num_qos_attribute_set, + { "Number of QoS Attribute Sets", "a11.ext.fqi.num_qos_attribute_set", + FT_UINT8, BASE_DEC, NULL, 0x0E, + NULL, HFILL } + }, + { &hf_a11_fqi_qos_attribute_setlen, + { "QoS Attribute Set Length", "a11.ext.fqi.qos_attribute_setlen", + FT_UINT16, BASE_DEC, NULL, 0x01E0, + NULL, HFILL } + }, + { &hf_a11_fqi_qos_attribute_setid, + { "QoS Attribute SetID", "a11.ext.fqi.qos_attribute_setid", + FT_UINT16, BASE_DEC, NULL, 0x1FC0, + NULL, HFILL } + }, + { &hf_a11_fqi_verbose, + { "Verbose", "a11.ext.fqi.verbose", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_a11_fqi_flow_profileid, + { "Flow Profile Id", "a11.ext.fqi.flow_profileid", + FT_UINT24, BASE_DEC, NULL, 0x1FFFE0, + NULL, HFILL } + }, + { &hf_a11_fqi_qos_granted_attribute_setid, + { "QoS Attribute SetID", "a11.ext.fqi.qos_granted_attribute_setid", + FT_UINT8, BASE_DEC, NULL, 0xFE, + NULL, HFILL } + }, + { &hf_a11_fqi_granted_qoslen, + { "Granted QoS Length", "a11.ext.fqi.graqoslen", + FT_UINT8, BASE_DEC, NULL, 0, + "Forward Granted QoS Length", HFILL } + }, + { &hf_a11_rqi_flow_priority, + { "Flow Priority", "a11.ext.rqi.flow_priority", + FT_UINT8, BASE_DEC, NULL, 0xF0, + NULL, HFILL } + }, + { &hf_a11_rqi_num_qos_attribute_set, + { "Number of QoS Attribute Sets", "a11.ext.rqi.num_qos_attribute_set", + FT_UINT8, BASE_DEC, NULL, 0x0E, + NULL, HFILL } + }, + { &hf_a11_rqi_qos_attribute_setlen, + { "QoS Attribute Set Length", "a11.ext.rqi.qos_attribute_setlen", + FT_UINT16, BASE_DEC, NULL, 0x01E0, + NULL, HFILL } + }, + { &hf_a11_rqi_qos_attribute_setid, + { "QoS Attribute SetID", "a11.ext.rqi.qos_attribute_setid", + FT_UINT16, BASE_DEC, NULL, 0x1FC0, + NULL, HFILL } + }, + { &hf_a11_rqi_verbose, + { "Verbose", "a11.ext.rqi.verbose", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_a11_rqi_flow_profileid, + { "Flow Profile Id", "a11.ext.rqi.flow_profileid", + FT_UINT24, BASE_DEC, NULL, 0x1FFFE0, + NULL, HFILL } + }, + { &hf_a11_rqi_qos_granted_attribute_setid, + { "QoS Attribute SetID", "a11.ext.rqi.qos_granted_attribute_setid", + FT_UINT8, BASE_DEC, NULL, 0xFE, + NULL, HFILL } + }, + { &hf_a11_rqi_srid, + { "SRID", "a11.ext.rqi.srid", + FT_UINT8, BASE_DEC, NULL, 0, + "Reverse Flow Entry SRID", HFILL } + }, + { &hf_a11_rqi_flowcount, + { "Reverse Flow Count", "a11.ext.rqi.flowcount", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_rqi_flowid, + { "Reverse Flow Id", "a11.ext.rqi.flowid", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_rqi_entrylen, + { "Entry Length", "a11.ext.rqi.entrylen", + FT_UINT8, BASE_DEC, NULL, 0, + "Reverse Flow Entry Length", HFILL } + }, + { &hf_a11_rqi_entry_flag, + { "Flags", "a11.ext.rqi.entry_flag", + FT_UINT8, BASE_HEX, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_rqi_entry_flag_flow_state, + { "Flow State", "a11.ext.rqi.entry_flag.flow_state", + FT_BOOLEAN, 8, TFS(&tfs_active_inactive), 0x01, + NULL, HFILL } + }, +#if 0 + { &hf_a11_rqi_flowstate, + { "Flow State", "a11.ext.rqi.flowstate", + FT_UINT8, BASE_HEX, NULL, 0, + "Reverse Flow State", HFILL } + }, +#endif + { &hf_a11_rqi_requested_qoslen, + { "Requested QoS Length", "a11.ext.rqi.reqqoslen", + FT_UINT8, BASE_DEC, NULL, 0, + "Reverse Requested QoS Length", HFILL } + }, +#if 0 + { &hf_a11_rqi_requested_qos, + { "Requested QoS", "a11.ext.rqi.reqqos", + FT_BYTES, BASE_NONE, NULL, 0, + "Reverse Requested QoS", HFILL } + }, +#endif + { &hf_a11_rqi_granted_qoslen, + { "Granted QoS Length", "a11.ext.rqi.graqoslen", + FT_UINT8, BASE_DEC, NULL, 0, + "Reverse Granted QoS Length", HFILL } + }, +#if 0 + { &hf_a11_rqi_granted_qos, + { "Granted QoS", "a11.ext.rqi.graqos", + FT_BYTES, BASE_NONE, NULL, 0, + "Reverse Granted QoS", HFILL } + }, +#endif + { &hf_a11_fqui_flowcount, + { "Forward QoS Update Flow Count", "a11.ext.fqui.flowcount", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_rqui_flowcount, + { "Reverse QoS Update Flow Count", "a11.ext.rqui.flowcount", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_fqui_updated_qoslen, + { "Forward Updated QoS Sub-Blob Length", "a11.ext.fqui.updatedqoslen", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_fqui_updated_qos, + { "Forward Updated QoS Sub-Blob", "a11.ext.fqui.updatedqos", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_rqui_updated_qoslen, + { "Reverse Updated QoS Sub-Blob Length", "a11.ext.rqui.updatedqoslen", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_rqui_updated_qos, + { "Reverse Updated QoS Sub-Blob", "a11.ext.rqui.updatedqos", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } + }, +#if 0 + { &hf_a11_subsciber_profile_len, + { "Subscriber QoS Profile Length", "a11.ext.sqp.profilelen", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } + }, +#endif + { &hf_a11_subsciber_profile, + { "Subscriber QoS Profile", "a11.ext.sqp.profile", + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } + }, + + { &hf_a11_ase_forward_rohc_info_len, + { "Forward ROHC Info Length", "a11.ext.ase.forwardlen", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + + { &hf_a11_ase_forward_maxcid, + { "Forward MAXCID", "a11.ext.ase.maxcid", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + + { &hf_a11_ase_forward_mrru, + { "Forward MRRU", "a11.ext.ase.mrru", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + + { &hf_a11_ase_forward_large_cids, + { "Forward Large CIDS", "a11.ext.ase.forwardlargecids", + FT_BOOLEAN, 8, NULL, 0x80, + NULL, HFILL } + }, + + { &hf_a11_ase_forward_profile_count, + { "Forward Profile Count", "a11.ext.ase.profilecount", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + + + { &hf_a11_ase_forward_profile, + { "Forward Profile", "a11.ext.ase.forwardprofile", + FT_UINT16, BASE_DEC | BASE_EXT_STRING, &a11_rohc_profile_vals_ext, 0, + NULL, HFILL } + }, + + { &hf_a11_ase_reverse_rohc_info_len, + { "Reverse ROHC Info Length", "a11.ext.ase.reverselen", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + + { &hf_a11_ase_reverse_maxcid, + { "Reverse MAXCID", "a11.ext.ase.revmaxcid", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + + { &hf_a11_ase_reverse_mrru, + { "Reverse MRRU", "a11.ext.ase.revmrru", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + + { &hf_a11_ase_reverse_large_cids, + { "Reverse Large CIDS", "a11.ext.ase.reverselargecids", + FT_UINT8, BASE_DEC, NULL, 128, + NULL, HFILL } + }, + + { &hf_a11_ase_reverse_profile_count, + { "Reverse Profile Count", "a11.ext.ase.revprofilecount", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + + + { &hf_a11_ase_reverse_profile, + { "Reverse Profile", "a11.ext.ase.reverseprofile", + FT_UINT16, BASE_DEC | BASE_EXT_STRING, &a11_rohc_profile_vals_ext, 0, + NULL, HFILL } + }, + { &hf_a11_aut_flow_prof_sub_type, + { "Sub type", "a11.aut_flow_prof.sub_type", + FT_UINT8, BASE_DEC, VALS(a11_aut_flow_prof_subtype_vals), 0, + NULL, HFILL } + }, + { &hf_a11_aut_flow_prof_sub_type_len, + { "Length", "a11.aut_flow_prof.length", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_aut_flow_prof_sub_type_value, + { "Value", "a11.aut_flow_prof.value", + FT_UINT16, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_serv_opt_prof_max_serv, + { "Service-Connections-Per-Link-flow", "a11.serv_opt_prof.scplf", + FT_UINT32, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_sub_type, + { "Sub-Type", "a11.sub_type", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_sub_type_length, + { "Sub-Type Length", "a11.sub_type_length", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_serv_opt, + { "Service Option", "a11.serviceoption", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_max_num_serv_opt, + { "Max number of service instances of Service Option", "a11.max_serviceoptions", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + { &hf_a11_bcmcs_stype, + { "Protocol Type", "a11.ext.bcmcs.ptype", + FT_UINT8, BASE_HEX, VALS(a11_bcmcs_stype_vals), 0, + NULL, HFILL } + }, + { &hf_a11_bcmcs_entry_len, + { "Entry length", "a11.ext.bcmcs.entry_len", + FT_UINT8, BASE_DEC, NULL, 0, + NULL, HFILL } + }, + + }; + + /* Setup protocol subtree array */ + static gint *ett[] = { + &ett_a11, + &ett_a11_flags, + &ett_a11_ext, + &ett_a11_exts, + &ett_a11_radius, + &ett_a11_radiuses, + &ett_a11_ase, + &ett_a11_fqi_flowentry, + &ett_a11_fqi_requestedqos, + &ett_a11_fqi_qos_attribute_set, + &ett_a11_fqi_grantedqos, + &ett_a11_rqi_flowentry, + &ett_a11_rqi_requestedqos, + &ett_a11_rqi_qos_attribute_set, + &ett_a11_rqi_grantedqos, + &ett_a11_fqi_flags, + &ett_a11_fqi_entry_flags, + &ett_a11_rqi_entry_flags, + &ett_a11_fqui_flowentry, + &ett_a11_rqui_flowentry, + &ett_a11_subscriber_profile, + &ett_a11_forward_rohc, + &ett_a11_reverse_rohc, + &ett_a11_forward_profile, + &ett_a11_reverse_profile, + &ett_a11_aut_flow_profile_ids, + &ett_a11_bcmcs_entry, + }; + + static ei_register_info ei[] = { + { &ei_a11_sub_type_length_not2, { "a11.sub_type_length.bad", PI_PROTOCOL, PI_WARN, "Sub-Type Length should be at least 2", EXPFILL }}, + { &ei_a11_sse_too_short, { "a11.sse_too_short", PI_MALFORMED, PI_ERROR, "SSE too short", EXPFILL }}, + { &ei_a11_bcmcs_too_short, { "a11.bcmcs_too_short", PI_MALFORMED, PI_ERROR, "BCMCS too short", EXPFILL }}, + { &ei_a11_entry_data_not_dissected, { "a11.entry_data_not_dissected", PI_UNDECODED, PI_WARN, "Entry Data, Not dissected yet", EXPFILL }}, + { &ei_a11_session_data_not_dissected, { "a11.session_data_not_dissected", PI_UNDECODED, PI_WARN, "Session Data Type Not dissected yet", EXPFILL }}, + }; + + expert_module_t* expert_a11; + + /* Register the protocol name and description */ + proto_a11 = proto_register_protocol("3GPP2 A11", "3GPP2 A11", "a11"); + + /* Register the dissector by name */ + a11_handle = register_dissector("a11", dissect_a11, proto_a11); + + /* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_a11, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + expert_a11 = expert_register_protocol(proto_a11); + expert_register_field_array(expert_a11, ei, array_length(ei)); +} + +void +proto_reg_handoff_a11(void) +{ + dissector_add_uint_with_preference("udp.port", UDP_PORT_3GA11, a11_handle); + + /* 3GPP2-Service-Option-Profile(74) */ + radius_register_avp_dissector(VENDOR_THE3GPP2, 74, dissect_3gpp2_service_option_profile); + /* 3GPP2-Authorized-Flow-Profile-IDs(131) */ + radius_register_avp_dissector(VENDOR_THE3GPP2, 131, dissect_3gpp2_radius_aut_flow_profile_ids); +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ |