Use MAC address documentation range in filter examples
[metze/wireshark/wip.git] / epan / dissectors / packet-ax25-kiss.c
index ac0d3019aad00b1d0a04ecfb75abc56ca6f38456..1c93320ad1fd4ab1adda45251258235ee90116fe 100644 (file)
@@ -3,10 +3,8 @@
  * Routines for AX.25 KISS protocol dissection
  * Copyright 2010,2012 R.W. Stearn <richard@rns-stearn.demon.co.uk>
  *
- * $Id$
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
@@ -21,7 +19,7 @@
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 /*
@@ -33,8 +31,8 @@
  * and here:
  *   http://www.ax25.net/kiss.aspx
  *
- * Linux implementation does not appear to attempt to implement that
- * protocol in full. Does provide the ability to send a KISS command via
+ * The Linux implementation does not appear to attempt to implement that
+ * protocol in full. It does provide the ability to send a KISS command via
  * ax25_kiss_cmd() and internally will send FULLDUPLEX KISS commands if
  * DAMA is enabled/disabled.
  * i.e.:
  *    FF         Return            Exit KISS and return control to a
  *                                 higher-level program. This is useful
  *                                 only when KISS is  incorporated
- *                                 into  the TNC along with other
+ *                                 into the TNC along with other
  *                                 applications.
  *
+ *
+ * G8BPQ extensions:
+ *
+ *    12          Data frame       Data with acknowledge request
+ *
+ *    14          Poll mode        Set poll mode
+ *
+ *   Checksum mode
+ *
 */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <glib.h>
+#include "config.h"
 
-#include <epan/strutil.h>
 #include <epan/packet.h>
 #include <epan/prefs.h>
-#include <epan/emem.h>
-#include <epan/etypes.h>
-
+#include <wiretap/wtap.h>
 #include "packet-ax25-kiss.h"
+#include "packet-ax25.h"
 
 #define STRLEN 80
 
-#define KISS_HEADER_SIZE       1 /* length of the KISS type header */
+#define KISS_HEADER_SIZE        1 /* length of the KISS type header */
 
 /* KISS frame types */
-#define KISS_DATA_FRAME                0
-#define KISS_TXDELAY           1
-#define KISS_PERSISTENCE       2
-#define KISS_SLOT_TIME         3
-#define KISS_TXTAIL            4
-#define KISS_FULLDUPLEX                5
-#define KISS_SETHARDWARE       6
+#define KISS_DATA_FRAME                 0
+#define KISS_TXDELAY            1
+#define KISS_PERSISTENCE        2
+#define KISS_SLOT_TIME          3
+#define KISS_TXTAIL             4
+#define KISS_FULLDUPLEX                 5
+#define KISS_SETHARDWARE        6
+#define KISS_DATA_FRAME_ACK    12
+#define KISS_POLL_MODE         14
 #define KISS_RETURN            15
 
 #define KISS_CMD_MASK           0x0f
 #define KISS_PORT_MASK          0xf0
 
-/* Forward declaration we need below */
-void proto_reg_handoff_ax25_kiss(void);
+/* Global preferences */
+static gboolean gPREF_CKSUM_MODE = FALSE;
 
-/* Dissector handles - all the possibles are listed */
+void proto_register_ax25_kiss(void);
+void proto_reg_handoff_ax25_kiss(void);
 
 /* Initialize the protocol and registered fields */
 static int proto_ax25_kiss           = -1;
+
 static int hf_ax25_kiss_cmd            = -1;
 static int hf_ax25_kiss_port           = -1;
-static int hf_ax25_kiss_txdelay        = -1;
+static int hf_ax25_kiss_txdelay                = -1;
 static int hf_ax25_kiss_persistence    = -1;
 static int hf_ax25_kiss_slottime       = -1;
-static int hf_ax25_kiss_txtail = -1;
+static int hf_ax25_kiss_txtail         = -1;
 static int hf_ax25_kiss_fullduplex     = -1;
 static int hf_ax25_kiss_sethardware    = -1;
+static int hf_ax25_kiss_data_ack       = -1;
+static int hf_ax25_kiss_cksum          = -1;
 
-/* Global preference ("controls" display of numbers) */
-/*
-static gboolean gPREF_HEX = FALSE;
-*/
 
 /* Initialize the subtree pointers */
 static gint ett_ax25_kiss = -1;
 
