Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-aprs.c
blobebc332efb03af6937985b087a17b197784f25b90
1 /* packet-aprs.c
2 * Routines for Amateur Packet Radio protocol dissection
3 * Copyright 2007,2008,2009,2010,2012 R.W. Stearn <richard@rns-stearn.demon.co.uk>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * This dissector is for APRS (Automatic Packet Reporting System)
15 * Information was drawn from:
16 * http://www.aprs.org/
17 * Specification: http://www.aprs.org/doc/APRS101.PDF
19 * Inspiration on how to build the dissector drawn from
20 * packet-sdlc.c
21 * packet-x25.c
22 * packet-lapb.c
23 * paket-gprs-llc.c
24 * xdlc.c
25 * with the base file built from README.developers.
28 #include "config.h"
30 #include <math.h>
32 #include <epan/packet.h>
33 #include <epan/prefs.h>
34 #include <epan/to_str.h>
36 #define STRLEN 100
38 void proto_register_aprs(void);
40 static int proto_aprs;
42 /* aprs timestamp items */
43 static int hf_aprs_dhm;
44 static int hf_aprs_hms;
45 static int hf_aprs_mdhm;
46 static int hf_aprs_tz;
48 /* aprs position items */
49 /* static int hf_aprs_position; */
50 static int hf_aprs_lat;
51 static int hf_aprs_long;
53 /* aprs msg items */
54 static int hf_aprs_msg;
55 static int hf_aprs_msg_rng;
56 static int hf_aprs_msg_cse;
57 static int hf_aprs_msg_spd;
58 static int hf_aprs_msg_dir;
59 static int hf_aprs_msg_brg;
60 static int hf_aprs_msg_nrq;
62 /* aprs compression type items */
63 static int hf_aprs_compression_type;
64 static int hf_aprs_ct_gps_fix;
65 static int hf_aprs_ct_nmea_src;
66 static int hf_aprs_ct_origin;
68 /* phg msg items */
69 static int hf_aprs_msg_phg_p;
70 static int hf_aprs_msg_phg_h;
71 static int hf_aprs_msg_phg_g;
72 static int hf_aprs_msg_phg_d;
74 /* dfs msg items */
75 static int hf_aprs_msg_dfs_s;
76 static int hf_aprs_msg_dfs_h;
77 static int hf_aprs_msg_dfs_g;
78 static int hf_aprs_msg_dfs_d;
80 /* weather items */
81 static int hf_aprs_weather_dir;
82 static int hf_aprs_weather_spd;
83 static int hf_aprs_weather_peak;
84 static int hf_aprs_weather_temp;
85 static int hf_aprs_weather_rain_1;
86 static int hf_aprs_weather_rain_24;
87 static int hf_aprs_weather_rain;
88 static int hf_aprs_weather_humidty;
89 static int hf_aprs_weather_press;
90 static int hf_aprs_weather_luminosity;
91 static int hf_aprs_weather_snow;
92 static int hf_aprs_weather_raw_rain;
93 static int hf_aprs_weather_software;
94 static int hf_aprs_weather_unit;
96 /* aod msg items */
97 static int hf_aprs_msg_aod_t;
98 static int hf_aprs_msg_aod_c;
100 /* mic-e msg items */
101 static int hf_aprs_mic_e_dst;
102 static int hf_aprs_mic_e_long_d;
103 static int hf_aprs_mic_e_long_m;
104 static int hf_aprs_mic_e_long_h;
105 static int hf_aprs_mic_e_spd_sp;
106 static int hf_aprs_mic_e_spd_dc;
107 static int hf_aprs_mic_e_spd_se;
108 static int hf_aprs_mic_e_telemetry;
109 static int hf_aprs_mic_e_status;
111 /* Storm items */
112 static int hf_aprs_storm_dir;
113 static int hf_aprs_storm_spd;
114 static int hf_aprs_storm_type;
115 static int hf_aprs_storm_sws;
116 static int hf_aprs_storm_pwg;
117 static int hf_aprs_storm_cp;
118 static int hf_aprs_storm_rhw;
119 static int hf_aprs_storm_rtsw;
120 static int hf_aprs_storm_rwg;
122 /* aprs sundry items */
123 static int hf_aprs_dti;
124 static int hf_aprs_sym_id;
125 static int hf_aprs_sym_code;
126 static int hf_aprs_comment;
127 static int hf_aprs_storm;
129 /* aprs main catagories items */
130 static int hf_ultimeter_2000;
131 static int hf_aprs_status;
132 static int hf_aprs_object;
133 static int hf_aprs_item;
134 static int hf_aprs_query;
135 static int hf_aprs_telemetry;
136 static int hf_aprs_raw;
137 static int hf_aprs_station;
138 static int hf_aprs_message;
139 static int hf_aprs_agrelo;
140 static int hf_aprs_maidenhead;
141 static int hf_aprs_weather;
142 static int hf_aprs_invalid_test;
143 static int hf_aprs_user_defined;
144 static int hf_aprs_third_party;
145 static int hf_aprs_mic_e_0_current;
146 static int hf_aprs_mic_e_0_old;
147 static int hf_aprs_mic_e_old;
148 static int hf_aprs_mic_e_current;
149 static int hf_aprs_peet_1;
150 static int hf_aprs_peet_2;
151 static int hf_aprs_map_feature;
152 static int hf_aprs_shelter_data;
153 static int hf_aprs_space_weather;
156 static bool gPREF_APRS_LAX;
158 static int ett_aprs;
159 static int ett_aprs_msg;
160 static int ett_aprs_ct;
161 static int ett_aprs_weather;
162 static int ett_aprs_storm;
163 static int ett_aprs_mic_e;
166 static const value_string ctype_vals[] = {
167 { 0, "Compressed" },
168 { 1, "TNC BText" },
169 { 2, "Software (DOS/Mac/Win/+SA)" },
170 { 3, "[tbd]" },
171 { 4, "KPC3" },
172 { 5, "Pico" },
173 { 6, "Other tracker [tbd]" },
174 { 7, "Digipeater conversion" },
175 { 0, NULL }
178 static const value_string nmea_vals[] = {
179 { 0, "other" },
180 { 1, "GLL" },
181 { 2, "GGA" },
182 { 3, "RMC" },
183 { 0, NULL }
186 static const value_string gps_vals[] = {
187 { 0, "old (last)" },
188 { 1, "current" },
189 { 0, NULL }
192 /* sorted */
193 static const value_string aprs_description[] = {
194 { 0x1c, "Current Mic-E Data (Rev 0 beta)" },
195 { 0x1d, "Old Mic-E Data (Rev 0 beta)" },
196 { '#', "Peet Bros U-II Weather Station" },
197 { '$', "Raw GPS data or Ultimeter 2000" },
198 { '%', "Agrelo DFJr / MicroFinder" },
199 { '&', "[Reserved - Map Feature]" },
200 { '\'', "Old Mic-E Data (current data for TM-D700)" },
201 { ')', "Item" },
202 { '*', "Peet Bros U-II Weather Station" },
203 { '+', "[Reserved - Shelter data with time]" },
204 { ',', "Invalid data or test data" },
205 { '.', "[Reserved - Space weather]" },
206 { '/', "Position + timestamp" },
207 { ':', "Message" },
208 { ';', "Object" },
209 { '<', "Station Capabilities" },
210 { '=', "Position + APRS data extension" },
211 { '>', "Status" },
212 { '?', "Query" },
213 { '@', "Position + timestamp + APRS data extension" },
214 { 'T', "Telemetry data" },
215 { '[', "Maidenhead grid locator beacon (obsolete)" },
216 { '_', "Weather Report (without position)" },
217 { '`', "Current Mic-E Data (not used in TM-D700)" },
218 { '{', "User-Defined APRS packet format" },
219 { '}', "Third-party traffic" },
220 { 0, NULL }
222 static value_string_ext aprs_description_ext = VALUE_STRING_EXT_INIT(aprs_description);
224 /* MIC-E destination field code table */
225 typedef struct
227 uint8_t key;
228 char digit;
229 int msg;
230 char n_s;
231 int long_offset;
232 char w_e;
233 } mic_e_dst_code_table_s;
235 static const mic_e_dst_code_table_s dst_code[] =
237 { '0' << 1, '0', 0, 'S', 0, 'E' },
238 { '1' << 1, '1', 0, 'S', 0, 'E' },
239 { '2' << 1, '2', 0, 'S', 0, 'E' },
240 { '3' << 1, '3', 0, 'S', 0, 'E' },
241 { '4' << 1, '4', 0, 'S', 0, 'E' },
242 { '5' << 1, '5', 0, 'S', 0, 'E' },
243 { '6' << 1, '6', 0, 'S', 0, 'E' },
244 { '7' << 1, '7', 0, 'S', 0, 'E' },
245 { '8' << 1, '8', 0, 'S', 0, 'E' },
246 { '9' << 1, '9', 0, 'S', 0, 'E' },
247 { 'A' << 1, '0', 1, '?', 0, '?' },
248 { 'B' << 1, '1', 1, '?', 0, '?' },
249 { 'C' << 1, '2', 1, '?', 0, '?' },
250 { 'D' << 1, '3', 1, '?', 0, '?' },
251 { 'E' << 1, '4', 1, '?', 0, '?' },
252 { 'F' << 1, '5', 1, '?', 0, '?' },
253 { 'G' << 1, '6', 1, '?', 0, '?' },
254 { 'H' << 1, '7', 1, '?', 0, '?' },
255 { 'I' << 1, '8', 1, '?', 0, '?' },
256 { 'J' << 1, '9', 1, '?', 0, '?' },
257 { 'K' << 1, ' ', 1, '?', 0, '?' },
258 { 'L' << 1, ' ', 0, 'S', 0, 'E' },
259 { 'P' << 1, '0', 1, 'N', 100, 'W' },
260 { 'Q' << 1, '1', 1, 'N', 100, 'W' },
261 { 'R' << 1, '2', 1, 'N', 100, 'W' },
262 { 'S' << 1, '3', 1, 'N', 100, 'W' },
263 { 'T' << 1, '4', 1, 'N', 100, 'W' },
264 { 'U' << 1, '5', 1, 'N', 100, 'W' },
265 { 'V' << 1, '6', 1, 'N', 100, 'W' },
266 { 'W' << 1, '7', 1, 'N', 100, 'W' },
267 { 'X' << 1, '8', 1, 'N', 100, 'W' },
268 { 'Y' << 1, '9', 1, 'N', 100, 'W' },
269 { 'Z' << 1, ' ', 1, 'N', 100, 'W' },
270 { 0, '_', 3, '?', 3, '?' },
274 /* MIC-E message table */
275 typedef struct
277 const char *std;
278 const char *custom;
279 } mic_e_msg_table_s;
281 static const mic_e_msg_table_s mic_e_msg_table[] =
283 { "Emergency", "Emergency" },
284 { "Priority", "Custom 6" },
285 { "Special", "Custom 5" },
286 { "Committed", "Custom 4" },
287 { "Returning", "Custom 3" },
288 { "In Service", "Custom 2" },
289 { "En Route", "Custom 1" },
290 { "Off Duty", "Custom 0" }
293 /* Code to actually dissect the packets */
295 static int
296 dissect_aprs_compression_type( tvbuff_t *tvb,
297 int offset,
298 proto_tree *parent_tree
301 proto_tree *tc;
302 proto_tree *compression_tree;
303 int new_offset;
304 int data_len;
305 uint8_t compression_type;
308 data_len = 1;
309 new_offset = offset + data_len;
311 if ( parent_tree )
313 compression_type = tvb_get_uint8( tvb, offset ) - 33;
315 tc = proto_tree_add_uint( parent_tree, hf_aprs_compression_type, tvb, offset, data_len,
316 compression_type );
317 compression_tree = proto_item_add_subtree( tc, ett_aprs_ct );
319 proto_tree_add_item( compression_tree, hf_aprs_ct_gps_fix, tvb, offset, data_len, ENC_BIG_ENDIAN );
320 proto_tree_add_item( compression_tree, hf_aprs_ct_nmea_src, tvb, offset, data_len, ENC_BIG_ENDIAN );
321 proto_tree_add_item( compression_tree, hf_aprs_ct_origin, tvb, offset, data_len, ENC_BIG_ENDIAN );
324 return new_offset;
327 static int
328 dissect_aprs_msg( tvbuff_t *tvb,
329 int offset,
330 proto_tree *parent_tree,
331 int wind,
332 int brg_nrq
335 proto_tree *msg_tree = NULL;
336 uint8_t ch;
339 if ( parent_tree )
341 proto_tree *tc;
342 tc = proto_tree_add_item( parent_tree, hf_aprs_msg, tvb, offset, 7, ENC_ASCII );
343 msg_tree = proto_item_add_subtree( tc, ett_aprs_msg );
346 ch = tvb_get_uint8( tvb, offset );
348 if ( g_ascii_isdigit( ch ) )
350 if ( wind )
351 proto_tree_add_item( msg_tree, hf_aprs_msg_dir, tvb, offset, 3, ENC_ASCII );
352 else
353 proto_tree_add_item( msg_tree, hf_aprs_msg_cse, tvb, offset, 3, ENC_ASCII );
354 offset += 3;
355 /* verify the separator */
356 offset += 1;
357 proto_tree_add_item( msg_tree, hf_aprs_msg_spd, tvb, offset, 3, ENC_ASCII );
358 offset += 3;
360 else
362 switch ( ch )
364 case 'D' : /* dfs */
365 offset += 3;
366 proto_tree_add_item( msg_tree, hf_aprs_msg_dfs_s, tvb, offset, 1, ENC_ASCII );
367 offset += 1;
368 proto_tree_add_item( msg_tree, hf_aprs_msg_dfs_h, tvb, offset, 1, ENC_ASCII );
369 offset += 1;
370 proto_tree_add_item( msg_tree, hf_aprs_msg_dfs_g, tvb, offset, 1, ENC_ASCII );
371 offset += 1;
372 proto_tree_add_item( msg_tree, hf_aprs_msg_dfs_d, tvb, offset, 1, ENC_ASCII );
373 break;
374 case 'P' : /* phgd */
375 offset += 3;
376 proto_tree_add_item( msg_tree, hf_aprs_msg_phg_p, tvb, offset, 1, ENC_ASCII );
377 offset += 1;
378 proto_tree_add_item( msg_tree, hf_aprs_msg_phg_h, tvb, offset, 1, ENC_ASCII );
379 offset += 1;
380 proto_tree_add_item( msg_tree, hf_aprs_msg_phg_g, tvb, offset, 1, ENC_ASCII );
381 offset += 1;
382 proto_tree_add_item( msg_tree, hf_aprs_msg_phg_d, tvb, offset, 1, ENC_ASCII );
383 break;
384 case 'R' : /* rng */
385 proto_tree_add_item( msg_tree, hf_aprs_msg_rng, tvb, offset, 7, ENC_ASCII );
386 break;
387 case 'T' : /* aod */
388 offset += 1;
389 proto_tree_add_item( msg_tree, hf_aprs_msg_aod_t, tvb, offset, 2, ENC_ASCII );
390 offset += 2;
391 /* step over the /C */
392 offset += 2;
393 proto_tree_add_item( msg_tree, hf_aprs_msg_aod_c, tvb, offset, 2, ENC_ASCII );
394 break;
395 default : /* wtf */
396 break;
399 if ( brg_nrq )
401 proto_tree_add_item( msg_tree, hf_aprs_msg_brg, tvb, offset, 3, ENC_ASCII );
402 offset += 3;
403 /* verify the separator */
404 offset += 1;
405 proto_tree_add_item( msg_tree, hf_aprs_msg_nrq, tvb, offset, 3, ENC_ASCII );
406 offset += 3;
409 return offset;
412 static int
413 dissect_aprs_compressed_msg( wmem_allocator_t *scope,
414 tvbuff_t *tvb,
415 int offset,
416 proto_tree *parent_tree
419 proto_tree *tc;
420 proto_tree *msg_tree;
421 int new_offset;
422 int data_len;
423 uint8_t ch;
424 uint8_t course;
425 double speed;
426 double range;
427 char *info_buffer;
430 data_len = 2;
431 new_offset = offset + data_len;
433 if ( parent_tree )
435 tc = proto_tree_add_item( parent_tree, hf_aprs_msg, tvb, offset, data_len, ENC_ASCII );
436 msg_tree = proto_item_add_subtree( tc, ett_aprs_msg );
438 ch = tvb_get_uint8( tvb, offset );
439 if ( ch != ' ' )
441 if ( ch == '{' )
442 { /* Pre-Calculated Radio Range */
443 offset += 1;
444 ch = tvb_get_uint8( tvb, offset );
445 range = exp( log( 1.08 ) * (ch - 33) );
446 info_buffer = wmem_strdup_printf( scope, "%7.2f", range );
447 proto_tree_add_string( msg_tree, hf_aprs_msg_rng, tvb, offset, 1, info_buffer );
449 else
450 if ( ch >= '!' && ch <= 'z' )
451 { /* Course/Speed */
452 course = (ch - 33) * 4;
453 info_buffer = wmem_strdup_printf( scope, "%d", course );
454 proto_tree_add_string( msg_tree, hf_aprs_msg_cse,
455 tvb, offset, 1, info_buffer );
456 offset += 1;
457 ch = tvb_get_uint8( tvb, offset );
458 speed = exp( log( 1.08 ) * (ch - 33) );
459 info_buffer = wmem_strdup_printf( scope, "%7.2f", speed );
460 proto_tree_add_string( msg_tree, hf_aprs_msg_spd,
461 tvb, offset, 1, info_buffer );
467 return new_offset;
471 static const mic_e_dst_code_table_s *
472 dst_code_lookup( uint8_t ch )
474 unsigned indx;
476 indx = 0;
477 while (indx < array_length(dst_code)
478 && dst_code[ indx ].key != ch
479 && dst_code[ indx ].key > 0 )
480 indx++;
481 return &( dst_code[ indx ] );
484 static int
485 d28_to_deg( uint8_t code, int long_offset )
487 int value;
489 value = code - 28 + long_offset;
490 if ( value >= 180 && value <= 189 )
491 value -= 80;
492 else
493 if ( value >= 190 && value <= 199 )
494 value -= 190;
495 return value;
498 static int
499 d28_to_min( uint8_t code )
501 int value;
503 value = code - 28;
504 if ( value >= 60 )
505 value -= 60;
506 return value;
509 static int
510 dissect_mic_e( tvbuff_t *tvb,
511 int offset,
512 packet_info *pinfo,
513 proto_tree *parent_tree,
514 int hf_mic_e_idx
517 proto_tree *tc;
518 proto_tree *mic_e_tree;
519 int new_offset;
520 int data_len;
521 char *info_buffer;
522 char latitude[8] = { '?', '?', '?', '?', '.', '?', '?', 0x0 };
523 int msg_a;
524 int msg_b;
525 int msg_c;
526 char n_s;
527 int long_offset;
528 char w_e;
529 int cse;
530 int spd;
531 uint8_t ssid;
532 const uint8_t *addr;
533 const mic_e_dst_code_table_s *dst_code_entry;
535 data_len = tvb_reported_length_remaining( tvb, offset );
536 new_offset = offset + data_len;
538 info_buffer = (char *)wmem_alloc( pinfo->pool, STRLEN );
540 msg_a = 0;
541 msg_b = 0;
542 msg_c = 0;
544 n_s = '?';
545 long_offset = 0;
546 w_e = '?';
547 ssid = 0;
549 if ( pinfo->dst.type == AT_AX25 && pinfo->dst.len == AX25_ADDR_LEN )
551 /* decode the AX.25 destination address */
552 addr = (const uint8_t *)pinfo->dst.data;
554 dst_code_entry = dst_code_lookup( addr[ 0 ] );
555 latitude[ 0 ] = dst_code_entry->digit;
556 msg_a = dst_code_entry->msg & 0x1;
558 dst_code_entry = dst_code_lookup( addr[ 1 ] );
559 latitude[ 1 ] = dst_code_entry->digit;
560 msg_b = dst_code_entry->msg & 0x1;
562 dst_code_entry = dst_code_lookup( addr[ 2 ] );
563 latitude[ 2 ] = dst_code_entry->digit;
564 msg_c = dst_code_entry->msg & 0x1;
566 dst_code_entry = dst_code_lookup( addr[ 3 ] );
567 latitude[ 3 ] = dst_code_entry->digit;
568 n_s = dst_code_entry->n_s;
570 /* '.' already set */
572 dst_code_entry = dst_code_lookup( addr[ 4 ] );
573 latitude[ 5 ] = dst_code_entry->digit;
574 long_offset = dst_code_entry->long_offset;
576 dst_code_entry = dst_code_lookup( addr[ 5 ] );
577 latitude[ 6 ] = dst_code_entry->digit;
578 w_e = dst_code_entry->w_e;
580 ssid = (addr[ 6 ] >> 1) & 0x0f;
583 /* decode the mic-e info fields */
584 spd = ((tvb_get_uint8( tvb, offset + 3 ) - 28) * 10) + ((tvb_get_uint8( tvb, offset + 4 ) - 28) / 10);
585 if ( spd >= 800 )
586 spd -= 800;
588 cse = (((tvb_get_uint8( tvb, offset + 4 ) - 28) % 10) * 100) + ((tvb_get_uint8( tvb, offset + 5 ) - 28) * 10);
589 if ( cse >= 400 )
590 cse -= 400;
592 snprintf( info_buffer, STRLEN,
593 "Lat: %7.7s%c Long: %03d%02d.%02d%c, Cse: %d, Spd: %d, SSID: %d, Msg %s",
594 latitude,
595 n_s,
596 d28_to_deg( tvb_get_uint8( tvb, offset ), long_offset ),
597 d28_to_min( tvb_get_uint8( tvb, offset + 1 ) ),
598 tvb_get_uint8( tvb, offset + 2 ) - 28,
599 w_e,
600 cse,
601 spd,
602 ssid,
603 mic_e_msg_table[ (msg_a << 2) + (msg_b << 1) + msg_c ].std
606 col_set_str( pinfo->cinfo, COL_INFO, "MIC-E " );
607 col_append_str( pinfo->cinfo, COL_INFO, info_buffer );
609 if ( parent_tree )
611 tc = proto_tree_add_string( parent_tree, hf_mic_e_idx, tvb, offset, data_len, info_buffer );
612 mic_e_tree = proto_item_add_subtree( tc, ett_aprs_mic_e );
614 snprintf( info_buffer, STRLEN,
615 "Lat %7.7s, Msg A %d, Msg B %d, Msg C %d, N/S %c, Long off %3d, W/E %c, SSID %d",
616 latitude,
617 msg_a,
618 msg_b,
619 msg_c,
620 n_s,
621 long_offset,
622 w_e,
623 ssid
626 proto_tree_add_string( mic_e_tree, hf_aprs_mic_e_dst, tvb, 0, 0, info_buffer ); /* ?? */
628 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_long_d, tvb, offset, 1, ENC_BIG_ENDIAN );
629 offset += 1;
631 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_long_m, tvb, offset, 1, ENC_BIG_ENDIAN );
632 offset += 1;
634 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_long_h, tvb, offset, 1, ENC_BIG_ENDIAN );
635 offset += 1;
637 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_spd_sp, tvb, offset, 1, ENC_BIG_ENDIAN );
638 offset += 1;
640 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_spd_dc, tvb, offset, 1, ENC_BIG_ENDIAN );
641 offset += 1;
643 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_spd_se, tvb, offset, 1, ENC_BIG_ENDIAN );
644 offset += 1;
646 proto_tree_add_item( mic_e_tree, hf_aprs_sym_code, tvb, offset, 1, ENC_ASCII );
647 offset += 1;
649 proto_tree_add_item( mic_e_tree, hf_aprs_sym_id, tvb, offset, 1, ENC_ASCII );
650 offset += 1;
652 if ( offset < new_offset )
654 uint8_t c = tvb_get_uint8(tvb, offset);
655 if ( (c == ',') || (c == 0x1d) )
656 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_telemetry,
657 tvb, offset, -1, ENC_NA );
658 else
659 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_status,
660 tvb, offset, -1, ENC_ASCII );
665 return new_offset;
668 static int
669 dissect_aprs_storm( tvbuff_t *tvb,
670 int offset,
671 proto_tree *parent_tree
674 proto_tree *storm_tree;
675 proto_tree *tc;
677 tc = proto_tree_add_item( parent_tree, hf_aprs_storm, tvb, offset, -1, ENC_ASCII );
678 storm_tree = proto_item_add_subtree( tc, ett_aprs_storm );
680 proto_tree_add_item( storm_tree, hf_aprs_storm_dir, tvb, offset, 3, ENC_ASCII );
681 offset += 3;
682 offset += 1;
683 proto_tree_add_item( storm_tree, hf_aprs_storm_spd, tvb, offset, 3, ENC_ASCII );
684 offset += 3;
685 proto_tree_add_item( storm_tree, hf_aprs_storm_type, tvb, offset, 3, ENC_ASCII );
686 offset += 3;
687 proto_tree_add_item( storm_tree, hf_aprs_storm_sws, tvb, offset, 4, ENC_ASCII );
688 offset += 4;
689 proto_tree_add_item( storm_tree, hf_aprs_storm_pwg, tvb, offset, 4, ENC_ASCII );
690 offset += 4;
691 proto_tree_add_item( storm_tree, hf_aprs_storm_cp, tvb, offset, 5, ENC_ASCII );
692 offset += 5;
693 proto_tree_add_item( storm_tree, hf_aprs_storm_rhw, tvb, offset, 4, ENC_ASCII );
694 offset += 4;
695 proto_tree_add_item( storm_tree, hf_aprs_storm_rtsw, tvb, offset, 4, ENC_ASCII );
696 offset += 4;
697 proto_tree_add_item( storm_tree, hf_aprs_storm_rwg, tvb, offset, 4, ENC_ASCII );
698 offset += 4;
700 return offset;
703 static int
704 dissect_aprs_weather( wmem_allocator_t *scope _U_,
705 tvbuff_t *tvb,
706 int offset,
707 proto_tree *parent_tree
710 proto_tree *tc;
711 proto_tree *weather_tree;
712 int new_offset;
713 int data_len;
714 uint8_t ch;
717 data_len = tvb_reported_length_remaining( tvb, offset );
718 new_offset = offset + data_len;
720 tc = proto_tree_add_item( parent_tree, hf_aprs_weather, tvb, offset, data_len, ENC_ASCII );
721 weather_tree = proto_item_add_subtree( tc, ett_aprs_weather );
723 ch = tvb_get_uint8( tvb, offset );
724 if ( g_ascii_isdigit( ch ) )
726 proto_tree_add_item( weather_tree, hf_aprs_weather_dir, tvb, offset, 3, ENC_ASCII );
727 offset += 3;
728 /* verify the separator */
729 offset += 1;
730 proto_tree_add_item( weather_tree, hf_aprs_weather_spd, tvb, offset, 3, ENC_ASCII );
731 offset += 3;
734 if ( parent_tree )
736 while ( offset < new_offset )
738 ch = tvb_get_uint8( tvb, offset );
739 switch ( ch )
741 case 'c' :
742 proto_tree_add_item( weather_tree, hf_aprs_weather_dir,
743 tvb, offset, 4, ENC_ASCII );
744 offset += 4;
745 break;
746 case 's' :
747 proto_tree_add_item( weather_tree, hf_aprs_weather_spd,
748 tvb, offset, 4, ENC_ASCII );
749 offset += 4;
750 break;
751 case 'g' :
752 proto_tree_add_item( weather_tree, hf_aprs_weather_peak,
753 tvb, offset, 4, ENC_ASCII );
754 offset += 4;
755 break;
756 case 't' :
757 proto_tree_add_item( weather_tree, hf_aprs_weather_temp,
758 tvb, offset, 4, ENC_ASCII );
759 offset += 4;
760 break;
761 case 'r' :
762 proto_tree_add_item( weather_tree, hf_aprs_weather_rain_1,
763 tvb, offset, 4, ENC_ASCII );
764 offset += 4;
765 break;
766 case 'P' :
767 proto_tree_add_item( weather_tree, hf_aprs_weather_rain_24,
768 tvb, offset, 4, ENC_ASCII );
769 offset += 4;
770 break;
771 case 'p' :
772 proto_tree_add_item( weather_tree, hf_aprs_weather_rain,
773 tvb, offset, 4, ENC_ASCII );
774 offset += 4;
775 break;
776 case 'h' :
777 proto_tree_add_item( weather_tree, hf_aprs_weather_humidty,
778 tvb, offset, 3, ENC_ASCII );
779 offset += 3;
780 break;
781 case 'b' :
782 proto_tree_add_item( weather_tree, hf_aprs_weather_press,
783 tvb, offset, 6, ENC_ASCII );
784 offset += 6;
785 break;
786 case 'l' :
787 case 'L' :
788 proto_tree_add_item( weather_tree, hf_aprs_weather_luminosity,
789 tvb, offset, 4, ENC_ASCII );
790 offset += 4;
791 break;
792 case 'S' :
793 proto_tree_add_item( weather_tree, hf_aprs_weather_snow,
794 tvb, offset, 4, ENC_ASCII );
795 offset += 4;
796 break;
797 case '#' :
798 proto_tree_add_item( weather_tree, hf_aprs_weather_raw_rain,
799 tvb, offset, 4, ENC_ASCII );
800 offset += 4;
801 break;
802 default : {
803 int lr;
804 /* optional: software type/unit: see if present */
805 lr = new_offset - offset;
806 #if 0 /* fcn'al change: defer */
808 * XXX - ASCII or UTF-8?
809 * See http://www.aprs.org/aprs12/utf-8.txt
811 if ( ((lr < 3) || (lr > 5)) ||
812 ( lr != strspn( tvb_get_string_enc( scope, tvb, offset, lr, ENC_ASCII|ENC_NA ), "a-zA-Z0-9-_" ) ) )
814 new_offset = offset; /* Assume rest is a comment: force exit from while */
815 break; /* from switch */
817 #endif
818 proto_tree_add_item( weather_tree, hf_aprs_weather_software,
819 tvb, offset, 1, ENC_ASCII );
820 offset += 1;
821 proto_tree_add_item( weather_tree, hf_aprs_weather_unit,
822 tvb, offset, lr-1, ENC_ASCII );
823 offset = new_offset;
824 break;
826 } /* switch */
827 } /* while */
828 } /* if (parent_tree) */
829 return new_offset;
832 static int
833 aprs_timestamp( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
835 int data_len;
836 const char *tzone;
837 uint8_t ch;
839 data_len = 8;
840 tzone = "zulu";
842 ch= tvb_get_uint8( tvb, offset + 6 );
843 if ( g_ascii_isdigit( ch ) )
844 { /* MDHM */
845 proto_tree_add_item( aprs_tree, hf_aprs_mdhm, tvb, offset, data_len, ENC_ASCII );
846 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset, data_len, tzone );
848 else
850 data_len -= 1;
851 if ( ch == 'h' )
852 { /* HMS */
853 proto_tree_add_item( aprs_tree, hf_aprs_hms, tvb, offset, data_len, ENC_ASCII );
854 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset, data_len, tzone );
856 else
857 { /* DHM */
858 switch ( ch )
860 case 'z' : tzone = "zulu"; break;
861 case '/' : tzone = "local"; break;
862 default : tzone = "unknown"; break;
864 proto_tree_add_item( aprs_tree, hf_aprs_dhm, tvb, offset, data_len, ENC_ASCII );
865 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset + 6, 1, tzone );
869 return offset + data_len;
872 static int
873 aprs_latitude_compressed( wmem_allocator_t *scope, proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
875 if ( aprs_tree )
877 char *info_buffer;
878 int temp;
880 info_buffer = (char *)wmem_alloc( scope, STRLEN );
882 temp = ( tvb_get_uint8( tvb, offset + 0 ) - 33 );
883 temp = ( tvb_get_uint8( tvb, offset + 1 ) - 33 ) + ( temp * 91 );
884 temp = ( tvb_get_uint8( tvb, offset + 2 ) - 33 ) + ( temp * 91 );
885 temp = ( tvb_get_uint8( tvb, offset + 3 ) - 33 ) + ( temp * 91 );
887 snprintf( info_buffer, STRLEN, "%6.2f", 90.0 - (temp / 380926.0) );
888 proto_tree_add_string( aprs_tree, hf_aprs_lat, tvb, offset, 4, info_buffer );
890 return offset + 4;
893 static int
894 aprs_longitude_compressed( wmem_allocator_t *scope, proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
896 if ( aprs_tree )
898 char *info_buffer;
899 int temp;
901 info_buffer = (char *)wmem_alloc( scope, STRLEN );
903 temp = ( tvb_get_uint8( tvb, offset + 0 ) - 33 );
904 temp = ( tvb_get_uint8( tvb, offset + 1 ) - 33 ) + ( temp * 91 );
905 temp = ( tvb_get_uint8( tvb, offset + 2 ) - 33 ) + ( temp * 91 );
906 temp = ( tvb_get_uint8( tvb, offset + 3 ) - 33 ) + ( temp * 91 );
908 snprintf( info_buffer, STRLEN, "%7.2f", (temp / 190463.0) - 180.0 );
909 proto_tree_add_string( aprs_tree, hf_aprs_long, tvb, offset, 4, info_buffer );
911 return offset + 4;
914 static int
915 aprs_status( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
917 int data_len;
919 data_len = tvb_reported_length_remaining( tvb, offset );
921 if ( ( data_len > 7 ) && ( tvb_get_uint8( tvb, offset+6 ) == 'z' ) )
923 proto_tree_add_item( aprs_tree, hf_aprs_dhm, tvb, offset, 6, ENC_ASCII );
924 offset += 6;
925 data_len -= 6;
926 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset, 1, "zulu" );
927 offset += 1;
928 data_len -= 1;
930 proto_tree_add_item( aprs_tree, hf_aprs_status, tvb, offset, data_len, ENC_ASCII );
932 return offset + data_len;
935 static int
936 aprs_item( wmem_allocator_t *scope, proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
938 char *info_buffer;
939 int data_len;
940 char *ch_ptr;
942 data_len = 10;
945 * XXX - ASCII or UTF-8?
946 * See http://www.aprs.org/aprs12/utf-8.txt
948 info_buffer = tvb_get_string_enc( scope, tvb, offset, data_len, ENC_ASCII|ENC_NA );
950 ch_ptr = strchr( info_buffer, '!' );
951 if ( ch_ptr != NULL )
953 data_len = (int)(ch_ptr - info_buffer + 1);
954 *ch_ptr = '\0';
956 else
958 ch_ptr = strchr( info_buffer, '!' );
959 if ( ch_ptr != NULL )
961 data_len = (int)(ch_ptr - info_buffer + 1);
962 *ch_ptr = '\0';
965 proto_tree_add_string( aprs_tree, hf_aprs_item, tvb, offset, data_len, info_buffer );
967 return offset + data_len;
970 static int
971 aprs_3rd_party( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, int data_len )
973 /* If the type of the hf[] entry pointed to by hfindex is FT_BYTES or FT_STRING */
974 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
975 if ( data_len == -1 )
977 data_len = tvb_reported_length_remaining( tvb, offset );
978 #if 0 /* fcn'al change: defer */
979 if ( data_len <= 0 )
980 return offset; /* there's no data */
981 #endif
983 proto_tree_add_item( aprs_tree, hf_aprs_third_party, tvb, offset, data_len, ENC_NA );
984 /* tnc-2 */
985 /* aea */
986 return offset + data_len;
989 static int
990 aprs_default_string( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, int data_len, int hfindex )
992 /* Assumption: hfindex points to an hf[] entry with type FT_STRING; should be validated ? */
993 /* If the type of the hf[] entry pointed to by hfindex is FT_STRING */
994 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
995 if ( data_len == -1 )
997 data_len = tvb_reported_length_remaining( tvb, offset );
998 #if 0 /* fcn'al change: defer */
999 if ( data_len <= 0 )
1000 return offset; /* there's no data */
1001 #endif
1003 proto_tree_add_item( aprs_tree, hfindex, tvb, offset, data_len, ENC_ASCII|ENC_NA );
1004 return offset + data_len;
1007 static int
1008 aprs_default_bytes( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, int data_len, int hfindex )
1010 /* Assumption: hfindex points to an hf[] entry with type FT_BYTES; should be validated ? */
1011 /* If the type of the hf[] entry pointed to by hfindex is FT_BYTES */
1012 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
1013 if ( data_len == -1 )
1015 data_len = tvb_reported_length_remaining( tvb, offset );
1016 #if 0 /* fcn'al change: defer */
1017 if ( data_len <= 0 )
1018 return offset; /* there's no data */
1019 #endif
1021 proto_tree_add_item( aprs_tree, hfindex, tvb, offset, data_len, ENC_NA );
1022 return offset + data_len;
1025 static int
1026 aprs_position( packet_info *pinfo, proto_tree *aprs_tree, tvbuff_t *tvb, int offset, bool with_msg )
1028 uint8_t symbol_table_id = 0;
1029 uint8_t symbol_code = 0;
1030 bool probably_a_msg = false;
1031 bool probably_not_a_msg = false;
1033 if ( g_ascii_isdigit( tvb_get_uint8( tvb, offset ) ) )
1035 offset = aprs_default_string( aprs_tree, tvb, offset, 8, hf_aprs_lat );
1036 symbol_table_id = tvb_get_uint8( tvb, offset );
1037 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_id );
1038 offset = aprs_default_string( aprs_tree, tvb, offset, 9, hf_aprs_long );
1039 symbol_code = tvb_get_uint8( tvb, offset );
1040 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_code );
1041 if ( gPREF_APRS_LAX )
1043 switch ( tvb_get_uint8( tvb, offset ) )
1045 case 'D' : probably_a_msg = true; break;
1046 case 'P' : probably_a_msg = true; break;
1047 case 'R' : probably_a_msg = true; break;
1048 case 'T' : probably_a_msg = true; break;
1049 default : probably_not_a_msg = true; break;
1052 if ( with_msg || probably_a_msg || ! probably_not_a_msg )
1053 offset = dissect_aprs_msg( tvb,
1054 offset,
1055 aprs_tree,
1056 ( symbol_code == '_' ),
1057 ( symbol_table_id == '/' && symbol_code == '\\' )
1060 else
1062 symbol_table_id = tvb_get_uint8( tvb, offset );
1063 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_id );
1064 offset = aprs_latitude_compressed( pinfo->pool, aprs_tree, tvb, offset );
1065 offset = aprs_longitude_compressed( pinfo->pool, aprs_tree, tvb, offset );
1066 symbol_code = tvb_get_uint8( tvb, offset );
1067 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_code );
1068 offset = dissect_aprs_compressed_msg( pinfo->pool,
1069 tvb,
1070 offset,
1071 aprs_tree
1073 offset = dissect_aprs_compression_type( tvb,
1074 offset,
1075 aprs_tree
1077 if ( symbol_table_id == '/' && symbol_code == '\\' )
1078 offset = aprs_default_string( aprs_tree, tvb, offset, 8, hf_aprs_msg_brg );
1081 if ( symbol_code == '_' )
1082 offset = dissect_aprs_weather( pinfo->pool,
1083 tvb,
1084 offset,
1085 aprs_tree
1087 if ( ( symbol_table_id == '/' && symbol_code == '@' ) || ( symbol_table_id == '\\' && symbol_code == '@' ) )
1088 offset = dissect_aprs_storm( tvb,
1089 offset,
1090 aprs_tree
1093 return offset;
1096 static int
1097 dissect_aprs( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data _U_ )
1099 proto_item *ti;
1100 proto_tree *aprs_tree;
1102 int offset;
1103 uint8_t dti;
1104 wmem_strbuf_t *sb;
1106 col_set_str( pinfo->cinfo, COL_PROTOCOL, "APRS" );
1107 col_clear( pinfo->cinfo, COL_INFO );
1109 offset = 0;
1111 dti = tvb_get_uint8( tvb, offset );
1113 sb = wmem_strbuf_create(pinfo->pool);
1115 if (dti != '!')
1116 wmem_strbuf_append(sb, val_to_str_ext_const(dti, &aprs_description_ext, ""));
1118 switch ( dti )
1120 case '!':
1121 /* Position or Ultimeter 2000 WX Station */
1122 if ( tvb_get_uint8( tvb, offset + 1 ) == '!' )
1124 wmem_strbuf_append(sb, "Ultimeter 2000 WX Station");
1126 else
1128 /* Position "without APRS messaging" */
1129 wmem_strbuf_append(sb, "Position (");
1130 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1, 8)); /* Lat */
1131 wmem_strbuf_append(sb, " ");
1132 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8 + 1, 9)); /* Long */
1133 wmem_strbuf_append(sb, " ");
1134 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8, 1)); /* Symbol table id */
1135 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8 + 1 + 9, 1)); /* Symbol Code */
1137 break;
1139 case '=':
1140 /* Position "with APRS messaging" + Ext APRS message */
1141 wmem_strbuf_append(sb, " (");
1142 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1, 8)); /* Lat */
1143 wmem_strbuf_append(sb, " ");
1144 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8 + 1, 9)); /* Long */
1145 wmem_strbuf_append(sb, " ");
1146 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8, 1)); /* Symbol table id */
1147 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8 + 1 + 9, 1)); /* Symbol Code */
1148 break;
1150 case '/':
1151 /* Position + timestamp "without APRS messaging" */
1152 wmem_strbuf_append(sb, " (");
1153 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1, 7)); /* Timestamp */
1154 wmem_strbuf_append(sb, " ");
1155 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 1, 8)); /*??*/ /* Lat */
1156 wmem_strbuf_append(sb, " ");
1157 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 8 + 1, 9)); /* Long */
1158 wmem_strbuf_append(sb, " ");
1159 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7, 1)); /* Symbol table id */
1160 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 1 + 9, 1)); /* Symbol Code */
1161 break;
1163 case '@':
1164 /* Position + timestamp "with APRS messaging" + Ext APRS message */
1165 wmem_strbuf_append(sb, " (");
1166 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1, 7)); /* Timestamp */
1167 wmem_strbuf_append(sb, " ");
1168 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 1, 8)); /*??*/ /* Lat */
1169 wmem_strbuf_append(sb, " ");
1170 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 8 + 1, 9)); /* Long */
1171 wmem_strbuf_append(sb, " ");
1172 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7, 1)); /* Symbol table id */
1173 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 1 + 9, 1)); /* Symbol Code */
1174 break;
1177 col_add_str( pinfo->cinfo, COL_INFO, wmem_strbuf_get_str(sb) );
1179 /* create display subtree for the protocol */
1180 ti = proto_tree_add_protocol_format( parent_tree , proto_aprs, tvb, 0, -1, "%s", wmem_strbuf_get_str(sb) );
1181 aprs_tree = proto_item_add_subtree( ti, ett_aprs );
1183 proto_tree_add_item( aprs_tree, hf_aprs_dti, tvb, offset, 1, ENC_ASCII );
1184 offset += 1;
1186 switch ( dti )
1188 case '<' : /* Station Capabilities */
1189 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_station );
1190 break;
1191 case '>' : /* Status */
1192 offset = aprs_status( aprs_tree, tvb, offset );
1193 break;
1194 case '?' : /* Query */
1195 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_query );
1196 break;
1197 case '$' : /* Raw GPS data or Ultimeter 2000 */
1198 if ( tvb_get_uint8( tvb, offset ) == 'U' )
1199 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_ultimeter_2000 );
1200 else
1201 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_raw );
1202 break;
1203 case '%' : /* Agrelo DFJr / MicroFinder */
1204 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_agrelo );
1205 break;
1206 case 'T' : /* Telemetry data */
1207 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_telemetry );
1208 break;
1209 case '[' : /* Maidenhead grid locator beacon (obsolete) */
1210 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_maidenhead );
1211 break;
1212 case '_' : /* Weather Report (without position) */
1213 offset = aprs_timestamp( aprs_tree, tvb, offset );
1214 offset = dissect_aprs_weather( pinfo->pool,
1215 tvb,
1216 offset,
1217 aprs_tree
1219 break;
1220 case ',' : /* Invalid data or test data */
1221 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_invalid_test );
1222 break;
1223 case '{' : /* User-Defined APRS packet format */
1224 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_user_defined );
1225 break;
1226 case '}' : /* Third-party traffic */
1227 offset = aprs_3rd_party( aprs_tree, tvb, offset, -1 );
1228 break;
1229 case ':' : /* Message */
1230 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_message );
1231 break;
1232 case 0x1c : /* Current Mic-E Data (Rev 0 beta) */
1233 offset = dissect_mic_e( tvb,
1234 offset,
1235 pinfo,
1236 aprs_tree,
1237 hf_aprs_mic_e_0_current
1239 break;
1240 case 0x1d : /* Old Mic-E Data (Rev 0 beta) */
1241 offset = dissect_mic_e( tvb,
1242 offset,
1243 pinfo,
1244 aprs_tree,
1245 hf_aprs_mic_e_0_old
1247 break;
1248 case '\'' : /* Old Mic-E Data (but Current data for TM-D700) */
1249 offset = dissect_mic_e( tvb,
1250 offset,
1251 pinfo,
1252 aprs_tree,
1253 hf_aprs_mic_e_old
1255 break;
1256 case '`' : /* Current Mic-E Data (not used in TM-D700) */
1257 offset = dissect_mic_e( tvb,
1258 offset,
1259 pinfo,
1260 aprs_tree,
1261 hf_aprs_mic_e_current
1263 break;
1264 case '#' : /* Peet Bros U-II Weather Station */
1265 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_peet_1 );
1266 break;
1267 case '*' : /* Peet Bros U-II Weather Station */
1268 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_peet_2 );
1269 break;
1270 case '&' : /* [Reserved - Map Feature] */
1271 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_map_feature );
1272 break;
1273 case '+' : /* [Reserved - Shelter data with time] */
1274 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_shelter_data );
1275 break;
1276 case '.' : /* [Reserved - Space weather] */
1277 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_space_weather );
1278 break;
1279 case ')' : /* Item */
1280 offset = aprs_item( pinfo->pool, aprs_tree, tvb, offset );
1281 offset = aprs_position( pinfo, aprs_tree, tvb, offset, true );
1282 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1283 break;
1284 case ';' : /* Object */
1285 offset = aprs_default_string( aprs_tree, tvb, offset, 10, hf_aprs_object );
1286 offset = aprs_timestamp( aprs_tree, tvb, offset );
1287 offset = aprs_position( pinfo, aprs_tree, tvb, offset, true );
1288 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1289 break;
1290 case '!' : /* Position or Ultimeter 2000 WX Station */
1291 if ( tvb_get_uint8( tvb, offset ) == '!' )
1292 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_ultimeter_2000 );
1293 else
1295 offset = aprs_position( pinfo, aprs_tree, tvb, offset, false );
1296 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1298 break;
1299 case '=' : /* Position + Ext APRS message */
1300 offset = aprs_position( pinfo, aprs_tree, tvb, offset, true );
1301 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1302 break;
1303 case '/' : /* Position + timestamp */
1304 offset = aprs_timestamp( aprs_tree, tvb, offset );
1305 offset = aprs_position( pinfo, aprs_tree, tvb, offset, false );
1306 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1307 break;
1308 case '@' : /* Position + timestamp + Ext APRS message */
1309 offset = aprs_timestamp( aprs_tree, tvb, offset );
1310 offset = aprs_position( pinfo, aprs_tree, tvb, offset, true );
1311 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1312 break;
1313 default : break;
1315 return offset;
1318 void
1319 proto_register_aprs( void )
1321 module_t *aprs_module;
1323 static hf_register_info hf[] = {
1324 { &hf_aprs_dti,
1325 { "Data Type Indicator", "aprs.dti",
1326 FT_STRING, BASE_NONE, NULL, 0x0,
1327 NULL, HFILL }
1329 { &hf_aprs_sym_code,
1330 { "Symbol code", "aprs.sym_code",
1331 FT_STRING, BASE_NONE, NULL, 0x0,
1332 NULL, HFILL }
1334 { &hf_aprs_sym_id,
1335 { "Symbol table ID", "aprs.sym_id",
1336 FT_STRING, BASE_NONE, NULL, 0x0,
1337 NULL, HFILL }
1340 /* Position */
1341 #if 0
1342 { &hf_aprs_position,
1343 { "Position", "aprs.position",
1344 FT_STRING, BASE_NONE, NULL, 0x0,
1345 NULL, HFILL }
1347 #endif
1348 { &hf_aprs_lat,
1349 { "Latitude", "aprs.position.lat",
1350 FT_STRING, BASE_NONE, NULL, 0x0,
1351 NULL, HFILL }
1353 { &hf_aprs_long,
1354 { "Longitude", "aprs.position.long",
1355 FT_STRING, BASE_NONE, NULL, 0x0,
1356 NULL, HFILL }
1359 /* APRS Messages */
1360 { &hf_aprs_comment,
1361 { "Comment", "aprs.comment",
1362 FT_STRING, BASE_NONE, NULL, 0x0,
1363 NULL, HFILL }
1365 { &hf_ultimeter_2000,
1366 { "Ultimeter 2000", "aprs.ultimeter_2000",
1367 FT_STRING, BASE_NONE, NULL, 0x0,
1368 NULL, HFILL }
1370 { &hf_aprs_status,
1371 { "Status", "aprs.status",
1372 FT_STRING, BASE_NONE, NULL, 0x0,
1373 NULL, HFILL }
1375 { &hf_aprs_object,
1376 { "Object", "aprs.object",
1377 FT_STRING, BASE_NONE, NULL, 0x0,
1378 NULL, HFILL }
1380 { &hf_aprs_item,
1381 { "Item", "aprs.item",
1382 FT_STRING, BASE_NONE, NULL, 0x0,
1383 NULL, HFILL }
1385 { &hf_aprs_query,
1386 { "Query", "aprs.query",
1387 FT_STRING, BASE_NONE, NULL, 0x0,
1388 NULL, HFILL }
1390 { &hf_aprs_telemetry,
1391 { "Telemetry", "aprs.telemetry",
1392 FT_STRING, BASE_NONE, NULL, 0x0,
1393 NULL, HFILL }
1395 { &hf_aprs_raw,
1396 { "Raw", "aprs.raw",
1397 FT_STRING, BASE_NONE, NULL, 0x0,
1398 "Raw NMEA position report format", HFILL }
1400 { &hf_aprs_station,
1401 { "Station", "aprs.station",
1402 FT_STRING, BASE_NONE, NULL, 0x0,
1403 "Station capabilities", HFILL }
1405 { &hf_aprs_message,
1406 { "Message", "aprs.message",
1407 FT_STRING, BASE_NONE, NULL, 0x0,
1408 NULL, HFILL }
1410 { &hf_aprs_agrelo,
1411 { "Agrelo", "aprs.agrelo",
1412 FT_BYTES, BASE_NONE, NULL, 0x0,
1413 "Agrelo DFJr / MicroFinder", HFILL }
1415 { &hf_aprs_maidenhead,
1416 { "Maidenhead", "aprs.maidenhead",
1417 FT_BYTES, BASE_NONE, NULL, 0x0,
1418 "Maidenhead grid locator beacon (obsolete)", HFILL }
1420 { &hf_aprs_invalid_test,
1421 { "Invalid or test", "aprs.invalid_test",
1422 FT_BYTES, BASE_NONE, NULL, 0x0,
1423 "Invalid data or test data", HFILL }
1425 { &hf_aprs_user_defined,
1426 { "User-Defined", "aprs.user_defined",
1427 FT_BYTES, BASE_NONE, NULL, 0x0,
1428 "User-Defined APRS packet format", HFILL }
1430 { &hf_aprs_third_party,
1431 { "Third-party", "aprs.third_party",
1432 FT_BYTES, BASE_NONE, NULL, 0x0,
1433 "Third-party traffic", HFILL }
1435 { &hf_aprs_peet_1,
1436 { "Peet U-II (1)", "aprs.peet_1",
1437 FT_BYTES, BASE_NONE, NULL, 0x0,
1438 "Peet Bros U-II Weather Station", HFILL }
1440 { &hf_aprs_peet_2,
1441 { "Peet U-II (2)", "aprs.peet_2",
1442 FT_BYTES, BASE_NONE, NULL, 0x0,
1443 "Peet Bros U-II Weather Station", HFILL }
1445 { &hf_aprs_map_feature,
1446 { "Map Feature", "aprs.map_feature",
1447 FT_BYTES, BASE_NONE, NULL, 0x0,
1448 "Reserved - Map Feature", HFILL }
1450 { &hf_aprs_shelter_data,
1451 { "Shelter data", "aprs.shelter_data",
1452 FT_BYTES, BASE_NONE, NULL, 0x0,
1453 "[Reserved - Shelter data with time]", HFILL }
1455 { &hf_aprs_space_weather,
1456 { "Space weather", "aprs.space_weather",
1457 FT_BYTES, BASE_NONE, NULL, 0x0,
1458 "[Reserved - Space weather]", HFILL }
1460 { &hf_aprs_storm,
1461 { "Storm", "aprs.storm",
1462 FT_STRING, BASE_NONE, NULL, 0x0,
1463 NULL, HFILL }
1466 /* Time stamp */
1467 { &hf_aprs_dhm,
1468 { "Day/Hour/Minute", "aprs.dhm",
1469 FT_STRING, BASE_NONE, NULL, 0x0,
1470 NULL, HFILL }
1472 { &hf_aprs_hms,
1473 { "Hour/Minute/Second", "aprs.hms",
1474 FT_STRING, BASE_NONE, NULL, 0x0,
1475 NULL, HFILL }
1477 { &hf_aprs_mdhm,
1478 { "Month/Day/Hour/Minute", "aprs.mdhm",
1479 FT_STRING, BASE_NONE, NULL, 0x0,
1480 NULL, HFILL }
1482 { &hf_aprs_tz,
1483 { "Time Zone", "aprs.tz",
1484 FT_STRING, BASE_NONE, NULL, 0x0,
1485 NULL, HFILL }
1488 /* Compressed Msg */
1489 { &hf_aprs_compression_type,
1490 { "Compression type", "aprs.ct",
1491 FT_UINT8, BASE_HEX, NULL, 0x0,
1492 NULL, HFILL }
1494 { &hf_aprs_ct_gps_fix,
1495 { "GPS fix type", "aprs.ct.gps_fix",
1496 FT_UINT8, BASE_HEX, VALS(gps_vals), 0x20,
1497 NULL, HFILL }
1499 { &hf_aprs_ct_nmea_src,
1500 { "NMEA source", "aprs.ct.nmea_src",
1501 FT_UINT8, BASE_HEX, VALS(nmea_vals), 0x18,
1502 NULL, HFILL }
1504 { &hf_aprs_ct_origin,
1505 { "Compression origin", "aprs.ct.origin",
1506 FT_UINT8, BASE_HEX, VALS(ctype_vals), 0x07,
1507 NULL, HFILL }
1510 /* Ext Msg */
1511 { &hf_aprs_msg,
1512 { "Extended message", "aprs.msg",
1513 FT_STRING, BASE_NONE, NULL, 0x0,
1514 NULL, HFILL }
1516 { &hf_aprs_msg_rng,
1517 { "Range", "aprs.msg.rng",
1518 FT_STRING, BASE_NONE, NULL, 0x0,
1519 "Pre-calculated radio range", HFILL }
1521 { &hf_aprs_msg_cse,
1522 { "Course", "aprs.msg.cse",
1523 FT_STRING, BASE_NONE, NULL, 0x0,
1524 NULL, HFILL }
1526 { &hf_aprs_msg_spd,
1527 { "Speed", "aprs.msg.spd",
1528 FT_STRING, BASE_NONE, NULL, 0x0,
1529 NULL, HFILL }
1531 { &hf_aprs_msg_dir,
1532 { "Wind direction", "aprs.msg.dir",
1533 FT_STRING, BASE_NONE, NULL, 0x0,
1534 NULL, HFILL }
1536 { &hf_aprs_msg_brg,
1537 { "Bearing", "aprs.msg.brg",
1538 FT_STRING, BASE_NONE, NULL, 0x0,
1539 NULL, HFILL }
1541 { &hf_aprs_msg_nrq,
1542 { "Number/Range/Quality", "aprs.msg.nrq",
1543 FT_STRING, BASE_NONE, NULL, 0x0,
1544 NULL, HFILL }
1547 /* Msg PHGD */
1548 { &hf_aprs_msg_phg_p,
1549 { "Power", "aprs.msg.phg.p",
1550 FT_STRING, BASE_NONE, NULL, 0x0,
1551 NULL, HFILL }
1553 { &hf_aprs_msg_phg_h,
1554 { "Height", "aprs.msg.phg.h",
1555 FT_STRING, BASE_NONE, NULL, 0x0,
1556 NULL, HFILL }
1558 { &hf_aprs_msg_phg_g,
1559 { "Gain", "aprs.msg.phg.g",
1560 FT_STRING, BASE_NONE, NULL, 0x0,
1561 NULL, HFILL }
1563 { &hf_aprs_msg_phg_d,
1564 { "Directivity", "aprs.msg.phg.d",
1565 FT_STRING, BASE_NONE, NULL, 0x0,
1566 NULL, HFILL }
1569 /* Msg DFS */
1570 { &hf_aprs_msg_dfs_s,
1571 { "Strength", "aprs.msg.dfs.s",
1572 FT_STRING, BASE_NONE, NULL, 0x0,
1573 NULL, HFILL }
1575 { &hf_aprs_msg_dfs_h,
1576 { "Height", "aprs.msg.dfs.h",
1577 FT_STRING, BASE_NONE, NULL, 0x0,
1578 NULL, HFILL }
1580 { &hf_aprs_msg_dfs_g,
1581 { "Gain", "aprs.msg.dfs.g",
1582 FT_STRING, BASE_NONE, NULL, 0x0,
1583 NULL, HFILL }
1585 { &hf_aprs_msg_dfs_d,
1586 { "Directivity", "aprs.msg.dfs.d",
1587 FT_STRING, BASE_NONE, NULL, 0x0,
1588 NULL, HFILL }
1591 /* Msg AOD */
1592 { &hf_aprs_msg_aod_t,
1593 { "Type", "aprs.msg.aod.t",
1594 FT_STRING, BASE_NONE, NULL, 0x0,
1595 NULL, HFILL }
1597 { &hf_aprs_msg_aod_c,
1598 { "Colour", "aprs.msg.aod.c",
1599 FT_STRING, BASE_NONE, NULL, 0x0,
1600 NULL, HFILL }
1603 /* Weather */
1604 { &hf_aprs_weather,
1605 { "Weather report", "aprs.weather",
1606 FT_STRING, BASE_NONE, NULL, 0x0,
1607 NULL, HFILL }
1609 { &hf_aprs_weather_dir,
1610 { "Wind direction", "aprs.weather.dir",
1611 FT_STRING, BASE_NONE, NULL, 0x0,
1612 NULL, HFILL }
1614 { &hf_aprs_weather_spd,
1615 { "Wind speed", "aprs.weather.speed",
1616 FT_STRING, BASE_NONE, NULL, 0x0,
1617 "Wind speed (1 minute)", HFILL }
1619 { &hf_aprs_weather_peak,
1620 { "Peak wind speed", "aprs.weather.peak",
1621 FT_STRING, BASE_NONE, NULL, 0x0,
1622 NULL, HFILL }
1624 { &hf_aprs_weather_temp,
1625 { "Temperature (F)", "aprs.weather.temp",
1626 FT_STRING, BASE_NONE, NULL, 0x0,
1627 NULL, HFILL }
1629 { &hf_aprs_weather_rain_1,
1630 { "Rain (last 1 hour)", "aprs.weather.1_hour",
1631 FT_STRING, BASE_NONE, NULL, 0x0,
1632 NULL, HFILL }
1634 { &hf_aprs_weather_rain_24,
1635 { "Rain (last 24 hours)", "aprs.weather.24_hour",
1636 FT_STRING, BASE_NONE, NULL, 0x0,
1637 NULL, HFILL }
1639 { &hf_aprs_weather_rain,
1640 { "Rain", "aprs.weather.rain",
1641 FT_STRING, BASE_NONE, NULL, 0x0,
1642 NULL, HFILL }
1644 { &hf_aprs_weather_humidty,
1645 { "Humidity", "aprs.weather.humidity",
1646 FT_STRING, BASE_NONE, NULL, 0x0,
1647 NULL, HFILL }
1649 { &hf_aprs_weather_press,
1650 { "Pressure", "aprs.weather.pressure",
1651 FT_STRING, BASE_NONE, NULL, 0x0,
1652 NULL, HFILL }
1654 { &hf_aprs_weather_luminosity,
1655 { "Luminosity", "aprs.weather.luminosity",
1656 FT_STRING, BASE_NONE, NULL, 0x0,
1657 NULL, HFILL }
1659 { &hf_aprs_weather_snow,
1660 { "Snow", "aprs.weather.snow",
1661 FT_STRING, BASE_NONE, NULL, 0x0,
1662 NULL, HFILL }
1664 { &hf_aprs_weather_raw_rain,
1665 { "Raw rain", "aprs.weather.raw_rain",
1666 FT_STRING, BASE_NONE, NULL, 0x0,
1667 NULL, HFILL }
1669 { &hf_aprs_weather_software,
1670 { "Software", "aprs.weather.software",
1671 FT_STRING, BASE_NONE, NULL, 0x0,
1672 NULL, HFILL }
1674 { &hf_aprs_weather_unit,
1675 { "Unit", "aprs.weather.unit",
1676 FT_STRING, BASE_NONE, NULL, 0x0,
1677 NULL, HFILL }
1680 /* MIC-E */
1681 { &hf_aprs_mic_e_0_current,
1682 { "Current Mic-E (Rev 0)", "aprs.mic_e_0_current",
1683 FT_STRING, BASE_NONE, NULL, 0x0,
1684 NULL, HFILL }
1686 { &hf_aprs_mic_e_0_old,
1687 { "Old Mic-E (Rev 0)", "aprs.mic_e_0_old",
1688 FT_STRING, BASE_NONE, NULL, 0x0,
1689 NULL, HFILL }
1691 { &hf_aprs_mic_e_old,
1692 { "Old Mic-E", "aprs.mic_e_old",
1693 FT_STRING, BASE_NONE, NULL, 0x0,
1694 "Old Mic-E Data (but Current data for TM-D700)", HFILL }
1696 { &hf_aprs_mic_e_current,
1697 { "Current Mic-E", "aprs.mic_e_current",
1698 FT_STRING, BASE_NONE, NULL, 0x0,
1699 "Current Mic-E Data (not used in TM-D700)", HFILL }
1701 { &hf_aprs_mic_e_dst,
1702 { "Destination Address", "aprs.mic_e.dst",
1703 FT_STRING, BASE_NONE, NULL, 0x0,
1704 NULL, HFILL }
1706 { &hf_aprs_mic_e_long_d,
1707 { "Longitude degrees", "aprs.mic_e.long_d",
1708 FT_UINT8, BASE_HEX, NULL, 0x0,
1709 NULL, HFILL }
1711 { &hf_aprs_mic_e_long_m ,
1712 { "Longitude minutes", "aprs.mic_e.long_m",
1713 FT_UINT8, BASE_HEX, NULL, 0x0,
1714 NULL, HFILL }
1716 { &hf_aprs_mic_e_long_h,
1717 { "Longitude hundredths of minutes", "aprs.mic_e.long_h",
1718 FT_UINT8, BASE_HEX, NULL, 0x0,
1719 NULL, HFILL }
1721 { &hf_aprs_mic_e_spd_sp,
1722 { "Speed (hundreds & tens)", "aprs.mic_e.speed_sp",
1723 FT_UINT8, BASE_HEX, NULL, 0x0,
1724 NULL, HFILL }
1726 { &hf_aprs_mic_e_spd_dc,
1727 { "Speed (tens), Course (hundreds)", "aprs.mic_e.speed_dc",
1728 FT_UINT8, BASE_HEX, NULL, 0x0,
1729 NULL, HFILL }
1731 { &hf_aprs_mic_e_spd_se,
1732 { "Course (tens & units)", "aprs.mic_e.speed_se",
1733 FT_UINT8, BASE_HEX, NULL, 0x0,
1734 NULL, HFILL }
1736 { &hf_aprs_mic_e_telemetry,
1737 { "Telemetry", "aprs.mic_e.telemetry",
1738 FT_BYTES, BASE_NONE, NULL, 0x0,
1739 NULL, HFILL }
1741 { &hf_aprs_mic_e_status,
1742 { "Status", "aprs.mic_e.status",
1743 FT_STRING, BASE_NONE, NULL, 0x0,
1744 NULL, HFILL }
1746 { &hf_aprs_storm_dir,
1747 { "Direction", "aprs.storm.direction",
1748 FT_STRING, BASE_NONE, NULL, 0x0,
1749 NULL, HFILL }
1751 { &hf_aprs_storm_spd,
1752 { "Speed (knots)", "aprs.storm.speed",
1753 FT_STRING, BASE_NONE, NULL, 0x0,
1754 NULL, HFILL }
1756 { &hf_aprs_storm_type,
1757 { "Type", "aprs.storm.type",
1758 FT_STRING, BASE_NONE, NULL, 0x0,
1759 NULL, HFILL }
1761 { &hf_aprs_storm_sws,
1762 { "Sustained wind speed (knots)", "aprs.storm.sws",
1763 FT_STRING, BASE_NONE, NULL, 0x0,
1764 NULL, HFILL }
1766 { &hf_aprs_storm_pwg,
1767 { "Peak wind gusts (knots)", "aprs.storm.pwg",
1768 FT_STRING, BASE_NONE, NULL, 0x0,
1769 NULL, HFILL }
1771 { &hf_aprs_storm_cp,
1772 { "Central pressure (millibars/hPascal)", "aprs.storm.central_pressure",
1773 FT_STRING, BASE_NONE, NULL, 0x0,
1774 NULL, HFILL }
1776 { &hf_aprs_storm_rhw,
1777 { "Radius Hurricane Winds (nautical miles)", "aprs.storm.radius_hurricane_winds",
1778 FT_STRING, BASE_NONE, NULL, 0x0,
1779 NULL, HFILL }
1781 { &hf_aprs_storm_rtsw,
1782 { "Radius Tropical Storm Winds (nautical miles)", "aprs.storm.radius_tropical_storms_winds",
1783 FT_STRING, BASE_NONE, NULL, 0x0,
1784 NULL, HFILL }
1786 { &hf_aprs_storm_rwg,
1787 { "Radius Whole Gale (nautical miles)", "aprs.storm.radius_whole_gale",
1788 FT_STRING, BASE_NONE, NULL, 0x0,
1789 NULL, HFILL }
1793 static int *ett[] = {
1794 &ett_aprs,
1795 &ett_aprs_msg,
1796 &ett_aprs_ct,
1797 &ett_aprs_weather,
1798 &ett_aprs_storm,
1799 &ett_aprs_mic_e,
1802 proto_aprs = proto_register_protocol("Automatic Position Reporting System", "APRS", "aprs");
1804 register_dissector( "aprs", dissect_aprs, proto_aprs);
1806 proto_register_field_array( proto_aprs, hf, array_length(hf ) );
1807 proto_register_subtree_array( ett, array_length( ett ) );
1809 aprs_module = prefs_register_protocol( proto_aprs, NULL);
1811 prefs_register_bool_preference(aprs_module, "showaprslax",
1812 "Allow APRS violations.",
1813 "Attempt to display common APRS protocol violations correctly",
1814 &gPREF_APRS_LAX );
1819 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1821 * Local variables:
1822 * c-basic-offset: 8
1823 * tab-width: 8
1824 * indent-tabs-mode: t
1825 * End:
1827 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1828 * :indentSize=8:tabSize=8:noTabs=false: