2 * Routines for Wellfleet Compression frame disassembly
3 * Copyright 2001, Jeffrey C. Foster <jfoste@woodward.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * Add preference to allow/disallow decompression
27 * Calculate and verify check byte (last byte), if only we knew how!
28 * Handle Wellfleet compression over PPP links.
29 * - This will require changing the sub-dissector call
30 * routine to determine if layer 2 is frame relay or
31 * or PPP and different sub-dissector routines for each.
33 * Based upon information in the Nortel TCL based Pcaptap code.
34 *http://www.mynetworkforum.com/tools/PCAPTAP/pcaptap-Win32-3.00.exe
37 *http://www.rasip.fer.hr/research/compress/algorithms/fund/lz/lzss.html
41 * Wellfleet compression is a variation on LZSS encoding.
43 * Compression is done by keeping a sliding window of previous
44 * data transmited. The sender will use a pattern match to
45 * encode repeated data as a data pointer field. Then a stream
46 * of pointers and actual data bytes. The pointer values include
47 * an offset to previous data in the stream and the length of the
50 * The data pattern matching is done on the octets.
52 * The data is encoded as 8 field blocks with a compression flag
53 * byte at the beginning. If the bit is set in the compression
54 * flag, then that field has a compression field. If it isn't set
55 * then the byte is raw data.
57 * The compression field is either 2 or 3 bytes long. The length
58 * is determined by the length of the matching data, for short
59 * matches the match length is encoded in the high nibble of the
60 * first byte. Otherwise the third byte of the field contains
65 * High order nibble of the offset
68 * 1 = length is in 3rd byte
69 * 2-F = length of matching data - 1
72 * Lower byte of the source offset.
75 * Length of match - 1 if First byte upper nibble = 1, otherwise
76 * this byte isn't added to data stream.
79 * Uncompressed data (hex): 11 22 22 22 22 33 44 55 66 77
83 * Flag bits: 0x20 (third field is compressed)
84 * Data: 11 22 20 00 33 44 55
86 * raw data ------+--+ / /
87 * (Comp length - 1)<<4+ /
88 * Data offset ----------+
90 * Output data (hex): 20 11 22 20 00 33 44 55 66 77
92 * In this example the copy src is one byte behind the copy destination
93 * so if appears as if output is being loaded with the source byte.
104 #include <epan/packet.h>
105 #include <wsutil/pint.h>
106 #include <epan/circuit.h>
107 #include <epan/wmem/wmem.h>
108 #include <epan/etypes.h>
109 #include <epan/nlpid.h>
110 #include <epan/expert.h>
112 #define MAX_WIN_BUF_LEN 0x7fff /* storage size for decompressed data */
113 #define MAX_WCP_BUF_LEN 2048 /* storage size for decompressed data */
114 #define FROM_DCE 0x80 /* for direction setting */
119 guint8 buffer
[MAX_WIN_BUF_LEN
];
126 } wcp_circuit_data_t
;
128 /*XXX do I really want the length in here */
132 guint8 buffer
[MAX_WCP_BUF_LEN
];
137 static int proto_wcp
= -1;
138 static int hf_wcp_cmd
= -1;
139 static int hf_wcp_ext_cmd
= -1;
140 static int hf_wcp_seq
= -1;
141 static int hf_wcp_chksum
= -1;
142 static int hf_wcp_tid
= -1;
143 static int hf_wcp_rev
= -1;
144 static int hf_wcp_init
= -1;
145 static int hf_wcp_seq_size
= -1;
146 static int hf_wcp_alg
= -1;
147 static int hf_wcp_alg_cnt
= -1;
148 static int hf_wcp_alg_a
= -1;
149 static int hf_wcp_alg_b
= -1;
150 static int hf_wcp_alg_c
= -1;
151 static int hf_wcp_alg_d
= -1;
152 /* static int hf_wcp_rexmit = -1; */
154 static int hf_wcp_hist_size
= -1;
155 static int hf_wcp_ppc
= -1;
156 static int hf_wcp_pib
= -1;
158 static int hf_wcp_compressed_data
= -1;
159 static int hf_wcp_comp_bits
= -1;
160 /* static int hf_wcp_comp_marker = -1; */
161 static int hf_wcp_short_len
= -1;
162 static int hf_wcp_long_len
= -1;
163 static int hf_wcp_short_run
= -1;
164 static int hf_wcp_long_run
= -1;
165 static int hf_wcp_offset
= -1;
167 static gint ett_wcp
= -1;
168 static gint ett_wcp_comp_data
= -1;
169 static gint ett_wcp_field
= -1;
171 static expert_field ei_wcp_compressed_data_exceeds
= EI_INIT
;
172 static expert_field ei_wcp_uncompressed_data_exceeds
= EI_INIT
;
174 static dissector_handle_t fr_uncompressed_handle
;
177 * Bits in the address field.
179 #define WCP_CMD 0xf0 /* WCP Command */
180 #define WCP_EXT_CMD 0x0f /* WCP Extended Command */
181 #define WCP_SEQ 0x0fff /* WCP Sequence number */
182 #define WCP_OFFSET_MASK 0x0fff /* WCP Pattern source offset */
184 #define PPC_COMPRESSED_IND 0x0
185 #define PPC_UNCOMPRESSED_IND 0x1
186 #define PPC_TPPC_COMPRESSED_IND 0x2
187 #define PPC_TPPC_UNCOMPRESSED_IND 0x3
188 #define CONNECT_REQ 0x4
189 #define CONNECT_ACK 0x5
190 #define CONNECT_NAK 0x6
191 #define DISCONNECT_REQ 0x7
192 #define DISCONNECT_ACK 0x8
195 #define RESET_REQ 0xb
196 #define RESET_ACK 0xc
197 #define REXMIT_NAK 0xd
200 static const value_string cmd_string
[] = {
201 {0, "Compressed Data"},
202 {1, "Uncompressed Data"},
207 static const value_string ext_cmd_string
[] = {
208 {0, "Per Packet Compression"},
219 static tvbuff_t
*wcp_uncompress( tvbuff_t
*src_tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
);
220 static wcp_window_t
*get_wcp_window_ptr( packet_info
*pinfo
);
223 dissect_wcp_con_req(tvbuff_t
*tvb
, int offset
, proto_tree
*tree
) {
225 /* WCP connector request message */
227 guint alg_cnt
= tvb_get_guint8(tvb
, 5);
229 proto_tree_add_uint(tree
, hf_wcp_tid
, tvb
, offset
, 2, tvb_get_ntohs(tvb
, offset
));
230 proto_tree_add_uint(tree
, hf_wcp_rev
, tvb
, offset
+ 2, 1, tvb_get_guint8(tvb
, offset
+ 2));
231 proto_tree_add_uint(tree
, hf_wcp_init
, tvb
, offset
+ 3, 1, tvb_get_guint8(tvb
, offset
+ 3));
232 proto_tree_add_uint(tree
, hf_wcp_seq_size
, tvb
, offset
+ 4, 1, tvb_get_guint8(tvb
, offset
+ 4));
233 proto_tree_add_uint(tree
, hf_wcp_alg_cnt
, tvb
, offset
+ 5, 1, alg_cnt
);
234 proto_tree_add_uint(tree
, hf_wcp_alg_a
, tvb
, offset
+ 6, 1, tvb_get_guint8(tvb
, offset
+ 6));
236 proto_tree_add_uint(tree
, hf_wcp_alg_b
, tvb
, offset
+ 7, 1, tvb_get_guint8(tvb
, offset
+ 7));
238 proto_tree_add_uint(tree
, hf_wcp_alg_c
, tvb
, offset
+ 8, 1, tvb_get_guint8(tvb
, offset
+ 8));
240 proto_tree_add_uint(tree
, hf_wcp_alg_d
, tvb
, offset
+ 9, 1, tvb_get_guint8(tvb
, offset
+ 9));
244 dissect_wcp_con_ack( tvbuff_t
*tvb
, int offset
, proto_tree
*tree
){
246 /* WCP connector ack message */
248 proto_tree_add_uint(tree
, hf_wcp_tid
, tvb
, offset
, 2, tvb_get_ntohs(tvb
, offset
));
249 proto_tree_add_uint(tree
, hf_wcp_rev
, tvb
, offset
+ 2, 1, tvb_get_guint8(tvb
, offset
+ 2));
250 proto_tree_add_uint(tree
, hf_wcp_seq_size
, tvb
, offset
+ 3, 1, tvb_get_guint8(tvb
, offset
+ 3));
251 proto_tree_add_uint(tree
, hf_wcp_alg
, tvb
, offset
+ 4, 1, tvb_get_guint8(tvb
, offset
+ 4));
255 dissect_wcp_init( tvbuff_t
*tvb
, int offset
, proto_tree
*tree
){
257 /* WCP Initiate Request/Ack message */
259 proto_tree_add_uint(tree
, hf_wcp_tid
, tvb
, offset
, 2, tvb_get_ntohs(tvb
, offset
));
260 proto_tree_add_uint(tree
, hf_wcp_rev
, tvb
, offset
+ 2, 1, tvb_get_guint8(tvb
, offset
+ 2));
261 proto_tree_add_uint(tree
, hf_wcp_hist_size
, tvb
, offset
+ 3, 1, tvb_get_guint8(tvb
, offset
+ 3));
262 proto_tree_add_uint(tree
, hf_wcp_ppc
, tvb
, offset
+ 4, 1, tvb_get_guint8(tvb
, offset
+ 4));
263 proto_tree_add_uint(tree
, hf_wcp_pib
, tvb
, offset
+ 5, 1, tvb_get_guint8(tvb
, offset
+ 5));
268 dissect_wcp_reset( tvbuff_t
*tvb
, int offset
, proto_tree
*tree
){
270 /* Process WCP Reset Request/Ack message */
272 proto_tree_add_uint(tree
, hf_wcp_tid
, tvb
, offset
, 2, tvb_get_ntohs(tvb
, offset
));
276 static void wcp_save_data( tvbuff_t
*tvb
, packet_info
*pinfo
){
278 wcp_window_t
*buf_ptr
= 0;
281 /* discard first 2 bytes, header and last byte (check byte) */
282 len
= tvb_reported_length( tvb
)-3;
283 buf_ptr
= get_wcp_window_ptr( pinfo
);
285 if (( buf_ptr
->buf_cur
+ len
) <= (buf_ptr
->buffer
+ MAX_WIN_BUF_LEN
)){
286 tvb_memcpy( tvb
, buf_ptr
->buf_cur
, 2, len
);
287 buf_ptr
->buf_cur
= buf_ptr
->buf_cur
+ len
;
290 guint8
*buf_end
= buf_ptr
->buffer
+ MAX_WIN_BUF_LEN
;
291 tvb_memcpy( tvb
, buf_ptr
->buf_cur
, 2, buf_end
- buf_ptr
->buf_cur
);
292 tvb_memcpy( tvb
, buf_ptr
->buffer
, (gint
) (buf_end
- buf_ptr
->buf_cur
-2),
293 len
- (buf_end
- buf_ptr
->buf_cur
));
294 buf_ptr
->buf_cur
= buf_ptr
->buf_cur
+ len
- MAX_WIN_BUF_LEN
;
300 static void dissect_wcp( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
) {
302 proto_tree
*wcp_tree
;
305 guint16 temp
, cmd
, ext_cmd
, seq
;
308 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "WCP");
309 col_clear(pinfo
->cinfo
, COL_INFO
);
311 temp
=tvb_get_ntohs(tvb
, 0);
313 cmd
= (temp
& 0xf000) >> 12;
314 ext_cmd
= (temp
& 0x0f00) >> 8;
323 /*XXX should test seq to be sure it the last + 1 !! */
325 col_set_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(cmd
, cmd_string
, "Unknown"));
327 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
328 val_to_str_const(ext_cmd
, ext_cmd_string
, "Unknown"));
331 ti
= proto_tree_add_item(tree
, proto_wcp
, tvb
, 0, wcp_header_len
, ENC_NA
);
333 wcp_tree
= proto_item_add_subtree(ti
, ett_wcp
);
335 proto_tree_add_uint(wcp_tree
, hf_wcp_cmd
, tvb
, 0, 1, tvb_get_guint8( tvb
, 0));
337 proto_tree_add_uint(wcp_tree
, hf_wcp_ext_cmd
, tvb
, 1, 1,
338 tvb_get_guint8( tvb
, 0));
341 dissect_wcp_con_req( tvb
, 1, wcp_tree
);
345 dissect_wcp_con_ack( tvb
, 1, wcp_tree
);
349 dissect_wcp_init( tvb
, 1, wcp_tree
);
353 dissect_wcp_reset( tvb
, 1, wcp_tree
);
359 proto_tree_add_uint(wcp_tree
, hf_wcp_seq
, tvb
, 0, 2, seq
);
368 if ( cmd
!= 1 && cmd
!= 0 && !(cmd
== 0xf && ext_cmd
== 0))
371 if ( cmd
== 1) { /* uncompressed data */
372 if ( !pinfo
->fd
->flags
.visited
){ /* if first pass */
373 wcp_save_data( tvb
, pinfo
);
375 next_tvb
= tvb_new_subset_remaining(tvb
, wcp_header_len
);
377 else { /* cmd == 0 || (cmd == 0xf && ext_cmd == 0) */
379 next_tvb
= wcp_uncompress( tvb
, wcp_header_len
, pinfo
, wcp_tree
);
386 if ( tree
) /* add the check byte */
387 proto_tree_add_uint(wcp_tree
, hf_wcp_chksum
, tvb
,
388 tvb_reported_length( tvb
)-1, 1,
389 tvb_get_guint8( tvb
, tvb_reported_length(tvb
)-1));
391 call_dissector(fr_uncompressed_handle
, next_tvb
, pinfo
, tree
);
397 static guint8
*decompressed_entry( guint8
*src
, guint8
*dst
, int *len
, guint8
* buf_start
, guint8
*buf_end
){
399 /* do the decompression for one field */
401 guint16 data_offset
, data_cnt
;
404 data_offset
= (*(src
++) & 0xf) << 8; /* get high byte */
405 data_offset
+= *(src
++); /* add next byte */
407 if (( tmp
& 0xf0) == 0x10){ /* 2 byte count */
411 }else { /* one byte count */
417 src
= (dst
- 1 - data_offset
);
418 if ( src
< buf_start
)
419 src
+= MAX_WIN_BUF_LEN
;
422 /*XXX could do some fancy memory moves, later if speed is problem */
426 if ( ++(*len
) >MAX_WCP_BUF_LEN
){
427 return NULL
; /* end of buffer error */
429 if ( dst
++ == buf_end
)
431 if ( src
++ == buf_end
)
440 wcp_window_t
*get_wcp_window_ptr( packet_info
*pinfo
){
442 /* find the circuit for this DLCI, create one if needed */
443 /* and return the wcp_window data structure pointer */
444 /* for the direction of this packet */
447 wcp_circuit_data_t
*wcp_circuit_data
;
449 circuit
= find_circuit( pinfo
->ctype
, pinfo
->circuit_id
,
452 circuit
= circuit_new( pinfo
->ctype
, pinfo
->circuit_id
,
455 wcp_circuit_data
= (wcp_circuit_data_t
*)circuit_get_proto_data(circuit
, proto_wcp
);
456 if ( !wcp_circuit_data
){
457 wcp_circuit_data
= wmem_new(wmem_file_scope(), wcp_circuit_data_t
);
458 wcp_circuit_data
->recv
.buf_cur
= wcp_circuit_data
->recv
.buffer
;
459 wcp_circuit_data
->send
.buf_cur
= wcp_circuit_data
->send
.buffer
;
460 circuit_add_proto_data(circuit
, proto_wcp
, wcp_circuit_data
);
462 if (pinfo
->pseudo_header
->x25
.flags
& FROM_DCE
)
463 return &wcp_circuit_data
->recv
;
465 return &wcp_circuit_data
->send
;
469 static tvbuff_t
*wcp_uncompress( tvbuff_t
*src_tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
) {
471 /* do the packet data uncompression and load it into the dst buffer */
473 proto_tree
*cd_tree
, *sub_tree
;
474 proto_item
*cd_item
, *ti
;
477 int cnt
= tvb_reported_length( src_tvb
)-1; /* don't include check byte */
479 guint8
*dst
, *src
, *buf_start
, *buf_end
, comp_flag_bits
= 0;
480 guint8 src_buf
[ MAX_WCP_BUF_LEN
];
482 wcp_window_t
*buf_ptr
= 0;
483 wcp_pdata_t
*pdata_ptr
;
485 buf_ptr
= get_wcp_window_ptr( pinfo
);
487 buf_start
= buf_ptr
->buffer
;
488 buf_end
= buf_start
+ MAX_WIN_BUF_LEN
;
490 cd_item
= proto_tree_add_item(tree
, hf_wcp_compressed_data
,
491 src_tvb
, offset
, cnt
- offset
, ENC_NA
);
492 cd_tree
= proto_item_add_subtree(cd_item
, ett_wcp_comp_data
);
493 if (cnt
- offset
> MAX_WCP_BUF_LEN
) {
494 expert_add_info_format(pinfo
, cd_item
, &ei_wcp_compressed_data_exceeds
,
495 "Compressed data exceeds maximum buffer length (%d > %d)",
496 cnt
- offset
, MAX_WCP_BUF_LEN
);
500 src
= (guint8
*)tvb_memcpy(src_tvb
, src_buf
, offset
, cnt
- offset
);
501 dst
= buf_ptr
->buf_cur
;
505 while( offset
< cnt
){
508 if ( comp_flag_bits
& 0x80){ /* if this is a compressed entry */
510 if ( !pinfo
->fd
->flags
.visited
){ /* if first pass */
511 dst
= decompressed_entry( src
, dst
, &len
, buf_start
, buf_end
);
513 expert_add_info_format(pinfo
, cd_item
, &ei_wcp_uncompressed_data_exceeds
,
514 "Uncompressed data exceeds maximum buffer length (%d > %d)",
515 len
, MAX_WCP_BUF_LEN
);
519 if ((*src
& 0xf0) == 0x10){
521 ti
= proto_tree_add_item( cd_tree
, hf_wcp_long_run
, src_tvb
,
523 sub_tree
= proto_item_add_subtree(ti
, ett_wcp_field
);
524 proto_tree_add_uint(sub_tree
, hf_wcp_offset
, src_tvb
,
525 offset
, 2, pntohs(src
));
527 proto_tree_add_item( sub_tree
, hf_wcp_long_len
, src_tvb
,
528 offset
+2, 1, ENC_BIG_ENDIAN
);
534 ti
= proto_tree_add_item( cd_tree
, hf_wcp_short_run
, src_tvb
,
536 sub_tree
= proto_item_add_subtree(ti
, ett_wcp_field
);
537 proto_tree_add_uint( sub_tree
, hf_wcp_short_len
, src_tvb
,
539 proto_tree_add_uint(sub_tree
, hf_wcp_offset
, src_tvb
,
540 offset
, 2, pntohs(src
));
546 if ( ++len
>MAX_WCP_BUF_LEN
){
547 expert_add_info_format(pinfo
, cd_item
, &ei_wcp_uncompressed_data_exceeds
,
548 "Uncompressed data exceeds maximum buffer length (%d > %d)",
549 len
, MAX_WCP_BUF_LEN
);
553 if ( !pinfo
->fd
->flags
.visited
){ /* if first pass */
555 if ( dst
++ == buf_end
)
562 comp_flag_bits
<<= 1;
564 }else { /* compressed data flag */
566 comp_flag_bits
= *src
++;
568 proto_tree_add_uint(cd_tree
, hf_wcp_comp_bits
, src_tvb
, offset
, 1,
576 if ( pinfo
->fd
->flags
.visited
){ /* if not first pass */
577 /* get uncompressed data */
578 pdata_ptr
= (wcp_pdata_t
*)p_get_proto_data( pinfo
->fd
, proto_wcp
, 0);
580 if ( !pdata_ptr
) { /* exit if no data */
581 REPORT_DISSECTOR_BUG("Can't find uncompressed data");
584 len
= pdata_ptr
->len
;
587 /* save the new data as per packet data */
588 pdata_ptr
= wmem_new(wmem_file_scope(), wcp_pdata_t
);
589 memcpy( &pdata_ptr
->buffer
, buf_ptr
->buf_cur
, len
);
590 pdata_ptr
->len
= len
;
592 p_add_proto_data( pinfo
->fd
, proto_wcp
, 0, (void*)pdata_ptr
);
594 buf_ptr
->buf_cur
= dst
;
597 tvb
= tvb_new_child_real_data(src_tvb
, pdata_ptr
->buffer
, pdata_ptr
->len
, pdata_ptr
->len
);
599 /* Add new data to the data source list */
600 add_new_data_source( pinfo
, tvb
, "Uncompressed WCP");
607 proto_register_wcp(void)
609 static hf_register_info hf
[] = {
611 { "Command", "wcp.cmd", FT_UINT8
, BASE_HEX
, VALS(cmd_string
), WCP_CMD
,
612 "Compression Command", HFILL
}},
614 { "Extended Command", "wcp.ext_cmd", FT_UINT8
, BASE_HEX
, VALS(ext_cmd_string
), WCP_EXT_CMD
,
615 "Extended Compression Command", HFILL
}},
617 { "SEQ", "wcp.seq", FT_UINT16
, BASE_HEX
, NULL
, WCP_SEQ
,
618 "Sequence Number", HFILL
}},
620 { "Checksum", "wcp.checksum", FT_UINT8
, BASE_DEC
, NULL
, 0,
621 "Packet Checksum", HFILL
}},
623 { "TID", "wcp.tid", FT_UINT16
, BASE_DEC
, NULL
, 0,
626 { "Revision", "wcp.rev", FT_UINT8
, BASE_DEC
, NULL
, 0,
629 { "Initiator", "wcp.init", FT_UINT8
, BASE_DEC
, NULL
, 0,
632 { "Seq Size", "wcp.seq_size", FT_UINT8
, BASE_DEC
, NULL
, 0,
633 "Sequence Size", HFILL
}},
635 { "Alg Count", "wcp.alg_cnt", FT_UINT8
, BASE_DEC
, NULL
, 0,
636 "Algorithm Count", HFILL
}},
638 { "Alg 1", "wcp.alg1", FT_UINT8
, BASE_DEC
, NULL
, 0,
639 "Algorithm #1", HFILL
}},
641 { "Alg 2", "wcp.alg2", FT_UINT8
, BASE_DEC
, NULL
, 0,
642 "Algorithm #2", HFILL
}},
644 { "Alg 3", "wcp.alg3", FT_UINT8
, BASE_DEC
, NULL
, 0,
645 "Algorithm #3", HFILL
}},
647 { "Alg 4", "wcp.alg4", FT_UINT8
, BASE_DEC
, NULL
, 0,
648 "Algorithm #4", HFILL
}},
650 { "Alg", "wcp.alg", FT_UINT8
, BASE_DEC
, NULL
, 0,
651 "Algorithm", HFILL
}},
654 { "Rexmit", "wcp.rexmit", FT_UINT8
, BASE_DEC
, NULL
, 0,
655 "Retransmit", HFILL
}},
658 { "History", "wcp.hist", FT_UINT8
, BASE_DEC
, NULL
, 0,
659 "History Size", HFILL
}},
661 { "PerPackComp", "wcp.ppc", FT_UINT8
, BASE_DEC
, NULL
, 0,
662 "Per Packet Compression", HFILL
}},
664 { "PIB", "wcp.pib", FT_UINT8
, BASE_DEC
, NULL
, 0,
666 { &hf_wcp_compressed_data
,
667 { "Compressed Data", "wcp.compressed_data", FT_NONE
, BASE_NONE
, NULL
, 0,
668 "Raw compressed data", HFILL
}},
670 { "Compress Flag", "wcp.flag", FT_UINT8
, BASE_HEX
, NULL
, 0,
671 "Compressed byte flag", HFILL
}},
673 { &hf_wcp_comp_marker
,
674 { "Compress Marker", "wcp.mark", FT_UINT8
, BASE_DEC
, NULL
, 0,
675 "Compressed marker", HFILL
}},
678 { "Source offset", "wcp.off", FT_UINT16
, BASE_HEX
, NULL
, WCP_OFFSET_MASK
,
679 "Data source offset", HFILL
}},
681 { "Compress Length", "wcp.short_len", FT_UINT8
, BASE_HEX
, NULL
, 0xf0,
682 "Compressed length", HFILL
}},
684 { "Compress Length", "wcp.long_len", FT_UINT8
, BASE_HEX
, NULL
, 0,
685 "Compressed length", HFILL
}},
687 { "Long Compression", "wcp.long_comp", FT_BYTES
, BASE_NONE
, NULL
, 0,
688 "Long Compression type", HFILL
}},
690 { "Short Compression", "wcp.short_comp", FT_BYTES
, BASE_NONE
, NULL
, 0,
691 "Short Compression type", HFILL
}},
696 static gint
*ett
[] = {
702 static ei_register_info ei
[] = {
703 { &ei_wcp_compressed_data_exceeds
, { "wcp.compressed_data.exceeds", PI_MALFORMED
, PI_ERROR
, "Compressed data exceeds maximum buffer length", EXPFILL
}},
704 { &ei_wcp_uncompressed_data_exceeds
, { "wcp.uncompressed_data.exceeds", PI_MALFORMED
, PI_ERROR
, "Uncompressed data exceeds maximum buffer length", EXPFILL
}},
707 expert_module_t
* expert_wcp
;
709 proto_wcp
= proto_register_protocol ("Wellfleet Compression", "WCP", "wcp");
710 proto_register_field_array (proto_wcp
, hf
, array_length(hf
));
711 proto_register_subtree_array(ett
, array_length(ett
));
712 expert_wcp
= expert_register_protocol(proto_wcp
);
713 expert_register_field_array(expert_wcp
, ei
, array_length(ei
));
718 proto_reg_handoff_wcp(void) {
719 dissector_handle_t wcp_handle
;
722 * Get handle for the Frame Relay (uncompressed) dissector.
724 fr_uncompressed_handle
= find_dissector("fr_uncompressed");
726 wcp_handle
= create_dissector_handle(dissect_wcp
, proto_wcp
);
727 dissector_add_uint("fr.nlpid", NLPID_COMPRESSED
, wcp_handle
);
728 dissector_add_uint("ethertype", ETHERTYPE_WCP
, wcp_handle
);