Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-ax25-kiss.c
blobb879852416a92ef9c3ab67fb355a5d9918bfbff7
1 /* packet-ax25-kiss.c
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
15 * Linux kernel.
17 * The original definition of the KISS protocol can be found here:
18 * http://www.ka9q.net/papers/kiss.html
19 * and here:
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.
26 * i.e.:
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
31 * be always 0.
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
36 * port number,
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
48 * (i.e., 500 ms).
50 * 2 P The next byte is the persistence
51 * parameter, p, scaled to the range
52 * 0 - 255 with the following
53 * formula:
55 * P = p * 256 - 1
57 * The default value is P = 63
58 * (i.e., p = 0.25).
60 * 3 SlotTime The next byte is the slot interval
61 * in 10 ms units.
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.
73 * The default is 0
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
86 * applications.
89 * G8BPQ extensions:
91 * 12 Data frame Data with acknowledge request
93 * 14 Poll mode Set poll mode
95 * Checksum mode
99 #include "config.h"
101 #include <epan/packet.h>
102 #include <epan/capture_dissectors.h>
103 #include <epan/prefs.h>
105 #define STRLEN 80
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" },
166 { 0, NULL }
169 static bool
170 capture_ax25_kiss( const unsigned char *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header)
172 int l_offset;
173 uint8_t kiss_cmd;
175 if ( ! BYTES_ARE_IN_FRAME( offset, len, KISS_HEADER_SIZE ) )
176 return false;
178 l_offset = offset;
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:
192 l_offset += 2;
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;
196 default : break;
198 return false;
201 /* Code to actually dissect the packets */
202 static int
203 dissect_ax25_kiss( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_ )
205 proto_item *ti;
206 proto_tree *kiss_tree;
207 int offset;
208 int kiss_cmd;
209 int kiss_type;
210 int kiss_port;
211 int kiss_param;
212 int kiss_param_len;
213 int kiss_cksum;
214 int kiss_cksum_index;
215 int kiss_tvb_length;
216 const char *frame_type_text;
217 char *info_buffer;
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 */
227 offset = 0;
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;
234 kiss_param = 0;
235 kiss_param_len = 0;
236 switch ( kiss_type )
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 )
246 kiss_param_len = 0;
247 if ( (kiss_param_len > 0) && gPREF_CKSUM_MODE )
248 kiss_param_len--;
249 break;
250 case KISS_DATA_FRAME_ACK: kiss_param_len = 2; kiss_param = tvb_get_uint8( tvb, offset ) & 0xff; break;
251 default : 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 );
262 if ( parent_tree )
264 /* protocol offset for the KISS header */
265 offset = 0;
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 ),
270 "KISS: %s",
271 info_buffer
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,
277 kiss_cmd );
278 proto_tree_add_uint( kiss_tree, hf_ax25_kiss_port, tvb, offset, KISS_HEADER_SIZE,
279 kiss_port );
280 offset += KISS_HEADER_SIZE;
282 switch ( kiss_type )
284 case KISS_DATA_FRAME : break;
285 case KISS_TXDELAY :
286 proto_tree_add_uint( kiss_tree, hf_ax25_kiss_txdelay,
287 tvb, offset, kiss_param_len, kiss_param );
288 offset += kiss_param_len;
289 break;
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;
294 break;
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;
299 break;
300 case KISS_TXTAIL :
301 proto_tree_add_uint( kiss_tree, hf_ax25_kiss_txtail,
302 tvb, offset, kiss_param_len, kiss_param );
303 offset += kiss_param_len;
304 break;
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;
309 break;
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;
314 break;
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;
319 break;
320 case KISS_POLL_MODE : break;
321 case KISS_RETURN : break;
322 default : break;
325 if ( gPREF_CKSUM_MODE )
327 kiss_cksum = 0;
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);
350 void
351 proto_register_ax25_kiss(void)
353 module_t *ax25_kiss_module;
355 /* Setup list of header fields */
356 static hf_register_info hf[] = {
357 { &hf_ax25_kiss_cmd,
358 { "Cmd", "ax25_kiss.cmd",
359 FT_UINT8, BASE_DEC, VALS(kiss_frame_types), KISS_CMD_MASK,
360 NULL, HFILL }
362 { &hf_ax25_kiss_port,
363 { "Port", "ax25_kiss.port",
364 FT_UINT8, BASE_DEC, NULL, KISS_PORT_MASK,
365 NULL, HFILL }
367 { &hf_ax25_kiss_txdelay,
368 { "Tx delay", "ax25_kiss.txdelay",
369 FT_UINT8, BASE_DEC, NULL, 0x0,
370 NULL, HFILL }
372 { &hf_ax25_kiss_persistence,
373 { "Persistence", "ax25_kiss.persistence",
374 FT_UINT8, BASE_DEC, NULL, 0x0,
375 NULL, HFILL }
377 { &hf_ax25_kiss_slottime,
378 { "Slot time", "ax25_kiss.slottime",
379 FT_UINT8, BASE_DEC, NULL, 0x0,
380 NULL, HFILL }
382 { &hf_ax25_kiss_txtail,
383 { "Tx tail", "ax25_kiss.txtail",
384 FT_UINT8, BASE_DEC, NULL, 0x0,
385 NULL, HFILL }
387 { &hf_ax25_kiss_fullduplex,
388 { "Full duplex", "ax25_kiss.fullduplex",
389 FT_UINT8, BASE_DEC, NULL, 0x0,
390 NULL, HFILL }
392 { &hf_ax25_kiss_sethardware,
393 { "Set hardware", "ax25_kiss.sethardware",
394 FT_BYTES, BASE_NONE, NULL, 0x0,
395 NULL, HFILL }
397 { &hf_ax25_kiss_data_ack,
398 { "Data ack", "ax25_kiss.data_ack",
399 FT_UINT16, BASE_DEC, NULL, 0x0,
400 NULL, HFILL }
402 { &hf_ax25_kiss_cksum,
403 { "Checksum", "ax25_kiss.cksum",
404 FT_UINT16, BASE_HEX, NULL, 0x0,
405 NULL, HFILL }
409 /* Setup protocol subtree array */
410 static int *ett[] = {
411 &ett_ax25_kiss,
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",
428 "Set checksum mode",
429 "Enable checksum calculation.",
430 &gPREF_CKSUM_MODE );
434 void
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
452 * Local variables:
453 * c-basic-offset: 8
454 * tab-width: 8
455 * indent-tabs-mode: t
456 * End:
458 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
459 * :indentSize=8:tabSize=8:noTabs=false: