/* packet-mausb.c * Routines for Media Agnostic USB dissection * Copyright 2014, Intel Corporation * Author: Sean O. Stalley * * Dedicated to Robert & Dorothy Stalley * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include "packet-tcp.h" #include "packet-llc.h" #include "packet-usb.h" #include "packet-mausb.h" void proto_reg_handoff_mausb(void); void proto_register_mausb(void); static dissector_handle_t mausb_tcp_handle; static dissector_handle_t mausb_pkt_handle; /* For SNAP Packets */ static int hf_llc_mausb_pid; /* Initialize the protocol and registered fields */ static int proto_mausb; static int hf_mausb_version; static int hf_mausb_flags; static int hf_mausb_flag_host; static int hf_mausb_flag_retry; static int hf_mausb_flag_timestamp; static int hf_mausb_flag_reserved; static int * const mausb_flag_fields[] = { &hf_mausb_flag_host, &hf_mausb_flag_retry, &hf_mausb_flag_timestamp, &hf_mausb_flag_reserved, NULL }; static int hf_mausb_type; static int hf_mausb_length; static int hf_mausb_dev_handle; static int hf_mausb_ep_handle; static int hf_mausb_ep_handle_d; static int hf_mausb_ep_handle_ep_num; static int hf_mausb_ep_handle_dev_addr; static int hf_mausb_ep_handle_bus_num; static int hf_mausb_ma_dev_addr; static int hf_mausb_ssid; static int hf_mausb_status; /* management packet specific */ static int hf_mausb_token; static int hf_mausb_mgmt_pad; static int hf_mausb_mgmt_ep_handle_num; static int hf_mausb_mgmt_ep_handle_pad; static int hf_mausb_mgmt_ep_des_num; static int hf_mausb_mgmt_ep_des_size; static int hf_mausb_mgmt_ep_des_pad; static int hf_mausb_mgmt_type_spec; static int hf_mausb_mgmt_type_spec_generic; /* CapResp packet specific */ static int hf_mausb_cap_resp_num_ep; static int hf_mausb_cap_resp_num_dev; static int hf_mausb_cap_resp_num_stream; static int hf_mausb_cap_resp_dev_type; static int hf_mausb_cap_resp_desc_count; static int hf_mausb_cap_resp_desc_len; static int hf_mausb_cap_resp_transfer_req; static int hf_mausb_cap_resp_mgmt_req; static int hf_mausb_cap_resp_rsvd; static int hf_mausb_dev_cap_len; static int hf_mausb_dev_cap_type; static int hf_mausb_dev_cap_generic; /* EPHandleReq & Resp packet specific */ static int hf_mausb_ep_handle_req_pad; static int hf_mausb_ep_handle_resp_dir; static int hf_mausb_ep_handle_resp_iso; static int hf_mausb_ep_handle_resp_lman; static int hf_mausb_ep_handle_resp_valid; static int hf_mausb_ep_handle_resp_ccu; static int hf_mausb_ep_handle_resp_buf_size; static int hf_mausb_ep_handle_resp_iso_prog_dly; static int hf_mausb_ep_handle_resp_iso_resp_dly; /* (Clear/Cancel)TransferReq & Resp packet specific */ static int hf_mausb_clear_transfers_info_block; static int hf_mausb_clear_transfers_status_block; static int hf_mausb_cancel_transfer_rsvd; static int hf_mausb_clear_transfers_req_num; static int hf_mausb_clear_transfers_req_rsvd; static int hf_mausb_clear_transfers_resp_num; static int hf_mausb_clear_transfers_resp_rsvd; static int hf_mausb_cancel_transfer_status; static int hf_mausb_cancel_transfer_rsvd_2; static int hf_mausb_clear_transfers_status; static int hf_mausb_clear_transfers_partial; static int hf_mausb_clear_transfers_start_req_id; static int hf_mausb_clear_transfers_last_req_id; static int hf_mausb_clear_transfers_req_block_rsvd; static int hf_mausb_clear_transfers_resp_block_rsvd; static int hf_mausb_cancel_transfer_seq_num; static int hf_mausb_cancel_transfer_byte_offset; /* data packet specific */ static int hf_mausb_eps; static int hf_mausb_eps_rsvd; static int hf_mausb_tflags; static int hf_mausb_tflag_arq; static int hf_mausb_tflag_neg; static int hf_mausb_tflag_eot; static int hf_mausb_tflag_type; static int hf_mausb_tflag_rsvd; static int * const mausb_tflag_fields[] = { &hf_mausb_tflag_arq, &hf_mausb_tflag_neg, &hf_mausb_tflag_eot, &hf_mausb_tflag_type, &hf_mausb_tflag_rsvd, NULL }; static int hf_mausb_num_iso_hdr; static int hf_mausb_iflags; static int hf_mausb_iflag_mtd; static int hf_mausb_iflag_hdr_format; static int hf_mausb_iflag_asap; static int * const mausb_iflag_fields[] = { &hf_mausb_iflag_mtd, &hf_mausb_iflag_hdr_format, &hf_mausb_iflag_asap, NULL }; static int hf_mausb_stream_id; static int hf_mausb_seq_num; static int hf_mausb_req_id; static int hf_mausb_present_time; static int hf_mausb_uframe; static int hf_mausb_frame; static int hf_mausb_num_segs; static int hf_mausb_timestamp; static int hf_mausb_delta; static int hf_mausb_nom_interval; static int hf_mausb_mtd; static int hf_mausb_rem_size_credit; /* expert info fields */ static expert_field ei_ep_handle_len; static expert_field ei_len; static expert_field ei_mgmt_type_undef; static expert_field ei_mgmt_type_spec_len_long; static expert_field ei_mgmt_type_spec_len_short; static expert_field ei_dev_cap_len; static expert_field ei_dev_cap_resp_desc_len; static expert_field ei_cap_resp_desc_len; /* MAUSB Version, per 6.2.1.1 */ #define MAUSB_VERSION_1_0 0x0 #define MAUSB_VERSION_MASK 0x0F /* for dissecting snap packets */ /* * TODO: determine assigned PID value * (yet to be assigned as of Earth Day 2014) */ #define PID_MAUSB 0x1500 static const value_string mausb_pid_string[] = { { PID_MAUSB, "MAUSB" }, { 0, NULL} }; static const value_string mausb_version_string[] = { { MAUSB_VERSION_1_0, "MAUSB protocol version 1.0" }, { 0, NULL} }; /* Packet flags, per 6.2.1.2 */ #define MAUSB_FLAG_MASK 0xF0 #define MAUSB_FLAG_HOST (1 << 0) #define MAUSB_FLAG_RETRY (1 << 1) #define MAUSB_FLAG_TIMESTAMP (1 << 2) #define MAUSB_FLAG_RESERVED (1 << 3) #define MAUSB_FLAG_OFFSET 4 /* Packet Types, per 6.2.1.3 */ #define MAUSB_PKT_TYPE_MASK 0xC0 #define MAUSB_PKT_TYPE_MGMT (0 << 6) #define MAUSB_PKT_TYPE_CTRL (1 << 6) #define MAUSB_PKT_TYPE_DATA (2 << 6) /* Packet Subtypes, per 6.2.1.3 */ #define MAUSB_SUBTYPE_MASK 0x3F enum mausb_pkt_type { /* Management packets */ CapReq = 0x00 | MAUSB_PKT_TYPE_MGMT, CapResp , USBDevHandleReq , USBDevHandleResp , EPHandleReq , EPHandleResp , EPActivateReq , EPActivateResp , EPInactivateReq , EPInactivateResp , EPResetReq , EPResetResp , ClearTransfersReq , ClearTransfersResp , EPHandleDeleteReq , EPHandleDeleteResp , DevResetReq , DevResetResp , ModifyEP0Req , ModifyEP0Resp , SetUSBDevAddrReq , SetUSBDevAddrResp , UpdateDevReq , UpdateDevResp , USBDevDisconnectReq , USBDevDisconnectResp , USBSuspendReq , USBSuspendResp , USBResumeReq , USBResumeResp , RemoteWakeReq , RemoteWakeResp , PingReq , PingResp , DevDisconnectReq , DevDisconnectResp , DevInitDisconnectReq , DevInitDisconnectResp , SynchReq , SynchResp , CancelTransferReq , CancelTransferResp , EPOpenStreamReq , EPOpenStreamResp , EPCloseStreamReq , EPCloseStreamResp , USBDevResetReq , USBDevResetResp , DevNotificationReq , DevNotificationResp , EPSetKeepAliveReq , EPSetKeepAliveResp , GetPortBWReq , GetPortBWResp , SleepReq , SleepResp , WakeReq , WakeResp , /* Vendor-Specific Management Packets */ VendorSpecificReq = 0x3E | MAUSB_PKT_TYPE_MGMT, VendorSpecificResp , /* Control Packets */ TransferSetupReq = 0x00 | MAUSB_PKT_TYPE_CTRL, TransferSetupResp , TransferTearDownConf , /* Data Packets */ TransferReq = 0x00 | MAUSB_PKT_TYPE_DATA, TransferResp , TransferAck , IsochTransferReq , IsochTransferResp }; /** * Type & Subtype values for MAUSB packet variants, per 6.2.1.3, Table 5 */ static const value_string mausb_type_string[] = { /* Management packets */ { CapReq , "CapReq" }, { CapResp , "CapResp" }, { USBDevHandleReq , "USBDevHandleReq" }, { USBDevHandleResp , "USBDevHandleResp" }, { EPHandleReq , "EPHandleReq" }, { EPHandleResp , "EPHandleResp" }, { EPActivateReq , "EPActivateReq" }, { EPActivateResp , "EPActivateResp" }, { EPInactivateReq , "EPInactivateReq" }, { EPInactivateResp , "EPInactivateResp" }, { EPResetReq , "EPResetReq" }, { EPResetResp , "EPResetResp" }, { ClearTransfersReq , "ClearTransfersReq" }, { ClearTransfersResp , "ClearTransfersResp" }, { EPHandleDeleteReq , "EPHandleDeleteReq" }, { EPHandleDeleteResp , "EPHandleDeleteResp" }, { DevResetReq , "DevResetReq" }, { DevResetResp , "DevResetResp" }, { ModifyEP0Req , "ModifyEP0Req" }, { ModifyEP0Resp , "ModifyEP0Resp" }, { SetUSBDevAddrReq , "SetUSBDevAddrReq" }, { SetUSBDevAddrResp , "SetUSBDevAddrResp" }, { UpdateDevReq , "UpdateDevReq" }, { UpdateDevResp , "UpdateDevResp" }, { USBDevDisconnectReq , "USBDevDisconnectReq" }, { USBDevDisconnectResp , "USBDevDisconnectResp" }, { USBSuspendReq , "USBSuspendReq" }, { USBSuspendResp , "USBSuspendResp" }, { USBResumeReq , "USBResumeReq" }, { USBResumeResp , "USBResumeResp" }, { RemoteWakeReq , "RemoteWakeReq" }, { RemoteWakeResp , "RemoteWakeResp" }, { PingReq , "PingReq" }, { PingResp , "PingResp" }, { DevDisconnectReq , "DevDisconnectReq " }, { DevDisconnectResp , "DevDisconnectResp" }, { DevInitDisconnectReq , "DevInitDisconnectReq" }, { DevInitDisconnectResp, "DevInitDisconnectResp" }, { SynchReq , "SynchReq" }, { SynchResp , "SynchResp" }, { CancelTransferReq , "CancelTransferReq" }, { CancelTransferResp , "CancelTransferResp" }, { EPOpenStreamReq , "EPOpenStreamReq" }, { EPOpenStreamResp , "EPOpenStreamResp" }, { EPCloseStreamReq , "EPCloseStreamReq" }, { EPCloseStreamResp , "EPCloseStreamResp" }, { USBDevResetReq , "USBDevResetReq" }, { USBDevResetResp , "USBDevResetResp" }, { DevNotificationReq , "DevNotificationReq" }, { DevNotificationResp , "DevNotificationResp" }, { EPSetKeepAliveReq , "EPSetKeepAliveReq" }, { EPSetKeepAliveResp , "EPSetKeepAliveResp" }, { GetPortBWReq , "GetPortBWReq" }, { GetPortBWResp , "GetPortBWResp" }, { SleepReq , "SleepReq" }, { SleepResp , "SleepResp" }, { WakeReq , "WakeReq" }, { WakeResp , "WakeResp" }, /* Vendor-Specific Management Packets */ { VendorSpecificReq , "VendorSpecificReq" }, { VendorSpecificResp , "VendorSpecificResp" }, /* Control Packets */ { TransferSetupReq , "TransferSetupReq" }, { TransferSetupResp , "TransferSetupResp" }, { TransferTearDownConf , "TransferTearDownConf" }, /* Data Packets */ { TransferReq , "TransferReq" }, { TransferResp , "TransferResp" }, { TransferAck , "TransferAck" }, { IsochTransferReq , "IsochTransferReq" }, { IsochTransferResp , "IsochTransferResp" }, { 0, NULL} }; #define MAUSB_EP_HANDLE_D 0x0001 #define MAUSB_EP_HANDLE_EP_NUM 0x001e #define MAUSB_EP_HANDLE_DEV_ADDR 0x0fe0 #define MAUSB_EP_HANDLE_BUS_NUM 0xf000 #define MAUSB_EP_HANDLE_D_OFFSET 0 #define MAUSB_EP_HANDLE_EP_NUM_OFFSET 1 #define MAUSB_EP_HANDLE_DEV_ADDR_OFFSET 5 #define MAUSB_EP_HANDLE_BUS_NUM_OFFSET 12 static const value_string mausb_status_string[] = { { 0, "SUCCESS (NO_ERROR)" }, { 128, "UNSUCCESSFUL" }, { 129, "INVALID_MA_USB_SESSION_STATE" }, { 130, "INVALID_DEVICE_HANDLE" }, { 131, "INVALID_EP_HANDLE" }, { 132, "INVALID_EP_HANDLE_STATE" }, { 133, "INVALID_REQUEST" }, { 134, "MISSING_SEQUENCE_NUMBER" }, { 135, "TRANSFER_PENDING" }, { 136, "TRANSFER_EP_STALL" }, { 137, "TRANSFER_SIZE_ERROR" }, { 138, "TRANSFER_DATA_BUFFER_ERROR" }, { 139, "TRANSFER_BABBLE_DETECTED" }, { 140, "TRANSFER_TRANSACTION_ERROR" }, { 141, "TRANSFER_SHORT_TRANSFER" }, { 142, "TRANSFER_CANCELLED" }, { 143, "INSUFFICIENT_RESOURCES" }, { 144, "NOT_SUFFICIENT_BANDWIDTH" }, { 145, "INTERNAL_ERROR" }, { 146, "DATA_OVERRUN" }, { 147, "DEVICE_NOT_ACCESSED" }, { 148, "BUFFER_OVERRUN" }, { 149, "BUSY" }, { 150, "DROPPED_PACKET" }, { 151, "ISOC_TIME_EXPIRED" }, { 152, "ISOCH_TIME_INVALID" }, { 153, "NO_USB_PING_RESPONSE" }, { 154, "NOT_SUPPORTED" }, { 155, "REQUEST_DENIED" }, { 156, "MISSING_REQUEST_ID" }, { 0, NULL} }; /* Number of Isochronous Headers, per 6.5.1.7 */ #define MAUSB_NUM_ISO_HDR_MASK 0x0fff /* I-Flags, per 6.5.1.8 */ #define MAUSB_IFLAG_ASAP (1 << 0) #define MAUSB_IFLAG_HDR_FORMAT (3 << 1) #define MAUSB_IFLAG_MTD (1 << 3) #define MAUSB_IFLAG_OFFSET 12 #define MAUSB_IFLAG_MASK (0xF << MAUSB_IFLAG_OFFSET) /* Presentation Time, per 6.5.1.9 */ #define MAUSB_PRESENT_TIME_MASK 0x000fffff #define MAUSB_UFRAME_MASK 0x00000007 #define MAUSB_FRAME_MASK 0x000ffff8 /* Number of Segments, per 6.5.1.10 */ #define MAUSB_NUM_SEGS_MASK 0xfff00000 /* MA USB Global Time fields, per 6.6.1 */ #define MAUSB_DELTA_MASK 0x00000fff #define MAUSB_INTERVAL_MASK 0xfffff000 #define MAUSB_TOKEN_MASK 0x03ff #define MAUSB_MGMT_PAD_MASK 0xfffc #define MAUSB_MGMT_NUM_EP_DES_MASK 0x1f #define MAUSB_MGMT_SIZE_EP_DES_OFFSET 5 #define MAUSB_MGMT_SIZE_EP_DES_MASK (0x003f << MAUSB_MGMT_SIZE_EP_DES_OFFSET) #define MAUSB_MGMT_CLEAR_TRANSFER_RESP_NUM_MASK 0x1f /* CapResp Bitfield Masks */ #define MAUSB_CAP_RESP_NUM_STREAM_MASK 0x1f #define MAUSB_CAP_RESP_DEV_TYPE_OFFSET 5 #define MAUSB_CAP_RESP_DEV_TYPE_MASK (0x07 << MAUSB_CAP_RESP_DEV_TYPE_OFFSET) #define MAUSB_CAP_RESP_MGMT_REQ_MASK 0x0fff #define MAUSB_CAP_RESP_RSVD_MASK 0xf000 static const value_string mausb_cap_resp_dev_type[] = { { 0, "Integrated Device" }, { 1, "MAUSB 2.0 hub" }, { 2, "MAUSB 3.1 hub" }, { 0, NULL} }; static const value_string mausb_dev_cap_string[] = { { 0, "Speed Capability" }, { 1, "P-managed OUT Capabilities" }, { 2, "Isochronous Capabilities" }, { 3, "Synchronization Capabilities" }, { 4, "Container ID Capability" }, { 5, "Link Sleep Capability" }, { 0, NULL} }; enum mausb_dev_cap_type { SpeedCap = 0, PmanCap, IsoCap, SyncCap, ContainerIDCap, LinkSleepCap }; #define DWORD_MASK 0xffffffff #define MAUSB_MGMT_NUM_EP_HANDLE_PAD_MASK \ (DWORD_MASK & !(MAUSB_MGMT_NUM_EP_DES_MASK)) #define MAUSB_MGMT_EP_DES_PAD_MASK \ ((DWORD_MASK & !(MAUSB_MGMT_NUM_EP_DES_MASK | \ MAUSB_MGMT_SIZE_EP_DES_MASK)) >> 8) /* EPHandleResp Bitfield Masks */ #define MAUSB_EP_HANDLE_RESP_DIR_MASK (1 << 0) #define MAUSB_EP_HANDLE_RESP_ISO_MASK (1 << 1) #define MAUSB_EP_HANDLE_RESP_LMAN_MASK (1 << 2) #define MAUSB_EP_HANDLE_RESP_VALID_MASK (1 << 3) static const value_string mausb_eps_string[] = { { 0, "Unassigned" }, { 1, "Active" }, { 2, "Inactive" }, { 3, "Halted" }, { 0, NULL} }; #define MAUSB_EPS_MASK 0x03 #define MAUSB_TFLAG_MASK 0xfc #define MAUSB_TX_TYPE_CTRL (0 << 3) #define MAUSB_TX_TYPE_ISOC (1 << 3) #define MAUSB_TX_TYPE_BULK (2 << 3) #define MAUSB_TX_TYPE_INTR (3 << 3) #define MAUSB_TFLAG_OFFSET 2 #define MAUSB_TFLAG_ARQ (1 << 0) #define MAUSB_TFLAG_NEG (1 << 1) #define MAUSB_TFLAG_EOT (1 << 2) #define MAUSB_TFLAG_TRANSFER_TYPE (3 << 3) #define MAUSB_TFLAG_RSVD (1 << 5) static const value_string mausb_transfer_type_string[] = { { 0, "Control" }, { 1, "Isochronous" }, { 2, "Bulk" }, { 3, "Interrupt" }, { 0, NULL} }; static const true_false_string tfs_ep_handle_resp_dir = { "IN", "OUT or Control" }; #define MAUSB_TRANSFER_TYPE_OFFSET 3 /* Offset from start of TFlags Field */ /* (EPS not included) */ #define MAUSB_TRANSFER_TYPE_CTRL (0 << MAUSB_TRANSFER_TYPE_OFFSET) #define MAUSB_TRANSFER_TYPE_ISO (1 << MAUSB_TRANSFER_TYPE_OFFSET) #define MAUSB_TRANSFER_TYPE_BULK (2 << MAUSB_TRANSFER_TYPE_OFFSET) #define MAUSB_TRANSFER_TYPE_INTERRUPT (3 << MAUSB_TRANSFER_TYPE_OFFSET) static const value_string mausb_cancel_transfer_status_string[] = { { 0, "Cancel Unsuccessful"}, { 1, "Canceled before any data was moved"}, { 2, "Canceled after some data was moved"}, { 3, "Transfer completed"}, { 4, "Transfer not yet received"}, { 5, "Transfer cleared without any data moved"}, { 0, NULL} }; #define MAUSB_CANCEL_TRANSFER_STATUS_MASK 0x07 #define MAUSB_CLEAR_TRANSFERS_RESP_NUM_MASK 0x1f #define MAUSB_CLEAR_TRANSFERS_STATUS_MASK 0x01 #define MAUSB_CLEAR_TRANSFERS_PARTIAL_MASK 0x02 #define MAUSB_CLEAR_TRANSFERS_RESP_BLOCK_RSVD_MASK 0xfffffffc /* We need at least the first DWORD to determine the packet length (for TCP) */ #define MAUSB_MIN_LENGTH 4 #define MAUSB_MIN_MGMT_LENGTH 12 #define MAUSB_MIN_DATA_LENGTH 20 #define MAUSB_COMMON_LEN 9 /*** Packet parsing helper functions ***/ bool mausb_is_from_host(struct mausb_header *header) { return (MAUSB_FLAG_HOST << MAUSB_FLAG_OFFSET) & header->ver_flags; } static bool mausb_is_mgmt_pkt(struct mausb_header *header) { return MAUSB_PKT_TYPE_MGMT == (header->type & MAUSB_PKT_TYPE_MASK); } static bool mausb_is_data_pkt(struct mausb_header *header) { return MAUSB_PKT_TYPE_DATA == (header->type & MAUSB_PKT_TYPE_MASK); } static bool mausb_is_transfer_req(struct mausb_header *header) { return TransferReq == header->type; } static bool mausb_is_transfer_ack(struct mausb_header *header) { return TransferAck == header->type; } static int8_t mausb_tx_type(struct mausb_header *header) { return (header->u.s.eps_tflags >> MAUSB_TFLAG_OFFSET) & MAUSB_TFLAG_TRANSFER_TYPE; } static bool mausb_is_iso_pkt(struct mausb_header *header) { return MAUSB_TX_TYPE_ISOC == mausb_tx_type(header); } static bool mausb_has_timestamp(struct mausb_header *header) { return (MAUSB_FLAG_TIMESTAMP << MAUSB_FLAG_OFFSET) & header->ver_flags; } static bool mausb_has_mtd(struct mausb_header *header) { return (MAUSB_IFLAG_MTD << MAUSB_IFLAG_OFFSET) & header->u.s.u1.num_headers_iflags; } static bool mausb_has_setup_data(struct mausb_header *header) { if ((TransferReq == header->type ) && (mausb_is_from_host(header)) && (0 == header->u.s.seq_num) && (MAUSB_TX_TYPE_CTRL == mausb_tx_type(header))) { return true; } return false; } static bool mausb_is_setup_response(struct mausb_header *header) { if ((TransferResp == header->type) && (!mausb_is_from_host(header)) && (MAUSB_TX_TYPE_CTRL == mausb_tx_type(header))) { return true; } return false; } /*** EP Handle parsing helper functions */ uint8_t mausb_ep_handle_ep_d(uint16_t handle) { return (handle & MAUSB_EP_HANDLE_D) >> MAUSB_EP_HANDLE_D_OFFSET; } uint8_t mausb_ep_handle_ep_num(uint16_t handle) { return (handle & MAUSB_EP_HANDLE_EP_NUM) >> MAUSB_EP_HANDLE_EP_NUM_OFFSET; } uint8_t mausb_ep_handle_dev_addr(uint16_t handle) { return (handle & MAUSB_EP_HANDLE_DEV_ADDR) >> MAUSB_EP_HANDLE_DEV_ADDR_OFFSET; } uint8_t mausb_ep_handle_bus_num(uint16_t handle) { return (handle & MAUSB_EP_HANDLE_BUS_NUM) >> MAUSB_EP_HANDLE_BUS_NUM_OFFSET; } /* returns the length field of the MAUSB packet */ static unsigned mausb_get_pkt_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) { return tvb_get_letohs(tvb, offset + 2); } /* Initialize the subtree pointers */ static int ett_mausb; static int ett_mausb_flags; static int ett_mausb_ep_handle; static int ett_mausb_tflags; static int ett_mausb_iflags; static int ett_mausb_present_time; static int ett_mausb_timestamp; static int ett_mgmt; static int ett_dev_cap; static int ett_clear_transfers_block; #define USB_DT_EP_SIZE 7 #define USB_DT_SS_EP_COMP_SIZE 6 #define USB_DT_ISO_SSP_EP_COMP_SIZE 8 /* Size of EPHandleReq Descriptors */ #define MAUSB_EP_DES_SIZE 8 #define MAUSB_SS_EP_DES_SIZE 16 #define MAUSB_ISO_SSP_EP_DES_SIZE 24 /* EPHandleReq Descriptor Padding */ #define MAUSB_EP_DES_PAD (MAUSB_EP_DES_SIZE - USB_DT_EP_SIZE) #define MAUSB_SS_EP_DES_PAD (MAUSB_SS_EP_DES_SIZE - \ (USB_DT_EP_SIZE + USB_DT_SS_EP_COMP_SIZE)) #define MAUSB_ISO_SSP_EP_DES_PAD (MAUSB_ISO_SSP_EP_DES_SIZE - \ (USB_DT_EP_SIZE + USB_DT_SS_EP_COMP_SIZE + USB_DT_ISO_SSP_EP_COMP_SIZE)) /* Size of EPHandleResp Descriptor */ #define MAUSB_SIZE_MAUSB_EP_DES 16 /* Size of EPHandleResp Descriptor */ #define MAUSB_SIZE_EP_HANDLE 2 /* Dissects an individual Device Capability Descriptor */ static uint16_t dissect_mausb_dev_cap_desc(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int16_t offset) { uint8_t desc_len; uint8_t cap_type; int16_t desc_offset; proto_item *len_field; proto_tree *dev_cap_tree; desc_offset = offset; desc_len = tvb_get_uint8(tvb, desc_offset); cap_type = tvb_get_uint8(tvb, desc_offset + 1); dev_cap_tree = proto_tree_add_subtree(tree, tvb, desc_offset, desc_len, ett_dev_cap, NULL, val_to_str_const(cap_type, mausb_dev_cap_string, "Unknown Capability")); len_field = proto_tree_add_item(dev_cap_tree, hf_mausb_dev_cap_len, tvb, desc_offset, 1, ENC_LITTLE_ENDIAN); desc_offset += 1; proto_tree_add_item(dev_cap_tree, hf_mausb_dev_cap_type, tvb, desc_offset, 1, ENC_LITTLE_ENDIAN); desc_offset += 1; if (desc_len > 2) { /* TODO: dissect individual capabilities */ switch (cap_type) { case SpeedCap: case PmanCap: case IsoCap: case SyncCap: case ContainerIDCap: case LinkSleepCap: default: proto_tree_add_item(dev_cap_tree, hf_mausb_dev_cap_generic, tvb, desc_offset, (desc_len - 2), ENC_NA); desc_offset += (desc_len - 2); break; } } /* Was this descriptor a different length than expected */ if (desc_offset != offset + desc_len) { expert_add_info(pinfo, len_field, &ei_dev_cap_len); } return offset + desc_len; } /* Dissects a MAUSB capability response packet * also dissects Capability Descriptors */ static uint16_t dissect_mausb_mgmt_pkt_cap_resp(struct mausb_header *header, proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int16_t offset) { unsigned desc_len; uint8_t desc_count; proto_item *len_field; uint16_t loop_offset; int i; /* Fields present in all CapResp packets */ proto_tree_add_item(tree, hf_mausb_cap_resp_num_ep, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(tree, hf_mausb_cap_resp_num_dev, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; proto_tree_add_item(tree, hf_mausb_cap_resp_num_stream, tvb, offset, 1, ENC_LITTLE_ENDIAN); /* really 5 bits */ proto_tree_add_item(tree, hf_mausb_cap_resp_dev_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); /* really 3 bits */ offset += 1; proto_tree_add_item(tree, hf_mausb_cap_resp_desc_count, tvb, offset, 1, ENC_LITTLE_ENDIAN); desc_count = tvb_get_uint8(tvb, offset); offset += 1; len_field = proto_tree_add_item(tree, hf_mausb_cap_resp_desc_len, tvb, offset, 3, ENC_LITTLE_ENDIAN); desc_len = tvb_get_letoh24(tvb, offset); offset += 3; proto_tree_add_item(tree, hf_mausb_cap_resp_transfer_req, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(tree, hf_mausb_cap_resp_mgmt_req, tvb, offset, 2, ENC_LITTLE_ENDIAN); /* really 12 bits */ proto_tree_add_item(tree, hf_mausb_cap_resp_rsvd, tvb, offset, 2, ENC_LITTLE_ENDIAN); /* really 4 bits */ offset += 2; /* Descriptors length longer than remainder of packet */ if (offset + desc_len > header->length) { expert_add_info(pinfo, len_field, &ei_cap_resp_desc_len); desc_len = header->length - offset; /* to avoid overflows */ } loop_offset = offset; /* dissect capability descriptors */ for (i = 0; i < desc_count; i++) { loop_offset = dissect_mausb_dev_cap_desc(tree, tvb, pinfo, loop_offset); } /* were the descriptors a different length than expected */ if (loop_offset != offset + desc_len) { expert_add_info(pinfo, len_field, &ei_dev_cap_resp_desc_len); desc_len = header->length - offset; /* to avoid overflows */ } return offset + desc_len; } /* Dissects a MAUSB endpoint handle */ static int dissect_ep_handle(proto_tree *tree, tvbuff_t *tvb, int offset) { proto_item *ti; proto_tree *ep_handle_tree; ti = proto_tree_add_item(tree, hf_mausb_ep_handle, tvb, offset, MAUSB_SIZE_EP_HANDLE, ENC_LITTLE_ENDIAN); ep_handle_tree = proto_item_add_subtree(ti, ett_mausb_ep_handle); proto_tree_add_item(ep_handle_tree, hf_mausb_ep_handle_d, tvb, offset, MAUSB_SIZE_EP_HANDLE, ENC_LITTLE_ENDIAN); proto_tree_add_item(ep_handle_tree, hf_mausb_ep_handle_ep_num, tvb, offset, MAUSB_SIZE_EP_HANDLE, ENC_LITTLE_ENDIAN); proto_tree_add_item(ep_handle_tree, hf_mausb_ep_handle_dev_addr, tvb, offset, MAUSB_SIZE_EP_HANDLE, ENC_LITTLE_ENDIAN); proto_tree_add_item(ep_handle_tree, hf_mausb_ep_handle_bus_num, tvb, offset, MAUSB_SIZE_EP_HANDLE, ENC_LITTLE_ENDIAN); return MAUSB_SIZE_EP_HANDLE; } /* dissects presentation time & subfields */ static void dissect_mausb_present_time(proto_tree *tree, tvbuff_t *tvb, int offset) { proto_item *ti; proto_tree *present_time_tree; ti = proto_tree_add_item(tree, hf_mausb_present_time, tvb, offset, 4, ENC_LITTLE_ENDIAN); present_time_tree = proto_item_add_subtree(ti, ett_mausb_present_time); proto_tree_add_item(present_time_tree, hf_mausb_uframe, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(present_time_tree, hf_mausb_frame, tvb, offset, 4, ENC_LITTLE_ENDIAN); } static void dissect_mausb_timestamp(proto_tree *tree, tvbuff_t *tvb, int offset) { proto_item *ti; proto_tree *timestamp_tree; ti = proto_tree_add_item(tree, hf_mausb_timestamp, tvb, offset, 4, ENC_LITTLE_ENDIAN); timestamp_tree = proto_item_add_subtree(ti, ett_mausb_timestamp); proto_tree_add_item(timestamp_tree, hf_mausb_delta, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(timestamp_tree, hf_mausb_nom_interval, tvb, offset, 4, ENC_LITTLE_ENDIAN); } /* gets the size of the endpoint descriptors in a EPHandleReq packet */ static uint8_t mausb_get_size_ep_des(tvbuff_t *tvb, int offset) { uint8_t size_ep_des = 0; uint16_t temp_buffer = 0; /* for storing the offset data */ /* grab the 2 bytes with the size field */ temp_buffer = tvb_get_letohs(tvb, offset); /* mask & shift the size field */ temp_buffer = temp_buffer & MAUSB_MGMT_SIZE_EP_DES_MASK; size_ep_des = (temp_buffer >> MAUSB_MGMT_SIZE_EP_DES_OFFSET); return size_ep_des; } /* dissect an individual block for ClearTransfers */ static uint16_t dissect_clear_transfers_block(proto_tree *tree, tvbuff_t *tvb, int16_t offset, bool req) { proto_item *ti; proto_tree *block_tree; if (req) { ti = proto_tree_add_item(tree, hf_mausb_clear_transfers_info_block, tvb, offset, 8, ENC_NA); } else { ti = proto_tree_add_item(tree, hf_mausb_clear_transfers_status_block, tvb, offset, 16, ENC_NA); } block_tree = proto_item_add_subtree(ti, ett_clear_transfers_block); /* EP Handle */ offset += dissect_ep_handle(block_tree, tvb, offset); /* Stream ID */ proto_tree_add_item(block_tree, hf_mausb_stream_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; if (req) { /* Start Request ID */ proto_tree_add_item(block_tree, hf_mausb_clear_transfers_start_req_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; /* Rsvd */ proto_tree_add_item(block_tree, hf_mausb_clear_transfers_req_block_rsvd, tvb, offset, 3, ENC_NA); offset += 3; } else { /* Cancel Status */ proto_tree_add_item(block_tree, hf_mausb_clear_transfers_status, tvb, offset, 4, ENC_LITTLE_ENDIAN); /* Partial Delivery */ proto_tree_add_item(block_tree, hf_mausb_clear_transfers_partial, tvb, offset, 4, ENC_LITTLE_ENDIAN); /* Rsvd */ proto_tree_add_item(block_tree, hf_mausb_clear_transfers_resp_block_rsvd, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; /* Last Request ID */ proto_tree_add_item(block_tree, hf_mausb_clear_transfers_last_req_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; /* Delivered Sequence Number */ proto_tree_add_item(block_tree, hf_mausb_cancel_transfer_seq_num, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; /* Delivered Byte Offset */ proto_tree_add_item(block_tree, hf_mausb_cancel_transfer_byte_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; } return offset; } /* dissects portions of a MA USB packet specific to ClearTransfers packets */ static uint16_t dissect_mausb_mgmt_pkt_clear_transfers(proto_tree *tree, tvbuff_t *tvb, int16_t offset, bool req) { uint8_t num_block; int i; num_block = tvb_get_uint8(tvb, offset); if (req) { /* Number of entries */ proto_tree_add_item(tree, hf_mausb_clear_transfers_req_num, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; /* Rsvd */ proto_tree_add_item(tree, hf_mausb_clear_transfers_req_rsvd, tvb, offset, 3, ENC_NA); offset += 3; } else { num_block &= MAUSB_MGMT_CLEAR_TRANSFER_RESP_NUM_MASK; /* Number of entries */ proto_tree_add_item(tree, hf_mausb_clear_transfers_resp_num, tvb, offset, 1, ENC_LITTLE_ENDIAN); /* Rsvd */ proto_tree_add_item(tree, hf_mausb_clear_transfers_resp_rsvd, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 4; } for (i = 0; i < num_block; i++) { offset = dissect_clear_transfers_block(tree, tvb, offset, req); } return offset; } /* dissects portions of a MA USB packet specific to Endpoint Handle Request packets */ static uint16_t dissect_mausb_mgmt_pkt_ep_handle( proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int16_t start, bool req, bool del) { urb_info_t urb; proto_item *size_field = NULL; uint16_t offset = start; uint16_t loop_offset; uint8_t num_ep; uint8_t size_ep_des; uint8_t last_ep_type = ENDPOINT_TYPE_NOT_SET; int i; memset(&urb, 0, sizeof(urb_info_t)); num_ep = tvb_get_uint8(tvb, offset) & MAUSB_MGMT_NUM_EP_DES_MASK; if (!del) { proto_tree_add_item(tree, hf_mausb_mgmt_ep_des_num, tvb, offset, 1, ENC_LITTLE_ENDIAN); /* really 5 bits */ } else { proto_tree_add_item(tree, hf_mausb_mgmt_ep_handle_num, tvb, offset, 1, ENC_LITTLE_ENDIAN); /* really 5 bits */ } if (req && !del) { size_ep_des = mausb_get_size_ep_des(tvb, offset); size_field = proto_tree_add_item(tree, hf_mausb_mgmt_ep_des_size, tvb, offset, 2, ENC_LITTLE_ENDIAN); /* really 6 bits over a byte boundary */ offset += 1; /* Padding to DWORD */ proto_tree_add_item(tree, hf_mausb_mgmt_ep_des_pad, tvb, offset, 3, ENC_NA); offset += 3; } else if (!req && !del) { size_ep_des = MAUSB_SIZE_MAUSB_EP_DES; proto_tree_add_item(tree, hf_mausb_mgmt_ep_handle_pad, tvb, offset, 4, ENC_NA); /* really 5 bits */ /* Padding to DWORD */ offset += 4; } else { /* If it is an EPHandleDelete Req or Resp */ size_ep_des = MAUSB_SIZE_EP_HANDLE; /* Padding to DWORD */ proto_tree_add_item(tree, hf_mausb_mgmt_ep_handle_pad, tvb, offset, 4, ENC_NA); offset += 4; /* Padding to DWORD */ } /* For every entry */ for (i = 0; i < num_ep; ++i) { loop_offset = offset; /* If it is an EPHandleDelete Req or Resp */ if (del) { loop_offset += dissect_ep_handle(tree, tvb, loop_offset); } else if (req) { /* Standard USB Endpoint Descriptor */ dissect_usb_endpoint_descriptor(pinfo, tree, tvb, loop_offset, &urb, &last_ep_type, USB_SPEED_UNKNOWN); loop_offset += USB_DT_EP_SIZE; /* If there are more descriptors to read */ if (MAUSB_EP_DES_SIZE < size_ep_des) { /* TODO: Dissector for SS EP Companion Descriptors */ dissect_usb_unknown_descriptor(pinfo, tree, tvb, loop_offset, &urb); loop_offset += USB_DT_SS_EP_COMP_SIZE; if (MAUSB_SS_EP_DES_SIZE < size_ep_des) { /* TODO: Dissector for SSP ISO EP Companion Descriptors */ loop_offset += dissect_usb_unknown_descriptor(pinfo, tree, tvb, loop_offset, &urb); /* Pad to a DWORD */ proto_tree_add_item(tree, hf_mausb_ep_handle_req_pad, tvb, loop_offset, MAUSB_ISO_SSP_EP_DES_PAD, ENC_NA); loop_offset += MAUSB_ISO_SSP_EP_DES_PAD; } else { /* Pad to a DWORD */ proto_tree_add_item(tree, hf_mausb_ep_handle_req_pad, tvb, loop_offset, MAUSB_SS_EP_DES_PAD, ENC_NA); loop_offset += MAUSB_SS_EP_DES_PAD; } } else { /* Pad to a DWORD */ proto_tree_add_item(tree, hf_mausb_ep_handle_req_pad, tvb, loop_offset, MAUSB_EP_DES_PAD, ENC_NA); loop_offset += MAUSB_EP_DES_PAD; } } else { /* IE: it's a EPHandleResp */ /* EP Handle */ loop_offset += dissect_ep_handle(tree, tvb, loop_offset); /* direction */ proto_tree_add_item(tree, hf_mausb_ep_handle_resp_dir, tvb, loop_offset, 1, ENC_LITTLE_ENDIAN); /* isochronous */ proto_tree_add_item(tree, hf_mausb_ep_handle_resp_iso, tvb, loop_offset, 1, ENC_LITTLE_ENDIAN); /* L-managed transfers */ proto_tree_add_item(tree, hf_mausb_ep_handle_resp_lman, tvb, loop_offset, 1, ENC_LITTLE_ENDIAN); /* valid handle bit */ proto_tree_add_item(tree, hf_mausb_ep_handle_resp_valid, tvb, loop_offset, 1, ENC_LITTLE_ENDIAN); loop_offset += 2; /* 4 bit flags + 12 reserved bits */ /* credit consumption unit */ proto_tree_add_item(tree, hf_mausb_ep_handle_resp_ccu, tvb, loop_offset, 2, ENC_LITTLE_ENDIAN); loop_offset += 2; loop_offset += 2; /* 2 bytes reserved */ /* buffer size (in bytes) */ proto_tree_add_item(tree, hf_mausb_ep_handle_resp_buf_size, tvb, loop_offset, 4, ENC_LITTLE_ENDIAN); loop_offset += 4; /* max iso programming delay (in uSec) */ proto_tree_add_item(tree, hf_mausb_ep_handle_resp_iso_prog_dly, tvb, loop_offset, 2, ENC_LITTLE_ENDIAN); loop_offset += 2; /* max iso response delay (in uSec) */ proto_tree_add_item(tree, hf_mausb_ep_handle_resp_iso_resp_dly, tvb, loop_offset, 2, ENC_LITTLE_ENDIAN); loop_offset += 2; } offset += size_ep_des; if (req && !del && loop_offset != offset){ expert_add_info(pinfo, size_field, &ei_ep_handle_len); } } return offset; } /* dissects portions of a MA USB packet specific to CancelTransfer packets */ static uint16_t dissect_mausb_mgmt_pkt_cancel_transfer( proto_tree *tree, tvbuff_t *tvb, int offset, bool req) { uint8_t status; offset += dissect_ep_handle(tree, tvb, offset); proto_tree_add_item(tree, hf_mausb_stream_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(tree, hf_mausb_req_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; if (req) { proto_tree_add_item(tree, hf_mausb_cancel_transfer_rsvd, tvb, offset, 3, ENC_NA); offset += 3; return offset; } /* else resp */ status = tvb_get_uint8(tvb, offset) | MAUSB_CANCEL_TRANSFER_STATUS_MASK; proto_tree_add_item(tree, hf_mausb_cancel_transfer_status, tvb, offset, 3, ENC_LITTLE_ENDIAN); proto_tree_add_item(tree, hf_mausb_cancel_transfer_rsvd_2, tvb, offset, 3, ENC_LITTLE_ENDIAN); /* Reserved */ offset += 3; /* if some data was moved */ if (2 == status) { /* TODO: sequence number reserved for INs */ proto_tree_add_item(tree, hf_mausb_cancel_transfer_seq_num, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; proto_tree_add_item(tree, hf_mausb_cancel_transfer_rsvd, tvb, offset, 1, ENC_NA); offset += 1; proto_tree_add_item(tree, hf_mausb_cancel_transfer_byte_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; } else { proto_tree_add_item(tree, hf_mausb_cancel_transfer_rsvd, tvb, offset, 8, ENC_NA); offset += 8; } return offset; } /* dissects portions of a MA USB packet specific to particular management packets */ static uint16_t dissect_mausb_mgmt_pkt_flds(struct mausb_header *header, proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int16_t start) { proto_item *ti; proto_tree *mgmt_tree; uint16_t offset = start; int type_spec_len = tvb_reported_length(tvb) - start; if (0 > type_spec_len) { expert_add_info(pinfo, tree, &ei_mgmt_type_spec_len_short); return offset; } ti = proto_tree_add_item(tree, hf_mausb_mgmt_type_spec, tvb, offset, type_spec_len, ENC_NA); mgmt_tree = proto_item_add_subtree(ti, ett_mgmt); switch (header->type) { /* subtypes with variable length additional data */ case CapResp: offset = dissect_mausb_mgmt_pkt_cap_resp(header, mgmt_tree, tvb, pinfo, offset); break; case EPHandleReq: offset = dissect_mausb_mgmt_pkt_ep_handle(mgmt_tree, tvb, pinfo, offset, true, false); break; case EPHandleResp: offset = dissect_mausb_mgmt_pkt_ep_handle(mgmt_tree, tvb, pinfo, offset, false, false); break; /* TODO: Dissect type-specific management packet fields */ case EPActivateReq: case EPActivateResp: case EPInactivateReq: case EPInactivateResp: case EPResetReq: case EPResetResp: proto_tree_add_item(mgmt_tree, hf_mausb_mgmt_type_spec_generic, tvb, offset, type_spec_len, ENC_NA); offset += type_spec_len; break; case ClearTransfersReq: offset = dissect_mausb_mgmt_pkt_clear_transfers(mgmt_tree, tvb, offset, true); break; case ClearTransfersResp: offset = dissect_mausb_mgmt_pkt_clear_transfers(mgmt_tree, tvb, offset, false); break; case EPHandleDeleteReq: offset = dissect_mausb_mgmt_pkt_ep_handle(mgmt_tree, tvb, pinfo, offset, true, true); break; case EPHandleDeleteResp: offset = dissect_mausb_mgmt_pkt_ep_handle(mgmt_tree, tvb, pinfo, offset, false, true); break; case ModifyEP0Resp: case EPCloseStreamResp: case USBDevResetReq: case USBDevResetResp: case EPOpenStreamResp: case VendorSpecificReq: case VendorSpecificResp: /* FALLTHROUGH */ /* subtypes with constant length additional data */ case CapReq: case USBDevHandleReq: case USBDevHandleResp: case ModifyEP0Req: case SetUSBDevAddrReq: case SetUSBDevAddrResp: case UpdateDevReq: case SynchReq: case EPCloseStreamReq: proto_tree_add_item(mgmt_tree, hf_mausb_mgmt_type_spec_generic, tvb, offset, type_spec_len, ENC_NA); offset += type_spec_len; break; case CancelTransferReq: offset = dissect_mausb_mgmt_pkt_cancel_transfer(mgmt_tree, tvb, offset, true); break; case CancelTransferResp: offset = dissect_mausb_mgmt_pkt_cancel_transfer(mgmt_tree, tvb, offset, false); break; case EPOpenStreamReq: proto_tree_add_item(mgmt_tree, hf_mausb_mgmt_type_spec_generic, tvb, offset, type_spec_len, ENC_NA); offset += type_spec_len; break; /* Management packets with no additional data */ case DevResetReq: case DevResetResp: case UpdateDevResp: case USBDevDisconnectReq: case USBDevDisconnectResp: case SleepReq: case SleepResp: case WakeReq: case WakeResp: case PingReq: case PingResp: case DevDisconnectReq: case DevDisconnectResp: case DevInitDisconnectReq: case DevInitDisconnectResp: case SynchResp: break; default: expert_add_info(pinfo, mgmt_tree, &ei_mgmt_type_undef); break; } if (offset < tvb_reported_length(tvb)) { expert_add_info(pinfo, mgmt_tree, &ei_mgmt_type_spec_len_long); } return offset; } void mausb_set_urb_info(urb_info_t *urb, struct mausb_header *header) { urb->is_request = mausb_is_transfer_req(header); urb->bus_id = mausb_ep_handle_bus_num(header->handle); urb->device_address = mausb_ep_handle_dev_addr(header->handle); urb->direction = mausb_is_from_host(header); urb->endpoint = mausb_ep_handle_ep_num(header->handle); if (mausb_ep_handle_ep_d(header->handle)) { /* IN endpoint */ urb->endpoint |= 0x80; } urb->is_setup = mausb_has_setup_data(header) || mausb_is_setup_response(header); switch (mausb_tx_type(header)) { case MAUSB_TX_TYPE_CTRL: urb->transfer_type = URB_CONTROL; break; case MAUSB_TX_TYPE_ISOC: urb->transfer_type = URB_ISOCHRONOUS; break; case MAUSB_TX_TYPE_BULK: urb->transfer_type = URB_BULK; break; case MAUSB_TX_TYPE_INTR: urb->transfer_type = URB_INTERRUPT; break; default: urb->transfer_type = URB_UNKNOWN; break; } } /* Used to detect multiple MA Packets in a single TCP packet */ /* Not used for MA Packets in SNAP Packets */ static int mausb_num_pdus; /* dissect fields common to all MAUSB packet types */ static int dissect_mausb_pkt_common(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *mausb_tree, struct mausb_header *header) { proto_item *len_field; /* MAUSB Protocol Version */ header->ver_flags = tvb_get_uint8(tvb, offset); proto_tree_add_item(mausb_tree, hf_mausb_version, tvb, offset, 1, ENC_LITTLE_ENDIAN); /* Flags */ proto_tree_add_bitmask(mausb_tree, tvb, offset, hf_mausb_flags, ett_mausb_flags, mausb_flag_fields, ENC_LITTLE_ENDIAN); offset += 1; /* Packet Type */ header->type = tvb_get_uint8(tvb, offset); col_append_str(pinfo->cinfo, COL_INFO, val_to_str(header->type, mausb_type_string, "%d")); proto_tree_add_item(mausb_tree, hf_mausb_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; /* Packet Length */ header->length = tvb_get_letohs(tvb, offset); col_append_fstr(pinfo->cinfo, COL_INFO, " Length=%u", header->length); len_field = proto_tree_add_item(mausb_tree, hf_mausb_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; /* Check to see if length field is valid */ if (tvb_reported_length(tvb) != header->length) { expert_add_info(pinfo, len_field, &ei_len); } /* Is the next field a device handle or an endpoint handle */ header->handle = tvb_get_letohs(tvb, offset); if (mausb_is_mgmt_pkt(header)) { proto_tree_add_item(mausb_tree, hf_mausb_dev_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; } else { offset += dissect_ep_handle(mausb_tree, tvb, offset); } /* MA Device Address */ header->ma_dev_addr = tvb_get_uint8(tvb, offset); proto_tree_add_item(mausb_tree, hf_mausb_ma_dev_addr, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; /* SSID */ header->mass_id = tvb_get_uint8(tvb, offset); proto_tree_add_item(mausb_tree, hf_mausb_ssid, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; /* Status */ header->status = tvb_get_uint8(tvb, offset); proto_tree_add_item(mausb_tree, hf_mausb_status, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; return offset; } /* dissect datapacket specific values */ static int dissect_mausb_pkt_data(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *mausb_tree, struct mausb_header *header) { /* EPS */ header->u.s.eps_tflags = tvb_get_uint8(tvb, offset); if (mausb_is_from_host(header)) { proto_tree_add_item(mausb_tree, hf_mausb_eps_rsvd, tvb, offset, 1, ENC_LITTLE_ENDIAN); } else { proto_tree_add_item(mausb_tree, hf_mausb_eps, tvb, offset, 1, ENC_LITTLE_ENDIAN); } /* T-Flags */ proto_tree_add_bitmask(mausb_tree, tvb, offset, hf_mausb_tflags, ett_mausb_tflags, mausb_tflag_fields, ENC_LITTLE_ENDIAN); offset += 1; if (mausb_is_iso_pkt(header)) { /* Number of Headers */ header->u.s.u1.num_headers_iflags = tvb_get_letohs(tvb, offset); proto_tree_add_item(mausb_tree, hf_mausb_num_iso_hdr, tvb, offset, 2, ENC_LITTLE_ENDIAN); /* I-Flags */ proto_tree_add_bitmask(mausb_tree, tvb, offset, hf_mausb_iflags, ett_mausb_iflags, mausb_iflag_fields, ENC_LITTLE_ENDIAN); } else { /* Stream ID */ header->u.s.u1.stream_id = tvb_get_letohs(tvb, offset); proto_tree_add_item(mausb_tree, hf_mausb_stream_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); } offset += 2; /* Sequence Number */ header->u.s.seq_num = tvb_get_letoh24(tvb, offset); col_append_fstr(pinfo->cinfo, COL_INFO, " SeqNum=%u", header->u.s.seq_num); proto_tree_add_item(mausb_tree, hf_mausb_seq_num, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; /* Request ID */ header->u.s.req_id = tvb_get_uint8(tvb, offset); col_append_fstr(pinfo->cinfo, COL_INFO, " ReqID=%u", header->u.s.req_id); proto_tree_add_item(mausb_tree, hf_mausb_req_id, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; if (mausb_is_iso_pkt(header)) { /* Presentation Time */ header->u.s.u2.present_time_num_seg = tvb_get_letohl(tvb, offset); dissect_mausb_present_time(mausb_tree, tvb, offset); /* Number of Segments */ proto_tree_add_item(mausb_tree, hf_mausb_num_segs, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; /* MA USB Timestamp */ if (mausb_has_timestamp(header)) { header->u.s.timestamp = tvb_get_letohl(tvb, offset); dissect_mausb_timestamp(mausb_tree, tvb, offset); offset += 4; } /* Media Time/Transmission Delay */ if (mausb_has_mtd(header)) { header->u.s.tx_dly = tvb_get_letohl(tvb, offset); proto_tree_add_item(mausb_tree, hf_mausb_mtd, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; } /* Not Iso */ } else { /* Remaining Size/Credit */ header->u.s.u2.credit = tvb_get_letohl(tvb, offset); proto_tree_add_item(mausb_tree, hf_mausb_rem_size_credit, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; } return offset; } /* Code to actually dissect the packets */ static int dissect_mausb_pkt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { /* Set up structures needed to add the protocol subtree and manage it */ proto_item *ti; proto_tree *mausb_tree; /* Other misc. local variables. */ struct mausb_header header; int offset = 0; memset(&header, 0, sizeof(struct mausb_header)); /* Set the Protocol column to the constant string of mausb */ col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAUSB"); mausb_num_pdus++; col_set_str(pinfo->cinfo, COL_INFO, "["); col_set_fence(pinfo->cinfo, COL_INFO); /*** PROTOCOL TREE ***/ /* create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_mausb, tvb, 0, mausb_get_pkt_len(pinfo, tvb, offset, NULL), ENC_NA); mausb_tree = proto_item_add_subtree(ti, ett_mausb); /* Add an item to the subtree, see section 1.5 of README.dissector for more * information. */ offset = dissect_mausb_pkt_common(tvb, offset, pinfo, mausb_tree, &header); if (mausb_is_mgmt_pkt(&header)) { /* Dialog Token */ header.u.token = tvb_get_letohs(tvb, 9) & MAUSB_TOKEN_MASK; col_append_fstr(pinfo->cinfo, COL_INFO, " Token=%u", header.u.token); proto_tree_add_item(mausb_tree, hf_mausb_token, tvb, offset, 2, ENC_LITTLE_ENDIAN); /* Really 10 bits */ offset += 1; /* token */ /* Padding to a DWORD */ proto_tree_add_item(mausb_tree, hf_mausb_mgmt_pad, tvb, offset, 2, ENC_LITTLE_ENDIAN); /* Really 14 bits */ offset += 2; /* DWORD*/ /* Dissect additional management fields (when applicable) */ if (offset < header.length) { dissect_mausb_mgmt_pkt_flds(&header, mausb_tree, tvb, pinfo, offset); } } else if (mausb_is_data_pkt(&header)) { dissect_mausb_pkt_data(tvb, offset, pinfo, mausb_tree, &header); if (!mausb_is_transfer_ack(&header)) { dissect_usb_common(tvb, pinfo, tree, USB_HEADER_MAUSB, &header); } } col_append_str(pinfo->cinfo, COL_INFO, "]"); col_set_fence(pinfo->cinfo, COL_INFO); return header.length; } /* Code to dissect the stream */ static int dissect_mausb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { mausb_num_pdus = 0; tcp_dissect_pdus(tvb, pinfo, tree, true, MAUSB_MIN_LENGTH, mausb_get_pkt_len, dissect_mausb_pkt, data); if (1 < mausb_num_pdus) { col_clear_fence(pinfo->cinfo, COL_INFO); col_prepend_fstr(pinfo->cinfo, COL_INFO, "[%i packets] ", mausb_num_pdus); } return tvb_reported_length(tvb); } /* Register the protocol with Wireshark. */ void proto_register_mausb(void) { static hf_register_info hf[] = { { &hf_mausb_version, { "Version", "mausb.version", FT_UINT8, BASE_DEC, VALS(mausb_version_string), MAUSB_VERSION_MASK, NULL, HFILL } }, { &hf_mausb_flags, { "Flags", "mausb.flags", FT_UINT8, BASE_HEX, NULL, MAUSB_FLAG_MASK, NULL, HFILL } }, /* Flag Subfields */ { &hf_mausb_flag_host, { "Host", "mausb.flags.host", FT_BOOLEAN, 8, TFS(&tfs_set_notset), (MAUSB_FLAG_HOST << MAUSB_FLAG_OFFSET), NULL, HFILL } }, { &hf_mausb_flag_retry, { "Retry", "mausb.flags.retry", FT_BOOLEAN, 8, TFS(&tfs_yes_no), (MAUSB_FLAG_RETRY << MAUSB_FLAG_OFFSET), NULL, HFILL } }, { &hf_mausb_flag_timestamp, { "Timestamp", "mausb.flags.timestamp", FT_BOOLEAN, 8, TFS(&tfs_present_not_present), (MAUSB_FLAG_TIMESTAMP << MAUSB_FLAG_OFFSET), NULL, HFILL } }, { &hf_mausb_flag_reserved, { "Reserved", "mausb.flags.reserved", FT_BOOLEAN, 8, TFS(&tfs_set_notset), (MAUSB_FLAG_RESERVED << MAUSB_FLAG_OFFSET), NULL, HFILL } }, { &hf_mausb_type, { "Type", "mausb.type", FT_UINT8, BASE_HEX, VALS(mausb_type_string), 0, NULL, HFILL } }, { &hf_mausb_length, { "Length", "mausb.length", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_dev_handle, { "Device Handle", "mausb.dev_handle", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_mausb_ep_handle, { "Endpoint Handle", "mausb.ep_handle", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } }, /* EP Handle Subfields */ { &hf_mausb_ep_handle_d, { "Direction", "mausb.ep_handle.d", FT_BOOLEAN, 16, TFS(&tfs_endpoint_direction), MAUSB_EP_HANDLE_D, NULL, HFILL } }, { &hf_mausb_ep_handle_ep_num, { "Endpoint Number", "mausb.ep_handle.ep_num", FT_UINT16, BASE_DEC, NULL, MAUSB_EP_HANDLE_EP_NUM, NULL, HFILL } }, { &hf_mausb_ep_handle_dev_addr, { "USB Device Address", "mausb.ep_handle.dev_addr", FT_UINT16, BASE_DEC, NULL, MAUSB_EP_HANDLE_DEV_ADDR, NULL, HFILL } }, { &hf_mausb_ep_handle_bus_num, { "USB Bus Number", "mausb.ep_handle.bus_num", FT_UINT16, BASE_DEC, NULL, MAUSB_EP_HANDLE_BUS_NUM, NULL, HFILL } }, { &hf_mausb_ma_dev_addr, { "MA Device Address", "mausb.ma_dev_addr", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_mausb_ssid, { "Service Set ID", "mausb.ssid", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } }, { &hf_mausb_status, { "Status", "mausb.status", FT_UINT8, BASE_DEC, VALS(mausb_status_string), 0, NULL, HFILL } }, /* Management Packets Only */ { &hf_mausb_token, { "Token", "mausb.token", FT_UINT16, BASE_DEC, NULL, MAUSB_TOKEN_MASK, NULL, HFILL } }, { &hf_mausb_mgmt_pad, { "Padding to a DWORD", "mausb.mgmt_pad", FT_UINT16, BASE_HEX, NULL, MAUSB_MGMT_PAD_MASK, NULL, HFILL } }, { &hf_mausb_mgmt_type_spec, { "Type-specific management packet fields", "mausb.mgmt_flds", FT_NONE, 0, NULL, 0, NULL, HFILL } }, { &hf_mausb_mgmt_type_spec_generic, { "Type-specific management packet fields", "mausb.mgmt_flds.generic", FT_NONE, 0, NULL, 0, NULL, HFILL } }, /* Data Packets Only */ { &hf_mausb_eps, { "EP Status", "mausb.eps", FT_UINT8, BASE_HEX, VALS(mausb_eps_string), MAUSB_EPS_MASK, NULL, HFILL } }, { &hf_mausb_eps_rsvd, { "EP Status", "mausb.eps.reserved", FT_UINT8, BASE_HEX, NULL, MAUSB_EPS_MASK, NULL, HFILL } }, { &hf_mausb_tflags, { "Transfer Flags", "mausb.tflag", FT_UINT8, BASE_HEX, NULL, MAUSB_TFLAG_MASK, NULL, HFILL } }, /* T-Flag Subfields */ { &hf_mausb_tflag_arq, { "ARQ", "mausb.tflag.arq", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MAUSB_TFLAG_ARQ << MAUSB_TFLAG_OFFSET, NULL, HFILL } }, { &hf_mausb_tflag_neg, { "NEG", "mausb.tflag.neg", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MAUSB_TFLAG_NEG << MAUSB_TFLAG_OFFSET, NULL, HFILL } }, { &hf_mausb_tflag_eot, { "EoT", "mausb.tflag.eot", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MAUSB_TFLAG_EOT << MAUSB_TFLAG_OFFSET, NULL, HFILL } }, { &hf_mausb_tflag_type, { "Transfer Type", "mausb.tflag.type", FT_UINT8, BASE_HEX, VALS(mausb_transfer_type_string), MAUSB_TFLAG_TRANSFER_TYPE << MAUSB_TFLAG_OFFSET, NULL, HFILL } }, { &hf_mausb_tflag_rsvd, { "Reserved", "mausb.tflag.rsvd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MAUSB_TFLAG_RSVD << MAUSB_TFLAG_OFFSET, NULL, HFILL } }, { &hf_mausb_num_iso_hdr, { "Number of Iso Headers", "mausb.numisohdr", FT_UINT16, BASE_DEC, NULL, MAUSB_NUM_ISO_HDR_MASK, NULL, HFILL } }, { &hf_mausb_iflags, { "Isochronous Flags", "mausb.iflag", FT_UINT16, BASE_HEX, NULL, MAUSB_IFLAG_MASK, NULL, HFILL } }, /* I-Flag Subfields */ { &hf_mausb_iflag_mtd, { "MTD Valid", "mausb.iflag.mtd", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MAUSB_IFLAG_MTD << MAUSB_IFLAG_OFFSET, NULL, HFILL } }, { &hf_mausb_iflag_hdr_format, { "Isochronous Header Format", "mausb.iflag.ihf", FT_UINT8, BASE_HEX, NULL, MAUSB_IFLAG_HDR_FORMAT << MAUSB_IFLAG_OFFSET, NULL, HFILL } }, { &hf_mausb_iflag_asap, { "ASAP", "mausb.iflag.asap", FT_BOOLEAN, 8, TFS(&tfs_set_notset), MAUSB_IFLAG_ASAP << MAUSB_IFLAG_OFFSET, NULL, HFILL } }, { &hf_mausb_stream_id, { "Stream ID", "mausb.streamid", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_seq_num, { "Sequence Number", "mausb.seqnum", FT_UINT24, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_req_id, { "Request ID", "mausb.reqid", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_present_time, { "Presentation Time", "mausb.presenttime", FT_UINT32, BASE_DEC, NULL, MAUSB_PRESENT_TIME_MASK, NULL, HFILL } }, { &hf_mausb_uframe, { "Microframe Number", "mausb.uframe", FT_UINT32, BASE_DEC, NULL, MAUSB_UFRAME_MASK, NULL, HFILL } }, { &hf_mausb_frame, { "Frame Number", "mausb.frame", FT_UINT32, BASE_DEC, NULL, MAUSB_FRAME_MASK, NULL, HFILL } }, { &hf_mausb_num_segs, { "Number of Segments", "mausb.numseg", FT_UINT32, BASE_DEC, NULL, MAUSB_NUM_SEGS_MASK, NULL, HFILL } }, { &hf_mausb_timestamp, { "Timestamp", "mausb.timestamp", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_delta, { "Delta", "mausb.delta", FT_UINT32, BASE_DEC, NULL, MAUSB_DELTA_MASK, NULL, HFILL } }, { &hf_mausb_nom_interval, { "Nominal Bus Interval", "mausb.nomitvl", FT_UINT32, BASE_DEC, NULL, MAUSB_INTERVAL_MASK, NULL, HFILL } }, { &hf_mausb_mtd, { "Media Time/Transmission Delay", "mausb.mtd", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_rem_size_credit, { "Remaining Size/Credit", "mausb.remsize_credit", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } }, }; /* Register info for CapReq/Resp specific fields */ static hf_register_info hf_cap[] = { { &hf_mausb_cap_resp_num_ep, { "Number of Endpoints", "mausb.cap_resp.num_ep", FT_UINT16, BASE_DEC, NULL, 0, "the maximum number of endpoints for this device", HFILL } }, { &hf_mausb_cap_resp_num_dev, { "Number of Devices", "mausb.cap_resp.num_dev", FT_UINT8, BASE_DEC, NULL, 0, "the maximum number of USB devices the MA USB device can manage", HFILL } }, { &hf_mausb_cap_resp_num_stream, { "Number of Streams", "mausb.cap_resp.num_stream", FT_UINT8, BASE_DEC, NULL, MAUSB_CAP_RESP_NUM_STREAM_MASK, "2 to the power of this value is the max number of streams supported", /* TODO: have dissector print the actual number of streams supported */ HFILL } }, { &hf_mausb_cap_resp_dev_type, { "Device Type", "mausb.cap_resp.dev_type", FT_UINT8, BASE_HEX, VALS(mausb_cap_resp_dev_type), MAUSB_CAP_RESP_DEV_TYPE_MASK, NULL, HFILL } }, { &hf_mausb_cap_resp_desc_count, { "Descriptors Count", "mausb.cap_resp.desc_count", FT_UINT8, BASE_DEC, NULL, 0, "The total number of MA Device Capabilities descriptors", HFILL } }, { &hf_mausb_cap_resp_desc_len, { "Descriptors Length", "mausb.cap_resp.desc_len", FT_UINT24, BASE_DEC, NULL, 0, "The total size of MA Device Capabilities descriptors", HFILL } }, { &hf_mausb_cap_resp_transfer_req, { "Number of Outstanding Transfer Requests", "mausb.cap_resp.transfer_req", FT_UINT16, BASE_DEC, NULL, 0, "The maximum number of total outstanding transfer requests", HFILL } }, { &hf_mausb_cap_resp_mgmt_req, { "Number of Outstanding Management Requests", "mausb.cap_resp.mgmt_req", FT_UINT16, BASE_DEC, NULL, MAUSB_CAP_RESP_MGMT_REQ_MASK, "The maximum number of host initiated outstanding management requests", HFILL } }, { &hf_mausb_cap_resp_rsvd, { "Reserved", "mausb.cap_resp.rsvd", FT_UINT16, BASE_HEX, NULL, MAUSB_CAP_RESP_RSVD_MASK, NULL, HFILL } }, /* Device Capability Descriptors */ { &hf_mausb_dev_cap_len, { "Length", "mausb.cap_resp.dev_cap.length", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_dev_cap_type, { "Type", "mausb.cap_resp.dev_cap.type", FT_UINT8, BASE_DEC, VALS(mausb_dev_cap_string), 0, NULL, HFILL } }, { &hf_mausb_dev_cap_generic, { "Type-specific device capability descriptor fields", "mausb.cap_resp.dev_cap.generic", FT_NONE, 0, NULL, 0, NULL, HFILL } } }; /* register info for ep_handle_* specific fields */ static hf_register_info hf_ep_handle[] = { { &hf_mausb_mgmt_ep_handle_num, { "Number of Endpoint Handles", "mausb.ep_handle_num", FT_UINT8, BASE_DEC, NULL, MAUSB_MGMT_NUM_EP_DES_MASK, NULL, HFILL } }, { &hf_mausb_mgmt_ep_handle_pad, { "Padding to a DWORD", "mausb.ep_handle_pad", FT_NONE, 0, NULL, 0x0, NULL, HFILL } }, { &hf_mausb_mgmt_ep_des_num, { "Number of Endpoint Descriptors", "mausb.ep_des_num", FT_UINT8, BASE_DEC, NULL, MAUSB_MGMT_NUM_EP_DES_MASK, NULL, HFILL } }, { &hf_mausb_mgmt_ep_des_size, { "Size of Endpoint Descriptors", "mausb.ep_des_size", FT_UINT16, BASE_DEC, NULL, MAUSB_MGMT_SIZE_EP_DES_MASK, NULL, HFILL } }, { &hf_mausb_mgmt_ep_des_pad, { "Padding to a DWORD", "mausb.ep_des_pad", FT_NONE, 0, NULL, 0x0, NULL, HFILL } }, { &hf_mausb_ep_handle_req_pad, { "Padding to a DWORD", "mausb.ep_handle_req.pad", FT_NONE, 0, NULL, 0, NULL, HFILL } }, { &hf_mausb_ep_handle_resp_dir, { "Direction", "mausb.ep_dir", FT_BOOLEAN, 6, TFS(&tfs_ep_handle_resp_dir), MAUSB_EP_HANDLE_RESP_DIR_MASK, NULL, HFILL } }, { &hf_mausb_ep_handle_resp_iso, { "Isochronous", "mausb.ep_iso", FT_BOOLEAN, 6, TFS(&tfs_yes_no), MAUSB_EP_HANDLE_RESP_ISO_MASK, NULL, HFILL } }, { &hf_mausb_ep_handle_resp_lman, { "L-Managed", "mausb.ep_lman", FT_BOOLEAN, 6, TFS(&tfs_supported_not_supported), MAUSB_EP_HANDLE_RESP_LMAN_MASK, NULL, HFILL } }, { &hf_mausb_ep_handle_resp_valid, { "Valid", "mausb.ep_valid", FT_BOOLEAN, 6, TFS(&tfs_invalid_valid), MAUSB_EP_HANDLE_RESP_VALID_MASK, NULL, HFILL } }, { &hf_mausb_ep_handle_resp_ccu, { "CCU", "mausb.ep_ccu", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_ep_handle_resp_buf_size, { "Buffer Size", "mausb.ep_buf_size", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_ep_handle_resp_iso_prog_dly, { "Iso Programming Delay", "mausb.ep_iso_prog_dly", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_ep_handle_resp_iso_resp_dly, { "Iso Response Delay", "mausb.ep_iso_resp_dly", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } } }; /* (Cancel/Clear)Transfer(Req/Resp) specific fields */ static hf_register_info hf_cancel_transfer[] = { { &hf_mausb_clear_transfers_info_block, { "Clear Transfers Information Block", "mausb.clear_transfers.info", FT_NONE, 0, NULL, 0, NULL, HFILL } }, { &hf_mausb_clear_transfers_status_block, { "Cancel Transfers Status Block", "mausb.clear_transfers.status_block", FT_NONE, 0, NULL, 0, NULL, HFILL } }, { &hf_mausb_cancel_transfer_rsvd, { "Reserved", "mausb.cancel_transfer.rsvd", FT_NONE, 0, NULL, 0, NULL, HFILL } }, { &hf_mausb_clear_transfers_req_num, { "Number of Blocks", "mausb.clear_transfers_req.num", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_clear_transfers_req_rsvd, { "Reserved", "mausb.clear_transfers_req.rsvd", FT_NONE, 0, NULL, 0, NULL, HFILL } }, { &hf_mausb_clear_transfers_resp_num, { "Number of Blocks", "mausb.clear_transfers_resp.num", FT_UINT32, BASE_DEC, NULL, MAUSB_CLEAR_TRANSFERS_RESP_NUM_MASK , NULL, HFILL } }, { &hf_mausb_clear_transfers_resp_rsvd, { "Reserved", "mausb.clear_transfers_resp.rsvd", FT_UINT32, BASE_HEX, NULL, ~MAUSB_CLEAR_TRANSFERS_RESP_NUM_MASK, NULL, HFILL } }, { &hf_mausb_cancel_transfer_status, { "Status", "mausb.cancel_transfer.status", FT_UINT24, BASE_HEX, VALS(mausb_cancel_transfer_status_string), MAUSB_CANCEL_TRANSFER_STATUS_MASK, NULL, HFILL } }, { &hf_mausb_cancel_transfer_rsvd_2, { "Reserved", "mausb.cancel_transfer.rsvd_2", FT_UINT24, BASE_HEX, NULL, ~MAUSB_CANCEL_TRANSFER_STATUS_MASK, NULL, HFILL } }, { &hf_mausb_clear_transfers_status, { "Cancellation Status", "mausb.clear_transfers.status", FT_BOOLEAN, 6, TFS(&tfs_success_fail), MAUSB_CLEAR_TRANSFERS_STATUS_MASK, NULL, HFILL } }, { &hf_mausb_clear_transfers_partial, { "Partial Delivery", "mausb.clear_transfers.partial", FT_BOOLEAN, 6, NULL, MAUSB_CLEAR_TRANSFERS_PARTIAL_MASK, NULL, HFILL } }, { &hf_mausb_clear_transfers_start_req_id, { "Start Request ID", "mausb.clear_transfers.start_reqid", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_clear_transfers_last_req_id, { "Last Request ID", "mausb.clear_transfers.last_reqid", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_clear_transfers_req_block_rsvd, { "Reserved", "mausb.clear_transfers_req.block_rsvd", FT_NONE, 0, NULL, 0, NULL, HFILL } }, { &hf_mausb_clear_transfers_resp_block_rsvd, { "Reserved", "mausb.clear_transfers_resp.block_rsvd", FT_UINT32, BASE_HEX, NULL, MAUSB_CLEAR_TRANSFERS_RESP_BLOCK_RSVD_MASK, NULL, HFILL } }, { &hf_mausb_cancel_transfer_seq_num, { "Delivered Sequence Number", "mausb.cancel_transfer.seqnum", FT_UINT24, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_mausb_cancel_transfer_byte_offset, { "Delivered Byte Offset", "mausb.cancel_transfer.byte_offset", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } }, }; static hf_register_info oui_hf[] = { { &hf_llc_mausb_pid, { "PID", "mausb.pid", FT_UINT16, BASE_HEX, VALS(mausb_pid_string), 0x0, NULL, HFILL } } }; /* Setup protocol subtree array */ static int *ett[] = { &ett_mausb, &ett_mausb_flags, &ett_mausb_ep_handle, &ett_mausb_tflags, &ett_mausb_iflags, &ett_mausb_present_time, &ett_mausb_timestamp, &ett_mgmt, &ett_dev_cap, &ett_clear_transfers_block }; static ei_register_info ei[] = { { &ei_ep_handle_len, { "mausb.ei.ep_handle.length", PI_PROTOCOL, PI_WARN, "Invalid Endpoint handle length field", EXPFILL } }, { &ei_len, { "mausb.ei.length", PI_MALFORMED, PI_ERROR, "Packet length field does not match size of packet", EXPFILL } }, { &ei_mgmt_type_undef, { "mausb.ei.type", PI_PROTOCOL, PI_WARN, "Undefined management packet type", EXPFILL } }, { &ei_mgmt_type_spec_len_long, { "mausb.ei.type_spec.len", PI_PROTOCOL, PI_WARN, "Data exists after type-specific management packet field", EXPFILL } }, { &ei_mgmt_type_spec_len_short, { "mausb.ei.type_spec.len", PI_PROTOCOL, PI_WARN, "Expected type-specific management packet data", EXPFILL } }, { &ei_dev_cap_len, { "mausb.ei.cap_resp.dev_cap.length", PI_PROTOCOL, PI_WARN, "Incorrect length value for this device capability descriptor", EXPFILL } }, { &ei_dev_cap_resp_desc_len, { "mausb.ei.dev_cap_resp.desc_len", PI_PROTOCOL, PI_WARN, "Incorrect value in Device Descriptors Length field", EXPFILL } }, { &ei_cap_resp_desc_len, { "mausb.ei.cap_resp.desc_len", PI_PROTOCOL, PI_WARN, "Value in Descriptors Length field exceeds actual space in packet", EXPFILL } }, }; expert_module_t* expert_mausb; /* Register the protocol name and description */ proto_mausb = proto_register_protocol("Media Agnostic USB", "MAUSB", "mausb"); /* Required function calls to register the header fields and subtrees */ proto_register_field_array(proto_mausb, hf, array_length(hf)); proto_register_field_array(proto_mausb, hf_cap, array_length(hf_cap)); proto_register_field_array(proto_mausb, hf_ep_handle, array_length(hf_ep_handle)); proto_register_field_array(proto_mausb, hf_cancel_transfer, array_length(hf_cancel_transfer)); proto_register_subtree_array(ett, array_length(ett)); /* for Expert info */ expert_mausb = expert_register_protocol(proto_mausb); expert_register_field_array(expert_mausb, ei, array_length(ei)); llc_add_oui(OUI_WFA, "llc.wfa_pid", "LLC WFA OUI PID", oui_hf, proto_mausb); /* Register the dissectors */ mausb_tcp_handle = register_dissector("mausb", dissect_mausb, proto_mausb); mausb_pkt_handle = register_dissector("mausb.pkt", dissect_mausb_pkt, proto_mausb); } void proto_reg_handoff_mausb(void) { dissector_add_uint("llc.wfa_pid", PID_MAUSB, mausb_pkt_handle); dissector_add_uint_range_with_preference("tcp.port", "", mausb_tcp_handle); dissector_add_for_decode_as_with_preference("udp.port", mausb_pkt_handle); } /* * 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: */