+static dissector_handle_t kiss_handle;
+
+/* Dissector handles - all the possibles are listed */
+static dissector_handle_t ax25_handle;
+
+static const value_string kiss_frame_types[] = {
+       { KISS_DATA_FRAME,      "Data frame" },
+       { KISS_TXDELAY,         "Tx delay" },
+       { KISS_PERSISTENCE,     "Persistence" },
+       { KISS_SLOT_TIME,       "Slot time" },
+       { KISS_TXTAIL,          "Tx tail" },
+       { KISS_FULLDUPLEX,      "Full duplex" },
+       { KISS_SETHARDWARE,     "Set hardware" },
+       { KISS_DATA_FRAME_ACK,  "Data frame ack" },
+       { KISS_POLL_MODE,       "Poll mode" },
+       { KISS_RETURN,          "Return" },
+       { 0, NULL }
+};
+
+void
+capture_ax25_kiss( const guchar *pd, int offset, int len, packet_counts *ld)
+{
+       int    l_offset;
+       guint8 kiss_cmd;
+
+       if ( ! BYTES_ARE_IN_FRAME( offset, len, KISS_HEADER_SIZE ) )
+               {
+               ld->other++;
+               return;
+               }
+
+       l_offset  = offset;
+       kiss_cmd  = pd[ l_offset ];
+       l_offset += KISS_HEADER_SIZE; /* step over kiss header */
+       switch ( kiss_cmd & KISS_CMD_MASK )
+               {
+               case KISS_DATA_FRAME    : capture_ax25( pd, l_offset, len, ld ); break;
+               case KISS_TXDELAY       : break;
+               case KISS_PERSISTENCE   : break;
+               case KISS_SLOT_TIME     : break;
+               case KISS_TXTAIL        : break;
+               case KISS_FULLDUPLEX    : break;
+               case KISS_SETHARDWARE   : break;
+               case KISS_DATA_FRAME_ACK: l_offset += 2; capture_ax25( pd, l_offset, len, ld ); break;
+               case KISS_POLL_MODE     : break;
+               case KISS_RETURN        : break;
+               default                 : break;
+               }
+}
+
 /* Code to actually dissect the packets */
 static void
 dissect_ax25_kiss( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree )
 {
        proto_item *ti;
        proto_tree *kiss_tree;
-       int offset;
-       int kiss_cmd;
-       int kiss_type;
-       int kiss_port;
-       int kiss_param;
-       int kiss_param_len;
-       char *frame_type_text;
-       char *info_buffer;
-#if 0
-       void *saved_private_data;
-       tvbuff_t *next_tvb = NULL;
-#endif
-
-
-       info_buffer = ep_alloc( STRLEN );
-       info_buffer[0]='\0';
-
-       if ( check_col( pinfo->cinfo, COL_PROTOCOL ) )
-               col_set_str( pinfo->cinfo, COL_PROTOCOL, "KISS" );
-
+       int         offset;
+       int         kiss_cmd;
+       int         kiss_type;
+       int         kiss_port;
+       int         kiss_param;
+       int         kiss_param_len;
+       int         kiss_cksum;
+       int         kiss_cksum_index;
+       int         kiss_tvb_length;
+       const char *frame_type_text;
+       char       *info_buffer;
+       tvbuff_t   *next_tvb = NULL;
+
+       info_buffer    = (char *)wmem_alloc( wmem_packet_scope(), STRLEN );
+       info_buffer[0] = '\0';
+
+       col_set_str( pinfo->cinfo, COL_PROTOCOL, "AX.25 KISS" );
        col_clear( pinfo->cinfo, COL_INFO );
 
        /* protocol offset for the KISS header */
        offset = 0;
 
-       kiss_cmd = tvb_get_guint8( tvb, offset ) & 0xff;
-       kiss_type = kiss_cmd & KISS_CMD_MASK;
-       kiss_port = (kiss_cmd & KISS_PORT_MASK) >> 4;
-       offset += KISS_HEADER_SIZE;
+       kiss_cmd   = tvb_get_guint8( tvb, offset ) & 0xff;
+       kiss_type  = kiss_cmd & KISS_CMD_MASK;
+       kiss_port  = (kiss_cmd & KISS_PORT_MASK) >> 4;
+       offset    += KISS_HEADER_SIZE;
 
-       frame_type_text = "????";
-       kiss_param = 0;
-       kiss_param_len = 0;
+       kiss_param      = 0;
+       kiss_param_len  = 0;
        switch ( kiss_type )
                {
-               case KISS_DATA_FRAME    : frame_type_text = "Data frame"; break;
-               case KISS_TXDELAY       : frame_type_text = "Tx Delay";     kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
-               case KISS_PERSISTENCE   : frame_type_text = "Persistence";  kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
-               case KISS_SLOT_TIME     : frame_type_text = "Slot time";    kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
-               case KISS_TXTAIL        : frame_type_text = "Tx tail";      kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
-               case KISS_FULLDUPLEX    : frame_type_text = "Full duplex";  kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
-               case KISS_SETHARDWARE   : frame_type_text = "Set hardware"; kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
-               case KISS_RETURN        : frame_type_text = "Return"; break;
+               case KISS_TXDELAY       : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
+               case KISS_PERSISTENCE   : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
+               case KISS_SLOT_TIME     : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
+               case KISS_TXTAIL        : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
+               case KISS_FULLDUPLEX    : kiss_param_len = 1; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
+               case KISS_SETHARDWARE   :
+                                       kiss_param_len = tvb_captured_length_remaining( tvb, offset );
+                                       if ( kiss_param_len < 0 )
+                                               kiss_param_len = 0;
+                                       if ( (kiss_param_len > 0) && gPREF_CKSUM_MODE )
+                                               kiss_param_len--;
+                                       break;
+               case KISS_DATA_FRAME_ACK: kiss_param_len = 2; kiss_param = tvb_get_guint8( tvb, offset ) & 0xff; break;
                default                 : break;
                }
+       frame_type_text = val_to_str(kiss_type, kiss_frame_types, "Unknown (%u)");
        g_snprintf( info_buffer, STRLEN, "%s, Port %u", frame_type_text, kiss_port );
        if ( kiss_param_len > 0 )
-               g_snprintf( info_buffer, STRLEN, "%s %u, Port %u", frame_type_text, kiss_param,
-                               kiss_port );
+               g_snprintf( info_buffer, STRLEN, "%s %u, Port %u", frame_type_text, kiss_param, kiss_port );
 
        offset += kiss_param_len;
 
@@ -227,7 +277,7 @@ dissect_ax25_kiss( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree )
 
                /* create display subtree for the protocol */
                ti = proto_tree_add_protocol_format( parent_tree, proto_ax25_kiss, tvb, offset,
-                       KISS_HEADER_SIZE + kiss_param_len,
+                       tvb_captured_length_remaining( tvb, offset ),
                        "KISS: %s",
                        info_buffer
                        );
@@ -237,7 +287,7 @@ dissect_ax25_kiss( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree )
                proto_tree_add_uint( kiss_tree, hf_ax25_kiss_cmd,  tvb, offset, KISS_HEADER_SIZE,
                                        kiss_cmd );
                proto_tree_add_uint( kiss_tree, hf_ax25_kiss_port, tvb, offset, KISS_HEADER_SIZE,
-                                       kiss_cmd );
+                                       kiss_port );
                offset += KISS_HEADER_SIZE;
 
                switch ( kiss_type  )
