Add a "contains" operator for byte-strings, strings, and tvbuffs (protocols).
[obnox/wireshark/wip.git] / packet-wcp.c
index f2a5bcef013ce05c81d7e0c4f4383206521f3554..c714005d69aa56a95f5d78cf51282d640a4cbfa9 100644 (file)
@@ -2,22 +2,22 @@
  * Routines for Wellfleet Compression frame disassembly
  * Copyright 2001, Jeffrey C. Foster <jfoste@woodward.com>
  *
- * $Id: packet-wcp.c,v 1.12 2001/11/15 10:58:49 guy Exp $
+ * $Id: packet-wcp.c,v 1.31 2003/01/31 03:17:47 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998
- * 
+ *
  * 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.
 /*
  * Wellfleet compression is a variation on LZSS encoding.
  *
- * Compression is done by keeping a sliding window of previous 
- * data transmited. The sender will use a pattern match to 
+ * Compression is done by keeping a sliding window of previous
+ * data transmited. The sender will use a pattern match to
  * encode repeated data as a data pointer field. Then a stream
  * of pointers and actual data bytes. The pointer values include
  * an offset to previous data in the stream and the length of the
  *  matching data.
  *
- * The data pattern matching is done on the octects. 
+ * The data pattern matching is done on the octects.
  *
  * The data is encoded as 8 field blocks with a compression flag
  * byte at the beginning.  If the bit is set in the compression
@@ -57,7 +57,7 @@
  * The compression field is either 2 or 3 bytes long. The length
  * is determined by the length of the matching data, for short
  * matches the match length is encoded in the high nibble of the
- * first byte. Otherwise the third byte of the field contains 
+ * first byte. Otherwise the third byte of the field contains
  * the match length.
  *
  * First byte -
  *             High order nibble of the offset
  *
  * upper 4 bits:
- *             1   = length is in 3rd byte 
+ *             1   = length is in 3rd byte
  *             2-F = length of matching data - 1
- *             
- * Second byte - 
+ *
+ * Second byte -
  *  Lower byte of the source offset.
  *
- * Third byte - 
+ * Third byte -
  *  Length of match - 1 if First byte upper nibble = 1, otherwise
  *  this byte isn't added to data stream.
  *
@@ -83,7 +83,7 @@
  *                     Flag bits:      0x20 (third field is compressed)
  *                     Data:   11 22 20 00 33 44 55
  *                             /  /  /  /
- *             raw data ------+--+  /  /               
+ *             raw data ------+--+  /  /
  *              (Comp length - 1)<<4+  /
  *             Data offset ----------+
  *
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
 #include <stdio.h>
 #include <glib.h>
 #include <string.h>
-#include "packet.h"
+#include <epan/packet.h>
 #include "packet-frame.h"
-#include "packet-fr.h"
-#include "conversation.h"
+#include <epan/circuit.h>
 #include "etypes.h"
 #include "nlpid.h"
 
@@ -125,6 +120,11 @@ typedef struct {
 
 }wcp_window_t;
 
+typedef struct {
+       wcp_window_t recv;
+       wcp_window_t send;
+} wcp_circuit_data_t;
+
 /*XXX do I really want the length in here  */
 typedef struct {
 
@@ -137,14 +137,12 @@ typedef struct {
 #define wcp_win_init_count 4
 #define wcp_packet_init_count 10
 
-#define wcp_win_length (sizeof(wcp_window_t))
+#define wcp_circuit_length (sizeof(wcp_circuit_data_t))
 #define wcp_packet_length (sizeof(wcp_pdata_t))
 
-static GMemChunk *wcp_window = NULL;
+static GMemChunk *wcp_circuit = NULL;
 static GMemChunk *wcp_pdata = NULL;
 
-extern dissector_table_t fr_subdissector_table;
-
 static int proto_wcp = -1;
 static int hf_wcp_cmd = -1;
 static int hf_wcp_ext_cmd = -1;
@@ -177,6 +175,8 @@ static int hf_wcp_offset = -1;
 static gint ett_wcp = -1;
 static gint ett_wcp_field = -1;
 
+static dissector_handle_t fr_uncompressed_handle;
+
 /*
  * Bits in the address field.
  */
@@ -224,7 +224,7 @@ static tvbuff_t *wcp_uncompress( tvbuff_t *src_tvb, int offset, packet_info *pin
 static wcp_window_t *get_wcp_window_ptr( packet_info *pinfo);
 
 static void
-dissect_wcp_con_req(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree) {
+dissect_wcp_con_req(tvbuff_t *tvb, int offset, proto_tree *tree) {
 
 /* WCP connector request message */
 
@@ -245,7 +245,7 @@ dissect_wcp_con_req(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *t
 }
 
 static void
-dissect_wcp_con_ack( tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree){
+dissect_wcp_con_ack( tvbuff_t *tvb, int offset, proto_tree *tree){
 
 /* WCP connector ack message */
 
@@ -256,7 +256,7 @@ dissect_wcp_con_ack( tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *
 }
 
 static void
-dissect_wcp_init( tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree){
+dissect_wcp_init( tvbuff_t *tvb, int offset, proto_tree *tree){
 
 /* WCP Initiate Request/Ack message */
 
@@ -269,7 +269,7 @@ dissect_wcp_init( tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tre
 
 
 static void
-dissect_wcp_reset( tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree){
+dissect_wcp_reset( tvbuff_t *tvb, int offset, proto_tree *tree){
 
 /* Process WCP Reset Request/Ack message */
 
@@ -277,21 +277,21 @@ dissect_wcp_reset( tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tr
 }
 
 
-void wcp_save_data( tvbuff_t *tvb, packet_info *pinfo){
+static void wcp_save_data( tvbuff_t *tvb, packet_info *pinfo){
 
        wcp_window_t *buf_ptr = 0;
-       int len; 
+       int len;
 
        /* discard first 2 bytes, header and last byte (check byte) */
        len = tvb_reported_length( tvb)-3;
-       buf_ptr = get_wcp_window_ptr( pinfo); 
+       buf_ptr = get_wcp_window_ptr( pinfo);
 
        if (( buf_ptr->buf_cur + len) <= (buf_ptr->buffer + MAX_WIN_BUF_LEN)){
                tvb_memcpy( tvb, buf_ptr->buf_cur, 2, len);
                buf_ptr->buf_cur = buf_ptr->buf_cur + len;
-       
+
        } else {
-               guint8 *buf_end = buf_ptr->buffer + MAX_WIN_BUF_LEN; 
+               guint8 *buf_end = buf_ptr->buffer + MAX_WIN_BUF_LEN;
                tvb_memcpy( tvb, buf_ptr->buf_cur, 2, buf_end - buf_ptr->buf_cur);
                tvb_memcpy( tvb, buf_ptr->buffer, buf_end - buf_ptr->buf_cur-2,
                        len - (int)(buf_end - buf_ptr->buf_cur));
@@ -301,43 +301,39 @@ void wcp_save_data( tvbuff_t *tvb, packet_info *pinfo){
 }
 
 
-void dissect_wcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
+static void dissect_wcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 
        proto_tree      *wcp_tree;
        proto_item      *ti;
        int             wcp_header_len;
        guint16         temp, cmd, ext_cmd, seq;
        tvbuff_t        *next_tvb;
-       packet_info     save_pi;
-       gboolean        must_restore_pi = FALSE;
-
-       pinfo->current_proto = "WCP";
 
-       if (check_col(pinfo->fd, COL_PROTOCOL))
-               col_set_str(pinfo->fd, COL_PROTOCOL, "WCP");
-       if (check_col(pinfo->fd, COL_INFO))
-               col_clear(pinfo->fd, COL_INFO);
+       if (check_col(pinfo->cinfo, COL_PROTOCOL))
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "WCP");
+       if (check_col(pinfo->cinfo, COL_INFO))
+               col_clear(pinfo->cinfo, COL_INFO);
 
-       temp =tvb_get_ntohs(tvb, 0); 
+       temp =tvb_get_ntohs(tvb, 0);
 
        cmd = (temp & 0xf000) >> 12;
        ext_cmd = (temp & 0x0f00) >> 8;
 
        if ( cmd == 0xf)
                wcp_header_len= 1;
-       else 
+       else
                wcp_header_len= 2;
 
        seq = temp & 0x0fff;
 
 /*XXX should test seq to be sure it the last + 1 !! */
 
-       if (check_col(pinfo->fd, COL_INFO)){
-               col_add_str(pinfo->fd, COL_INFO, val_to_str(cmd, cmd_string, "Unknown"));
+       if (check_col(pinfo->cinfo, COL_INFO)){
+               col_add_str(pinfo->cinfo, COL_INFO, val_to_str(cmd, cmd_string, "Unknown"));
                if ( cmd == 0xf)
-                       col_append_fstr(pinfo->fd, COL_INFO, ", %s",
+                       col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
                                val_to_str(ext_cmd, ext_cmd_string, "Unknown"));
-       }       
+       }
 
        if (tree) {
                ti = proto_tree_add_item(tree, proto_wcp, tvb, 0, wcp_header_len, FALSE);
@@ -350,24 +346,24 @@ void dissect_wcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                                        tvb_get_guint8( tvb, 0));
                        switch (ext_cmd){
                        case CONNECT_REQ:
-                               dissect_wcp_con_req( tvb, 1, pinfo, wcp_tree);
+                               dissect_wcp_con_req( tvb, 1, wcp_tree);
                                break;
 
                        case CONNECT_ACK:
-                               dissect_wcp_con_ack( tvb, 1, pinfo, wcp_tree);
+                               dissect_wcp_con_ack( tvb, 1, wcp_tree);
                                break;
                        case INIT_REQ:
                        case INIT_ACK:
-                               dissect_wcp_init( tvb, 1, pinfo, wcp_tree);
+                               dissect_wcp_init( tvb, 1, wcp_tree);
                                break;
                        case RESET_REQ:
                        case RESET_ACK:
-                               dissect_wcp_reset( tvb, 1, pinfo, wcp_tree);
+                               dissect_wcp_reset( tvb, 1, wcp_tree);
                                break;
                        default:
                                break;
                        }
-               }else { 
+               }else {
                        proto_tree_add_uint(wcp_tree, hf_wcp_seq,  tvb, 0, 2, seq);
                }
        }
@@ -377,7 +373,7 @@ void dissect_wcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
 
 
                                        /* exit if done */
-       if ( cmd != 1 && cmd != 0 && !(cmd == 0xf && ext_cmd == 0)) 
+       if ( cmd != 1 && cmd != 0 && !(cmd == 0xf && ext_cmd == 0))
                return;
 
        if ( cmd == 1) {                /* uncompressed data */
@@ -395,13 +391,6 @@ void dissect_wcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                                        "[Malformed Frame: Bad WCP compressed data]" );
                        return;
                }
-
-               /* Save the current value of "pi", and adjust certain fields to
-                  reflect the new tvbuff. */
-               save_pi = pi;
-               pi.len = tvb_reported_length(next_tvb);
-               pi.captured_len = tvb_length(next_tvb);
-               must_restore_pi = TRUE;
        }
 
        if ( tree)                      /* add the check byte */
@@ -409,16 +398,13 @@ void dissect_wcp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                        tvb_reported_length( tvb)-1, 1,
                        tvb_get_guint8( tvb, tvb_reported_length(tvb)-1));
 
-       dissect_fr_uncompressed(next_tvb, pinfo, tree);
-
-       if (must_restore_pi)
-               pi = save_pi;
+       call_dissector(fr_uncompressed_handle, next_tvb, pinfo, tree);
 
        return;
 }
 
 
-guint8 *decompressed_entry( guint8 *src, guint8 *dst, int *len, guint8 * buf_start, guint8 *buf_end){
+static guint8 *decompressed_entry( guint8 *src, guint8 *dst, int *len, guint8 * buf_start, guint8 *buf_end){
 
 /* do the decompression for one field */
 
@@ -435,9 +421,9 @@ guint8 *decompressed_entry( guint8 *src, guint8 *dst, int *len, guint8 * buf_sta
        }else {                                 /* one byte count */
                data_cnt = tmp >> 4;
                data_cnt++;
-       }               
+       }
+
 
-       
        src = (dst - 1 - data_offset);
        if ( src < buf_start)
                src += MAX_WIN_BUF_LEN;
@@ -462,32 +448,33 @@ guint8 *decompressed_entry( guint8 *src, guint8 *dst, int *len, guint8 * buf_sta
 }
 
 
-static 
+static
 wcp_window_t *get_wcp_window_ptr( packet_info *pinfo){
 
-/* find the conversation for this side of the DLCI, create one if needed */
+/* find the circuit for this DLCI, create one if needed */
 /* and return the wcp_window data structure pointer */
+/* for the direction of this packet */
 
-       conversation_t *conv;
-       wcp_window_t *wcp_win_data;
-
-       conv = find_conversation( &pinfo->dl_src, &pinfo->dl_src, PT_NONE, 
-               ((pinfo->pseudo_header->x25.flags & FROM_DCE)? 1:0), 
-               ((pinfo->pseudo_header->x25.flags & FROM_DCE)? 1:0), 0);
-       if ( !conv){
-               conv = conversation_new( &pinfo->dl_src, &pinfo->dl_src, PT_NONE, 
-                       ((pinfo->pseudo_header->x25.flags & FROM_DCE)? 1:0), 
-                       ((pinfo->pseudo_header->x25.flags & FROM_DCE)? 1:0),
-                       0);
+       circuit_t *circuit;
+       wcp_circuit_data_t *wcp_circuit_data;
+
+       circuit = find_circuit( pinfo->ctype, pinfo->circuit_id,
+           pinfo->fd->num);
+       if ( !circuit){
+               circuit = circuit_new( pinfo->ctype, pinfo->circuit_id,
+                   pinfo->fd->num);
        }
-       wcp_win_data = conversation_get_proto_data(conv, proto_wcp);
-       if ( !wcp_win_data){
-               wcp_win_data = g_mem_chunk_alloc( wcp_window);
-               wcp_win_data->buf_cur = wcp_win_data->buffer;
-               conversation_add_proto_data(conv, proto_wcp, wcp_win_data);
+       wcp_circuit_data = circuit_get_proto_data(circuit, proto_wcp);
+       if ( !wcp_circuit_data){
+               wcp_circuit_data = g_mem_chunk_alloc( wcp_circuit);
+               wcp_circuit_data->recv.buf_cur = wcp_circuit_data->recv.buffer;
+               wcp_circuit_data->send.buf_cur = wcp_circuit_data->send.buffer;
+               circuit_add_proto_data(circuit, proto_wcp, wcp_circuit_data);
        }
-
-       return wcp_win_data;
+       if (pinfo->pseudo_header->x25.flags & FROM_DCE)
+               return &wcp_circuit_data->recv;
+       else
+               return &wcp_circuit_data->send;
 }
 
 
@@ -507,12 +494,20 @@ static tvbuff_t *wcp_uncompress( tvbuff_t *src_tvb, int offset, packet_info *pin
        wcp_window_t *buf_ptr = 0;
        wcp_pdata_t *volatile pdata_ptr;
 
-       buf_ptr = get_wcp_window_ptr( pinfo); 
+       buf_ptr = get_wcp_window_ptr( pinfo);
 
        buf_start = buf_ptr->buffer;
        buf_end = buf_start + MAX_WIN_BUF_LEN;
        tmp = buf_ptr->buf_cur;
 
+       if (cnt - offset > MAX_WCP_BUF_LEN) {
+               if (tree)
+                       proto_tree_add_text( tree, src_tvb, offset, -1,
+                               "Compressed data exceeds maximum buffer length (%d > %d)",
+                               cnt - offset, MAX_WCP_BUF_LEN);
+               return NULL;
+       }
+
        src = tvb_memcpy(src_tvb, src_buf, offset, cnt - offset);
        dst = buf_ptr->buf_cur;
 
@@ -573,7 +568,7 @@ static tvbuff_t *wcp_uncompress( tvbuff_t *src_tvb, int offset, packet_info *pin
                        if (tree)
                                proto_tree_add_uint( tree, hf_wcp_comp_bits,  src_tvb, offset-1, 1,
                                        comp_flag_bits);
-                               
+
                        i = 8;
                }
        }
@@ -584,7 +579,7 @@ static tvbuff_t *wcp_uncompress( tvbuff_t *src_tvb, int offset, packet_info *pin
 
                if ( !pdata_ptr)        /* exit if no data */
                        return NULL;
-               len = pdata_ptr->len;   
+               len = pdata_ptr->len;
        } else {
 
        /* save the new data as per packet data */
@@ -592,32 +587,32 @@ static tvbuff_t *wcp_uncompress( tvbuff_t *src_tvb, int offset, packet_info *pin
                memcpy( &pdata_ptr->buffer, buf_ptr->buf_cur,  len);
                pdata_ptr->len = len;
 
-               p_add_proto_data( pinfo->fd, proto_wcp, (void*)pdata_ptr);      
+               p_add_proto_data( pinfo->fd, proto_wcp, (void*)pdata_ptr);
 
                buf_ptr->buf_cur = dst;
        }
 
 
         TRY {
-                tvb = tvb_new_real_data( pdata_ptr->buffer, pdata_ptr->len, pdata_ptr->len, "uncompressed");
+                tvb = tvb_new_real_data( pdata_ptr->buffer, pdata_ptr->len, pdata_ptr->len);
 
         }
         CATCH(BoundsError) {
-                g_assert_not_reached();
+               g_assert_not_reached();
                g_free(buf);
                return NULL;
         }
         CATCH(ReportedBoundsError) {
-               g_free(buf);
-               return NULL;
+               g_free(buf);
+               return NULL;
         }
-        ENDTRY; 
+        ENDTRY;
 
        /* link new tvbuff into tvbuff chain so cleanup is done later */
         tvb_set_child_real_data_tvbuff( src_tvb, tvb);
 
        /* Add new data to the data source list */
-       pinfo->fd->data_src = g_slist_append( pinfo->fd->data_src, tvb);
+       add_new_data_source( pinfo, tvb, "Uncompressed WCP");
        return tvb;
 
 }
@@ -628,11 +623,11 @@ static void wcp_reinit( void){
 /* Do the cleanup work when a new pass through the packet list is       */
 /* performed. re-initialize the  memory chunks.                         */
 
-        if (wcp_window)
-                g_mem_chunk_destroy(wcp_window);
+        if (wcp_circuit)
+                g_mem_chunk_destroy(wcp_circuit);
 
-        wcp_window = g_mem_chunk_new("wcp_window", wcp_win_length,
-                wcp_win_init_count * wcp_win_length,
+        wcp_circuit = g_mem_chunk_new("wcp_circuit", wcp_circuit_length,
+                wcp_win_init_count * wcp_circuit_length,
                 G_ALLOC_AND_FREE);
 
         if (wcp_pdata)
@@ -650,13 +645,13 @@ proto_register_wcp(void)
 {
     static hf_register_info hf[] = {
        { &hf_wcp_cmd,
-         { "Command", "wcp.cmd", FT_UINT8, BASE_HEX, VALS(cmd_string), WCP_CMD, 
+         { "Command", "wcp.cmd", FT_UINT8, BASE_HEX, VALS(cmd_string), WCP_CMD,
                "Compression Command", HFILL }},
        { &hf_wcp_ext_cmd,
-         { "Extended Command", "wcp.ext_cmd", FT_UINT8, BASE_HEX, VALS(ext_cmd_string), WCP_EXT_CMD, 
+         { "Extended Command", "wcp.ext_cmd", FT_UINT8, BASE_HEX, VALS(ext_cmd_string), WCP_EXT_CMD,
                "Extended Compression Command", HFILL }},
        { &hf_wcp_seq,
-         { "SEQ", "wcp.seq", FT_UINT16, BASE_HEX, NULL, WCP_SEQ, 
+         { "SEQ", "wcp.seq", FT_UINT16, BASE_HEX, NULL, WCP_SEQ,
                "Sequence Number", HFILL }},
        { &hf_wcp_chksum,
          { "Checksum", "wcp.checksum", FT_UINT8, BASE_DEC, NULL, 0,
@@ -707,7 +702,7 @@ proto_register_wcp(void)
          { "Compress Flag", "wcp.flag", FT_UINT8, BASE_HEX, NULL, 0,
                "Compressed byte flag", HFILL }},
        { &hf_wcp_comp_marker,
-         { "Compress Marker", "wcp.mark", FT_UINT8, BASE_BIN, NULL, 0,
+         { "Compress Marker", "wcp.mark", FT_UINT8, BASE_DEC, NULL, 0,
                "Compressed marker", HFILL }},
        { &hf_wcp_offset,
          { "Source offset", "wcp.off", FT_UINT16, BASE_HEX, NULL, WCP_OFFSET_MASK,
@@ -742,7 +737,14 @@ proto_register_wcp(void)
 
 void
 proto_reg_handoff_wcp(void) {
+    dissector_handle_t wcp_handle;
+
+    /*
+     * Get handle for the Frame Relay (uncompressed) dissector.
+     */
+    fr_uncompressed_handle = find_dissector("fr_uncompressed");
 
-    dissector_add("fr.ietf", NLPID_COMPRESSED, dissect_wcp, proto_wcp);
-    dissector_add("ethertype",  ETHERTYPE_WCP, dissect_wcp, proto_wcp);
+    wcp_handle = create_dissector_handle(dissect_wcp, proto_wcp);
+    dissector_add("fr.ietf", NLPID_COMPRESSED, wcp_handle);
+    dissector_add("ethertype",  ETHERTYPE_WCP, wcp_handle);
 }