MSWSP: fix dissect_mswsp_smb()
[wireshark-wip.git] / epan / dissectors / packet-ax25.c
blobfba918620313f0f6dd2524aba3aed7375531a7ff
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 * $Id$
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
39 * packet-sdlc.c
40 * packet-x25.c
41 * packet-lapb.c
42 * paket-gprs-llc.c
43 * xdlc.c
44 * with the base file built from README.developers.
47 #include "config.h"
49 #include <glib.h>
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"
62 #define STRLEN 80
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);
71 /* Dissector table */
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 = {
98 &hf_ax25_n_r,
99 &hf_ax25_n_s,
100 &hf_ax25_p,
101 &hf_ax25_f,
102 &hf_ax25_ftype_s,
103 &hf_ax25_u_cmd,
104 &hf_ax25_u_resp,
105 &hf_ax25_ftype_i,
106 &hf_ax25_ftype_su
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" },
118 { AX25_P_IP, "IP" },
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" },
124 { 0, NULL }
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;
134 static void
135 dissect_ax25( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree )
137 proto_item *ti;
138 proto_tree *ax25_tree;
139 int offset;
140 int via_index;
141 char *info_buffer;
142 /* char v2cmdresp; */
143 const char *ax25_version;
144 int is_response;
145 const guint8 *src_addr;
146 const guint8 *dst_addr;
147 const guint8 *via_addr;
148 guint8 control;
149 guint8 pid = AX25_P_NO_L3;
150 guint8 src_ssid;
151 guint8 dst_ssid;
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 */
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 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'; */
198 is_response = TRUE;
199 break;
200 case 2 : /* V2.0 Command */
201 ax25_version = "V2.0+";
202 /* v2cmdresp = 'C'; */
203 is_response = FALSE;
204 break;
205 default :
206 ax25_version = "V?.?";
207 /* v2cmdresp = '?'; */
208 is_response = FALSE;
209 break;
211 proto_item_append_text( ti, ", Ver: %s", ax25_version );
213 /* handle the vias, if any */
214 via_index = 0;
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 );
221 via_index++;
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,
229 offset,
230 pinfo,
231 ax25_tree,
232 hf_ax25_ctl,
233 ett_ax25_ctl,
234 &ax25_cf_items,
235 NULL,
236 NULL,
237 NULL,
238 is_response,
239 FALSE,
240 FALSE );
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);
264 else
265 proto_item_set_end(ti, tvb, offset);
268 void
269 capture_ax25( const guchar *pd, int offset, int len, packet_counts *ld)
271 guint8 control;
272 guint8 pid;
273 int l_offset;
275 if ( ! BYTES_ARE_IN_FRAME( offset, len, AX25_HEADER_SIZE ) )
277 ld->other++;
278 return;
281 l_offset = offset;
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;
306 void
307 proto_register_ax25(void)
309 static const true_false_string flags_set_truth =
311 "Set",
312 "Not set"
316 /* Setup list of header fields */
317 static hf_register_info hf[] = {
318 { &hf_ax25_dst,
319 { "Destination", "ax25.dst",
320 FT_AX25, BASE_NONE, NULL, 0x0,
321 "Destination callsign", HFILL }
323 { &hf_ax25_src,
324 { "Source", "ax25.src",
325 FT_AX25, BASE_NONE, NULL, 0x0,
326 "Source callsign", HFILL }
328 { &hf_ax25_via[ 0 ],
329 { "Via 1", "ax25.via1",
330 FT_AX25, BASE_NONE, NULL, 0x0,
331 "Via callsign 1", HFILL }
333 { &hf_ax25_via[ 1 ],
334 { "Via 2", "ax25.via2",
335 FT_AX25, BASE_NONE, NULL, 0x0,
336 "Via callsign 2", HFILL }
338 { &hf_ax25_via[ 2 ],
339 { "Via 3", "ax25.via3",
340 FT_AX25, BASE_NONE, NULL, 0x0,
341 "Via callsign 3", HFILL }
343 { &hf_ax25_via[ 3 ],
344 { "Via 4", "ax25.via4",
345 FT_AX25, BASE_NONE, NULL, 0x0,
346 "Via callsign 4", HFILL }
348 { &hf_ax25_via[ 4 ],
349 { "Via 5", "ax25.via5",
350 FT_AX25, BASE_NONE, NULL, 0x0,
351 "Via callsign 5", HFILL }
353 { &hf_ax25_via[ 5 ],
354 { "Via 6", "ax25.via6",
355 FT_AX25, BASE_NONE, NULL, 0x0,
356 "Via callsign 6", HFILL }
358 { &hf_ax25_via[ 6 ],
359 { "Via 7", "ax25.via7",
360 FT_AX25, BASE_NONE, NULL, 0x0,
361 "Via callsign 7", HFILL }
363 { &hf_ax25_via[ 7 ],
364 { "Via 8", "ax25.via8",
365 FT_AX25, BASE_NONE, NULL, 0x0,
366 "Via callsign 8", HFILL }
368 { &hf_ax25_ctl,
369 { "Control", "ax25.ctl",
370 FT_UINT8, BASE_HEX, NULL, 0x0,
371 "Control field", HFILL }
373 { &hf_ax25_n_r,
374 { "n(r)", "ax25.ctl.n_r",
375 FT_UINT8, BASE_DEC, NULL, XDLC_N_R_MASK,
376 NULL, HFILL }
378 { &hf_ax25_n_s,
379 { "n(s)", "ax25.ctl.n_s",
380 FT_UINT8, BASE_DEC, NULL, XDLC_N_S_MASK,
381 NULL, HFILL }
383 { &hf_ax25_p,
384 { "Poll", "ax25.ctl.p",
385 FT_BOOLEAN, 8, TFS(&flags_set_truth), XDLC_P_F,
386 NULL, HFILL }
388 { &hf_ax25_f,
389 { "Final", "ax25.ctl.f",
390 FT_BOOLEAN, 8, TFS(&flags_set_truth), XDLC_P_F,
391 NULL, HFILL }
393 { &hf_ax25_ftype_s,
394 { "Frame type", "ax25.ctl.ftype_s",
395 FT_UINT8, BASE_HEX, VALS(stype_vals), XDLC_S_FTYPE_MASK,
396 NULL, HFILL }
398 { &hf_ax25_ftype_i,
399 { "Frame type", "ax25.ctl.ftype_i",
400 FT_UINT8, BASE_HEX, VALS(ftype_vals), XDLC_I_MASK,
401 NULL, HFILL }
403 { &hf_ax25_ftype_su,
404 { "Frame type", "ax25.ctl.ftype_su",
405 FT_UINT8, BASE_HEX, VALS(ftype_vals), XDLC_S_U_MASK,
406 NULL, HFILL }
408 { &hf_ax25_u_cmd,
409 { "Frame type", "ax25.ctl.u_cmd",
410 FT_UINT8, BASE_HEX, VALS(modifier_vals_cmd), XDLC_U_MODIFIER_MASK,
411 NULL, HFILL }
413 { &hf_ax25_u_resp,
414 { "Frame type", "ax25.ctl.u_resp",
415 FT_UINT8, BASE_HEX, VALS(modifier_vals_resp), XDLC_U_MODIFIER_MASK,
416 NULL, HFILL }
418 { &hf_ax25_pid,
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[] = {
427 &ett_ax25,
428 &ett_ax25_ctl,
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);
445 void
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" );