@@ -269,29 +319,53 @@ dissect_ax25_kiss( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree )
                                                offset += kiss_param_len;
                                                break;
                        case KISS_SETHARDWARE   :
-                                               proto_tree_add_uint( kiss_tree, hf_ax25_kiss_sethardware,
+                                               proto_tree_add_item( kiss_tree, hf_ax25_kiss_sethardware,
+                                                       tvb, offset, kiss_param_len, ENC_NA );
+                                               offset += kiss_param_len;
+                                               break;
+                       case KISS_DATA_FRAME_ACK:
+                                               proto_tree_add_uint( kiss_tree, hf_ax25_kiss_data_ack,
                                                        tvb, offset, kiss_param_len, kiss_param );
                                                offset += kiss_param_len;
                                                break;
+                       case KISS_POLL_MODE     : break;
                        case KISS_RETURN        : break;
                        default                 : break;
                        }
 
+               if ( gPREF_CKSUM_MODE )
+                       {
+                       kiss_cksum = 0;
+                       kiss_tvb_length = tvb_captured_length_remaining( tvb, 0 ) - 1;
+                       if ( kiss_tvb_length > 0 )
+                               {
+                               for ( kiss_cksum_index = 0; kiss_cksum_index < kiss_tvb_length; kiss_cksum_index++ )
+                                       kiss_cksum ^= (tvb_get_guint8( tvb, kiss_cksum_index ) & 0xff);
+                               proto_tree_add_uint( kiss_tree, hf_ax25_kiss_cksum,
+                                       tvb, kiss_cksum_index, 1, kiss_cksum );
+                               }
+                       }
        }
+
        /* Call sub-dissectors here */
 
+       if ( ( kiss_type == KISS_DATA_FRAME ) || ( kiss_type == KISS_DATA_FRAME_ACK ) )
+               {
+               next_tvb = tvb_new_subset_remaining( tvb, offset );
+               call_dissector( ax25_handle, next_tvb, pinfo, parent_tree );
+               }
 }
 
 void
 proto_register_ax25_kiss(void)
 {
-       /* module_t *ax25_kiss_module; */
+       module_t *ax25_kiss_module;
 
        /* Setup list of header fields */
        static hf_register_info hf[] = {
                { &hf_ax25_kiss_cmd,
                        { "Cmd",                        "ax25_kiss.cmd",
-                       FT_UINT8, BASE_DEC, NULL, KISS_CMD_MASK,
+                       FT_UINT8, BASE_DEC, VALS(kiss_frame_types), KISS_CMD_MASK,
                        NULL, HFILL }
                },
                { &hf_ax25_kiss_port,
@@ -326,7 +400,17 @@ proto_register_ax25_kiss(void)
                },
                { &hf_ax25_kiss_sethardware,
                        { "Set hardware",               "ax25_kiss.sethardware",
-                       FT_UINT8, BASE_DEC, NULL, 0x0,
+                       FT_BYTES, BASE_NONE, NULL, 0x0,
+                       NULL, HFILL }
+               },
+               { &hf_ax25_kiss_data_ack,
+                       { "Data ack",           "ax25_kiss.data_ack",
+                       FT_UINT16, BASE_DEC, NULL, 0x0,
+                       NULL, HFILL }
+               },
+               { &hf_ax25_kiss_cksum,
+                       { "Checksum",           "ax25_kiss.cksum",
+                       FT_UINT16, BASE_HEX, NULL, 0x0,
                        NULL, HFILL }
                },
        };
@@ -340,65 +424,40 @@ proto_register_ax25_kiss(void)
        proto_ax25_kiss = proto_register_protocol( "AX.25 KISS", "AX.25 KISS", "ax25_kiss" );
 
        /* Register the dissector */
-       register_dissector( "ax25_kiss", dissect_ax25_kiss, proto_ax25_kiss );
+       kiss_handle = register_dissector( "ax25_kiss", dissect_ax25_kiss, proto_ax25_kiss );
 
        /* Required function calls to register the header fields and subtrees used */
        proto_register_field_array( proto_ax25_kiss, hf, array_length( hf ) );
        proto_register_subtree_array( ett, array_length( ett ) );
 
        /* Register preferences module */
-        /* ax25_kiss_module = prefs_register_protocol( proto_ax25_kiss, proto_reg_handoff_ax25_kiss ); */
+       ax25_kiss_module = prefs_register_protocol( proto_ax25_kiss, NULL);
+
+       prefs_register_bool_preference(ax25_kiss_module, "showcksum",
+            "Set checksum mode",
+            "Enable checksum calculation.",
+            &gPREF_CKSUM_MODE );
 
-       /* Register any preference */
-/*
-        prefs_register_bool_preference( ax25_kiss_module, "showhex",
-             "Display numbers in Hex",
-            "Enable to display numerical values in hexadecimal.",
-            &gPREF_HEX );
-*/
 }
 
 void
 proto_reg_handoff_ax25_kiss(void)
 {
-       static gboolean inited = FALSE;
-
-       if( !inited ) {
+       dissector_add_uint( "wtap_encap", WTAP_ENCAP_AX25_KISS, kiss_handle );
 
-               dissector_handle_t kiss_handle;
-
-               kiss_handle = create_dissector_handle( dissect_ax25_kiss, proto_ax25_kiss );
-               dissector_add_uint( "wtap_encap", WTAP_ENCAP_AX25_KISS, kiss_handle );
-
-               inited = TRUE;
-       }
+       /* only currently implemented for AX.25 */
+       ax25_handle = find_dissector( "ax25" );
 }
 
-void
-capture_ax25_kiss( const guchar *pd, int offset, int len, packet_counts *ld)
-{
-       int l_offset;
-       guint8 kiss_cmd;
-
-       if ( ! BYTES_ARE_IN_FRAME( offset, len, KISS_HEADER_SIZE ) ) {
-               ld->other++;
-               return;
-       }
-
-       l_offset = offset;
-       kiss_cmd = pd[ l_offset ];
-       l_offset += KISS_HEADER_SIZE; /* step over kiss header */
-       switch ( kiss_cmd & KISS_CMD_MASK )
-               {
-               case KISS_DATA_FRAME    : break;
-               case KISS_TXDELAY       : l_offset += 1; break;
-               case KISS_PERSISTENCE   : l_offset += 1; break;
-               case KISS_SLOT_TIME     : l_offset += 1; break;
-               case KISS_TXTAIL        : l_offset += 1; break;
-               case KISS_FULLDUPLEX    : l_offset += 1; break;
-               case KISS_SETHARDWARE   : l_offset += 1; break;
-               case KISS_RETURN        : break;
-               default                 : break;
-               }
-
-}
+/*
+ * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */