3 * Routines for Amateur Packet Radio protocol dissection
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
30 * with the base file built from README.developers.
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>
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
;
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
;
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
= {
102 static const xdlc_cf_items ax25_cf_items_ext
= {
107 &hf_ax25_ftype_s_ext
,
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" },
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" },
133 static int ett_ax25_ctl
;
135 static dissector_handle_t ax25_handle
;
138 dissect_ax25( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void* data _U_
)
141 proto_tree
*ax25_tree
;
145 /* char v2cmdresp; */
146 const char *ax25_version
;
149 uint8_t pid
= AX25_P_NO_L3
;
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 */
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'; */
196 case 2 : /* V2.0 Command */
197 ax25_version
= "V2.0+";
198 /* v2cmdresp = 'C'; */
202 ax25_version
= "V?.?";
203 /* v2cmdresp = '?'; */
207 proto_item_append_text( ti
, ", Ver: %s", ax25_version
);
209 /* handle the vias, if any */
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
);
218 /* step over a via addr */
219 offset
+= AX25_ADDR_LEN
;
222 control
= dissect_xdlc_control( tvb
,
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
);
258 proto_item_set_end(ti
, tvb
, offset
);
260 return tvb_captured_length(tvb
);
264 capture_ax25( const unsigned char *pd
, int offset
, int len
, capture_packet_info_t
*cpinfo
, const union wtap_pseudo_header
*pseudo_header
)
270 if ( ! BYTES_ARE_IN_FRAME( offset
, len
, AX25_HEADER_SIZE
) )
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
);
294 proto_register_ax25(void)
296 /* Setup list of header fields */
297 static hf_register_info hf
[] = {
299 { "Destination", "ax25.dst",
300 FT_AX25
, BASE_NONE
, NULL
, 0x0,
301 "Destination callsign", HFILL
}
304 { "Source", "ax25.src",
305 FT_AX25
, BASE_NONE
, NULL
, 0x0,
306 "Source callsign", HFILL
}
309 { "Via 1", "ax25.via1",
310 FT_AX25
, BASE_NONE
, NULL
, 0x0,
311 "Via callsign 1", HFILL
}
314 { "Via 2", "ax25.via2",
315 FT_AX25
, BASE_NONE
, NULL
, 0x0,
316 "Via callsign 2", HFILL
}
319 { "Via 3", "ax25.via3",
320 FT_AX25
, BASE_NONE
, NULL
, 0x0,
321 "Via callsign 3", HFILL
}
324 { "Via 4", "ax25.via4",
325 FT_AX25
, BASE_NONE
, NULL
, 0x0,
326 "Via callsign 4", HFILL
}
329 { "Via 5", "ax25.via5",
330 FT_AX25
, BASE_NONE
, NULL
, 0x0,
331 "Via callsign 5", HFILL
}
334 { "Via 6", "ax25.via6",
335 FT_AX25
, BASE_NONE
, NULL
, 0x0,
336 "Via callsign 6", HFILL
}
339 { "Via 7", "ax25.via7",
340 FT_AX25
, BASE_NONE
, NULL
, 0x0,
341 "Via callsign 7", HFILL
}
344 { "Via 8", "ax25.via8",
345 FT_AX25
, BASE_NONE
, NULL
, 0x0,
346 "Via callsign 8", HFILL
}
349 { "Control", "ax25.ctl",
350 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
351 "Control field", HFILL
}
354 { "Control", "ax25.ctl_ext",
355 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
356 "Control field", HFILL
}
359 { "n(r)", "ax25.ctl.n_r",
360 FT_UINT8
, BASE_DEC
, NULL
, XDLC_N_R_MASK
,
364 { "n(r) ext", "ax25.ctl.n_r_ext",
365 FT_UINT16
, BASE_DEC
, NULL
, XDLC_N_R_EXT_MASK
,
369 { "n(s)", "ax25.ctl.n_s",
370 FT_UINT8
, BASE_DEC
, NULL
, XDLC_N_S_MASK
,
374 { "n(s) ext", "ax25.ctl.n_s_ext",
375 FT_UINT16
, BASE_DEC
, NULL
, XDLC_N_S_EXT_MASK
,
379 { "Poll", "ax25.ctl.p",
380 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), XDLC_P_F
,
384 { "Final", "ax25.ctl.f_ext",
385 FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), XDLC_P_F_EXT
,
389 { "Poll", "ax25.ctl.p_ext",
390 FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), XDLC_P_F_EXT
,
394 { "Final", "ax25.ctl.f",
395 FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), XDLC_P_F
,
399 { "Frame type", "ax25.ctl.ftype_s",
400 FT_UINT8
, BASE_HEX
, VALS(stype_vals
), XDLC_S_FTYPE_MASK
,
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
,
409 { "Frame type", "ax25.ctl.ftype_i",
410 FT_UINT8
, BASE_HEX
, VALS(ftype_vals
), XDLC_I_MASK
,
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
,
419 { "Frame type", "ax25.ctl.ftype_su",
420 FT_UINT8
, BASE_HEX
, VALS(ftype_vals
), XDLC_S_U_MASK
,
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
,
429 { "Frame type", "ax25.ctl.u_cmd",
430 FT_UINT8
, BASE_HEX
, VALS(modifier_vals_cmd
), XDLC_U_MODIFIER_MASK
,
434 { "Frame type", "ax25.ctl.u_resp",
435 FT_UINT8
, BASE_HEX
, VALS(modifier_vals_resp
), XDLC_U_MODIFIER_MASK
,
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
[] = {
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",
456 "Enable extended mode calculation.",
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
);
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
488 * indent-tabs-mode: t
491 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
492 * :indentSize=8:tabSize=8:noTabs=false: