HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-netrom.c
blob7b464a4350fc921997040d1590f88fa5d0816599
1 /* packet-netrom.c
3 * Routines for Amateur Packet Radio protocol dissection
4 * NET/ROM inter-node 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 * Information on the protocol drawn from:
31 * Protocol specification is at:
33 * ftp://ftp.ucsd.edu/hamradio/packet/tcpip/docs/netrom.ps.gz
35 * (yes, it's PostScript, and, yes, it's an FTP URL).
37 * Inspiration on how to build the dissector drawn from
38 * packet-sdlc.c
39 * packet-x25.c
40 * packet-lapb.c
41 * paket-gprs-llc.c
42 * xdlc.c
43 * with the base file built from README.developers.
46 #include "config.h"
48 #include <glib.h>
50 #include <epan/packet.h>
51 #include <epan/to_str.h>
52 #include <epan/wmem/wmem.h>
53 #include <epan/ax25_pids.h>
55 #include "packet-netrom.h"
57 #define STRLEN 80
59 #define AX25_ADDR_LEN 7 /* length of an AX.25 address */
61 #define NETROM_MIN_SIZE 7 /* minumum payload for a routing packet */
62 #define NETROM_HEADER_SIZE 20 /* minumum payload for a normal packet */
64 #define NETROM_PROTOEXT 0x00
65 #define NETROM_CONNREQ 0x01
66 #define NETROM_CONNACK 0x02
67 #define NETROM_DISCREQ 0x03
68 #define NETROM_DISCACK 0x04
69 #define NETROM_INFO 0x05
70 #define NETROM_INFOACK 0x06
72 #define NETROM_MORE_FLAG 0x20
73 #define NETROM_NAK_FLAG 0x40
74 #define NETROM_CHOKE_FLAG 0x80
76 #define NETROM_PROTO_IP 0x0C
78 /* Forward declaration we need below */
79 void proto_reg_handoff_netrom(void);
81 /* Dissector handles - all the possibles are listed */
82 static dissector_handle_t ip_handle;
83 static dissector_handle_t default_handle;
85 /* Initialize the protocol and registered fields */
86 static int proto_netrom = -1;
87 static int hf_netrom_src = -1;
88 static int hf_netrom_dst = -1;
89 static int hf_netrom_ttl = -1;
90 static int hf_netrom_my_cct_index = -1;
91 static int hf_netrom_my_cct_id = -1;
92 static int hf_netrom_your_cct_index = -1;
93 static int hf_netrom_your_cct_id = -1;
94 static int hf_netrom_n_r = -1;
95 static int hf_netrom_n_s = -1;
96 static int hf_netrom_type = -1;
97 static int hf_netrom_op = -1;
98 static int hf_netrom_more = -1;
99 static int hf_netrom_nak = -1;
100 static int hf_netrom_choke = -1;
102 static int hf_netrom_user = -1;
103 static int hf_netrom_node = -1;
104 static int hf_netrom_pwindow = -1;
105 static int hf_netrom_awindow = -1;
107 static int hf_netrom_mnemonic = -1;
110 * Structure containing pointers to hf_ values for various subfields of
111 * the type field.
113 typedef struct {
114 int *hf_tf_op;
115 int *hf_tf_more;
116 int *hf_tf_nak;
117 int *hf_tf_choke;
118 } netrom_tf_items;
120 static const netrom_tf_items netrom_type_items = {
121 &hf_netrom_op,
122 &hf_netrom_more,
123 &hf_netrom_nak,
124 &hf_netrom_choke
128 const value_string op_code_vals_abbrev[] = {
129 { NETROM_PROTOEXT , "PROTOEXT"},
130 { NETROM_CONNREQ , "CONNREQ"},
131 { NETROM_CONNACK , "CONNACK"},
132 { NETROM_DISCREQ , "DISCREQ"},
133 { NETROM_DISCACK , "DISCACK"},
134 { NETROM_INFO , "INFO"},
135 { NETROM_INFOACK , "INFOACK"},
136 { 0 , NULL}
139 const value_string op_code_vals_text[] = {
140 { NETROM_PROTOEXT , "Protocol extension"},
141 { NETROM_CONNREQ , "Connect request"},
142 { NETROM_CONNACK , "Connect acknowledge"},
143 { NETROM_DISCREQ , "Disconnect request"},
144 { NETROM_DISCACK , "Disconnect acknowledge"},
145 { NETROM_INFO , "Information"},
146 { NETROM_INFOACK , "Information acknowledge"},
147 { 0 , NULL}
150 /* Initialize the subtree pointers */
151 static gint ett_netrom = -1;
152 static gint ett_netrom_type = -1;
154 static void
155 dissect_netrom_type(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree,
156 int hf_netrom_type_param, gint ett_netrom_type_param, const netrom_tf_items *type_items )
158 proto_tree *tc;
159 proto_tree *type_tree;
160 char *info_buffer;
161 guint8 type;
162 guint8 op_code;
164 type = tvb_get_guint8( tvb, offset );
165 op_code = type &0x0f;
167 info_buffer = wmem_strdup_printf( wmem_packet_scope(), "%s%s%s%s (0x%02x)",
168 val_to_str_const( op_code, op_code_vals_text, "Unknown" ),
169 ( type & NETROM_MORE_FLAG ) ? ", More" : "",
170 ( type & NETROM_NAK_FLAG ) ? ", NAK" : "",
171 ( type & NETROM_CHOKE_FLAG ) ? ", Choke" : "",
172 type );
173 col_add_str( pinfo->cinfo, COL_INFO, info_buffer );
175 if ( tree )
177 tc = proto_tree_add_uint_format( tree,
178 hf_netrom_type_param,
179 tvb,
180 offset,
182 type,
183 "Type field: %s",
184 info_buffer
186 type_tree = proto_item_add_subtree( tc, ett_netrom_type_param );
188 proto_tree_add_item( type_tree, *type_items->hf_tf_op, tvb, offset, 1, ENC_BIG_ENDIAN );
189 proto_tree_add_item( type_tree, *type_items->hf_tf_choke, tvb, offset, 1, ENC_BIG_ENDIAN );
190 proto_tree_add_item( type_tree, *type_items->hf_tf_nak, tvb, offset, 1, ENC_BIG_ENDIAN );
191 proto_tree_add_item( type_tree, *type_items->hf_tf_more, tvb, offset, 1, ENC_BIG_ENDIAN );
195 static void
196 dissect_netrom_proto(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
198 proto_item *ti;
199 proto_tree *netrom_tree;
200 int offset;
201 const guint8 *src_addr;
202 const guint8 *dst_addr;
203 const guint8 *user_addr;
204 const guint8 *node_addr;
205 #if 0
206 guint8 src_ssid;
207 guint8 dst_ssid;
208 #endif
209 guint8 op_code;
210 guint8 cct_index;
211 guint8 cct_id;
212 tvbuff_t *next_tvb = NULL;
214 col_set_str( pinfo->cinfo, COL_PROTOCOL, "NET/ROM" );
215 col_clear( pinfo->cinfo, COL_INFO );
217 offset = 0;
219 /* source */
220 src_addr = tvb_get_ptr( tvb, offset, AX25_ADDR_LEN );
221 SET_ADDRESS(&pinfo->dl_src, AT_AX25, AX25_ADDR_LEN, src_addr);
222 SET_ADDRESS(&pinfo->src, AT_AX25, AX25_ADDR_LEN, src_addr);
223 /* src_ssid = *(src_addr + 6); */
224 offset += AX25_ADDR_LEN; /* step over src addr */
226 /* destination */
227 dst_addr = tvb_get_ptr( tvb, offset, AX25_ADDR_LEN );
228 SET_ADDRESS(&pinfo->dl_dst, AT_AX25, AX25_ADDR_LEN, dst_addr);
229 SET_ADDRESS(&pinfo->dst, AT_AX25, AX25_ADDR_LEN, dst_addr);
230 /* dst_ssid = *(dst_addr + 6); */
231 offset += AX25_ADDR_LEN; /* step over dst addr */
233 offset += 1; /* step over ttl */
234 cct_index = tvb_get_guint8( tvb, offset );
235 offset += 1; /* step over cct index*/
236 cct_id = tvb_get_guint8( tvb, offset );
237 offset += 1; /* step over cct id */
238 offset += 1; /* step over n_s */
239 offset += 1; /* step over n_r */
241 /* frame type */
242 op_code = tvb_get_guint8( tvb, offset ) & 0x0f;
243 offset += 1; /* step over op_code */
245 col_add_fstr( pinfo->cinfo, COL_INFO, "%s", val_to_str_const( op_code, op_code_vals_text, "Unknown" ));
247 if ( tree )
249 /* create display subtree for the protocol */
251 ti = proto_tree_add_protocol_format( tree, proto_netrom, tvb, 0, NETROM_HEADER_SIZE,
252 "NET/ROM, Src: %s (%s), Dst: %s (%s)",
253 get_ax25_name( src_addr ),
254 ax25_to_str( src_addr ),
255 get_ax25_name( dst_addr ),
256 ax25_to_str( dst_addr ) );
258 netrom_tree = proto_item_add_subtree( ti, ett_netrom );
260 offset = 0;
262 /* source */
263 proto_tree_add_ax25( netrom_tree, hf_netrom_src, tvb, offset, AX25_ADDR_LEN, src_addr );
264 offset += AX25_ADDR_LEN;
266 /* destination */
267 proto_tree_add_ax25( netrom_tree, hf_netrom_dst, tvb, offset, AX25_ADDR_LEN, dst_addr );
268 offset += AX25_ADDR_LEN;
270 /* ttl */
271 proto_tree_add_item( netrom_tree, hf_netrom_ttl, tvb, offset, 1, ENC_BIG_ENDIAN );
272 offset += 1;
274 switch ( op_code )
276 case NETROM_PROTOEXT :
277 /* cct index */
278 proto_tree_add_item( netrom_tree, hf_netrom_my_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN );
279 offset += 1;
281 /* cct id */
282 proto_tree_add_item( netrom_tree, hf_netrom_my_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN );
283 offset += 1;
285 /* unused */
286 offset += 1;
288 /* unused */
289 offset += 1;
290 break;
291 case NETROM_CONNREQ :
292 /* cct index */
293 proto_tree_add_item( netrom_tree, hf_netrom_my_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN );
294 offset += 1;
296 /* cct id */
297 proto_tree_add_item( netrom_tree, hf_netrom_my_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN );
298 offset += 1;
300 /* unused */
301 offset += 1;
303 /* unused */
304 offset += 1;
306 break;
307 case NETROM_CONNACK :
308 /* your cct index */
309 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN );
310 offset += 1;
312 /* your cct id */
313 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN );
314 offset += 1;
316 /* my cct index */
317 proto_tree_add_item( netrom_tree, hf_netrom_my_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN );
318 offset += 1;
320 /* my cct id */
321 proto_tree_add_item( netrom_tree, hf_netrom_my_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN );
322 offset += 1;
324 break;
325 case NETROM_DISCREQ :
326 /* your cct index */
327 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN );
328 offset += 1;
330 /* your cct id */
331 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN );
332 offset += 1;
334 /* unused */
335 offset += 1;
337 /* unused */
338 offset += 1;
340 break;
341 case NETROM_DISCACK :
342 /* your cct index */
343 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN );
344 offset += 1;
346 /* your cct id */
347 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN );
348 offset += 1;
350 /* unused */
351 offset += 1;
353 /* unused */
354 offset += 1;
356 break;
357 case NETROM_INFO :
358 /* your cct index */
359 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN );
360 offset += 1;
362 /* your cct id */
363 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN );
364 offset += 1;
366 /* n_s */
367 proto_tree_add_item( netrom_tree, hf_netrom_n_s, tvb, offset, 1, ENC_BIG_ENDIAN );
368 offset += 1;
370 /* n_r */
371 proto_tree_add_item( netrom_tree, hf_netrom_n_r, tvb, offset, 1, ENC_BIG_ENDIAN );
372 offset += 1;
374 break;
375 case NETROM_INFOACK :
376 /* your cct index */
377 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_index, tvb, offset, 1, ENC_BIG_ENDIAN );
378 offset += 1;
380 /* your cct id */
381 proto_tree_add_item( netrom_tree, hf_netrom_your_cct_id, tvb, offset, 1, ENC_BIG_ENDIAN );
382 offset += 1;
384 /* unused */
385 offset += 1;
387 /* n_r */
388 proto_tree_add_item( netrom_tree, hf_netrom_n_r, tvb, offset, 1, ENC_BIG_ENDIAN );
389 offset += 1;
391 break;
392 default :
393 offset += 1;
394 offset += 1;
395 offset += 1;
396 offset += 1;
398 break;
401 /* type */
402 dissect_netrom_type( tvb,
403 offset,
404 pinfo,
405 netrom_tree,
406 hf_netrom_type,
407 ett_netrom_type,
408 &netrom_type_items
410 offset += 1;
412 switch ( op_code )
414 case NETROM_PROTOEXT :
415 break;
416 case NETROM_CONNREQ :
417 /* proposed window size */
418 proto_tree_add_item( netrom_tree, hf_netrom_pwindow, tvb, offset, 1, ENC_BIG_ENDIAN );
419 offset += 1;
421 user_addr = tvb_get_ptr( tvb, offset, AX25_ADDR_LEN );
422 proto_tree_add_ax25( netrom_tree, hf_netrom_user, tvb, offset, AX25_ADDR_LEN, user_addr );
423 offset += AX25_ADDR_LEN;
425 node_addr = tvb_get_ptr( tvb, offset, AX25_ADDR_LEN );
426 proto_tree_add_ax25( netrom_tree, hf_netrom_node, tvb, offset, AX25_ADDR_LEN, node_addr );
427 offset += AX25_ADDR_LEN;
429 break;
430 case NETROM_CONNACK :
431 /* accepted window size */
432 proto_tree_add_item( netrom_tree, hf_netrom_awindow, tvb, offset, 1, ENC_BIG_ENDIAN );
433 offset += 1;
435 break;
436 case NETROM_DISCREQ :
437 break;
438 case NETROM_DISCACK :
439 break;
440 case NETROM_INFO :
441 break;
442 case NETROM_INFOACK :
443 break;
444 default :
445 break;
449 /* Call sub-dissectors here */
451 next_tvb = tvb_new_subset_remaining(tvb, offset);
453 switch ( op_code )
455 case NETROM_PROTOEXT :
456 if ( cct_index == NETROM_PROTO_IP && cct_id == NETROM_PROTO_IP )
457 call_dissector( ip_handle , next_tvb, pinfo, tree );
458 else
459 call_dissector( default_handle , next_tvb, pinfo, tree );
461 break;
462 case NETROM_INFO :
463 default :
464 call_dissector( default_handle , next_tvb, pinfo, tree );
465 break;
469 static void
470 dissect_netrom_routing(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
472 tvbuff_t *next_tvb;
474 col_set_str( pinfo->cinfo, COL_PROTOCOL, "NET/ROM");
475 col_set_str( pinfo->cinfo, COL_INFO, "routing table frame");
477 if (tree)
479 proto_item *ti;
480 proto_tree *netrom_tree;
481 ti = proto_tree_add_protocol_format( tree, proto_netrom, tvb, 0, -1,
482 "NET/ROM, routing table frame, Node: %.6s",
483 tvb_get_ptr( tvb, 1, 6 )
486 netrom_tree = proto_item_add_subtree( ti, ett_netrom );
488 proto_tree_add_item( netrom_tree, hf_netrom_mnemonic, tvb, 1, 6, ENC_ASCII|ENC_NA );
491 next_tvb = tvb_new_subset_remaining(tvb, 7);
493 call_dissector( default_handle , next_tvb, pinfo, tree );
496 /* Code to actually dissect the packets */
497 static void
498 dissect_netrom(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
500 if ( tvb_get_guint8( tvb, 0 ) == 0xff )
501 dissect_netrom_routing( tvb, pinfo, tree );
502 else
503 dissect_netrom_proto( tvb, pinfo, tree );
506 void
507 capture_netrom( const guchar *pd _U_, int offset, int len, packet_counts *ld)
509 if ( ! BYTES_ARE_IN_FRAME( offset, len, NETROM_MIN_SIZE ) )
511 ld->other++;
512 return;
514 /* XXX - check for IP-over-NetROM here! */
515 ld->other++;
518 void
519 proto_register_netrom(void)
521 static const true_false_string flags_set_truth =
523 "Set",
524 "Not set"
528 /* Setup list of header fields */
529 static hf_register_info hf[] = {
530 { &hf_netrom_src,
531 { "Source", "netrom.src",
532 FT_AX25, BASE_NONE, NULL, 0x0,
533 "Source callsign", HFILL }
535 { &hf_netrom_dst,
536 { "Destination", "netrom.dst",
537 FT_AX25, BASE_NONE, NULL, 0x0,
538 "Destination callsign", HFILL }
540 { &hf_netrom_ttl,
541 { "TTL", "netrom.ttl",
542 FT_UINT8, BASE_HEX, NULL, 0x0,
543 NULL, HFILL }
545 { &hf_netrom_my_cct_index,
546 { "My circuit index", "netrom.my.cct.index",
547 FT_UINT8, BASE_HEX, NULL, 0x0,
548 NULL, HFILL }
550 { &hf_netrom_my_cct_id,
551 { "My circuit ID", "netrom.my.cct.id",
552 FT_UINT8, BASE_HEX, NULL, 0x0,
553 NULL, HFILL }
555 { &hf_netrom_your_cct_index,
556 { "Your circuit index", "netrom.your.cct.index",
557 FT_UINT8, BASE_HEX, NULL, 0x0,
558 NULL, HFILL }
560 { &hf_netrom_your_cct_id,
561 { "Your circuit ID", "netrom.your.cct.id",
562 FT_UINT8, BASE_HEX, NULL, 0x0,
563 NULL, HFILL }
565 { &hf_netrom_n_r,
566 { "N(r)", "netrom.n_r",
567 FT_UINT8, BASE_DEC, NULL, 0x0,
568 NULL, HFILL }
570 { &hf_netrom_n_s,
571 { "N(s)", "netrom.n_s",
572 FT_UINT8, BASE_DEC, NULL, 0x0,
573 NULL, HFILL }
575 { &hf_netrom_type,
576 { "Type", "netrom.type",
577 FT_UINT8, BASE_HEX, NULL, 0x0,
578 "Packet type field", HFILL }
580 { &hf_netrom_op,
581 { "OP code", "netrom.op",
582 FT_UINT8, BASE_HEX, VALS( op_code_vals_abbrev ), 0x0f,
583 "Protocol operation code", HFILL }
585 { &hf_netrom_more,
586 { "More", "netrom.flag.more",
587 FT_BOOLEAN, 8, TFS(&flags_set_truth), NETROM_MORE_FLAG,
588 "More flag", HFILL }
590 { &hf_netrom_nak,
591 { "NAK", "netrom.flag.nak",
592 FT_BOOLEAN, 8, TFS(&flags_set_truth), NETROM_NAK_FLAG,
593 "NAK flag", HFILL }
595 { &hf_netrom_choke,
596 { "Choke", "netrom.flag.choke",
597 FT_BOOLEAN, 8, TFS(&flags_set_truth), NETROM_CHOKE_FLAG,
598 "Choke flag", HFILL }
600 { &hf_netrom_user,
601 { "User", "netrom.user",
602 FT_AX25, BASE_NONE, NULL, 0x0,
603 "User callsign", HFILL }
605 { &hf_netrom_node,
606 { "Node", "netrom.node",
607 FT_AX25, BASE_NONE, NULL, 0x0,
608 "Node callsign", HFILL }
610 { &hf_netrom_pwindow,
611 { "Window", "netrom.pwindow",
612 FT_UINT8, BASE_DEC, NULL, 0x0,
613 "Proposed window", HFILL }
615 { &hf_netrom_awindow,
616 { "Window", "netrom.awindow",
617 FT_UINT8, BASE_DEC, NULL, 0x0,
618 "Accepted window", HFILL }
620 { &hf_netrom_mnemonic,
621 { "Node name", "netrom.name",
622 FT_STRING, BASE_NONE, NULL, 0x0,
623 NULL, HFILL }
627 /* Setup protocol subtree array */
628 static gint *ett[] = {
629 &ett_netrom,
630 &ett_netrom_type,
633 /* Register the protocol name and description */
634 proto_netrom = proto_register_protocol( "Amateur Radio NET/ROM", "NET/ROM", "netrom" );
636 /* Required function calls to register the header fields and subtrees used */
637 proto_register_field_array( proto_netrom, hf, array_length(hf ) );
638 proto_register_subtree_array( ett, array_length( ett ) );
641 void
642 proto_reg_handoff_netrom(void)
644 dissector_add_uint( "ax25.pid", AX25_P_NETROM, create_dissector_handle( dissect_netrom, proto_netrom ) );
646 ip_handle = find_dissector( "ip" );
647 default_handle = find_dissector( "data" );