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>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 * This dissector is for:
30 * AX.25 Amateur Packet-Radio Link-Layer Protocol, Version 2.0, October 1984
32 * At the time of writing the specification could be found here:
33 * http://www.tapr.org/pub_ax25.html
35 * A newer version, Version 2.2, July 1998, can be found at
36 * http://www.ax25.net/AX25.2.2-Jul%2098-2.pdf
38 * Inspiration on how to build the dissector drawn from
44 * with the base file built from README.developers.
51 #include <epan/packet.h>
52 #include <epan/to_str.h>
53 #include <epan/wmem/wmem.h>
54 #include <epan/xdlc.h>
55 #include <epan/ax25_pids.h>
56 #include <epan/ipproto.h>
57 #include <packet-ip.h>
59 #include "packet-ax25.h"
60 #include "packet-netrom.h"
64 #define AX25_ADDR_LEN 7 /* length of an AX.25 address */
65 #define AX25_HEADER_SIZE 15 /* length of src_addr + dst_addr + cntl */
66 #define AX25_MAX_DIGIS 8
68 void proto_register_ax25(void);
69 void proto_reg_handoff_ax25(void);
72 static dissector_table_t ax25_dissector_table
;
74 /* Initialize the protocol and registered fields */
75 static int proto_ax25
= -1;
76 static int hf_ax25_dst
= -1;
77 static int hf_ax25_src
= -1;
78 static int hf_ax25_via
[ AX25_MAX_DIGIS
] = { -1,-1,-1,-1,-1,-1,-1,-1 };
80 static int hf_ax25_ctl
= -1;
82 static int hf_ax25_n_r
= -1;
83 static int hf_ax25_n_s
= -1;
85 static int hf_ax25_p
= -1;
86 static int hf_ax25_f
= -1;
88 static int hf_ax25_ftype_s
= -1;
89 static int hf_ax25_ftype_i
= -1;
90 static int hf_ax25_ftype_su
= -1;
92 static int hf_ax25_u_cmd
= -1;
93 static int hf_ax25_u_resp
= -1;
95 static int hf_ax25_pid
= -1;
97 static const xdlc_cf_items ax25_cf_items
= {
109 static const value_string pid_vals
[] = {
110 { AX25_P_ROSE
, "Rose" },
111 { AX25_P_RFC1144C
, "RFC1144 (compressed)" },
112 { AX25_P_RFC1144
, "RFC1144 (uncompressed)" },
113 { AX25_P_SEGMENT
, "Segment" },
114 { AX25_P_TEXNET
, "Texnet" },
115 { AX25_P_LCP
, "Link Quality protocol" },
116 { AX25_P_ATALK
, "AppleTalk" },
117 { AX25_P_ATALKARP
, "AppleTalk ARP" },
119 { AX25_P_ARP
, "ARP" },
120 { AX25_P_FLEXNET
, "FlexNet" },
121 { AX25_P_NETROM
, "NetRom" },
122 { AX25_P_NO_L3
, "No L3" },
123 { AX25_P_L3_ESC
, "L3 esc" },
127 static gint ett_ax25
= -1;
128 static gint ett_ax25_ctl
= -1;
130 static dissector_handle_t ax25_handle
;
132 static dissector_handle_t data_handle
;
135 dissect_ax25( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
)
138 proto_tree
*ax25_tree
;
142 /* char v2cmdresp; */
143 const char *ax25_version
;
145 const guint8
*src_addr
;
146 const guint8
*dst_addr
;
147 const guint8
*via_addr
;
149 guint8 pid
= AX25_P_NO_L3
;
152 tvbuff_t
*next_tvb
= NULL
;
155 info_buffer
= (char *)wmem_alloc( wmem_packet_scope(), 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 dst_addr
= tvb_get_ptr( tvb
, offset
, AX25_ADDR_LEN
);
168 proto_tree_add_ax25( ax25_tree
, hf_ax25_dst
, tvb
, offset
, AX25_ADDR_LEN
, dst_addr
);
169 SET_ADDRESS( &pinfo
->dl_dst
, AT_AX25
, AX25_ADDR_LEN
, dst_addr
);
170 SET_ADDRESS( &pinfo
->dst
, AT_AX25
, AX25_ADDR_LEN
, dst_addr
);
171 dst_ssid
= *(dst_addr
+ 6);
173 /* step over dst addr point at src addr */
174 offset
+= AX25_ADDR_LEN
;
176 src_addr
= tvb_get_ptr( tvb
, offset
, AX25_ADDR_LEN
);
177 proto_tree_add_ax25( ax25_tree
, hf_ax25_src
, tvb
, offset
, AX25_ADDR_LEN
, src_addr
);
178 SET_ADDRESS( &pinfo
->dl_src
, AT_AX25
, AX25_ADDR_LEN
, src_addr
);
179 SET_ADDRESS( &pinfo
->src
, AT_AX25
, AX25_ADDR_LEN
, src_addr
);
180 src_ssid
= *(src_addr
+ 6);
182 /* step over src addr point at either 1st via addr or control byte */
183 offset
+= AX25_ADDR_LEN
;
185 proto_item_append_text( ti
, ", Src: %s (%s), Dst: %s (%s)",
186 get_ax25_name( src_addr
),
187 ax25_to_str( src_addr
),
188 get_ax25_name( dst_addr
),
189 ax25_to_str( dst_addr
) );
191 /* decode the cmd/resp field */
192 /* v2cmdresp = '.'; */
193 switch ( ( (dst_ssid
>> 6) & 0x02) | ( (src_ssid
>> 7) & 0x01 ) )
195 case 1 : /* V2.0 Response */
196 ax25_version
= "V2.0+";
197 /* v2cmdresp = 'R'; */
200 case 2 : /* V2.0 Command */
201 ax25_version
= "V2.0+";
202 /* v2cmdresp = 'C'; */
206 ax25_version
= "V?.?";
207 /* v2cmdresp = '?'; */
211 proto_item_append_text( ti
, ", Ver: %s", ax25_version
);
213 /* handle the vias, if any */
215 while ( ( tvb_get_guint8( tvb
, offset
- 1 ) & 0x01 ) == 0 )
217 if ( via_index
< AX25_MAX_DIGIS
)
219 via_addr
= tvb_get_ptr( tvb
, offset
, AX25_ADDR_LEN
);
220 proto_tree_add_ax25( ax25_tree
, hf_ax25_via
[ via_index
], tvb
, offset
, AX25_ADDR_LEN
, via_addr
);
223 /* step over a via addr */
224 offset
+= AX25_ADDR_LEN
;
227 /* XXX - next-to-last argument should be TRUE if modulo 128 operation */
228 control
= dissect_xdlc_control( tvb
,
241 /* XXX - second argument should be TRUE if modulo 128 operation */
242 offset
+= XDLC_CONTROL_LEN(control
, FALSE
); /* step over control field */
244 if ( XDLC_IS_INFORMATION( control
) )
247 pid
= tvb_get_guint8( tvb
, offset
);
248 col_append_fstr( pinfo
->cinfo
, COL_INFO
, ", %s", val_to_str(pid
, pid_vals
, "Unknown (0x%02x)") );
249 proto_tree_add_uint( ax25_tree
, hf_ax25_pid
, tvb
, offset
, 1, pid
);
251 /* Call sub-dissectors here */
253 offset
+= 1; /* step over pid to the 1st byte of the payload */
255 proto_item_set_end(ti
, tvb
, offset
);
257 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
259 if (!dissector_try_uint(ax25_dissector_table
, pid
, next_tvb
, pinfo
, parent_tree
))
261 call_dissector(data_handle
, next_tvb
, pinfo
, parent_tree
);
265 proto_item_set_end(ti
, tvb
, offset
);
269 capture_ax25( const guchar
*pd
, int offset
, int len
, packet_counts
*ld
)
275 if ( ! BYTES_ARE_IN_FRAME( offset
, len
, AX25_HEADER_SIZE
) )
282 l_offset
+= AX25_ADDR_LEN
; /* step over dst addr point at src addr */
283 l_offset
+= AX25_ADDR_LEN
; /* step over src addr point at either 1st via addr or control byte */
284 while ( ( pd
[ l_offset
- 1 ] & 0x01 ) == 0 )
285 l_offset
+= AX25_ADDR_LEN
; /* step over a via addr */
287 control
= pd
[ l_offset
];
289 /* decode the pid field (if appropriate) */
290 if ( XDLC_IS_INFORMATION( control
) )
292 l_offset
+= 1; /* step over control byte point at pid */
293 pid
= pd
[ l_offset
];
295 l_offset
+= 1; /* step over the pid and point to the first byte of the payload */
296 switch ( pid
& 0x0ff )
298 case AX25_P_NETROM
: capture_netrom( pd
, l_offset
, len
, ld
); break;
299 case AX25_P_IP
: capture_ip( pd
, l_offset
, len
, ld
); break;
300 case AX25_P_ARP
: ld
->arp
++; break;
301 default : ld
->other
++; break;
307 proto_register_ax25(void)
309 static const true_false_string flags_set_truth
=
316 /* Setup list of header fields */
317 static hf_register_info hf
[] = {
319 { "Destination", "ax25.dst",
320 FT_AX25
, BASE_NONE
, NULL
, 0x0,
321 "Destination callsign", HFILL
}
324 { "Source", "ax25.src",
325 FT_AX25
, BASE_NONE
, NULL
, 0x0,
326 "Source callsign", HFILL
}
329 { "Via 1", "ax25.via1",
330 FT_AX25
, BASE_NONE
, NULL
, 0x0,
331 "Via callsign 1", HFILL
}
334 { "Via 2", "ax25.via2",
335 FT_AX25
, BASE_NONE
, NULL
, 0x0,
336 "Via callsign 2", HFILL
}
339 { "Via 3", "ax25.via3",
340 FT_AX25
, BASE_NONE
, NULL
, 0x0,
341 "Via callsign 3", HFILL
}
344 { "Via 4", "ax25.via4",
345 FT_AX25
, BASE_NONE
, NULL
, 0x0,
346 "Via callsign 4", HFILL
}
349 { "Via 5", "ax25.via5",
350 FT_AX25
, BASE_NONE
, NULL
, 0x0,
351 "Via callsign 5", HFILL
}
354 { "Via 6", "ax25.via6",
355 FT_AX25
, BASE_NONE
, NULL
, 0x0,
356 "Via callsign 6", HFILL
}
359 { "Via 7", "ax25.via7",
360 FT_AX25
, BASE_NONE
, NULL
, 0x0,
361 "Via callsign 7", HFILL
}
364 { "Via 8", "ax25.via8",
365 FT_AX25
, BASE_NONE
, NULL
, 0x0,
366 "Via callsign 8", HFILL
}
369 { "Control", "ax25.ctl",
370 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
371 "Control field", HFILL
}
374 { "n(r)", "ax25.ctl.n_r",
375 FT_UINT8
, BASE_DEC
, NULL
, XDLC_N_R_MASK
,
379 { "n(s)", "ax25.ctl.n_s",
380 FT_UINT8
, BASE_DEC
, NULL
, XDLC_N_S_MASK
,
384 { "Poll", "ax25.ctl.p",
385 FT_BOOLEAN
, 8, TFS(&flags_set_truth
), XDLC_P_F
,
389 { "Final", "ax25.ctl.f",
390 FT_BOOLEAN
, 8, TFS(&flags_set_truth
), XDLC_P_F
,
394 { "Frame type", "ax25.ctl.ftype_s",
395 FT_UINT8
, BASE_HEX
, VALS(stype_vals
), XDLC_S_FTYPE_MASK
,
399 { "Frame type", "ax25.ctl.ftype_i",
400 FT_UINT8
, BASE_HEX
, VALS(ftype_vals
), XDLC_I_MASK
,
404 { "Frame type", "ax25.ctl.ftype_su",
405 FT_UINT8
, BASE_HEX
, VALS(ftype_vals
), XDLC_S_U_MASK
,
409 { "Frame type", "ax25.ctl.u_cmd",
410 FT_UINT8
, BASE_HEX
, VALS(modifier_vals_cmd
), XDLC_U_MODIFIER_MASK
,
414 { "Frame type", "ax25.ctl.u_resp",
415 FT_UINT8
, BASE_HEX
, VALS(modifier_vals_resp
), XDLC_U_MODIFIER_MASK
,
419 { "Protocol ID", "ax25.pid",
420 FT_UINT8
, BASE_HEX
, VALS(pid_vals
), 0x0,
421 "Protocol identifier", HFILL
}
425 /* Setup protocol subtree array */
426 static gint
*ett
[] = {
431 /* Register the protocol name and description */
432 proto_ax25
= proto_register_protocol("Amateur Radio AX.25", "AX.25", "ax25");
434 /* Register the dissector */
435 ax25_handle
= register_dissector( "ax25", dissect_ax25
, proto_ax25
);
437 /* Required function calls to register the header fields and subtrees used */
438 proto_register_field_array( proto_ax25
, hf
, array_length(hf
) );
439 proto_register_subtree_array(ett
, array_length(ett
) );
441 /* Register dissector table for protocol IDs */
442 ax25_dissector_table
= register_dissector_table("ax25.pid", "AX.25 protocol ID", FT_UINT8
, BASE_HEX
);
446 proto_reg_handoff_ax25(void)
448 dissector_add_uint("wtap_encap", WTAP_ENCAP_AX25
, ax25_handle
);
449 dissector_add_uint("ip.proto", IP_PROTO_AX25
, ax25_handle
);
451 data_handle
= find_dissector( "data" );