Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-ax25.c
blob40ba10c14a54946c1ae253cbe7582d0630d71970
1 /* packet-ax25.c
3 * Routines for Amateur Packet Radio protocol dissection
4 * AX.25 frames
5 * Copyright 2005,2006,2007,2008,2009,2010,2012 R.W. Stearn <richard@rns-stearn.demon.co.uk>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
15 * This dissector is for:
16 * AX.25 Amateur Packet-Radio Link-Layer Protocol, Version 2.0, October 1984
18 * At the time of writing the specification could be found here:
19 * http://www.tapr.org/pub_ax25.html
21 * A newer version, Version 2.2, July 1998, can be found at
22 * http://www.ax25.net/AX25.2.2-Jul%2098-2.pdf
24 * Inspiration on how to build the dissector drawn from
25 * packet-sdlc.c
26 * packet-x25.c
27 * packet-lapb.c
28 * paket-gprs-llc.c
29 * xdlc.c
30 * with the base file built from README.developers.
33 #include "config.h"
35 #include <epan/packet.h>
36 #include <epan/capture_dissectors.h>
37 #include <epan/to_str.h>
38 #include <epan/xdlc.h>
39 #include <epan/ax25_pids.h>
40 #include <epan/ipproto.h>
41 #include <epan/prefs.h>
42 #include <epan/tfs.h>
44 #define STRLEN 80
46 #define AX25_HEADER_SIZE 15 /* length of src_addr + dst_addr + cntl */
47 #define AX25_MAX_DIGIS 8
49 void proto_register_ax25(void);
50 void proto_reg_handoff_ax25(void);
52 static bool gEXTENDED_MODE;
54 /* Dissector table */
55 static dissector_table_t ax25_dissector_table;
57 static capture_dissector_handle_t ax25_cap_handle;
59 /* Initialize the protocol and registered fields */
60 static int proto_ax25;
61 static int hf_ax25_dst;
62 static int hf_ax25_src;
63 static int hf_ax25_via[ AX25_MAX_DIGIS ];
65 static int hf_ax25_ctl;
66 static int hf_ax25_ctl_ext;
68 static int hf_ax25_n_r;
69 static int hf_ax25_n_r_ext;
70 static int hf_ax25_n_s;
71 static int hf_ax25_n_s_ext;
73 static int hf_ax25_p;
74 static int hf_ax25_f;
75 static int hf_ax25_p_ext;
76 static int hf_ax25_f_ext;
78 static int hf_ax25_ftype_s;
79 static int hf_ax25_ftype_s_ext;
80 static int hf_ax25_ftype_i;
81 static int hf_ax25_ftype_i_ext;
82 static int hf_ax25_ftype_su;
83 static int hf_ax25_ftype_su_ext;
85 static int hf_ax25_u_cmd;
86 static int hf_ax25_u_resp;
88 static int hf_ax25_pid;
90 static const xdlc_cf_items ax25_cf_items = {
91 &hf_ax25_n_r,
92 &hf_ax25_n_s,
93 &hf_ax25_p,
94 &hf_ax25_f,
95 &hf_ax25_ftype_s,
96 &hf_ax25_u_cmd,
97 &hf_ax25_u_resp,
98 &hf_ax25_ftype_i,
99 &hf_ax25_ftype_su
102 static const xdlc_cf_items ax25_cf_items_ext = {
103 &hf_ax25_n_r_ext,
104 &hf_ax25_n_s_ext,
105 &hf_ax25_p_ext,
106 &hf_ax25_f_ext,
107 &hf_ax25_ftype_s_ext,
108 &hf_ax25_u_cmd,
109 &hf_ax25_u_resp,
110 &hf_ax25_ftype_i_ext,
111 &hf_ax25_ftype_su_ext
114 static const value_string pid_vals[] = {
115 { AX25_P_ROSE, "Rose" },
116 { AX25_P_RFC1144C, "RFC1144 (compressed)" },
117 { AX25_P_RFC1144, "RFC1144 (uncompressed)" },
118 { AX25_P_SEGMENT, "Segment" },
119 { AX25_P_TEXNET, "Texnet" },
120 { AX25_P_LCP, "Link Quality protocol" },
121 { AX25_P_ATALK, "AppleTalk" },
122 { AX25_P_ATALKARP, "AppleTalk ARP" },
123 { AX25_P_IP, "IP" },
124 { AX25_P_ARP, "ARP" },
125 { AX25_P_FLEXNET, "FlexNet" },
126 { AX25_P_NETROM, "NetRom" },
127 { AX25_P_NO_L3, "No L3" },
128 { AX25_P_L3_ESC, "L3 esc" },
129 { 0, NULL }
132 static int ett_ax25;
133 static int ett_ax25_ctl;
135 static dissector_handle_t ax25_handle;
137 static int
138 dissect_ax25( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void* data _U_ )
140 proto_item *ti;
141 proto_tree *ax25_tree;
142 int offset;
143 int via_index;
144 char *info_buffer;
145 /* char v2cmdresp; */
146 const char *ax25_version;
147 int is_response;
148 uint8_t control;
149 uint8_t pid = AX25_P_NO_L3;
150 uint8_t src_ssid;
151 uint8_t dst_ssid;
152 tvbuff_t *next_tvb = NULL;
155 info_buffer = (char *)wmem_alloc( pinfo->pool, STRLEN );
156 info_buffer[0] = '\0';
158 col_set_str( pinfo->cinfo, COL_PROTOCOL, "AX.25" );
159 col_clear( pinfo->cinfo, COL_INFO );
161 /* start at the dst addr */
162 offset = 0;
163 /* create display subtree for the protocol */
164 ti = proto_tree_add_protocol_format( parent_tree, proto_ax25, tvb, offset, -1, "AX.25");
165 ax25_tree = proto_item_add_subtree( ti, ett_ax25 );
167 proto_tree_add_item( ax25_tree, hf_ax25_dst, tvb, offset, AX25_ADDR_LEN, ENC_NA);
168 set_address_tvb(&pinfo->dl_dst, AT_AX25, AX25_ADDR_LEN, tvb, offset);
169 copy_address_shallow(&pinfo->dst, &pinfo->dl_dst);
170 dst_ssid = tvb_get_uint8(tvb, offset+6);
172 /* step over dst addr point at src addr */
173 offset += AX25_ADDR_LEN;
175 proto_tree_add_item( ax25_tree, hf_ax25_src, tvb, offset, AX25_ADDR_LEN, ENC_NA);
176 set_address_tvb(&pinfo->dl_src, AT_AX25, AX25_ADDR_LEN, tvb, offset);
177 copy_address_shallow(&pinfo->src, &pinfo->dl_src);
178 src_ssid = tvb_get_uint8(tvb, offset+6);
180 /* step over src addr point at either 1st via addr or control byte */
181 offset += AX25_ADDR_LEN;
183 proto_item_append_text( ti, ", Src: %s, Dst: %s",
184 address_to_str(pinfo->pool, &pinfo->src),
185 address_to_str(pinfo->pool, &pinfo->dst));
187 /* decode the cmd/resp field */
188 /* v2cmdresp = '.'; */
189 switch ( ( (dst_ssid >> 6) & 0x02) | ( (src_ssid >> 7) & 0x01 ) )
191 case 1 : /* V2.0 Response */
192 ax25_version = "V2.0+";
193 /* v2cmdresp = 'R'; */
194 is_response = true;
195 break;
196 case 2 : /* V2.0 Command */
197 ax25_version = "V2.0+";
198 /* v2cmdresp = 'C'; */
199 is_response = false;
200 break;
201 default :
202 ax25_version = "V?.?";
203 /* v2cmdresp = '?'; */
204 is_response = false;
205 break;
207 proto_item_append_text( ti, ", Ver: %s", ax25_version );
209 /* handle the vias, if any */
210 via_index = 0;
211 while ( ( tvb_get_uint8( tvb, offset - 1 ) & 0x01 ) == 0 )
213 if ( via_index < AX25_MAX_DIGIS )
215 proto_tree_add_item( ax25_tree, hf_ax25_via[ via_index ], tvb, offset, AX25_ADDR_LEN, ENC_NA);
216 via_index++;
218 /* step over a via addr */
219 offset += AX25_ADDR_LEN;
222 control = dissect_xdlc_control( tvb,
223 offset,
224 pinfo,
225 ax25_tree,
226 hf_ax25_ctl,
227 ett_ax25_ctl,
228 &ax25_cf_items,
229 &ax25_cf_items_ext,
230 NULL,
231 NULL,
232 is_response,
233 gEXTENDED_MODE,
234 false );
235 offset += XDLC_CONTROL_LEN(control, gEXTENDED_MODE); /* step over control field */
237 if ( XDLC_IS_INFORMATION( control ) )
240 pid = tvb_get_uint8( tvb, offset );
241 col_append_fstr( pinfo->cinfo, COL_INFO, ", %s", val_to_str(pid, pid_vals, "Unknown (0x%02x)") );
242 proto_tree_add_uint( ax25_tree, hf_ax25_pid, tvb, offset, 1, pid );
244 /* Call sub-dissectors here */
246 offset += 1; /* step over pid to the 1st byte of the payload */
248 proto_item_set_end(ti, tvb, offset);
250 next_tvb = tvb_new_subset_remaining(tvb, offset);
252 if (!dissector_try_uint(ax25_dissector_table, pid, next_tvb, pinfo, parent_tree))
254 call_data_dissector(next_tvb, pinfo, parent_tree);
257 else
258 proto_item_set_end(ti, tvb, offset);
260 return tvb_captured_length(tvb);
263 static bool
264 capture_ax25( const unsigned char *pd, int offset, int len, capture_packet_info_t *cpinfo, const union wtap_pseudo_header *pseudo_header)
266 uint8_t control;
267 uint8_t pid;
268 int l_offset;
270 if ( ! BYTES_ARE_IN_FRAME( offset, len, AX25_HEADER_SIZE ) )
271 return false;
273 l_offset = offset;
274 l_offset += AX25_ADDR_LEN; /* step over dst addr point at src addr */
275 l_offset += AX25_ADDR_LEN; /* step over src addr point at either 1st via addr or control byte */
276 while ( ( pd[ l_offset - 1 ] & 0x01 ) == 0 )
277 l_offset += AX25_ADDR_LEN; /* step over a via addr */
279 control = pd[ l_offset ];
281 /* decode the pid field (if appropriate) */
282 if ( XDLC_IS_INFORMATION( control ) )
284 l_offset += 1; /* step over control byte point at pid */
285 pid = pd[ l_offset ];
287 l_offset += 1; /* step over the pid and point to the first byte of the payload */
288 return try_capture_dissector("ax25.pid", pid & 0x0ff, pd, l_offset, len, cpinfo, pseudo_header);
290 return false;
293 void
294 proto_register_ax25(void)
296 /* Setup list of header fields */
297 static hf_register_info hf[] = {
298 { &hf_ax25_dst,
299 { "Destination", "ax25.dst",
300 FT_AX25, BASE_NONE, NULL, 0x0,
301 "Destination callsign", HFILL }
303 { &hf_ax25_src,
304 { "Source", "ax25.src",
305 FT_AX25, BASE_NONE, NULL, 0x0,
306 "Source callsign", HFILL }
308 { &hf_ax25_via[ 0 ],
309 { "Via 1", "ax25.via1",
310 FT_AX25, BASE_NONE, NULL, 0x0,
311 "Via callsign 1", HFILL }
313 { &hf_ax25_via[ 1 ],
314 { "Via 2", "ax25.via2",
315 FT_AX25, BASE_NONE, NULL, 0x0,
316 "Via callsign 2", HFILL }
318 { &hf_ax25_via[ 2 ],
319 { "Via 3", "ax25.via3",
320 FT_AX25, BASE_NONE, NULL, 0x0,
321 "Via callsign 3", HFILL }
323 { &hf_ax25_via[ 3 ],
324 { "Via 4", "ax25.via4",
325 FT_AX25, BASE_NONE, NULL, 0x0,
326 "Via callsign 4", HFILL }
328 { &hf_ax25_via[ 4 ],
329 { "Via 5", "ax25.via5",
330 FT_AX25, BASE_NONE, NULL, 0x0,
331 "Via callsign 5", HFILL }
333 { &hf_ax25_via[ 5 ],
334 { "Via 6", "ax25.via6",
335 FT_AX25, BASE_NONE, NULL, 0x0,
336 "Via callsign 6", HFILL }
338 { &hf_ax25_via[ 6 ],
339 { "Via 7", "ax25.via7",
340 FT_AX25, BASE_NONE, NULL, 0x0,
341 "Via callsign 7", HFILL }
343 { &hf_ax25_via[ 7 ],
344 { "Via 8", "ax25.via8",
345 FT_AX25, BASE_NONE, NULL, 0x0,
346 "Via callsign 8", HFILL }
348 { &hf_ax25_ctl,
349 { "Control", "ax25.ctl",
350 FT_UINT8, BASE_HEX, NULL, 0x0,
351 "Control field", HFILL }
353 { &hf_ax25_ctl_ext,
354 { "Control", "ax25.ctl_ext",
355 FT_UINT16, BASE_HEX, NULL, 0x0,
356 "Control field", HFILL }
358 { &hf_ax25_n_r,
359 { "n(r)", "ax25.ctl.n_r",
360 FT_UINT8, BASE_DEC, NULL, XDLC_N_R_MASK,
361 NULL, HFILL }
363 { &hf_ax25_n_r_ext,
364 { "n(r) ext", "ax25.ctl.n_r_ext",
365 FT_UINT16, BASE_DEC, NULL, XDLC_N_R_EXT_MASK,
366 NULL, HFILL }
368 { &hf_ax25_n_s,
369 { "n(s)", "ax25.ctl.n_s",
370 FT_UINT8, BASE_DEC, NULL, XDLC_N_S_MASK,
371 NULL, HFILL }
373 { &hf_ax25_n_s_ext,
374 { "n(s) ext", "ax25.ctl.n_s_ext",
375 FT_UINT16, BASE_DEC, NULL, XDLC_N_S_EXT_MASK,
376 NULL, HFILL }
378 { &hf_ax25_p,
379 { "Poll", "ax25.ctl.p",
380 FT_BOOLEAN, 8, TFS(&tfs_set_notset), XDLC_P_F,
381 NULL, HFILL }
383 { &hf_ax25_f_ext,
384 { "Final", "ax25.ctl.f_ext",
385 FT_BOOLEAN, 16, TFS(&tfs_set_notset), XDLC_P_F_EXT,
386 NULL, HFILL }
388 { &hf_ax25_p_ext,
389 { "Poll", "ax25.ctl.p_ext",
390 FT_BOOLEAN, 16, TFS(&tfs_set_notset), XDLC_P_F_EXT,
391 NULL, HFILL }
393 { &hf_ax25_f,
394 { "Final", "ax25.ctl.f",
395 FT_BOOLEAN, 8, TFS(&tfs_set_notset), XDLC_P_F,
396 NULL, HFILL }
398 { &hf_ax25_ftype_s,
399 { "Frame type", "ax25.ctl.ftype_s",
400 FT_UINT8, BASE_HEX, VALS(stype_vals), XDLC_S_FTYPE_MASK,
401 NULL, HFILL }
403 { &hf_ax25_ftype_s_ext,
404 { "Frame type", "ax25.ctl.ftype_s_ext",
405 FT_UINT16, BASE_HEX, VALS(stype_vals), XDLC_S_FTYPE_MASK,
406 NULL, HFILL }
408 { &hf_ax25_ftype_i,
409 { "Frame type", "ax25.ctl.ftype_i",
410 FT_UINT8, BASE_HEX, VALS(ftype_vals), XDLC_I_MASK,
411 NULL, HFILL }
413 { &hf_ax25_ftype_i_ext,
414 { "Frame type", "ax25.ctl.ftype_i_ext",
415 FT_UINT16, BASE_HEX, VALS(ftype_vals), XDLC_I_MASK,
416 NULL, HFILL }
418 { &hf_ax25_ftype_su,
419 { "Frame type", "ax25.ctl.ftype_su",
420 FT_UINT8, BASE_HEX, VALS(ftype_vals), XDLC_S_U_MASK,
421 NULL, HFILL }
423 { &hf_ax25_ftype_su_ext,
424 { "Frame type", "ax25.ctl.ftype_su_ext",
425 FT_UINT16, BASE_HEX, VALS(ftype_vals), XDLC_S_U_MASK,
426 NULL, HFILL }
428 { &hf_ax25_u_cmd,
429 { "Frame type", "ax25.ctl.u_cmd",
430 FT_UINT8, BASE_HEX, VALS(modifier_vals_cmd), XDLC_U_MODIFIER_MASK,
431 NULL, HFILL }
433 { &hf_ax25_u_resp,
434 { "Frame type", "ax25.ctl.u_resp",
435 FT_UINT8, BASE_HEX, VALS(modifier_vals_resp), XDLC_U_MODIFIER_MASK,
436 NULL, HFILL }
438 { &hf_ax25_pid,
439 { "Protocol ID", "ax25.pid",
440 FT_UINT8, BASE_HEX, VALS(pid_vals), 0x0,
441 "Protocol identifier", HFILL }
445 /* Setup protocol subtree array */
446 static int *ett[] = {
447 &ett_ax25,
448 &ett_ax25_ctl,
451 /* Register the protocol name and description */
452 proto_ax25 = proto_register_protocol("Amateur Radio AX.25", "AX.25", "ax25");
453 module_t *ax25_module = prefs_register_protocol(proto_ax25, NULL);
454 prefs_register_bool_preference(ax25_module, "extended",
455 "Set extended mode",
456 "Enable extended mode calculation.",
457 &gEXTENDED_MODE);
459 /* Register the dissector */
460 ax25_handle = register_dissector( "ax25", dissect_ax25, proto_ax25 );
462 /* Required function calls to register the header fields and subtrees used */
463 proto_register_field_array( proto_ax25, hf, array_length(hf ) );
464 proto_register_subtree_array(ett, array_length(ett ) );
466 /* Register dissector table for protocol IDs */
467 ax25_dissector_table = register_dissector_table("ax25.pid", "AX.25 protocol ID", proto_ax25, FT_UINT8, BASE_HEX);
468 register_capture_dissector_table("ax25.pid", "AX.25");
470 ax25_cap_handle = register_capture_dissector("ax25", capture_ax25, proto_ax25);
473 void
474 proto_reg_handoff_ax25(void)
476 dissector_add_uint("wtap_encap", WTAP_ENCAP_AX25, ax25_handle);
477 dissector_add_uint("ip.proto", IP_PROTO_AX25, ax25_handle);
479 capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_AX25, ax25_cap_handle);
483 * Editor modelines - https://www.wireshark.org/tools/modelines.html
485 * Local variables:
486 * c-basic-offset: 8
487 * tab-width: 8
488 * indent-tabs-mode: t
489 * End:
491 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
492 * :indentSize=8:tabSize=8:noTabs=false: