Wireshark-dev: [Wireshark-dev] New packet disassembly module
From: Sean Sheedy <seansh@xxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 14 Jul 2006 13:34:59 -0700
Attached is a packet disassembly module I wrote for Pegasus Lightweight Stream Control, a protocol used by some cable set-top boxes for video-on-demand. I would appreciate it being added to the source base. Thanks. Sean -- Sean Sheedy seansh@users.sourceforge.net1
/* packet-lsc.c * Routines for Pegasus LSC packet disassembly * Copyright 2006, Sean Sheedy <seansh@xxxxxxxxxxxxxxxxxxxxx> * * $Id$ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@xxxxxxxxxxxx> * Copyright 1998 Gerald Combs * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <glib.h> #include <epan/packet.h> #include <epan/emem.h> #include <epan/prefs.h> #include <packet-tcp.h> /* Forward declaration we need below */ void proto_reg_handoff_lsc(void); #define LSC_PAUSE 0x01 #define LSC_RESUME 0x02 #define LSC_STATUS 0x03 #define LSC_RESET 0x04 #define LSC_JUMP 0x05 #define LSC_PLAY 0x06 #define LSC_DONE 0x40 #define LSC_PAUSE_REPLY 0x81 #define LSC_RESUME_REPLY 0x82 #define LSC_STATUS_REPLY 0x83 #define LSC_RESET_REPLY 0x84 #define LSC_JUMP_REPLY 0x85 #define LSC_PLAY_REPLY 0x86 #define isReply(o) ((o) & 0x80) static const value_string op_code_vals[] = { { LSC_PAUSE, "LSC_PAUSE" }, { LSC_RESUME, "LSC_RESUME" }, { LSC_STATUS, "LSC_STATUS" }, { LSC_RESET, "LSC_RESET" }, { LSC_JUMP, "LSC_JUMP" }, { LSC_PLAY, "LSC_PLAY" }, { LSC_DONE, "LSC_DONE" }, { LSC_PAUSE_REPLY, "LSC_PAUSE_REPLY" }, { LSC_RESUME_REPLY, "LSC_RESUME_REPLY" }, { LSC_STATUS_REPLY, "LSC_STATUS_REPLY" }, { LSC_RESET_REPLY, "LSC_RESET_REPLY" }, { LSC_JUMP_REPLY, "LSC_JUMP_REPLY" }, { LSC_PLAY_REPLY, "LSC_PLAY_REPLY" }, { 0, NULL } }; #define LSC_OPCODE_LEN 3 /* Length to find op code */ #define LSC_MIN_LEN 8 /* Minimum packet length */ /* Length of each packet type */ #define LSC_PAUSE_LEN 12 #define LSC_RESUME_LEN 16 #define LSC_STATUS_LEN 8 #define LSC_RESET_LEN 8 #define LSC_JUMP_LEN 20 #define LSC_PLAY_LEN 20 #define LSC_REPLY_LEN 17 static const value_string status_code_vals[] = { { 0x00, "LSC_OK" }, { 0x10, "LSC_BAD_REQUEST" }, { 0x11, "LSC_BAD_STREAM" }, { 0x12, "LSC_WRONG_STATE" }, { 0x13, "LSC_UNKNOWN" }, { 0x14, "LSC_NO_PERMISSION" }, { 0x15, "LSC_BAD_PARAM" }, { 0x16, "LSC_NO_IMPLEMENT" }, { 0x17, "LSC_NO_MEMORY" }, { 0x18, "LSC_IMP_LIMIT" }, { 0x19, "LSC_TRANSIENT" }, { 0x1a, "LSC_NO_RESOURCES" }, { 0x20, "LSC_SERVER_ERROR" }, { 0x21, "LSC_SERVER_FAILURE" }, { 0x30, "LSC_BAD_SCALE" }, { 0x31, "LSC_BAD_START" }, { 0x32, "LSC_BAD_STOP" }, { 0x40, "LSC_MPEG_DELIVERY" }, { 0, NULL } }; static const value_string mode_vals[] = { { 0x00, "O - Open Mode" }, { 0x01, "P - Pause Mode" }, { 0x02, "ST - Search Transport" }, { 0x03, "T - Transport" }, { 0x04, "TP - Transport Pause" }, { 0x05, "STP - Search Transport Pause" }, { 0x06, "PST - Pause Search Transport" }, { 0x07, "EOS - End of Stream" }, { 0, NULL } }; /* Initialize the protocol and registered fields */ static int proto_lsc = -1; static int hf_lsc_version = -1; static int hf_lsc_trans_id = -1; static int hf_lsc_op_code = -1; static int hf_lsc_status_code = -1; static int hf_lsc_stream_handle = -1; static int hf_lsc_start_npt = -1; static int hf_lsc_stop_npt = -1; static int hf_lsc_current_npt = -1; static int hf_lsc_scale_num = -1; static int hf_lsc_scale_denom = -1; static int hf_lsc_mode = -1; /* Preferences */ static guint global_lsc_port = 0; static guint lsc_port = 0; /* Initialize the subtree pointers */ static gint ett_lsc = -1; /* Code to actually dissect the packets */ static void dissect_lsc_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { proto_item *ti; proto_tree *lsc_tree; guint8 op_code; guint32 stream; guint expected_len; /* Protocol is LSC, packet summary is not yet known */ if (check_col(pinfo->cinfo, COL_PROTOCOL)) col_set_str(pinfo->cinfo, COL_PROTOCOL, "LSC"); if (check_col(pinfo->cinfo, COL_INFO)) col_clear(pinfo->cinfo, COL_INFO); /* Too little data? */ if (tvb->length < LSC_MIN_LEN) { if (check_col(pinfo->cinfo, COL_INFO)) col_set_str(pinfo->cinfo, COL_INFO, "[Too short]"); return; } /* Get the op code */ op_code = tvb_get_guint8(tvb, 2); /* And the stream handle */ stream = tvb_get_ntohl(tvb, 4); /* Check the data length against what we actually received */ switch (op_code) { case LSC_PAUSE: expected_len = LSC_PAUSE_LEN; break; case LSC_RESUME: expected_len = LSC_RESUME_LEN; break; case LSC_STATUS: expected_len = LSC_STATUS_LEN; break; case LSC_RESET: expected_len = LSC_RESET_LEN; break; case LSC_JUMP: expected_len = LSC_JUMP_LEN; break; case LSC_PLAY: expected_len = LSC_PLAY_LEN; break; case LSC_DONE: case LSC_PAUSE_REPLY: case LSC_RESUME_REPLY: case LSC_STATUS_REPLY: case LSC_RESET_REPLY: case LSC_JUMP_REPLY: case LSC_PLAY_REPLY: expected_len = LSC_REPLY_LEN; break; default: /* Unrecognized op code */ expected_len = LSC_MIN_LEN; break; } /* Display the op code in the summary */ if (check_col(pinfo->cinfo, COL_INFO)) { col_add_fstr(pinfo->cinfo, COL_INFO, "%s, session %.8u", val_to_str(op_code, op_code_vals, "Unknown op code (0x%x)"), stream); if (tvb->length < expected_len) col_append_str(pinfo->cinfo, COL_INFO, " [Too short]"); else if (tvb->length > expected_len) col_append_str(pinfo->cinfo, COL_INFO, " [Too long]"); } if (tree) { /* Create display subtree for the protocol */ ti = proto_tree_add_item(tree, proto_lsc, tvb, 0, -1, FALSE); lsc_tree = proto_item_add_subtree(ti, ett_lsc); /* Add already fetched items to the tree */ proto_tree_add_uint(lsc_tree, hf_lsc_op_code, tvb, 2, 1, op_code); proto_tree_add_uint_format_value(lsc_tree, hf_lsc_stream_handle, tvb, 4, 4, stream, "%.8u", stream); /* Add rest of LSC header */ proto_tree_add_uint(lsc_tree, hf_lsc_version, tvb, 0, 1, tvb_get_guint8(tvb, 0)); proto_tree_add_uint(lsc_tree, hf_lsc_trans_id, tvb, 1, 1, tvb_get_guint8(tvb, 1)); /* Only replies contain a status code */ if (isReply(op_code)) proto_tree_add_uint(lsc_tree, hf_lsc_status_code, tvb, 3, 1, tvb_get_guint8(tvb, 3)); /* Add op code specific parts */ switch (op_code) { case LSC_PAUSE: proto_tree_add_int(lsc_tree, hf_lsc_stop_npt, tvb, 8, 4, tvb_get_ntohl(tvb, 8)); break; case LSC_RESUME: proto_tree_add_int(lsc_tree, hf_lsc_start_npt, tvb, 8, 4, tvb_get_ntohl(tvb, 8)); proto_tree_add_int(lsc_tree, hf_lsc_scale_num, tvb, 12, 2, tvb_get_ntohs(tvb, 12)); proto_tree_add_uint(lsc_tree, hf_lsc_scale_denom, tvb, 14, 2, tvb_get_ntohs(tvb, 14)); break; case LSC_JUMP: case LSC_PLAY: proto_tree_add_int(lsc_tree, hf_lsc_start_npt, tvb, 8, 4, tvb_get_ntohl(tvb, 8)); proto_tree_add_int(lsc_tree, hf_lsc_stop_npt, tvb, 12, 4, tvb_get_ntohl(tvb, 12)); proto_tree_add_int(lsc_tree, hf_lsc_scale_num, tvb, 16, 2, tvb_get_ntohs(tvb, 16)); proto_tree_add_uint(lsc_tree, hf_lsc_scale_denom, tvb, 18, 2, tvb_get_ntohs(tvb, 18)); break; case LSC_DONE: case LSC_PAUSE_REPLY: case LSC_RESUME_REPLY: case LSC_STATUS_REPLY: case LSC_RESET_REPLY: case LSC_JUMP_REPLY: case LSC_PLAY_REPLY: proto_tree_add_int(lsc_tree, hf_lsc_current_npt, tvb, 8, 4, tvb_get_ntohl(tvb, 8)); proto_tree_add_int(lsc_tree, hf_lsc_scale_num, tvb, 12, 2, tvb_get_ntohs(tvb, 12)); proto_tree_add_uint(lsc_tree, hf_lsc_scale_denom, tvb, 14, 2, tvb_get_ntohs(tvb, 14)); proto_tree_add_uint(lsc_tree, hf_lsc_mode, tvb, 16, 1, tvb_get_guint8(tvb, 16)); break; default: break; } } } /* Decode LSC over UDP */ static void dissect_lsc_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { dissect_lsc_common(tvb, pinfo, tree); } /* Determine length of LSC message */ static guint get_lsc_pdu_len(tvbuff_t *tvb, int offset) { guint8 op_code; guint pdu_len; /* Get the op code */ op_code = tvb_get_guint8(tvb, offset + 2); switch (op_code) { case LSC_PAUSE: pdu_len = LSC_PAUSE_LEN; break; case LSC_RESUME: pdu_len = LSC_RESUME_LEN; break; case LSC_STATUS: pdu_len = LSC_STATUS_LEN; break; case LSC_RESET: pdu_len = LSC_RESET_LEN; break; case LSC_JUMP: pdu_len = LSC_JUMP_LEN; break; case LSC_PLAY: pdu_len = LSC_PLAY_LEN; break; case LSC_DONE: case LSC_PAUSE_REPLY: case LSC_RESUME_REPLY: case LSC_STATUS_REPLY: case LSC_RESET_REPLY: case LSC_JUMP_REPLY: case LSC_PLAY_REPLY: pdu_len = LSC_REPLY_LEN; break; default: /* Unrecognized op code */ pdu_len = LSC_OPCODE_LEN; break; } return pdu_len; } /* Decode LSC over TCP */ static void dissect_lsc_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { tcp_dissect_pdus(tvb, pinfo, tree, TRUE, LSC_OPCODE_LEN, get_lsc_pdu_len, dissect_lsc_common); } /* Register the protocol with Ethereal */ void proto_register_lsc(void) { module_t *lsc_module; /* Setup list of header fields */ static hf_register_info hf[] = { { &hf_lsc_version, { "Version", "lsc.version", FT_UINT8, BASE_DEC, NULL, 0, "Version of the Pegasus LSC protocol", HFILL } }, { &hf_lsc_trans_id, { "Transaction ID", "lsc.trans_id", FT_UINT8, BASE_DEC, NULL, 0, "Transaction ID", HFILL } }, { &hf_lsc_op_code, { "Op Code", "lsc.op_code", FT_UINT8, BASE_HEX, VALS(op_code_vals), 0, "Operation Code", HFILL } }, { &hf_lsc_status_code, { "Status Code", "lsc.status_code", FT_UINT8, BASE_HEX, VALS(status_code_vals), 0, "Status Code", HFILL } }, { &hf_lsc_stream_handle, { "Stream Handle", "lsc.stream_handle", FT_UINT32, BASE_DEC, NULL, 0, "Stream identification handle", HFILL } }, { &hf_lsc_start_npt, { "Start NPT", "lsc.start_npt", FT_INT32, BASE_DEC, NULL, 0, "Start Time (milliseconds)", HFILL } }, { &hf_lsc_stop_npt, { "Stop NPT", "lsc.stop_npt", FT_INT32, BASE_DEC, NULL, 0, "Stop Time (milliseconds)", HFILL } }, { &hf_lsc_current_npt, { "Current NPT", "lsc.current_npt", FT_INT32, BASE_DEC, NULL, 0, "Current Time (milliseconds)", HFILL } }, { &hf_lsc_scale_num, { "Scale Numerator", "lsc.scale_num", FT_INT16, BASE_DEC, NULL, 0, "Scale Numerator", HFILL } }, { &hf_lsc_scale_denom, { "Scale Denominator", "lsc.scale_denum", FT_UINT16, BASE_DEC, NULL, 0, "Scale Denominator", HFILL } }, { &hf_lsc_mode, { "Server Mode", "lsc.mode", FT_UINT8, BASE_HEX, VALS(mode_vals), 0, "Current Server Mode", HFILL } } }; /* Setup protocol subtree array */ static gint *ett[] = { &ett_lsc, }; /* Register the protocol name and description */ proto_lsc = proto_register_protocol("Pegasus Lightweight Stream Control", "LSC", "lsc"); /* Required function calls to register the header fields and subtrees used */ proto_register_field_array(proto_lsc, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); /* Register preferences module */ lsc_module = prefs_register_protocol(proto_lsc, proto_reg_handoff_lsc); /* Register preferences */ prefs_register_uint_preference(lsc_module, "port", "LSC Port", "Set the TCP or UDP port for Pegasus LSC messages", 10, &global_lsc_port); } void proto_reg_handoff_lsc(void) { dissector_handle_t lsc_udp_handle; dissector_handle_t lsc_tcp_handle; lsc_udp_handle = create_dissector_handle(dissect_lsc_udp, proto_lsc); lsc_tcp_handle = create_dissector_handle(dissect_lsc_tcp, proto_lsc); /* Set the port number */ lsc_port = global_lsc_port; dissector_add("udp.port", lsc_port, lsc_udp_handle); dissector_add("tcp.port", lsc_port, lsc_tcp_handle); }
- Follow-Ups:
- Re: [Wireshark-dev] New packet disassembly module
- From: ronnie sahlberg
- Re: [Wireshark-dev] New packet disassembly module
- From: Anders Broman
- Re: [Wireshark-dev] New packet disassembly module
- Prev by Date: [Wireshark-dev] Expert dialog [patch] needed?
- Next by Date: Re: [Wireshark-dev] WireShark Indent Style (was: Kismet protocol dissector)
- Previous by thread: [Wireshark-dev] Expert dialog [patch] needed?
- Next by thread: Re: [Wireshark-dev] New packet disassembly module
- Index(es):