3 * Routines for Amateur Packet Radio protocol dissection
4 * Copyright 2007,2008,2009,2010,2012 R.W. Stearn <richard@rns-stearn.demon.co.uk>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 * This dissector is for APRS (Automatic Packet Reporting System)
30 * Information was drawn from:
31 * http://www.aprs.org/
33 * Inspiration on how to build the dissector drawn from
39 * with the base file built from README.developers.
50 #include <epan/packet.h>
51 #include <epan/prefs.h>
52 #include <epan/wmem/wmem.h>
54 #define AX25_ADDR_LEN 7 /* length of an AX.25 address */
57 void proto_register_aprs(void);
59 /* Initialize the protocol and registered fields */
60 static int proto_aprs
= -1;
62 /* aprs timestamp items */
63 static int hf_aprs_dhm
= -1;
64 static int hf_aprs_hms
= -1;
65 static int hf_aprs_mdhm
= -1;
66 static int hf_aprs_tz
= -1;
68 /* aprs position items */
69 /* static int hf_aprs_position = -1; */
70 static int hf_aprs_lat
= -1;
71 static int hf_aprs_long
= -1;
74 static int hf_aprs_msg
= -1;
75 static int hf_aprs_msg_rng
= -1;
76 static int hf_aprs_msg_cse
= -1;
77 static int hf_aprs_msg_spd
= -1;
78 static int hf_aprs_msg_dir
= -1;
79 static int hf_aprs_msg_brg
= -1;
80 static int hf_aprs_msg_nrq
= -1;
82 /* aprs compression type items */
83 static int hf_aprs_compression_type
= -1;
84 static int hf_aprs_ct_gps_fix
= -1;
85 static int hf_aprs_ct_nmea_src
= -1;
86 static int hf_aprs_ct_origin
= -1;
89 static int hf_aprs_msg_phg_p
= -1;
90 static int hf_aprs_msg_phg_h
= -1;
91 static int hf_aprs_msg_phg_g
= -1;
92 static int hf_aprs_msg_phg_d
= -1;
95 static int hf_aprs_msg_dfs_s
= -1;
96 static int hf_aprs_msg_dfs_h
= -1;
97 static int hf_aprs_msg_dfs_g
= -1;
98 static int hf_aprs_msg_dfs_d
= -1;
101 static int hf_aprs_weather_dir
= -1;
102 static int hf_aprs_weather_spd
= -1;
103 static int hf_aprs_weather_peak
= -1;
104 static int hf_aprs_weather_temp
= -1;
105 static int hf_aprs_weather_rain_1
= -1;
106 static int hf_aprs_weather_rain_24
= -1;
107 static int hf_aprs_weather_rain
= -1;
108 static int hf_aprs_weather_humidty
= -1;
109 static int hf_aprs_weather_press
= -1;
110 static int hf_aprs_weather_luminosity
= -1;
111 static int hf_aprs_weather_snow
= -1;
112 static int hf_aprs_weather_raw_rain
= -1;
113 static int hf_aprs_weather_software
= -1;
114 static int hf_aprs_weather_unit
= -1;
117 static int hf_aprs_msg_aod_t
= -1;
118 static int hf_aprs_msg_aod_c
= -1;
120 /* mic-e msg items */
121 static int hf_aprs_mic_e_dst
= -1;
122 static int hf_aprs_mic_e_long_d
= -1;
123 static int hf_aprs_mic_e_long_m
= -1;
124 static int hf_aprs_mic_e_long_h
= -1;
125 static int hf_aprs_mic_e_spd_sp
= -1;
126 static int hf_aprs_mic_e_spd_dc
= -1;
127 static int hf_aprs_mic_e_spd_se
= -1;
128 static int hf_aprs_mic_e_telemetry
= -1;
129 static int hf_aprs_mic_e_status
= -1;
132 static int hf_aprs_storm_dir
= -1;
133 static int hf_aprs_storm_spd
= -1;
134 static int hf_aprs_storm_type
= -1;
135 static int hf_aprs_storm_sws
= -1;
136 static int hf_aprs_storm_pwg
= -1;
137 static int hf_aprs_storm_cp
= -1;
138 static int hf_aprs_storm_rhw
= -1;
139 static int hf_aprs_storm_rtsw
= -1;
140 static int hf_aprs_storm_rwg
= -1;
142 /* aprs sundry items */
143 static int hf_aprs_dti
= -1;
144 static int hf_aprs_sym_id
= -1;
145 static int hf_aprs_sym_code
= -1;
146 static int hf_aprs_comment
= -1;
147 static int hf_aprs_storm
= -1;
149 /* aprs main catgories items */
150 static int hf_ultimeter_2000
= -1;
151 static int hf_aprs_status
= -1;
152 static int hf_aprs_object
= -1;
153 static int hf_aprs_item
= -1;
154 static int hf_aprs_query
= -1;
155 static int hf_aprs_telemetry
= -1;
156 static int hf_aprs_raw
= -1;
157 static int hf_aprs_station
= -1;
158 static int hf_aprs_message
= -1;
159 static int hf_aprs_agrelo
= -1;
160 static int hf_aprs_maidenhead
= -1;
161 static int hf_aprs_weather
= -1;
162 static int hf_aprs_invalid_test
= -1;
163 static int hf_aprs_user_defined
= -1;
164 static int hf_aprs_third_party
= -1;
165 static int hf_aprs_mic_e_0_current
= -1;
166 static int hf_aprs_mic_e_0_old
= -1;
167 static int hf_aprs_mic_e_old
= -1;
168 static int hf_aprs_mic_e_current
= -1;
169 static int hf_aprs_peet_1
= -1;
170 static int hf_aprs_peet_2
= -1;
171 static int hf_aprs_map_feature
= -1;
172 static int hf_aprs_shelter_data
= -1;
173 static int hf_aprs_space_weather
= -1;
176 /* Global preferences */
177 static gboolean gPREF_APRS_LAX
= FALSE
;
179 /* Initialize the subtree pointers */
180 static gint ett_aprs
= -1;
181 static gint ett_aprs_msg
= -1;
182 static gint ett_aprs_ct
= -1;
183 static gint ett_aprs_weather
= -1;
184 static gint ett_aprs_storm
= -1;
185 static gint ett_aprs_mic_e
= -1;
188 const value_string ctype_vals
[] = {
191 { 2, "Software (DOS/Mac/Win/+SA)" },
195 { 6, "Other tracker [tbd]" },
196 { 7, "Digipeater conversion" },
200 const value_string nmea_vals
[] = {
208 const value_string gps_vals
[] = {
215 static const value_string aprs_description
[] = {
216 { 0x1c, "Current Mic-E Data (Rev 0 beta)" },
217 { 0x1d, "Old Mic-E Data (Rev 0 beta)" },
218 { '#', "Peet Bros U-II Weather Station" },
219 { '$', "Raw GPS data or Ultimeter 2000" },
220 { '%', "Agrelo DFJr / MicroFinder" },
221 { '&', "[Reserved - Map Feature]" },
222 { '\'', "Old Mic-E Data (current data for TM-D700)" },
224 { '*', "Peet Bros U-II Weather Station" },
225 { '+', "[Reserved - Shelter data with time]" },
226 { ',', "Invalid data or test data" },
227 { '.', "[Reserved - Space weather]" },
228 { '/', "Position + timestamp" },
231 { '<', "Station Capabilities" },
232 { '=', "Position + APRS data extension" },
235 { '@', "Position + timestamp + APRS data extension" },
236 { 'T', "Telemetry data" },
237 { '[', "Maidenhead grid locator beacon (obsolete)" },
238 { '_', "Weather Report (without position)" },
239 { '`', "Current Mic-E Data (not used in TM-D700)" },
240 { '{', "User-Defined APRS packet format" },
241 { '}', "Third-party traffic" },
244 static value_string_ext aprs_description_ext
= VALUE_STRING_EXT_INIT(aprs_description
);
247 * Structure containing pointers to hf_ values for various subfields of
248 * the compression type field.
256 static const ct_items_s ct_items_gbl
= {
257 /* all items are FT_UINT8 */
259 &hf_aprs_ct_nmea_src
,
282 static const msg_items_s msg_items_gbl
= {
283 /* (All items are FT_STRING */
305 int *hf_weather_peak
;
306 int *hf_weather_temp
;
307 int *hf_weather_rain_1
;
308 int *hf_weather_rain_24
;
309 int *hf_weather_rain
;
310 int *hf_weather_humidty
;
311 int *hf_weather_press
;
312 int *hf_weather_luminosity
;
313 int *hf_weather_snow
;
314 int *hf_weather_raw_rain
;
315 int *hf_weather_software
;
316 int *hf_weather_unit
;
319 static const weather_items_s weather_items_gbl
= {
320 /* (All items are FT_STRING */
321 &hf_aprs_weather_dir
,
322 &hf_aprs_weather_spd
,
323 &hf_aprs_weather_peak
,
324 &hf_aprs_weather_temp
,
325 &hf_aprs_weather_rain_1
,
326 &hf_aprs_weather_rain_24
,
327 &hf_aprs_weather_rain
,
328 &hf_aprs_weather_humidty
,
329 &hf_aprs_weather_press
,
330 &hf_aprs_weather_luminosity
,
331 &hf_aprs_weather_snow
,
332 &hf_aprs_weather_raw_rain
,
333 &hf_aprs_weather_software
,
334 &hf_aprs_weather_unit
339 int *hf_mic_e_long_d
;
340 int *hf_mic_e_long_m
;
341 int *hf_mic_e_long_h
;
342 int *hf_mic_e_spd_sp
;
343 int *hf_mic_e_spd_dc
;
344 int *hf_mic_e_spd_se
;
345 int *hf_mic_e_sym_code
;
346 int *hf_mic_e_sym_id
;
347 int *hf_mic_e_telemetry
;
348 int *hf_mic_e_status
;
351 static const mic_e_items_s mic_e_items_gbl
= {
352 &hf_aprs_mic_e_dst
, /* FT_STRING */
353 &hf_aprs_mic_e_long_d
, /* FT_GUINT8 */
354 &hf_aprs_mic_e_long_m
, /* FT_GUINT8 */
355 &hf_aprs_mic_e_long_h
, /* FT_GUINT8 */
356 &hf_aprs_mic_e_spd_sp
, /* FT_GUINT8 */
357 &hf_aprs_mic_e_spd_dc
, /* FT_GUINT8 */
358 &hf_aprs_mic_e_spd_se
, /* FT_GUINT8 */
359 &hf_aprs_sym_code
, /* FT_STRING */
360 &hf_aprs_sym_id
, /* FT_STRING */
361 &hf_aprs_mic_e_telemetry
, /* FT_BYTES */
362 &hf_aprs_mic_e_status
/* FT_STRING */
366 int *hf_aprs_storm_dir
;
367 int *hf_aprs_storm_spd
;
368 int *hf_aprs_storm_type
;
369 int *hf_aprs_storm_sws
;
370 int *hf_aprs_storm_pwg
;
371 int *hf_aprs_storm_cp
;
372 int *hf_aprs_storm_rhw
;
373 int *hf_aprs_storm_rtsw
;
374 int *hf_aprs_storm_rwg
;
377 /*** XXX: hf[] entries for the following are missing ***/
378 static const storm_items_s storm_items_gbl
= {
390 /* MIC-E destination field code table */
399 } mic_e_dst_code_table_s
;
401 static const mic_e_dst_code_table_s dst_code
[] =
403 { '0' << 1, '0', 0, 'S', 0, 'E' },
404 { '1' << 1, '1', 0, 'S', 0, 'E' },
405 { '2' << 1, '2', 0, 'S', 0, 'E' },
406 { '3' << 1, '3', 0, 'S', 0, 'E' },
407 { '4' << 1, '4', 0, 'S', 0, 'E' },
408 { '5' << 1, '5', 0, 'S', 0, 'E' },
409 { '6' << 1, '6', 0, 'S', 0, 'E' },
410 { '7' << 1, '7', 0, 'S', 0, 'E' },
411 { '8' << 1, '8', 0, 'S', 0, 'E' },
412 { '9' << 1, '9', 0, 'S', 0, 'E' },
413 { 'A' << 1, '0', 1, '?', 0, '?' },
414 { 'B' << 1, '1', 1, '?', 0, '?' },
415 { 'C' << 1, '2', 1, '?', 0, '?' },
416 { 'D' << 1, '3', 1, '?', 0, '?' },
417 { 'E' << 1, '4', 1, '?', 0, '?' },
418 { 'F' << 1, '5', 1, '?', 0, '?' },
419 { 'G' << 1, '6', 1, '?', 0, '?' },
420 { 'H' << 1, '7', 1, '?', 0, '?' },
421 { 'I' << 1, '8', 1, '?', 0, '?' },
422 { 'J' << 1, '9', 1, '?', 0, '?' },
423 { 'K' << 1, ' ', 1, '?', 0, '?' },
424 { 'L' << 1, ' ', 0, 'S', 0, 'E' },
425 { 'P' << 1, '0', 1, 'N', 100, 'W' },
426 { 'Q' << 1, '1', 1, 'N', 100, 'W' },
427 { 'R' << 1, '2', 1, 'N', 100, 'W' },
428 { 'S' << 1, '3', 1, 'N', 100, 'W' },
429 { 'T' << 1, '4', 1, 'N', 100, 'W' },
430 { 'U' << 1, '5', 1, 'N', 100, 'W' },
431 { 'V' << 1, '6', 1, 'N', 100, 'W' },
432 { 'W' << 1, '7', 1, 'N', 100, 'W' },
433 { 'X' << 1, '8', 1, 'N', 100, 'W' },
434 { 'Y' << 1, '9', 1, 'N', 100, 'W' },
435 { 'Z' << 1, ' ', 1, 'N', 100, 'W' },
436 { 0, '_', 3, '?', 3, '?' },
440 /* MIC-E message table */
447 static const mic_e_msg_table_s mic_e_msg_table
[] =
449 { "Emergency", "Emergency" },
450 { "Priority", "Custom 6" },
451 { "Special", "Custom 5" },
452 { "Committed", "Custom 4" },
453 { "Returning", "Custom 3" },
454 { "In Service", "Custom 2" },
455 { "En Route", "Custom 1" },
456 { "Off Duty", "Custom 0" }
459 /* Code to actually dissect the packets */
462 dissect_aprs_compression_type( tvbuff_t
*tvb
,
464 proto_tree
*parent_tree
,
467 const ct_items_s
*ct_items
471 proto_tree
*compression_tree
;
474 guint8 compression_type
;
478 new_offset
= offset
+ data_len
;
482 compression_type
= tvb_get_guint8( tvb
, offset
) - 33;
484 tc
= proto_tree_add_uint( parent_tree
, hf_aprs_ctype
, tvb
, offset
, data_len
,
486 compression_tree
= proto_item_add_subtree( tc
, ett_aprs_ctype
);
488 proto_tree_add_item( compression_tree
, *ct_items
->hf_ct_gps_fix
, tvb
, offset
, data_len
, ENC_BIG_ENDIAN
);
489 proto_tree_add_item( compression_tree
, *ct_items
->hf_ct_nmea_src
, tvb
, offset
, data_len
, ENC_BIG_ENDIAN
);
490 proto_tree_add_item( compression_tree
, *ct_items
->hf_ct_origin
, tvb
, offset
, data_len
, ENC_BIG_ENDIAN
);
497 dissect_aprs_msg( tvbuff_t
*tvb
,
499 proto_tree
*parent_tree
,
501 gint ett_aprs_msg_idx
,
502 const msg_items_s
*msg_items
, /* Assumption: all referenced hf[] entries are FT_STRING */
507 proto_tree
*msg_tree
= NULL
;
514 tc
= proto_tree_add_item( parent_tree
, hf_aprs_msg_idx
, tvb
, offset
, 7, ENC_ASCII
|ENC_NA
);
515 msg_tree
= proto_item_add_subtree( tc
, ett_aprs_msg_idx
);
518 ch
= tvb_get_guint8( tvb
, offset
);
523 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_dir
, tvb
, offset
, 3, ENC_ASCII
|ENC_NA
);
525 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_cse
, tvb
, offset
, 3, ENC_ASCII
|ENC_NA
);
527 /* verify the separator */
529 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_spd
, tvb
, offset
, 3, ENC_ASCII
|ENC_NA
);
538 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_dfs_p
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
540 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_dfs_h
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
542 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_dfs_g
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
544 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_dfs_d
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
546 case 'P' : /* phgd */
548 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_phg_p
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
550 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_phg_h
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
552 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_phg_g
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
554 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_phg_d
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
557 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_rng
, tvb
, offset
, 7, ENC_ASCII
|ENC_NA
);
561 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_aod_t
, tvb
, offset
, 2, ENC_ASCII
|ENC_NA
);
563 /* step over the /C */
565 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_aod_c
, tvb
, offset
, 2, ENC_ASCII
|ENC_NA
);
573 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_brg
, tvb
, offset
, 3, ENC_ASCII
|ENC_NA
);
575 /* verify the separator */
577 proto_tree_add_item( msg_tree
, *msg_items
->hf_msg_nrq
, tvb
, offset
, 3, ENC_ASCII
|ENC_NA
);
585 dissect_aprs_compressed_msg( tvbuff_t
*tvb
,
587 proto_tree
*parent_tree
,
589 gint ett_aprs_msg_idx
,
590 const msg_items_s
*msg_items
594 proto_tree
*msg_tree
;
605 new_offset
= offset
+ data_len
;
609 tc
= proto_tree_add_item( parent_tree
, hf_msg_type_idx
, tvb
, offset
, data_len
, ENC_ASCII
|ENC_NA
);
610 msg_tree
= proto_item_add_subtree( tc
, ett_aprs_msg_idx
);
612 ch
= tvb_get_guint8( tvb
, offset
);
616 { /* Pre-Calculated Radio Range */
618 ch
= tvb_get_guint8( tvb
, offset
);
619 range
= exp( log( 1.08 ) * (ch
- 33) );
620 info_buffer
= wmem_strdup_printf( wmem_packet_scope(), "%7.2f", range
);
621 proto_tree_add_string( msg_tree
, *msg_items
->hf_msg_rng
, tvb
, offset
, 1, info_buffer
);
624 if ( ch
>= '!' && ch
<= 'z' )
626 course
= (ch
- 33) * 4;
627 info_buffer
= wmem_strdup_printf( wmem_packet_scope(), "%d", course
);
628 proto_tree_add_string( msg_tree
, *msg_items
->hf_msg_cse
,
629 tvb
, offset
, 1, info_buffer
);
631 ch
= tvb_get_guint8( tvb
, offset
);
632 speed
= exp( log( 1.08 ) * (ch
- 33) );
633 info_buffer
= wmem_strdup_printf( wmem_packet_scope(), "%7.2f", speed
);
634 proto_tree_add_string( msg_tree
, *msg_items
->hf_msg_spd
,
635 tvb
, offset
, 1, info_buffer
);
645 static const mic_e_dst_code_table_s
*
646 dst_code_lookup( guint8 ch
)
651 while ( indx
< ( sizeof( dst_code
) / sizeof( mic_e_dst_code_table_s
) )
652 && dst_code
[ indx
].key
!= ch
653 && dst_code
[ indx
].key
> 0 )
655 return &( dst_code
[ indx
] );
659 d28_to_deg( guint8 code
, int long_offset
)
663 value
= code
- 28 + long_offset
;
664 if ( value
>= 180 && value
<= 189 )
667 if ( value
>= 190 && value
<= 199 )
673 d28_to_min( guint8 code
)
684 dissect_mic_e( tvbuff_t
*tvb
,
687 proto_tree
*parent_tree
,
690 const mic_e_items_s
*mic_e_items
694 proto_tree
*mic_e_tree
;
698 char latitude
[7] = { '?', '?', '?', '?', '.', '?', '?' };
708 const mic_e_dst_code_table_s
*dst_code_entry
;
710 data_len
= tvb_length_remaining( tvb
, offset
);
711 new_offset
= offset
+ data_len
;
713 info_buffer
= (char *)wmem_alloc( wmem_packet_scope(), STRLEN
);
724 if ( pinfo
->dst
.type
== AT_AX25
&& pinfo
->dst
.len
== AX25_ADDR_LEN
)
726 /* decode the AX.25 destination address */
727 dst_code_entry
= dst_code_lookup( ((guint8
*)pinfo
->dst
.data
)[ 0 ] );
728 latitude
[ 0 ] = dst_code_entry
->digit
;
729 msg_a
= dst_code_entry
->msg
& 0x1;
731 dst_code_entry
= dst_code_lookup( ((guint8
*)pinfo
->dst
.data
)[ 1 ] );
732 latitude
[ 1 ] = dst_code_entry
->digit
;
733 msg_b
= dst_code_entry
->msg
& 0x1;
735 dst_code_entry
= dst_code_lookup( ((guint8
*)pinfo
->dst
.data
)[ 2 ] );
736 latitude
[ 2 ] = dst_code_entry
->digit
;
737 msg_c
= dst_code_entry
->msg
& 0x1;
739 dst_code_entry
= dst_code_lookup( ((guint8
*)pinfo
->dst
.data
)[ 3 ] );
740 latitude
[ 3 ] = dst_code_entry
->digit
;
741 n_s
= dst_code_entry
->n_s
;
745 dst_code_entry
= dst_code_lookup( ((guint8
*)pinfo
->dst
.data
)[ 4 ] );
746 latitude
[ 5 ] = dst_code_entry
->digit
;
747 long_offset
= dst_code_entry
->long_offset
;
749 dst_code_entry
= dst_code_lookup( ((guint8
*)pinfo
->dst
.data
)[ 5 ] );
750 latitude
[ 6 ] = dst_code_entry
->digit
;
751 w_e
= dst_code_entry
->w_e
;
753 ssid
= (((guint8
*)pinfo
->dst
.data
)[ 6 ] >> 1) & 0x0f;
756 /* decode the mic-e info fields */
757 spd
= ((tvb_get_guint8( tvb
, offset
+ 3 ) - 28) * 10) + ((tvb_get_guint8( tvb
, offset
+ 4 ) - 28) / 10);
761 cse
= (((tvb_get_guint8( tvb
, offset
+ 4 ) - 28) % 10) * 100) + ((tvb_get_guint8( tvb
, offset
+ 5 ) - 28) * 10);
765 g_snprintf( info_buffer
, STRLEN
,
766 "Lat: %7.7s%c Long: %03d%02d.%02d%c, Cse: %d, Spd: %d, SSID: %d, Msg %s",
769 d28_to_deg( tvb_get_guint8( tvb
, offset
), long_offset
),
770 d28_to_min( tvb_get_guint8( tvb
, offset
+ 1 ) ),
771 tvb_get_guint8( tvb
, offset
+ 2 ) - 28,
776 mic_e_msg_table
[ (msg_a
<< 2) + (msg_b
<< 1) + msg_c
].std
779 col_set_str( pinfo
->cinfo
, COL_INFO
, "MIC-E " );
780 col_append_str( pinfo
->cinfo
, COL_INFO
, info_buffer
);
784 tc
= proto_tree_add_string( parent_tree
, hf_mic_e_idx
, tvb
, offset
, data_len
, info_buffer
);
785 mic_e_tree
= proto_item_add_subtree( tc
, ett_mic_e_idx
);
787 g_snprintf( info_buffer
, STRLEN
,
788 "Lat %7.7s, Msg A %d, Msg B %d, Msg C %d, N/S %c, Long off %3d, W/E %c, SSID %d",
799 proto_tree_add_string( mic_e_tree
, *mic_e_items
->hf_mic_e_dst
, tvb
, 0, 0, info_buffer
); /* ?? */
801 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_long_d
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
804 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_long_m
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
807 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_long_h
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
810 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_spd_sp
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
813 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_spd_dc
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
816 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_spd_se
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
819 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_sym_code
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
822 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_sym_id
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
825 if ( offset
< new_offset
)
827 guint8 c
= tvb_get_guint8(tvb
, offset
);
828 if ( (c
== ',') || (c
== 0x1d) )
829 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_telemetry
,
830 tvb
, offset
, -1, ENC_NA
);
832 proto_tree_add_item( mic_e_tree
, *mic_e_items
->hf_mic_e_status
,
833 tvb
, offset
, -1, ENC_ASCII
|ENC_NA
);
842 dissect_aprs_storm( tvbuff_t
*tvb
,
844 proto_tree
*parent_tree
,
845 int hf_aprs_storm_idx
,
846 gint ett_aprs_storm_idx
,
847 const storm_items_s
*storm_items
850 proto_tree
*storm_tree
= NULL
;
857 static const char *storm_format
= " (%*.*s)";
859 data_len
= tvb_length_remaining( tvb
, offset
);
860 info_buffer
= (char *)wmem_alloc( wmem_packet_scope(), STRLEN
);
861 g_snprintf( info_buffer
, STRLEN
, storm_format
, data_len
, data_len
, tvb_get_ptr( tvb
, offset
, data_len
) );
862 tc
= proto_tree_add_string( parent_tree
, hf_aprs_storm_idx
, tvb
, offset
, data_len
, info_buffer
);
863 storm_tree
= proto_item_add_subtree( tc
, ett_aprs_storm_idx
);
865 proto_tree_add_item( storm_tree
, *storm_items
->hf_aprs_storm_dir
, tvb
, offset
, 3, ENC_BIG_ENDIAN
);
868 proto_tree_add_item( storm_tree
, *storm_items
->hf_aprs_storm_spd
, tvb
, offset
, 3, ENC_BIG_ENDIAN
);
870 proto_tree_add_item( storm_tree
, *storm_items
->hf_aprs_storm_type
, tvb
, offset
, 3, ENC_BIG_ENDIAN
);
872 proto_tree_add_item( storm_tree
, *storm_items
->hf_aprs_storm_sws
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
874 proto_tree_add_item( storm_tree
, *storm_items
->hf_aprs_storm_pwg
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
876 proto_tree_add_item( storm_tree
, *storm_items
->hf_aprs_storm_cp
, tvb
, offset
, 5, ENC_BIG_ENDIAN
);
878 proto_tree_add_item( storm_tree
, *storm_items
->hf_aprs_storm_rhw
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
880 proto_tree_add_item( storm_tree
, *storm_items
->hf_aprs_storm_rtsw
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
882 proto_tree_add_item( storm_tree
, *storm_items
->hf_aprs_storm_rwg
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
889 dissect_aprs_weather( tvbuff_t
*tvb
,
891 proto_tree
*parent_tree
,
892 int hf_aprs_weather_idx
,
893 gint ett_aprs_weather_idx
,
894 const weather_items_s
*weather_items
898 proto_tree
*weather_tree
;
902 static const char *weather_format
= " (%*.*s)";
906 data_len
= tvb_length_remaining( tvb
, offset
);
907 new_offset
= offset
+ data_len
;
909 info_buffer
= (char *)wmem_alloc( wmem_packet_scope(), STRLEN
);
910 g_snprintf( info_buffer
, STRLEN
, weather_format
, data_len
, data_len
, tvb_get_ptr( tvb
, offset
, data_len
) );
912 tc
= proto_tree_add_string( parent_tree
, hf_aprs_weather_idx
, tvb
, offset
, data_len
, info_buffer
);
913 weather_tree
= proto_item_add_subtree( tc
, ett_aprs_weather_idx
);
915 ch
= tvb_get_guint8( tvb
, offset
);
918 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_dir
, tvb
, offset
, 3, ENC_ASCII
|ENC_NA
);
920 /* verify the separator */
922 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_spd
, tvb
, offset
, 3, ENC_ASCII
|ENC_NA
);
928 while ( offset
< new_offset
)
930 ch
= tvb_get_guint8( tvb
, offset
);
934 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_dir
,
935 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
939 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_spd
,
940 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
944 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_peak
,
945 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
949 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_temp
,
950 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
954 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_rain_1
,
955 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
959 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_rain_24
,
960 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
964 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_rain
,
965 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
969 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_humidty
,
970 tvb
, offset
, 3, ENC_ASCII
|ENC_NA
);
974 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_press
,
975 tvb
, offset
, 6, ENC_ASCII
|ENC_NA
);
980 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_luminosity
,
981 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
985 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_snow
,
986 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
990 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_raw_rain
,
991 tvb
, offset
, 4, ENC_ASCII
|ENC_NA
);
996 /* optional: software type/unit: see if present */
997 lr
= new_offset
- offset
;
998 #if 0 /* fcn'al change: defer */
999 if ( ((lr
< 3) || (lr
> 5)) ||
1000 ( lr
!= strspn( tvb_get_string( wmem_packet_scope(), tvb
, offset
, lr
), "a-zA-Z0-9-_" ) ) )
1002 new_offset
= offset
; /* Assume rest is a comment: force exit from while */
1003 break; /* from switch */
1006 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_software
,
1007 tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
1009 proto_tree_add_item( weather_tree
, *weather_items
->hf_weather_unit
,
1010 tvb
, offset
, lr
-1, ENC_ASCII
|ENC_NA
);
1011 offset
= new_offset
;
1016 } /* if (parent_tree) */
1021 aprs_timestamp( proto_tree
*aprs_tree
, tvbuff_t
*tvb
, int offset
)
1030 ch
= tvb_get_guint8( tvb
, offset
+ 6 );
1031 if ( isdigit( ch
) )
1033 proto_tree_add_item( aprs_tree
, hf_aprs_mdhm
, tvb
, offset
, data_len
, ENC_ASCII
|ENC_NA
);
1034 proto_tree_add_string( aprs_tree
, hf_aprs_tz
, tvb
, offset
, data_len
, tzone
);
1041 proto_tree_add_item( aprs_tree
, hf_aprs_hms
, tvb
, offset
, data_len
, ENC_ASCII
|ENC_NA
);
1042 proto_tree_add_string( aprs_tree
, hf_aprs_tz
, tvb
, offset
, data_len
, tzone
);
1048 case 'z' : tzone
= "zulu"; break;
1049 case '/' : tzone
= "local"; break;
1050 default : tzone
= "unknown"; break;
1052 proto_tree_add_item( aprs_tree
, hf_aprs_dhm
, tvb
, offset
, data_len
, ENC_ASCII
|ENC_NA
);
1053 proto_tree_add_string( aprs_tree
, hf_aprs_tz
, tvb
, offset
+ 6, 1, tzone
);
1057 return offset
+ data_len
;
1061 aprs_latitude_compressed( proto_tree
*aprs_tree
, tvbuff_t
*tvb
, int offset
)
1068 info_buffer
= (char *)wmem_alloc( wmem_packet_scope(), STRLEN
);
1070 temp
= ( tvb_get_guint8( tvb
, offset
+ 0 ) - 33 );
1071 temp
= ( tvb_get_guint8( tvb
, offset
+ 1 ) - 33 ) + ( temp
* 91 );
1072 temp
= ( tvb_get_guint8( tvb
, offset
+ 2 ) - 33 ) + ( temp
* 91 );
1073 temp
= ( tvb_get_guint8( tvb
, offset
+ 3 ) - 33 ) + ( temp
* 91 );
1075 g_snprintf( info_buffer
, STRLEN
, "%6.2f", 90.0 - (temp
/ 380926.0) );
1076 proto_tree_add_string( aprs_tree
, hf_aprs_lat
, tvb
, offset
, 4, info_buffer
);
1082 aprs_longitude_compressed( proto_tree
*aprs_tree
, tvbuff_t
*tvb
, int offset
)
1089 info_buffer
= (char *)wmem_alloc( wmem_packet_scope(), STRLEN
);
1091 temp
= ( tvb_get_guint8( tvb
, offset
+ 0 ) - 33 );
1092 temp
= ( tvb_get_guint8( tvb
, offset
+ 1 ) - 33 ) + ( temp
* 91 );
1093 temp
= ( tvb_get_guint8( tvb
, offset
+ 2 ) - 33 ) + ( temp
* 91 );
1094 temp
= ( tvb_get_guint8( tvb
, offset
+ 3 ) - 33 ) + ( temp
* 91 );
1096 g_snprintf( info_buffer
, STRLEN
, "%7.2f", (temp
/ 190463.0) - 180.0 );
1097 proto_tree_add_string( aprs_tree
, hf_aprs_long
, tvb
, offset
, 4, info_buffer
);
1103 aprs_status( proto_tree
*aprs_tree
, tvbuff_t
*tvb
, int offset
)
1107 data_len
= tvb_length_remaining( tvb
, offset
);
1109 if ( ( data_len
> 7 ) && ( tvb_get_guint8( tvb
, offset
+6 ) == 'z' ) )
1111 proto_tree_add_item( aprs_tree
, hf_aprs_dhm
, tvb
, offset
, 6, ENC_ASCII
|ENC_NA
);
1114 proto_tree_add_string( aprs_tree
, hf_aprs_tz
, tvb
, offset
, 1, "zulu" );
1118 proto_tree_add_item( aprs_tree
, hf_aprs_status
, tvb
, offset
, data_len
, ENC_ASCII
|ENC_NA
);
1120 return offset
+ data_len
;
1124 aprs_item( proto_tree
*aprs_tree
, tvbuff_t
*tvb
, int offset
)
1132 info_buffer
= tvb_get_string( wmem_packet_scope(), tvb
, offset
, data_len
);
1134 ch_ptr
= strchr( info_buffer
, '!' );
1135 if ( ch_ptr
!= NULL
)
1137 data_len
= (int)(ch_ptr
- info_buffer
+ 1);
1142 ch_ptr
= strchr( info_buffer
, '!' );
1143 if ( ch_ptr
!= NULL
)
1145 data_len
= (int)(ch_ptr
- info_buffer
+ 1);
1149 proto_tree_add_string( aprs_tree
, hf_aprs_item
, tvb
, offset
, data_len
, info_buffer
);
1151 return offset
+ data_len
;
1155 aprs_3rd_party( proto_tree
*aprs_tree
, tvbuff_t
*tvb
, int offset
, int data_len
)
1157 /* If the type of the hf[] entry pointed to by hfindex is FT_BYTES or FT_STRING */
1158 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
1159 if ( data_len
== -1 )
1161 data_len
= tvb_reported_length_remaining( tvb
, offset
);
1162 #if 0 /* fcn'al change: defer */
1163 if ( data_len
<= 0 )
1164 return offset
; /* there's no data */
1167 proto_tree_add_item( aprs_tree
, hf_aprs_third_party
, tvb
, offset
, data_len
, ENC_NA
);
1170 return offset
+ data_len
;
1174 aprs_default_string( proto_tree
*aprs_tree
, tvbuff_t
*tvb
, int offset
, int data_len
, int hfindex
)
1176 /* Assumption: hfindex points to an hf[] entry with type FT_STRING; should be validated ? */
1177 /* If the type of the hf[] entry pointed to by hfindex is FT_STRING */
1178 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
1179 if ( data_len
== -1 )
1181 data_len
= tvb_reported_length_remaining( tvb
, offset
);
1182 #if 0 /* fcn'al change: defer */
1183 if ( data_len
<= 0 )
1184 return offset
; /* there's no data */
1187 proto_tree_add_item( aprs_tree
, hfindex
, tvb
, offset
, data_len
, ENC_ASCII
|ENC_NA
);
1188 return offset
+ data_len
;
1192 aprs_default_bytes( proto_tree
*aprs_tree
, tvbuff_t
*tvb
, int offset
, int data_len
, int hfindex
)
1194 /* Assumption: hfindex points to an hf[] entry with type FT_BYTES; should be validated ? */
1195 /* If the type of the hf[] entry pointed to by hfindex is FT_BYTES */
1196 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
1197 if ( data_len
== -1 )
1199 data_len
= tvb_reported_length_remaining( tvb
, offset
);
1200 #if 0 /* fcn'al change: defer */
1201 if ( data_len
<= 0 )
1202 return offset
; /* there's no data */
1205 proto_tree_add_item( aprs_tree
, hfindex
, tvb
, offset
, data_len
, ENC_NA
);
1206 return offset
+ data_len
;
1210 aprs_position( proto_tree
*aprs_tree
, tvbuff_t
*tvb
, int offset
, gboolean with_msg
)
1212 guint8 symbol_table_id
= 0;
1213 guint8 symbol_code
= 0;
1214 gboolean probably_a_msg
= FALSE
;
1215 gboolean probably_not_a_msg
= FALSE
;
1217 if ( isdigit( tvb_get_guint8( tvb
, offset
) ) )
1219 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, 8, hf_aprs_lat
);
1220 symbol_table_id
= tvb_get_guint8( tvb
, offset
);
1221 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, 1, hf_aprs_sym_id
);
1222 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, 9, hf_aprs_long
);
1223 symbol_code
= tvb_get_guint8( tvb
, offset
);
1224 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, 1, hf_aprs_sym_code
);
1225 if ( gPREF_APRS_LAX
)
1227 switch ( tvb_get_guint8( tvb
, offset
) )
1229 case 'D' : probably_a_msg
= TRUE
; break;
1230 case 'P' : probably_a_msg
= TRUE
; break;
1231 case 'R' : probably_a_msg
= TRUE
; break;
1232 case 'T' : probably_a_msg
= TRUE
; break;
1233 default : probably_not_a_msg
= TRUE
; break;
1236 if ( with_msg
|| probably_a_msg
|| ! probably_not_a_msg
)
1237 offset
= dissect_aprs_msg( tvb
,
1243 ( symbol_code
== '_' ),
1244 ( symbol_table_id
== '/' && symbol_code
== '\\' )
1249 symbol_table_id
= tvb_get_guint8( tvb
, offset
);
1250 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, 1, hf_aprs_sym_id
);
1251 offset
= aprs_latitude_compressed( aprs_tree
, tvb
, offset
);
1252 offset
= aprs_longitude_compressed( aprs_tree
, tvb
, offset
);
1253 symbol_code
= tvb_get_guint8( tvb
, offset
);
1254 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, 1, hf_aprs_sym_code
);
1255 offset
= dissect_aprs_compressed_msg( tvb
,
1262 offset
= dissect_aprs_compression_type( tvb
,
1265 hf_aprs_compression_type
,
1269 if ( symbol_table_id
== '/' && symbol_code
== '\\' )
1270 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, 8, hf_aprs_msg_brg
);
1273 if ( symbol_code
== '_' )
1274 offset
= dissect_aprs_weather( tvb
,
1281 if ( ( symbol_table_id
== '/' && symbol_code
== '@' ) || ( symbol_table_id
== '\\' && symbol_code
== '@' ) )
1282 offset
= dissect_aprs_storm( tvb
,
1294 dissect_aprs( tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*parent_tree
, void *data _U_
)
1297 proto_tree
*aprs_tree
;
1304 col_set_str( pinfo
->cinfo
, COL_PROTOCOL
, "APRS" );
1305 col_clear( pinfo
->cinfo
, COL_INFO
);
1309 dti
= tvb_get_guint8( tvb
, offset
);
1311 sb
= wmem_strbuf_new_label(wmem_packet_scope());
1314 wmem_strbuf_append(sb
, val_to_str_ext_const(dti
, &aprs_description_ext
, ""));;
1319 /* Position or Ultimeter 2000 WX Station */
1320 if ( tvb_get_guint8( tvb
, offset
+ 1 ) == '!' )
1322 wmem_strbuf_append(sb
, "Ultimeter 2000 WX Station");
1326 /* Position "without APRS messaging" */
1327 wmem_strbuf_append(sb
, "Position");
1328 bufp
= tvb_get_ptr(tvb
, offset
+ 1, 8 + 9 + 1 + 1);
1329 wmem_strbuf_append_printf(sb
, " (%8.8s %9.9s %1.1s%1.1s)",
1331 bufp
+ 8 + 1, /* Long */
1332 bufp
+ 8, /* Symbol table id */
1333 bufp
+ 8 + 1 + 9 /* Symbol Code */
1339 /* Position "with APRS messaging" + Ext APRS message */
1340 bufp
= tvb_get_ptr(tvb
, offset
+ 1, 8 + 9 + 1 + 1);
1341 wmem_strbuf_append_printf(sb
, " (%8.8s %9.9s %1.1s%1.1s)",
1343 bufp
+ 8 + 1, /* Long */
1344 bufp
+ 8 , /* Symbol table id */
1345 bufp
+ 8 + 1 + 9 /* Symbol Code */
1350 /* Position + timestamp "without APRS messaging" */
1351 bufp
= tvb_get_ptr(tvb
, offset
+ 1, 7 + 8 + 9 + 1 + 1);
1352 wmem_strbuf_append_printf(sb
, " (%7.7s %8.8s %9.9s %1.1s%1.1s)",
1353 bufp
, /* Timestamp */
1354 bufp
+ 7 + 1, /*??*/ /* Lat */
1355 bufp
+ 7 + 8 + 1, /* Long */
1356 bufp
+ 7 , /* Symbol table id */
1357 bufp
+ 7 + 1 + 9 /* Symbol Code */
1362 /* Position + timestamp "with APRS messaging" + Ext APRS message */
1363 bufp
= tvb_get_ptr(tvb
, offset
+ 1, 7 + 8 + 9 + 1 + 1);
1364 wmem_strbuf_append_printf(sb
, " (%7.7s %8.8s %9.9s %1.1s%1.1s)",
1365 bufp
, /* Timestamp */
1366 bufp
+ 7 + 1, /*??*/ /* Lat */
1367 bufp
+ 7 + 8 + 1, /* Long */
1368 bufp
+ 7 , /* Symbol table id */
1369 bufp
+ 7 + 1 + 9 /* Symbol Code */
1374 col_add_str( pinfo
->cinfo
, COL_INFO
, wmem_strbuf_get_str(sb
) );
1376 /* create display subtree for the protocol */
1377 ti
= proto_tree_add_protocol_format( parent_tree
, proto_aprs
, tvb
, 0, -1, "%s", wmem_strbuf_get_str(sb
) );
1378 aprs_tree
= proto_item_add_subtree( ti
, ett_aprs
);
1380 proto_tree_add_item( aprs_tree
, hf_aprs_dti
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
1385 case '<' : /* Station Capabilities */
1386 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_station
);
1388 case '>' : /* Status */
1389 offset
= aprs_status( aprs_tree
, tvb
, offset
);
1391 case '?' : /* Query */
1392 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_query
);
1394 case '$' : /* Raw GPS data or Ultimeter 2000 */
1395 if ( tvb_get_guint8( tvb
, offset
) == 'U' )
1396 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_ultimeter_2000
);
1398 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_raw
);
1400 case '%' : /* Agrelo DFJr / MicroFinder */
1401 offset
= aprs_default_bytes( aprs_tree
, tvb
, offset
, -1, hf_aprs_agrelo
);
1403 case 'T' : /* Telemetry data */
1404 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_telemetry
);
1406 case '[' : /* Maidenhead grid locator beacon (obsolete) */
1407 offset
= aprs_default_bytes( aprs_tree
, tvb
, offset
, -1, hf_aprs_maidenhead
);
1409 case '_' : /* Weather Report (without position) */
1410 offset
= aprs_timestamp( aprs_tree
, tvb
, offset
);
1411 offset
= dissect_aprs_weather( tvb
,
1419 case ',' : /* Invalid data or test data */
1420 offset
= aprs_default_bytes( aprs_tree
, tvb
, offset
, -1, hf_aprs_invalid_test
);
1422 case '{' : /* User-Defined APRS packet format */
1423 offset
= aprs_default_bytes( aprs_tree
, tvb
, offset
, -1, hf_aprs_user_defined
);
1425 case '}' : /* Third-party traffic */
1426 offset
= aprs_3rd_party( aprs_tree
, tvb
, offset
, -1 );
1428 case ':' : /* Message */
1429 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_message
);
1431 case 0x1c : /* Current Mic-E Data (Rev 0 beta) */
1432 offset
= dissect_mic_e( tvb
,
1436 hf_aprs_mic_e_0_current
,
1441 case 0x1d : /* Old Mic-E Data (Rev 0 beta) */
1442 offset
= dissect_mic_e( tvb
,
1446 hf_aprs_mic_e_0_old
,
1451 case '\'' : /* Old Mic-E Data (but Current data for TM-D700) */
1452 offset
= dissect_mic_e( tvb
,
1461 case '`' : /* Current Mic-E Data (not used in TM-D700) */
1462 offset
= dissect_mic_e( tvb
,
1466 hf_aprs_mic_e_current
,
1471 case '#' : /* Peet Bros U-II Weather Station */
1472 offset
= aprs_default_bytes( aprs_tree
, tvb
, offset
, -1, hf_aprs_peet_1
);
1474 case '*' : /* Peet Bros U-II Weather Station */
1475 offset
= aprs_default_bytes( aprs_tree
, tvb
, offset
, -1, hf_aprs_peet_2
);
1477 case '&' : /* [Reserved - Map Feature] */
1478 offset
= aprs_default_bytes( aprs_tree
, tvb
, offset
, -1, hf_aprs_map_feature
);
1480 case '+' : /* [Reserved - Shelter data with time] */
1481 offset
= aprs_default_bytes( aprs_tree
, tvb
, offset
, -1, hf_aprs_shelter_data
);
1483 case '.' : /* [Reserved - Space weather] */
1484 offset
= aprs_default_bytes( aprs_tree
, tvb
, offset
, -1, hf_aprs_space_weather
);
1486 case ')' : /* Item */
1487 offset
= aprs_item( aprs_tree
, tvb
, offset
);
1488 offset
= aprs_position( aprs_tree
, tvb
, offset
, TRUE
);
1489 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_comment
);
1491 case ';' : /* Object */
1492 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, 10, hf_aprs_object
);
1493 offset
= aprs_timestamp( aprs_tree
, tvb
, offset
);
1494 offset
= aprs_position( aprs_tree
, tvb
, offset
, TRUE
);
1495 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_comment
);
1497 case '!' : /* Position or Ultimeter 2000 WX Station */
1498 if ( tvb_get_guint8( tvb
, offset
) == '!' )
1499 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_ultimeter_2000
);
1502 offset
= aprs_position( aprs_tree
, tvb
, offset
, FALSE
);
1503 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_comment
);
1506 case '=' : /* Position + Ext APRS message */
1507 offset
= aprs_position( aprs_tree
, tvb
, offset
, TRUE
);
1508 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_comment
);
1510 case '/' : /* Position + timestamp */
1511 offset
= aprs_timestamp( aprs_tree
, tvb
, offset
);
1512 offset
= aprs_position( aprs_tree
, tvb
, offset
, FALSE
);
1513 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_comment
);
1515 case '@' : /* Position + timestamp + Ext APRS message */
1516 offset
= aprs_timestamp( aprs_tree
, tvb
, offset
);
1517 offset
= aprs_position( aprs_tree
, tvb
, offset
, TRUE
);
1518 offset
= aprs_default_string( aprs_tree
, tvb
, offset
, -1, hf_aprs_comment
);
1526 proto_register_aprs( void )
1528 module_t
*aprs_module
;
1530 /* Setup list of header fields */
1531 static hf_register_info hf
[] = {
1533 { "DTI", "aprs.dti",
1534 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1535 "Data type indicator", HFILL
}
1537 { &hf_aprs_sym_code
,
1538 { "Symbol code", "aprs.sym_code",
1539 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1543 { "Symbol table ID", "aprs.sym_id",
1544 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1550 { &hf_aprs_position
,
1551 { "Position", "aprs.position",
1552 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1557 { "Latitude", "aprs.position.lat",
1558 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1562 { "Longitude", "aprs.position.long",
1563 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1569 { "Comment", "aprs.comment",
1570 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1573 { &hf_ultimeter_2000
,
1574 { "Ultimeter 2000", "aprs.ultimeter_2000",
1575 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1579 { "Status", "aprs.status",
1580 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1584 { "Object", "aprs.object",
1585 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1589 { "Item", "aprs.item",
1590 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1594 { "Query", "aprs.query",
1595 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1598 { &hf_aprs_telemetry
,
1599 { "Telemetry", "aprs.telemetry",
1600 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1604 { "Raw", "aprs.raw",
1605 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1606 "Raw NMEA position report format", HFILL
}
1609 { "Station", "aprs.station",
1610 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1611 "Station capabilities", HFILL
}
1614 { "Message", "aprs.message",
1615 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1619 { "Agrelo", "aprs.agrelo",
1620 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1621 "Agrelo DFJr / MicroFinder", HFILL
}
1623 { &hf_aprs_maidenhead
,
1624 { "Maidenhead", "aprs.maidenhead",
1625 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1626 "Maidenhead grid locator beacon (obsolete)", HFILL
}
1628 { &hf_aprs_invalid_test
,
1629 { "Invalid or test", "aprs.invalid_test",
1630 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1631 "Invalid data or test data", HFILL
}
1633 { &hf_aprs_user_defined
,
1634 { "User-Defined", "aprs.user_defined",
1635 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1636 "User-Defined APRS packet format", HFILL
}
1638 { &hf_aprs_third_party
,
1639 { "Third-party", "aprs.third_party",
1640 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1641 "Third-party traffic", HFILL
}
1644 { "Peet U-II (1)", "aprs.peet_1",
1645 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1646 "Peet Bros U-II Weather Station", HFILL
}
1649 { "Peet U-II (2)", "aprs.peet_2",
1650 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1651 "Peet Bros U-II Weather Station", HFILL
}
1653 { &hf_aprs_map_feature
,
1654 { "Map Feature", "aprs.map_feature",
1655 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1656 "[Reserved - Map Feature", HFILL
}
1658 { &hf_aprs_shelter_data
,
1659 { "Shelter data", "aprs.shelter_data",
1660 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1661 "[Reserved - Shelter data with time]", HFILL
}
1663 { &hf_aprs_space_weather
,
1664 { "Space weather", "aprs.space_weather",
1665 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1666 "[Reserved - Space weather]", HFILL
}
1669 { "Storm", "aprs.storm",
1670 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1676 { "DHM", "aprs.dhm",
1677 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1678 "Day/Hour/Minute", HFILL
}
1681 { "HMS", "aprs.hms",
1682 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1683 "Hour/Minute/Second", HFILL
}
1686 { "MDHM", "aprs.mdhm",
1687 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1688 "Month/Day/Hour/Minute", HFILL
}
1692 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1693 "Time zone", HFILL
}
1696 /* Compressed Msg */
1697 { &hf_aprs_compression_type
,
1698 { "Compression type", "aprs.ct",
1699 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1702 { &hf_aprs_ct_gps_fix
,
1703 { "GPS fix type", "aprs.ct.gps_fix",
1704 FT_UINT8
, BASE_HEX
, VALS(gps_vals
), 0x20,
1707 { &hf_aprs_ct_nmea_src
,
1708 { "NMEA source", "aprs.ct.nmea_src",
1709 FT_UINT8
, BASE_HEX
, VALS(nmea_vals
), 0x18,
1712 { &hf_aprs_ct_origin
,
1713 { "Compression origin", "aprs.ct.origin",
1714 FT_UINT8
, BASE_HEX
, VALS(ctype_vals
), 0x07,
1720 { "Extended message", "aprs.msg",
1721 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1725 { "Range", "aprs.msg.rng",
1726 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1727 "Pre-calculated radio range", HFILL
}
1730 { "Course", "aprs.msg.cse",
1731 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1735 { "Speed", "aprs.msg.spd",
1736 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1740 { "Wind direction", "aprs.msg.dir",
1741 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1745 { "Bearing", "aprs.msg.brg",
1746 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1750 { "NRQ", "aprs.msg.nrq",
1751 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1752 "Number/Range/Quality", HFILL
}
1756 { &hf_aprs_msg_phg_p
,
1757 { "Power", "aprs.msg.phg.p",
1758 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1761 { &hf_aprs_msg_phg_h
,
1762 { "Height", "aprs.msg.phg.h",
1763 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1766 { &hf_aprs_msg_phg_g
,
1767 { "Gain", "aprs.msg.phg.g",
1768 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1771 { &hf_aprs_msg_phg_d
,
1772 { "Directivity", "aprs.msg.phg.d",
1773 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1778 { &hf_aprs_msg_dfs_s
,
1779 { "Strength", "aprs.msg.dfs.s",
1780 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1783 { &hf_aprs_msg_dfs_h
,
1784 { "Height", "aprs.msg.dfs.h",
1785 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1788 { &hf_aprs_msg_dfs_g
,
1789 { "Gain", "aprs.msg.dfs.g",
1790 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1793 { &hf_aprs_msg_dfs_d
,
1794 { "Directivity", "aprs.msg.dfs.d",
1795 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1800 { &hf_aprs_msg_aod_t
,
1801 { "Type", "aprs.msg.aod.t",
1802 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1805 { &hf_aprs_msg_aod_c
,
1806 { "Colour", "aprs.msg.aod.c",
1807 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1813 { "Weather", "aprs.weather",
1814 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1815 "Weather report", HFILL
}
1817 { &hf_aprs_weather_dir
,
1818 { "Wind direction", "aprs.weather.dir",
1819 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1822 { &hf_aprs_weather_spd
,
1823 { "Wind speed", "aprs.weather.speed",
1824 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1825 "Wind speed (1 minute)", HFILL
}
1827 { &hf_aprs_weather_peak
,
1828 { "Peak wind speed", "aprs.weather.peak",
1829 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1832 { &hf_aprs_weather_temp
,
1833 { "Temperature (F)", "aprs.weather.temp",
1834 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1837 { &hf_aprs_weather_rain_1
,
1838 { "Rain (last 1 hour)", "aprs.weather.1_hour",
1839 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1842 { &hf_aprs_weather_rain_24
,
1843 { "Rain (last 24 hours)", "aprs.weather.24_hour",
1844 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1847 { &hf_aprs_weather_rain
,
1848 { "Rain", "aprs.weather.rain",
1849 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1852 { &hf_aprs_weather_humidty
,
1853 { "Humidity", "aprs.weather.humidity",
1854 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1857 { &hf_aprs_weather_press
,
1858 { "Pressure", "aprs.weather.pressure",
1859 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1862 { &hf_aprs_weather_luminosity
,
1863 { "Luminosity", "aprs.weather.luminosity",
1864 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1867 { &hf_aprs_weather_snow
,
1868 { "Snow", "aprs.weather.snow",
1869 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1872 { &hf_aprs_weather_raw_rain
,
1873 { "Raw rain", "aprs.weather.raw_rain",
1874 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1877 { &hf_aprs_weather_software
,
1878 { "Software", "aprs.weather.software",
1879 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1882 { &hf_aprs_weather_unit
,
1883 { "Unit", "aprs.weather.unit",
1884 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1889 { &hf_aprs_mic_e_0_current
,
1890 { "Current Mic-E (Rev 0)", "aprs.mic_e_0_current",
1891 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1894 { &hf_aprs_mic_e_0_old
,
1895 { "Old Mic-E (Rev 0)", "aprs.mic_e_0_old",
1896 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1899 { &hf_aprs_mic_e_old
,
1900 { "Old Mic-E", "aprs.mic_e_old",
1901 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1902 "Old Mic-E Data (but Current data for TM-D700)", HFILL
}
1904 { &hf_aprs_mic_e_current
,
1905 { "Current Mic-E", "aprs.mic_e_current",
1906 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1907 "Current Mic-E Data (not used in TM-D700)", HFILL
}
1909 { &hf_aprs_mic_e_dst
,
1910 { "Destination Address", "aprs.mic_e.dst",
1911 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1914 { &hf_aprs_mic_e_long_d
,
1915 { "Longitude degrees", "aprs.mic_e.long_d",
1916 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1919 { &hf_aprs_mic_e_long_m
,
1920 { "Longitude minutes", "aprs.mic_e.long_m",
1921 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1924 { &hf_aprs_mic_e_long_h
,
1925 { "Longitude hundreths of minutes", "aprs.mic_e.long_h",
1926 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1929 { &hf_aprs_mic_e_spd_sp
,
1930 { "Speed (H & T)", "aprs.mic_e.speed_sp",
1931 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1932 "Speed (hundreds & tens)", HFILL
}
1934 { &hf_aprs_mic_e_spd_dc
,
1935 { "Spd (U), Cse (H)", "aprs.mic_e.speed_dc",
1936 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1937 "Speed (tens), Course (hundreds)", HFILL
}
1939 { &hf_aprs_mic_e_spd_se
,
1940 { "Course (T & U)", "aprs.mic_e.speed_se",
1941 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
1942 "Course (tens & units)", HFILL
}
1944 { &hf_aprs_mic_e_telemetry
,
1945 { "Telmetry", "aprs.mic_e.telemetry",
1946 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1947 "Telemetry", HFILL
}
1949 { &hf_aprs_mic_e_status
,
1950 { "Status", "aprs.mic_e.status",
1951 FT_STRING
, BASE_NONE
, NULL
, 0x0,
1956 /* Setup protocol subtree array */
1957 static gint
*ett
[] = {
1966 /* Register the protocol name and description */
1967 proto_aprs
= proto_register_protocol("Automatic Position Reporting System", "APRS", "aprs");
1969 /* Register the dissector */
1970 new_register_dissector( "aprs", dissect_aprs
, proto_aprs
);
1972 /* Required function calls to register the header fields and subtrees used */
1973 proto_register_field_array( proto_aprs
, hf
, array_length(hf
) );
1974 proto_register_subtree_array( ett
, array_length( ett
) );
1976 /* Register preferences module */
1977 aprs_module
= prefs_register_protocol( proto_aprs
, NULL
);
1979 /* Register any preference */
1980 prefs_register_bool_preference(aprs_module
, "showaprslax",
1981 "Allow APRS violations.",
1982 "Attempt to display common APRS protocol violations correctly",