3 * Routines for AX.25 KISS protocol dissection
4 * Copyright 2010,2012 R.W. Stearn <richard@rns-stearn.demon.co.uk>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * This dissector handles the "KISS" protocol as implemented by the
17 * The original definition of the KISS protocol can be found here:
18 * http://www.ka9q.net/papers/kiss.html
20 * http://www.ax25.net/kiss.aspx
22 * The Linux implementation does not appear to attempt to implement that
23 * protocol in full. It does provide the ability to send a KISS command via
24 * ax25_kiss_cmd() and internally will send FULLDUPLEX KISS commands if
25 * DAMA is enabled/disabled.
27 * ax25_dev_dama_on sends FullDuplex ON
28 * ax25_dev_dama_off sends FullDuplex OFF
30 * Data frames are prefixed with a "Data Frame" command but the port appears to
33 * Abstract from http://www.ka9q.net/papers/kiss.html
34 * --------------------------------------------------
35 * For reference the first byte of a KISS frame is the frame type and the TNC
37 * LSB 4 bits = frame type,
38 * MSB 4 bits = port number.
40 * The frame types are:
41 * Command Function Comments
42 * 0 Data frame The rest of the frame is data to
43 * be sent on the HDLC channel.
45 * 1 TXDELAY The next byte is the transmitter
46 * keyup delay in 10 ms units.
47 * The default start-up value is 50
50 * 2 P The next byte is the persistence
51 * parameter, p, scaled to the range
52 * 0 - 255 with the following
57 * The default value is P = 63
60 * 3 SlotTime The next byte is the slot interval
62 * The default is 10 (i.e., 100ms).
64 * 4 TXtail The next byte is the time to hold
65 * up the TX after the FCS has been
66 * sent, in 10 ms units. This command
67 * is obsolete, and is included here
68 * only for compatibility with some
69 * existing implementations.
71 * 5 FullDuplex The next byte is 0 for half duplex,
72 * nonzero for full duplex.
74 * (i.e., half duplex).
76 * 6 SetHardware Specific for each TNC. In the
77 * TNC-1, this command sets the
78 * modem speed. Other implementations
79 * may use this function for other
80 * hardware-specific functions.
82 * FF Return Exit KISS and return control to a
83 * higher-level program. This is useful
84 * only when KISS is incorporated
85 * into the TNC along with other
91 * 12 Data frame Data with acknowledge request
93 * 14 Poll mode Set poll mode
101 #include <epan/packet.h>
102 #include <epan/capture_dissectors.h>
103 #include <epan/prefs.h>
107 #define KISS_HEADER_SIZE 1 /* length of the KISS type header */
109 /* KISS frame types */
110 #define KISS_DATA_FRAME 0
111 #define KISS_TXDELAY 1
112 #define KISS_PERSISTENCE 2
113 #define KISS_SLOT_TIME 3
114 #define KISS_TXTAIL 4
115 #define KISS_FULLDUPLEX 5
116 #define KISS_SETHARDWARE 6
117 #define KISS_DATA_FRAME_ACK 12
118 #define KISS_POLL_MODE 14
119 #define KISS_RETURN 15
121 #define KISS_CMD_MASK 0x0f
122 #define KISS_PORT_MASK 0xf0
124 /* Global preferences */
125 static bool gPREF_CKSUM_MODE
;
127 void proto_register_ax25_kiss(void);
128 void proto_reg_handoff_ax25_kiss(void);
130 /* Initialize the protocol and registered fields */
131 static int proto_ax25_kiss
;
133 static int hf_ax25_kiss_cmd
;
134 static int hf_ax25_kiss_port
;
135 static int hf_ax25_kiss_txdelay
;
136 static int hf_ax25_kiss_persistence
;
137 static int hf_ax25_kiss_slottime
;
138 static int hf_ax25_kiss_txtail
;
139 static int hf_ax25_kiss_fullduplex
;
140 static int hf_ax25_kiss_sethardware
;
141 static int hf_ax25_kiss_data_ack
;
142 static int hf_ax25_kiss_cksum
;
145 /* Initialize the subtree pointers */
146 static int ett_ax25_kiss
;
148 static dissector_handle_t kiss_handle
;
150 static capture_dissector_handle_t ax25_cap_handle
;
152 /* Dissector handles - all the possibles are listed */
153 static dissector_handle_t ax25_handle
;
155 static const value_string kiss_frame_types
[] = {
156 { KISS_DATA_FRAME
, "Data frame" },
157 { KISS_TXDELAY
, "Tx delay" },
158 { KISS_PERSISTENCE
, "Persistence" },
159 { KISS_SLOT_TIME
, "Slot time" },
160 { KISS_TXTAIL
, "Tx tail" },
161 { KISS_FULLDUPLEX
, "Full duplex" },
162 { KISS_SETHARDWARE
, "Set hardware" },
163 { KISS_DATA_FRAME_ACK
, "Data frame ack" },
164 { KISS_POLL_MODE
, "Poll mode" },
165 { KISS_RETURN
, "Return" },
170 capture_ax25_kiss( const unsigned char *pd
, int offset
, int len
, capture_packet_info_t
*cpinfo
, const union wtap_pseudo_header
*pseudo_header
)
175 if ( ! BYTES_ARE_IN_FRAME( offset
, len
, KISS_HEADER_SIZE
) )
179 kiss_cmd
= pd
[ l_offset
];
180 l_offset
+= KISS_HEADER_SIZE
; /* step over kiss header */
181 switch ( kiss_cmd
& KISS_CMD_MASK
)
183 case KISS_DATA_FRAME
:
184 return call_capture_dissector( ax25_cap_handle
, pd
, l_offset
, len
, cpinfo
, pseudo_header
);
185 case KISS_TXDELAY
: break;
186 case KISS_PERSISTENCE
: break;
187 case KISS_SLOT_TIME
: break;
188 case KISS_TXTAIL
: break;
189 case KISS_FULLDUPLEX
: break;
190 case KISS_SETHARDWARE
: break;
191 case KISS_DATA_FRAME_ACK
:
193 return call_capture_dissector( ax25_cap_handle
, pd
, l_offset
, len
, cpinfo
, pseudo_header
);
194 case KISS_POLL_MODE
: break;
195 case KISS_RETURN
: break;
201 /* Code to actually dissect the packets */
203 dissect_ax25_kiss( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
206 proto_tree
*kiss_tree
;
214 int kiss_cksum_index
;
216 const char *frame_type_text
;
218 tvbuff_t
*next_tvb
= NULL
;
220 info_buffer
= (char *)wmem_alloc( pinfo
->pool
, STRLEN
);
221 info_buffer
[0] = '\0';
223 col_set_str( pinfo
->cinfo
, COL_PROTOCOL
, "AX.25 KISS" );
224 col_clear( pinfo
->cinfo
, COL_INFO
);
226 /* protocol offset for the KISS header */
229 kiss_cmd
= tvb_get_uint8( tvb
, offset
) & 0xff;
230 kiss_type
= kiss_cmd
& KISS_CMD_MASK
;
231 kiss_port
= (kiss_cmd
& KISS_PORT_MASK
) >> 4;
232 offset
+= KISS_HEADER_SIZE
;
238 case KISS_TXDELAY
: kiss_param_len
= 1; kiss_param
= tvb_get_uint8( tvb
, offset
) & 0xff; break;
239 case KISS_PERSISTENCE
: kiss_param_len
= 1; kiss_param
= tvb_get_uint8( tvb
, offset
) & 0xff; break;
240 case KISS_SLOT_TIME
: kiss_param_len
= 1; kiss_param
= tvb_get_uint8( tvb
, offset
) & 0xff; break;
241 case KISS_TXTAIL
: kiss_param_len
= 1; kiss_param
= tvb_get_uint8( tvb
, offset
) & 0xff; break;
242 case KISS_FULLDUPLEX
: kiss_param_len
= 1; kiss_param
= tvb_get_uint8( tvb
, offset
) & 0xff; break;
243 case KISS_SETHARDWARE
:
244 kiss_param_len
= tvb_captured_length_remaining( tvb
, offset
);
245 if ( kiss_param_len
< 0 )
247 if ( (kiss_param_len
> 0) && gPREF_CKSUM_MODE
)
250 case KISS_DATA_FRAME_ACK
: kiss_param_len
= 2; kiss_param
= tvb_get_uint8( tvb
, offset
) & 0xff; break;
253 frame_type_text
= val_to_str(kiss_type
, kiss_frame_types
, "Unknown (%u)");
254 snprintf( info_buffer
, STRLEN
, "%s, Port %u", frame_type_text
, kiss_port
);
255 if ( kiss_param_len
> 0 )
256 snprintf( info_buffer
, STRLEN
, "%s %u, Port %u", frame_type_text
, kiss_param
, kiss_port
);
258 offset
+= kiss_param_len
;
260 col_add_str( pinfo
->cinfo
, COL_INFO
, info_buffer
);
264 /* protocol offset for the KISS header */
267 /* create display subtree for the protocol */
268 ti
= proto_tree_add_protocol_format( parent_tree
, proto_ax25_kiss
, tvb
, offset
,
269 tvb_captured_length_remaining( tvb
, offset
),
274 kiss_tree
= proto_item_add_subtree( ti
, ett_ax25_kiss
);
276 proto_tree_add_uint( kiss_tree
, hf_ax25_kiss_cmd
, tvb
, offset
, KISS_HEADER_SIZE
,
278 proto_tree_add_uint( kiss_tree
, hf_ax25_kiss_port
, tvb
, offset
, KISS_HEADER_SIZE
,
280 offset
+= KISS_HEADER_SIZE
;
284 case KISS_DATA_FRAME
: break;
286 proto_tree_add_uint( kiss_tree
, hf_ax25_kiss_txdelay
,
287 tvb
, offset
, kiss_param_len
, kiss_param
);
288 offset
+= kiss_param_len
;
290 case KISS_PERSISTENCE
:
291 proto_tree_add_uint( kiss_tree
, hf_ax25_kiss_persistence
,
292 tvb
, offset
, kiss_param_len
, kiss_param
);
293 offset
+= kiss_param_len
;
295 case KISS_SLOT_TIME
:
296 proto_tree_add_uint( kiss_tree
, hf_ax25_kiss_slottime
,
297 tvb
, offset
, kiss_param_len
, kiss_param
);
298 offset
+= kiss_param_len
;
301 proto_tree_add_uint( kiss_tree
, hf_ax25_kiss_txtail
,
302 tvb
, offset
, kiss_param_len
, kiss_param
);
303 offset
+= kiss_param_len
;
305 case KISS_FULLDUPLEX
:
306 proto_tree_add_uint( kiss_tree
, hf_ax25_kiss_fullduplex
,
307 tvb
, offset
, kiss_param_len
, kiss_param
);
308 offset
+= kiss_param_len
;
310 case KISS_SETHARDWARE
:
311 proto_tree_add_item( kiss_tree
, hf_ax25_kiss_sethardware
,
312 tvb
, offset
, kiss_param_len
, ENC_NA
);
313 offset
+= kiss_param_len
;
315 case KISS_DATA_FRAME_ACK
:
316 proto_tree_add_uint( kiss_tree
, hf_ax25_kiss_data_ack
,
317 tvb
, offset
, kiss_param_len
, kiss_param
);
318 offset
+= kiss_param_len
;
320 case KISS_POLL_MODE
: break;
321 case KISS_RETURN
: break;
325 if ( gPREF_CKSUM_MODE
)
328 kiss_tvb_length
= tvb_captured_length(tvb
) - 1;
329 if ( kiss_tvb_length
> 0 )
331 for ( kiss_cksum_index
= 0; kiss_cksum_index
< kiss_tvb_length
; kiss_cksum_index
++ )
332 kiss_cksum
^= (tvb_get_uint8( tvb
, kiss_cksum_index
) & 0xff);
334 proto_tree_add_checksum(kiss_tree
, tvb
, 0, hf_ax25_kiss_cksum
, -1, NULL
, pinfo
, kiss_cksum
, ENC_NA
, PROTO_CHECKSUM_GENERATED
);
339 /* Call sub-dissectors here */
341 if ( ( kiss_type
== KISS_DATA_FRAME
) || ( kiss_type
== KISS_DATA_FRAME_ACK
) )
343 next_tvb
= tvb_new_subset_remaining( tvb
, offset
);
344 call_dissector( ax25_handle
, next_tvb
, pinfo
, parent_tree
);
347 return tvb_captured_length(tvb
);
351 proto_register_ax25_kiss(void)
353 module_t
*ax25_kiss_module
;
355 /* Setup list of header fields */
356 static hf_register_info hf
[] = {
358 { "Cmd", "ax25_kiss.cmd",
359 FT_UINT8
, BASE_DEC
, VALS(kiss_frame_types
), KISS_CMD_MASK
,
362 { &hf_ax25_kiss_port
,
363 { "Port", "ax25_kiss.port",
364 FT_UINT8
, BASE_DEC
, NULL
, KISS_PORT_MASK
,
367 { &hf_ax25_kiss_txdelay
,
368 { "Tx delay", "ax25_kiss.txdelay",
369 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
372 { &hf_ax25_kiss_persistence
,
373 { "Persistence", "ax25_kiss.persistence",
374 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
377 { &hf_ax25_kiss_slottime
,
378 { "Slot time", "ax25_kiss.slottime",
379 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
382 { &hf_ax25_kiss_txtail
,
383 { "Tx tail", "ax25_kiss.txtail",
384 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
387 { &hf_ax25_kiss_fullduplex
,
388 { "Full duplex", "ax25_kiss.fullduplex",
389 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
392 { &hf_ax25_kiss_sethardware
,
393 { "Set hardware", "ax25_kiss.sethardware",
394 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
397 { &hf_ax25_kiss_data_ack
,
398 { "Data ack", "ax25_kiss.data_ack",
399 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
402 { &hf_ax25_kiss_cksum
,
403 { "Checksum", "ax25_kiss.cksum",
404 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
409 /* Setup protocol subtree array */
410 static int *ett
[] = {
414 /* Register the protocol name and description */
415 proto_ax25_kiss
= proto_register_protocol( "AX.25 KISS", "AX.25 KISS", "ax25_kiss" );
417 /* Register the dissector */
418 kiss_handle
= register_dissector( "ax25_kiss", dissect_ax25_kiss
, proto_ax25_kiss
);
420 /* Required function calls to register the header fields and subtrees used */
421 proto_register_field_array( proto_ax25_kiss
, hf
, array_length( hf
) );
422 proto_register_subtree_array( ett
, array_length( ett
) );
424 /* Register preferences module */
425 ax25_kiss_module
= prefs_register_protocol( proto_ax25_kiss
, NULL
);
427 prefs_register_bool_preference(ax25_kiss_module
, "showcksum",
429 "Enable checksum calculation.",
435 proto_reg_handoff_ax25_kiss(void)
437 capture_dissector_handle_t ax25_kiss_cap_handle
;
439 dissector_add_uint( "wtap_encap", WTAP_ENCAP_AX25_KISS
, kiss_handle
);
440 ax25_kiss_cap_handle
= create_capture_dissector_handle(capture_ax25_kiss
, proto_ax25_kiss
);
441 capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_AX25_KISS
, ax25_kiss_cap_handle
);
443 /* only currently implemented for AX.25 */
444 ax25_handle
= find_dissector_add_dependency( "ax25", proto_ax25_kiss
);
446 ax25_cap_handle
= find_capture_dissector("ax25");
450 * Editor modelines - https://www.wireshark.org/tools/modelines.html
455 * indent-tabs-mode: t
458 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
459 * :indentSize=8:tabSize=8:noTabs=false: