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>
4 *
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 /*
13 * This dissector is for APRS (Automatic Packet Reporting System)
14 *
15 * Information was drawn from:
16 * http://www.aprs.org/
17 * Specification: http://www.aprs.org/doc/APRS101.PDF
18 *
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.
26 */
27
28 #include "config.h"
29
30 #include <math.h>
31
32 #include <epan/packet.h>
33 #include <epan/prefs.h>
34 #include <epan/to_str.h>
35
36 #define STRLEN 100
37
38 void proto_register_aprs(void);
39
40 static int proto_aprs = -1;
41
42 /* aprs timestamp items */
43 static int hf_aprs_dhm = -1;
44 static int hf_aprs_hms = -1;
45 static int hf_aprs_mdhm = -1;
46 static int hf_aprs_tz = -1;
47
48 /* aprs position items */
49 /* static int hf_aprs_position = -1; */
50 static int hf_aprs_lat = -1;
51 static int hf_aprs_long = -1;
52
53 /* aprs msg items */
54 static int hf_aprs_msg = -1;
55 static int hf_aprs_msg_rng = -1;
56 static int hf_aprs_msg_cse = -1;
57 static int hf_aprs_msg_spd = -1;
58 static int hf_aprs_msg_dir = -1;
59 static int hf_aprs_msg_brg = -1;
60 static int hf_aprs_msg_nrq = -1;
61
62 /* aprs compression type items */
63 static int hf_aprs_compression_type = -1;
64 static int hf_aprs_ct_gps_fix = -1;
65 static int hf_aprs_ct_nmea_src = -1;
66 static int hf_aprs_ct_origin = -1;
67
68 /* phg msg items */
69 static int hf_aprs_msg_phg_p = -1;
70 static int hf_aprs_msg_phg_h = -1;
71 static int hf_aprs_msg_phg_g = -1;
72 static int hf_aprs_msg_phg_d = -1;
73
74 /* dfs msg items */
75 static int hf_aprs_msg_dfs_s = -1;
76 static int hf_aprs_msg_dfs_h = -1;
77 static int hf_aprs_msg_dfs_g = -1;
78 static int hf_aprs_msg_dfs_d = -1;
79
80 /* weather items */
81 static int hf_aprs_weather_dir = -1;
82 static int hf_aprs_weather_spd = -1;
83 static int hf_aprs_weather_peak = -1;
84 static int hf_aprs_weather_temp = -1;
85 static int hf_aprs_weather_rain_1 = -1;
86 static int hf_aprs_weather_rain_24 = -1;
87 static int hf_aprs_weather_rain = -1;
88 static int hf_aprs_weather_humidty = -1;
89 static int hf_aprs_weather_press = -1;
90 static int hf_aprs_weather_luminosity = -1;
91 static int hf_aprs_weather_snow = -1;
92 static int hf_aprs_weather_raw_rain = -1;
93 static int hf_aprs_weather_software = -1;
94 static int hf_aprs_weather_unit = -1;
95
96 /* aod msg items */
97 static int hf_aprs_msg_aod_t = -1;
98 static int hf_aprs_msg_aod_c = -1;
99
100 /* mic-e msg items */
101 static int hf_aprs_mic_e_dst = -1;
102 static int hf_aprs_mic_e_long_d = -1;
103 static int hf_aprs_mic_e_long_m = -1;
104 static int hf_aprs_mic_e_long_h = -1;
105 static int hf_aprs_mic_e_spd_sp = -1;
106 static int hf_aprs_mic_e_spd_dc = -1;
107 static int hf_aprs_mic_e_spd_se = -1;
108 static int hf_aprs_mic_e_telemetry = -1;
109 static int hf_aprs_mic_e_status = -1;
110
111 /* Storm items */
112 static int hf_aprs_storm_dir = -1;
113 static int hf_aprs_storm_spd = -1;
114 static int hf_aprs_storm_type = -1;
115 static int hf_aprs_storm_sws = -1;
116 static int hf_aprs_storm_pwg = -1;
117 static int hf_aprs_storm_cp = -1;
118 static int hf_aprs_storm_rhw = -1;
119 static int hf_aprs_storm_rtsw = -1;
120 static int hf_aprs_storm_rwg = -1;
121
122 /* aprs sundry items */
123 static int hf_aprs_dti = -1;
124 static int hf_aprs_sym_id = -1;
125 static int hf_aprs_sym_code = -1;
126 static int hf_aprs_comment = -1;
127 static int hf_aprs_storm = -1;
128
129 /* aprs main catgories items */
130 static int hf_ultimeter_2000 = -1;
131 static int hf_aprs_status = -1;
132 static int hf_aprs_object = -1;
133 static int hf_aprs_item = -1;
134 static int hf_aprs_query = -1;
135 static int hf_aprs_telemetry = -1;
136 static int hf_aprs_raw = -1;
137 static int hf_aprs_station = -1;
138 static int hf_aprs_message = -1;
139 static int hf_aprs_agrelo = -1;
140 static int hf_aprs_maidenhead = -1;
141 static int hf_aprs_weather = -1;
142 static int hf_aprs_invalid_test = -1;
143 static int hf_aprs_user_defined = -1;
144 static int hf_aprs_third_party = -1;
145 static int hf_aprs_mic_e_0_current = -1;
146 static int hf_aprs_mic_e_0_old = -1;
147 static int hf_aprs_mic_e_old = -1;
148 static int hf_aprs_mic_e_current = -1;
149 static int hf_aprs_peet_1 = -1;
150 static int hf_aprs_peet_2 = -1;
151 static int hf_aprs_map_feature = -1;
152 static int hf_aprs_shelter_data = -1;
153 static int hf_aprs_space_weather = -1;
154
155
156 static gboolean gPREF_APRS_LAX = FALSE;
157
158 static gint ett_aprs = -1;
159 static gint ett_aprs_msg = -1;
160 static gint ett_aprs_ct = -1;
161 static gint ett_aprs_weather = -1;
162 static gint ett_aprs_storm = -1;
163 static gint ett_aprs_mic_e = -1;
164
165
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 }
176 };
177
178 static const value_string nmea_vals[] = {
179 { 0, "other" },
180 { 1, "GLL" },
181 { 2, "GGA" },
182 { 3, "RMC" },
183 { 0, NULL }
184 };
185
186 static const value_string gps_vals[] = {
187 { 0, "old (last)" },
188 { 1, "current" },
189 { 0, NULL }
190 };
191
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 }
221 };
222 static value_string_ext aprs_description_ext = VALUE_STRING_EXT_INIT(aprs_description);
223
224 /* MIC-E destination field code table */
225 typedef struct
226 {
227 guint8 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;
234
235 static const mic_e_dst_code_table_s dst_code[] =
236 {
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, '?' },
271 };
272
273
274 /* MIC-E message table */
275 typedef struct
276 {
277 const char *std;
278 const char *custom;
279 } mic_e_msg_table_s;
280
281 static const mic_e_msg_table_s mic_e_msg_table[] =
282 {
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" }
291 };
292
293 /* Code to actually dissect the packets */
294
295 static int
dissect_aprs_compression_type(tvbuff_t * tvb,int offset,proto_tree * parent_tree)296 dissect_aprs_compression_type( tvbuff_t *tvb,
297 int offset,
298 proto_tree *parent_tree
299 )
300 {
301 proto_tree *tc;
302 proto_tree *compression_tree;
303 int new_offset;
304 int data_len;
305 guint8 compression_type;
306
307
308 data_len = 1;
309 new_offset = offset + data_len;
310
311 if ( parent_tree )
312 {
313 compression_type = tvb_get_guint8( tvb, offset ) - 33;
314
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 );
318
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 );
322 }
323
324 return new_offset;
325 }
326
327 static int
dissect_aprs_msg(tvbuff_t * tvb,int offset,proto_tree * parent_tree,int wind,int brg_nrq)328 dissect_aprs_msg( tvbuff_t *tvb,
329 int offset,
330 proto_tree *parent_tree,
331 int wind,
332 int brg_nrq
333 )
334 {
335 proto_tree *msg_tree = NULL;
336 guint8 ch;
337
338
339 if ( parent_tree )
340 {
341 proto_tree *tc;
342 tc = proto_tree_add_item( parent_tree, hf_aprs_msg, tvb, offset, 7, ENC_ASCII|ENC_NA );
343 msg_tree = proto_item_add_subtree( tc, ett_aprs_msg );
344 }
345
346 ch = tvb_get_guint8( tvb, offset );
347
348 if ( g_ascii_isdigit( ch ) )
349 {
350 if ( wind )
351 proto_tree_add_item( msg_tree, hf_aprs_msg_dir, tvb, offset, 3, ENC_ASCII|ENC_NA );
352 else
353 proto_tree_add_item( msg_tree, hf_aprs_msg_cse, tvb, offset, 3, ENC_ASCII|ENC_NA );
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|ENC_NA );
358 offset += 3;
359 }
360 else
361 {
362 switch ( ch )
363 {
364 case 'D' : /* dfs */
365 offset += 3;
366 proto_tree_add_item( msg_tree, hf_aprs_msg_dfs_s, tvb, offset, 1, ENC_ASCII|ENC_NA );
367 offset += 1;
368 proto_tree_add_item( msg_tree, hf_aprs_msg_dfs_h, tvb, offset, 1, ENC_ASCII|ENC_NA );
369 offset += 1;
370 proto_tree_add_item( msg_tree, hf_aprs_msg_dfs_g, tvb, offset, 1, ENC_ASCII|ENC_NA );
371 offset += 1;
372 proto_tree_add_item( msg_tree, hf_aprs_msg_dfs_d, tvb, offset, 1, ENC_ASCII|ENC_NA );
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|ENC_NA );
377 offset += 1;
378 proto_tree_add_item( msg_tree, hf_aprs_msg_phg_h, tvb, offset, 1, ENC_ASCII|ENC_NA );
379 offset += 1;
380 proto_tree_add_item( msg_tree, hf_aprs_msg_phg_g, tvb, offset, 1, ENC_ASCII|ENC_NA );
381 offset += 1;
382 proto_tree_add_item( msg_tree, hf_aprs_msg_phg_d, tvb, offset, 1, ENC_ASCII|ENC_NA );
383 break;
384 case 'R' : /* rng */
385 proto_tree_add_item( msg_tree, hf_aprs_msg_rng, tvb, offset, 7, ENC_ASCII|ENC_NA );
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|ENC_NA );
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|ENC_NA );
394 break;
395 default : /* wtf */
396 break;
397 }
398 }
399 if ( brg_nrq )
400 {
401 proto_tree_add_item( msg_tree, hf_aprs_msg_brg, tvb, offset, 3, ENC_ASCII|ENC_NA );
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|ENC_NA );
406 offset += 3;
407 }
408
409 return offset;
410 }
411
412 static int
dissect_aprs_compressed_msg(tvbuff_t * tvb,int offset,proto_tree * parent_tree)413 dissect_aprs_compressed_msg( tvbuff_t *tvb,
414 int offset,
415 proto_tree *parent_tree
416 )
417 {
418 proto_tree *tc;
419 proto_tree *msg_tree;
420 int new_offset;
421 int data_len;
422 guint8 ch;
423 guint8 course;
424 double speed;
425 double range;
426 gchar *info_buffer;
427
428
429 data_len = 2;
430 new_offset = offset + data_len;
431
432 if ( parent_tree )
433 {
434 tc = proto_tree_add_item( parent_tree, hf_aprs_msg, tvb, offset, data_len, ENC_ASCII|ENC_NA );
435 msg_tree = proto_item_add_subtree( tc, ett_aprs_msg );
436
437 ch = tvb_get_guint8( tvb, offset );
438 if ( ch != ' ' )
439 {
440 if ( ch == '{' )
441 { /* Pre-Calculated Radio Range */
442 offset += 1;
443 ch = tvb_get_guint8( tvb, offset );
444 range = exp( log( 1.08 ) * (ch - 33) );
445 info_buffer = wmem_strdup_printf( wmem_packet_scope(), "%7.2f", range );
446 proto_tree_add_string( msg_tree, hf_aprs_msg_rng, tvb, offset, 1, info_buffer );
447 }
448 else
449 if ( ch >= '!' && ch <= 'z' )
450 { /* Course/Speed */
451 course = (ch - 33) * 4;
452 info_buffer = wmem_strdup_printf( wmem_packet_scope(), "%d", course );
453 proto_tree_add_string( msg_tree, hf_aprs_msg_cse,
454 tvb, offset, 1, info_buffer );
455 offset += 1;
456 ch = tvb_get_guint8( tvb, offset );
457 speed = exp( log( 1.08 ) * (ch - 33) );
458 info_buffer = wmem_strdup_printf( wmem_packet_scope(), "%7.2f", speed );
459 proto_tree_add_string( msg_tree, hf_aprs_msg_spd,
460 tvb, offset, 1, info_buffer );
461 }
462
463 }
464 }
465
466 return new_offset;
467 }
468
469
470 static const mic_e_dst_code_table_s *
dst_code_lookup(guint8 ch)471 dst_code_lookup( guint8 ch )
472 {
473 guint indx;
474
475 indx = 0;
476 while ( indx < ( sizeof( dst_code ) / sizeof( mic_e_dst_code_table_s ) )
477 && dst_code[ indx ].key != ch
478 && dst_code[ indx ].key > 0 )
479 indx++;
480 return &( dst_code[ indx ] );
481 }
482
483 static int
d28_to_deg(guint8 code,int long_offset)484 d28_to_deg( guint8 code, int long_offset )
485 {
486 int value;
487
488 value = code - 28 + long_offset;
489 if ( value >= 180 && value <= 189 )
490 value -= 80;
491 else
492 if ( value >= 190 && value <= 199 )
493 value -= 190;
494 return value;
495 }
496
497 static int
d28_to_min(guint8 code)498 d28_to_min( guint8 code )
499 {
500 int value;
501
502 value = code - 28;
503 if ( value >= 60 )
504 value -= 60;
505 return value;
506 }
507
508 static int
dissect_mic_e(tvbuff_t * tvb,int offset,packet_info * pinfo,proto_tree * parent_tree,int hf_mic_e_idx)509 dissect_mic_e( tvbuff_t *tvb,
510 int offset,
511 packet_info *pinfo,
512 proto_tree *parent_tree,
513 int hf_mic_e_idx
514 )
515 {
516 proto_tree *tc;
517 proto_tree *mic_e_tree;
518 int new_offset;
519 int data_len;
520 char *info_buffer;
521 char latitude[7] = { '?', '?', '?', '?', '.', '?', '?' };
522 int msg_a;
523 int msg_b;
524 int msg_c;
525 char n_s;
526 int long_offset;
527 char w_e;
528 int cse;
529 int spd;
530 guint8 ssid;
531 const guint8 *addr;
532 const mic_e_dst_code_table_s *dst_code_entry;
533
534 data_len = tvb_reported_length_remaining( tvb, offset );
535 new_offset = offset + data_len;
536
537 info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN );
538
539 msg_a = 0;
540 msg_b = 0;
541 msg_c = 0;
542
543 n_s = '?';
544 long_offset = 0;
545 w_e = '?';
546 ssid = 0;
547
548 if ( pinfo->dst.type == AT_AX25 && pinfo->dst.len == AX25_ADDR_LEN )
549 {
550 /* decode the AX.25 destination address */
551 addr = (const guint8 *)pinfo->dst.data;
552
553 dst_code_entry = dst_code_lookup( addr[ 0 ] );
554 latitude[ 0 ] = dst_code_entry->digit;
555 msg_a = dst_code_entry->msg & 0x1;
556
557 dst_code_entry = dst_code_lookup( addr[ 1 ] );
558 latitude[ 1 ] = dst_code_entry->digit;
559 msg_b = dst_code_entry->msg & 0x1;
560
561 dst_code_entry = dst_code_lookup( addr[ 2 ] );
562 latitude[ 2 ] = dst_code_entry->digit;
563 msg_c = dst_code_entry->msg & 0x1;
564
565 dst_code_entry = dst_code_lookup( addr[ 3 ] );
566 latitude[ 3 ] = dst_code_entry->digit;
567 n_s = dst_code_entry->n_s;
568
569 /* '.' already set */
570
571 dst_code_entry = dst_code_lookup( addr[ 4 ] );
572 latitude[ 5 ] = dst_code_entry->digit;
573 long_offset = dst_code_entry->long_offset;
574
575 dst_code_entry = dst_code_lookup( addr[ 5 ] );
576 latitude[ 6 ] = dst_code_entry->digit;
577 w_e = dst_code_entry->w_e;
578
579 ssid = (addr[ 6 ] >> 1) & 0x0f;
580 }
581
582 /* decode the mic-e info fields */
583 spd = ((tvb_get_guint8( tvb, offset + 3 ) - 28) * 10) + ((tvb_get_guint8( tvb, offset + 4 ) - 28) / 10);
584 if ( spd >= 800 )
585 spd -= 800;
586
587 cse = (((tvb_get_guint8( tvb, offset + 4 ) - 28) % 10) * 100) + ((tvb_get_guint8( tvb, offset + 5 ) - 28) * 10);
588 if ( cse >= 400 )
589 cse -= 400;
590
591 g_snprintf( info_buffer, STRLEN,
592 "Lat: %7.7s%c Long: %03d%02d.%02d%c, Cse: %d, Spd: %d, SSID: %d, Msg %s",
593 latitude,
594 n_s,
595 d28_to_deg( tvb_get_guint8( tvb, offset ), long_offset ),
596 d28_to_min( tvb_get_guint8( tvb, offset + 1 ) ),
597 tvb_get_guint8( tvb, offset + 2 ) - 28,
598 w_e,
599 cse,
600 spd,
601 ssid,
602 mic_e_msg_table[ (msg_a << 2) + (msg_b << 1) + msg_c ].std
603 );
604
605 col_set_str( pinfo->cinfo, COL_INFO, "MIC-E " );
606 col_append_str( pinfo->cinfo, COL_INFO, info_buffer );
607
608 if ( parent_tree )
609 {
610 tc = proto_tree_add_string( parent_tree, hf_mic_e_idx, tvb, offset, data_len, info_buffer );
611 mic_e_tree = proto_item_add_subtree( tc, ett_aprs_mic_e );
612
613 g_snprintf( info_buffer, STRLEN,
614 "Lat %7.7s, Msg A %d, Msg B %d, Msg C %d, N/S %c, Long off %3d, W/E %c, SSID %d",
615 latitude,
616 msg_a,
617 msg_b,
618 msg_c,
619 n_s,
620 long_offset,
621 w_e,
622 ssid
623 );
624
625 proto_tree_add_string( mic_e_tree, hf_aprs_mic_e_dst, tvb, 0, 0, info_buffer ); /* ?? */
626
627 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_long_d, tvb, offset, 1, ENC_BIG_ENDIAN );
628 offset += 1;
629
630 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_long_m, tvb, offset, 1, ENC_BIG_ENDIAN );
631 offset += 1;
632
633 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_long_h, tvb, offset, 1, ENC_BIG_ENDIAN );
634 offset += 1;
635
636 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_spd_sp, tvb, offset, 1, ENC_BIG_ENDIAN );
637 offset += 1;
638
639 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_spd_dc, tvb, offset, 1, ENC_BIG_ENDIAN );
640 offset += 1;
641
642 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_spd_se, tvb, offset, 1, ENC_BIG_ENDIAN );
643 offset += 1;
644
645 proto_tree_add_item( mic_e_tree, hf_aprs_sym_code, tvb, offset, 1, ENC_ASCII|ENC_NA );
646 offset += 1;
647
648 proto_tree_add_item( mic_e_tree, hf_aprs_sym_id, tvb, offset, 1, ENC_ASCII|ENC_NA );
649 offset += 1;
650
651 if ( offset < new_offset )
652 {
653 guint8 c = tvb_get_guint8(tvb, offset);
654 if ( (c == ',') || (c == 0x1d) )
655 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_telemetry,
656 tvb, offset, -1, ENC_NA );
657 else
658 proto_tree_add_item( mic_e_tree, hf_aprs_mic_e_status,
659 tvb, offset, -1, ENC_ASCII|ENC_NA );
660 }
661
662 }
663
664 return new_offset;
665 }
666
667 static int
dissect_aprs_storm(tvbuff_t * tvb,int offset,proto_tree * parent_tree)668 dissect_aprs_storm( tvbuff_t *tvb,
669 int offset,
670 proto_tree *parent_tree
671 )
672 {
673 proto_tree *storm_tree;
674 proto_tree *tc;
675
676 tc = proto_tree_add_item( parent_tree, hf_aprs_storm, tvb, offset, -1, ENC_ASCII|ENC_NA );
677 storm_tree = proto_item_add_subtree( tc, ett_aprs_storm );
678
679 proto_tree_add_item( storm_tree, hf_aprs_storm_dir, tvb, offset, 3, ENC_ASCII|ENC_NA );
680 offset += 3;
681 offset += 1;
682 proto_tree_add_item( storm_tree, hf_aprs_storm_spd, tvb, offset, 3, ENC_ASCII|ENC_NA );
683 offset += 3;
684 proto_tree_add_item( storm_tree, hf_aprs_storm_type, tvb, offset, 3, ENC_ASCII|ENC_NA );
685 offset += 3;
686 proto_tree_add_item( storm_tree, hf_aprs_storm_sws, tvb, offset, 4, ENC_ASCII|ENC_NA );
687 offset += 4;
688 proto_tree_add_item( storm_tree, hf_aprs_storm_pwg, tvb, offset, 4, ENC_ASCII|ENC_NA );
689 offset += 4;
690 proto_tree_add_item( storm_tree, hf_aprs_storm_cp, tvb, offset, 5, ENC_ASCII|ENC_NA );
691 offset += 5;
692 proto_tree_add_item( storm_tree, hf_aprs_storm_rhw, tvb, offset, 4, ENC_ASCII|ENC_NA );
693 offset += 4;
694 proto_tree_add_item( storm_tree, hf_aprs_storm_rtsw, tvb, offset, 4, ENC_ASCII|ENC_NA );
695 offset += 4;
696 proto_tree_add_item( storm_tree, hf_aprs_storm_rwg, tvb, offset, 4, ENC_ASCII|ENC_NA );
697 offset += 4;
698
699 return offset;
700 }
701
702 static int
dissect_aprs_weather(tvbuff_t * tvb,int offset,proto_tree * parent_tree)703 dissect_aprs_weather( tvbuff_t *tvb,
704 int offset,
705 proto_tree *parent_tree
706 )
707 {
708 proto_tree *tc;
709 proto_tree *weather_tree;
710 int new_offset;
711 int data_len;
712 guint8 ch;
713
714
715 data_len = tvb_reported_length_remaining( tvb, offset );
716 new_offset = offset + data_len;
717
718 tc = proto_tree_add_item( parent_tree, hf_aprs_weather, tvb, offset, data_len, ENC_ASCII|ENC_NA );
719 weather_tree = proto_item_add_subtree( tc, ett_aprs_weather );
720
721 ch = tvb_get_guint8( tvb, offset );
722 if ( g_ascii_isdigit( ch ) )
723 {
724 proto_tree_add_item( weather_tree, hf_aprs_weather_dir, tvb, offset, 3, ENC_ASCII|ENC_NA );
725 offset += 3;
726 /* verify the separator */
727 offset += 1;
728 proto_tree_add_item( weather_tree, hf_aprs_weather_spd, tvb, offset, 3, ENC_ASCII|ENC_NA );
729 offset += 3;
730 }
731
732 if ( parent_tree )
733 {
734 while ( offset < new_offset )
735 {
736 ch = tvb_get_guint8( tvb, offset );
737 switch ( ch )
738 {
739 case 'c' :
740 proto_tree_add_item( weather_tree, hf_aprs_weather_dir,
741 tvb, offset, 4, ENC_ASCII|ENC_NA );
742 offset += 4;
743 break;
744 case 's' :
745 proto_tree_add_item( weather_tree, hf_aprs_weather_spd,
746 tvb, offset, 4, ENC_ASCII|ENC_NA );
747 offset += 4;
748 break;
749 case 'g' :
750 proto_tree_add_item( weather_tree, hf_aprs_weather_peak,
751 tvb, offset, 4, ENC_ASCII|ENC_NA );
752 offset += 4;
753 break;
754 case 't' :
755 proto_tree_add_item( weather_tree, hf_aprs_weather_temp,
756 tvb, offset, 4, ENC_ASCII|ENC_NA );
757 offset += 4;
758 break;
759 case 'r' :
760 proto_tree_add_item( weather_tree, hf_aprs_weather_rain_1,
761 tvb, offset, 4, ENC_ASCII|ENC_NA );
762 offset += 4;
763 break;
764 case 'P' :
765 proto_tree_add_item( weather_tree, hf_aprs_weather_rain_24,
766 tvb, offset, 4, ENC_ASCII|ENC_NA );
767 offset += 4;
768 break;
769 case 'p' :
770 proto_tree_add_item( weather_tree, hf_aprs_weather_rain,
771 tvb, offset, 4, ENC_ASCII|ENC_NA );
772 offset += 4;
773 break;
774 case 'h' :
775 proto_tree_add_item( weather_tree, hf_aprs_weather_humidty,
776 tvb, offset, 3, ENC_ASCII|ENC_NA );
777 offset += 3;
778 break;
779 case 'b' :
780 proto_tree_add_item( weather_tree, hf_aprs_weather_press,
781 tvb, offset, 6, ENC_ASCII|ENC_NA );
782 offset += 6;
783 break;
784 case 'l' :
785 case 'L' :
786 proto_tree_add_item( weather_tree, hf_aprs_weather_luminosity,
787 tvb, offset, 4, ENC_ASCII|ENC_NA );
788 offset += 4;
789 break;
790 case 'S' :
791 proto_tree_add_item( weather_tree, hf_aprs_weather_snow,
792 tvb, offset, 4, ENC_ASCII|ENC_NA );
793 offset += 4;
794 break;
795 case '#' :
796 proto_tree_add_item( weather_tree, hf_aprs_weather_raw_rain,
797 tvb, offset, 4, ENC_ASCII|ENC_NA );
798 offset += 4;
799 break;
800 default : {
801 gint lr;
802 /* optional: software type/unit: see if present */
803 lr = new_offset - offset;
804 #if 0 /* fcn'al change: defer */
805 /*
806 * XXX - ASCII or UTF-8?
807 * See http://www.aprs.org/aprs12/utf-8.txt
808 */
809 if ( ((lr < 3) || (lr > 5)) ||
810 ( lr != strspn( tvb_get_string_enc( wmem_packet_scope(), tvb, offset, lr, ENC_ASCII|ENC_NA ), "a-zA-Z0-9-_" ) ) )
811 {
812 new_offset = offset; /* Assume rest is a comment: force exit from while */
813 break; /* from switch */
814 }
815 #endif
816 proto_tree_add_item( weather_tree, hf_aprs_weather_software,
817 tvb, offset, 1, ENC_ASCII|ENC_NA );
818 offset += 1;
819 proto_tree_add_item( weather_tree, hf_aprs_weather_unit,
820 tvb, offset, lr-1, ENC_ASCII|ENC_NA );
821 offset = new_offset;
822 break;
823 }
824 } /* switch */
825 } /* while */
826 } /* if (parent_tree) */
827 return new_offset;
828 }
829
830 static int
aprs_timestamp(proto_tree * aprs_tree,tvbuff_t * tvb,int offset)831 aprs_timestamp( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
832 {
833 int data_len;
834 const char *tzone;
835 guint8 ch;
836
837 data_len = 8;
838 tzone = "zulu";
839
840 ch= tvb_get_guint8( tvb, offset + 6 );
841 if ( g_ascii_isdigit( ch ) )
842 { /* MDHM */
843 proto_tree_add_item( aprs_tree, hf_aprs_mdhm, tvb, offset, data_len, ENC_ASCII|ENC_NA );
844 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset, data_len, tzone );
845 }
846 else
847 {
848 data_len -= 1;
849 if ( ch == 'h' )
850 { /* HMS */
851 proto_tree_add_item( aprs_tree, hf_aprs_hms, tvb, offset, data_len, ENC_ASCII|ENC_NA );
852 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset, data_len, tzone );
853 }
854 else
855 { /* DHM */
856 switch ( ch )
857 {
858 case 'z' : tzone = "zulu"; break;
859 case '/' : tzone = "local"; break;
860 default : tzone = "unknown"; break;
861 }
862 proto_tree_add_item( aprs_tree, hf_aprs_dhm, tvb, offset, data_len, ENC_ASCII|ENC_NA );
863 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset + 6, 1, tzone );
864 }
865 }
866
867 return offset + data_len;
868 }
869
870 static int
aprs_latitude_compressed(proto_tree * aprs_tree,tvbuff_t * tvb,int offset)871 aprs_latitude_compressed( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
872 {
873 if ( aprs_tree )
874 {
875 char *info_buffer;
876 int temp;
877
878 info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN );
879
880 temp = ( tvb_get_guint8( tvb, offset + 0 ) - 33 );
881 temp = ( tvb_get_guint8( tvb, offset + 1 ) - 33 ) + ( temp * 91 );
882 temp = ( tvb_get_guint8( tvb, offset + 2 ) - 33 ) + ( temp * 91 );
883 temp = ( tvb_get_guint8( tvb, offset + 3 ) - 33 ) + ( temp * 91 );
884
885 g_snprintf( info_buffer, STRLEN, "%6.2f", 90.0 - (temp / 380926.0) );
886 proto_tree_add_string( aprs_tree, hf_aprs_lat, tvb, offset, 4, info_buffer );
887 }
888 return offset + 4;
889 }
890
891 static int
aprs_longitude_compressed(proto_tree * aprs_tree,tvbuff_t * tvb,int offset)892 aprs_longitude_compressed( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
893 {
894 if ( aprs_tree )
895 {
896 char *info_buffer;
897 int temp;
898
899 info_buffer = (char *)wmem_alloc( wmem_packet_scope(), STRLEN );
900
901 temp = ( tvb_get_guint8( tvb, offset + 0 ) - 33 );
902 temp = ( tvb_get_guint8( tvb, offset + 1 ) - 33 ) + ( temp * 91 );
903 temp = ( tvb_get_guint8( tvb, offset + 2 ) - 33 ) + ( temp * 91 );
904 temp = ( tvb_get_guint8( tvb, offset + 3 ) - 33 ) + ( temp * 91 );
905
906 g_snprintf( info_buffer, STRLEN, "%7.2f", (temp / 190463.0) - 180.0 );
907 proto_tree_add_string( aprs_tree, hf_aprs_long, tvb, offset, 4, info_buffer );
908 }
909 return offset + 4;
910 }
911
912 static int
aprs_status(proto_tree * aprs_tree,tvbuff_t * tvb,int offset)913 aprs_status( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
914 {
915 int data_len;
916
917 data_len = tvb_reported_length_remaining( tvb, offset );
918
919 if ( ( data_len > 7 ) && ( tvb_get_guint8( tvb, offset+6 ) == 'z' ) )
920 {
921 proto_tree_add_item( aprs_tree, hf_aprs_dhm, tvb, offset, 6, ENC_ASCII|ENC_NA );
922 offset += 6;
923 data_len -= 6;
924 proto_tree_add_string( aprs_tree, hf_aprs_tz, tvb, offset, 1, "zulu" );
925 offset += 1;
926 data_len -= 1;
927 }
928 proto_tree_add_item( aprs_tree, hf_aprs_status, tvb, offset, data_len, ENC_ASCII|ENC_NA );
929
930 return offset + data_len;
931 }
932
933 static int
aprs_item(proto_tree * aprs_tree,tvbuff_t * tvb,int offset)934 aprs_item( proto_tree *aprs_tree, tvbuff_t *tvb, int offset )
935 {
936 char *info_buffer;
937 int data_len;
938 char *ch_ptr;
939
940 data_len = 10;
941
942 /*
943 * XXX - ASCII or UTF-8?
944 * See http://www.aprs.org/aprs12/utf-8.txt
945 */
946 info_buffer = tvb_get_string_enc( wmem_packet_scope(), tvb, offset, data_len, ENC_ASCII|ENC_NA );
947
948 ch_ptr = strchr( info_buffer, '!' );
949 if ( ch_ptr != NULL )
950 {
951 data_len = (int)(ch_ptr - info_buffer + 1);
952 *ch_ptr = '\0';
953 }
954 else
955 {
956 ch_ptr = strchr( info_buffer, '!' );
957 if ( ch_ptr != NULL )
958 {
959 data_len = (int)(ch_ptr - info_buffer + 1);
960 *ch_ptr = '\0';
961 }
962 }
963 proto_tree_add_string( aprs_tree, hf_aprs_item, tvb, offset, data_len, info_buffer );
964
965 return offset + data_len;
966 }
967
968 static int
aprs_3rd_party(proto_tree * aprs_tree,tvbuff_t * tvb,int offset,int data_len)969 aprs_3rd_party( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, int data_len )
970 {
971 /* If the type of the hf[] entry pointed to by hfindex is FT_BYTES or FT_STRING */
972 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
973 if ( data_len == -1 )
974 {
975 data_len = tvb_reported_length_remaining( tvb, offset );
976 #if 0 /* fcn'al change: defer */
977 if ( data_len <= 0 )
978 return offset; /* there's no data */
979 #endif
980 }
981 proto_tree_add_item( aprs_tree, hf_aprs_third_party, tvb, offset, data_len, ENC_NA );
982 /* tnc-2 */
983 /* aea */
984 return offset + data_len;
985 }
986
987 static int
aprs_default_string(proto_tree * aprs_tree,tvbuff_t * tvb,int offset,int data_len,int hfindex)988 aprs_default_string( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, int data_len, int hfindex )
989 {
990 /* Assumption: hfindex points to an hf[] entry with type FT_STRING; should be validated ? */
991 /* If the type of the hf[] entry pointed to by hfindex is FT_STRING */
992 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
993 if ( data_len == -1 )
994 {
995 data_len = tvb_reported_length_remaining( tvb, offset );
996 #if 0 /* fcn'al change: defer */
997 if ( data_len <= 0 )
998 return offset; /* there's no data */
999 #endif
1000 }
1001 proto_tree_add_item( aprs_tree, hfindex, tvb, offset, data_len, ENC_ASCII|ENC_NA );
1002 return offset + data_len;
1003 }
1004
1005 static int
aprs_default_bytes(proto_tree * aprs_tree,tvbuff_t * tvb,int offset,int data_len,int hfindex)1006 aprs_default_bytes( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, int data_len, int hfindex )
1007 {
1008 /* Assumption: hfindex points to an hf[] entry with type FT_BYTES; should be validated ? */
1009 /* If the type of the hf[] entry pointed to by hfindex is FT_BYTES */
1010 /* then data_len == -1 is allowed and means "remainder of the tvbuff" */
1011 if ( data_len == -1 )
1012 {
1013 data_len = tvb_reported_length_remaining( tvb, offset );
1014 #if 0 /* fcn'al change: defer */
1015 if ( data_len <= 0 )
1016 return offset; /* there's no data */
1017 #endif
1018 }
1019 proto_tree_add_item( aprs_tree, hfindex, tvb, offset, data_len, ENC_NA );
1020 return offset + data_len;
1021 }
1022
1023 static int
aprs_position(proto_tree * aprs_tree,tvbuff_t * tvb,int offset,gboolean with_msg)1024 aprs_position( proto_tree *aprs_tree, tvbuff_t *tvb, int offset, gboolean with_msg )
1025 {
1026 guint8 symbol_table_id = 0;
1027 guint8 symbol_code = 0;
1028 gboolean probably_a_msg = FALSE;
1029 gboolean probably_not_a_msg = FALSE;
1030
1031 if ( g_ascii_isdigit( tvb_get_guint8( tvb, offset ) ) )
1032 {
1033 offset = aprs_default_string( aprs_tree, tvb, offset, 8, hf_aprs_lat );
1034 symbol_table_id = tvb_get_guint8( tvb, offset );
1035 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_id );
1036 offset = aprs_default_string( aprs_tree, tvb, offset, 9, hf_aprs_long );
1037 symbol_code = tvb_get_guint8( tvb, offset );
1038 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_code );
1039 if ( gPREF_APRS_LAX )
1040 {
1041 switch ( tvb_get_guint8( tvb, offset ) )
1042 {
1043 case 'D' : probably_a_msg = TRUE; break;
1044 case 'P' : probably_a_msg = TRUE; break;
1045 case 'R' : probably_a_msg = TRUE; break;
1046 case 'T' : probably_a_msg = TRUE; break;
1047 default : probably_not_a_msg = TRUE; break;
1048 }
1049 }
1050 if ( with_msg || probably_a_msg || ! probably_not_a_msg )
1051 offset = dissect_aprs_msg( tvb,
1052 offset,
1053 aprs_tree,
1054 ( symbol_code == '_' ),
1055 ( symbol_table_id == '/' && symbol_code == '\\' )
1056 );
1057 }
1058 else
1059 {
1060 symbol_table_id = tvb_get_guint8( tvb, offset );
1061 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_id );
1062 offset = aprs_latitude_compressed( aprs_tree, tvb, offset );
1063 offset = aprs_longitude_compressed( aprs_tree, tvb, offset );
1064 symbol_code = tvb_get_guint8( tvb, offset );
1065 offset = aprs_default_string( aprs_tree, tvb, offset, 1, hf_aprs_sym_code );
1066 offset = dissect_aprs_compressed_msg( tvb,
1067 offset,
1068 aprs_tree
1069 );
1070 offset = dissect_aprs_compression_type( tvb,
1071 offset,
1072 aprs_tree
1073 );
1074 if ( symbol_table_id == '/' && symbol_code == '\\' )
1075 offset = aprs_default_string( aprs_tree, tvb, offset, 8, hf_aprs_msg_brg );
1076 }
1077
1078 if ( symbol_code == '_' )
1079 offset = dissect_aprs_weather( tvb,
1080 offset,
1081 aprs_tree
1082 );
1083 if ( ( symbol_table_id == '/' && symbol_code == '@' ) || ( symbol_table_id == '\\' && symbol_code == '@' ) )
1084 offset = dissect_aprs_storm( tvb,
1085 offset,
1086 aprs_tree
1087 );
1088
1089 return offset;
1090 }
1091
1092 static int
dissect_aprs(tvbuff_t * tvb,packet_info * pinfo,proto_tree * parent_tree,void * data _U_)1093 dissect_aprs( tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, void *data _U_ )
1094 {
1095 proto_item *ti;
1096 proto_tree *aprs_tree;
1097
1098 int offset;
1099 guint8 dti;
1100 wmem_strbuf_t *sb;
1101
1102 col_set_str( pinfo->cinfo, COL_PROTOCOL, "APRS" );
1103 col_clear( pinfo->cinfo, COL_INFO );
1104
1105 offset = 0;
1106
1107 dti = tvb_get_guint8( tvb, offset );
1108
1109 sb = wmem_strbuf_new_label(wmem_packet_scope());
1110
1111 if (dti != '!')
1112 wmem_strbuf_append(sb, val_to_str_ext_const(dti, &aprs_description_ext, ""));
1113
1114 switch ( dti )
1115 {
1116 case '!':
1117 /* Position or Ultimeter 2000 WX Station */
1118 if ( tvb_get_guint8( tvb, offset + 1 ) == '!' )
1119 {
1120 wmem_strbuf_append(sb, "Ultimeter 2000 WX Station");
1121 }
1122 else
1123 {
1124 /* Position "without APRS messaging" */
1125 wmem_strbuf_append(sb, "Position (");
1126 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1, 8)); /* Lat */
1127 wmem_strbuf_append(sb, " ");
1128 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8 + 1, 9)); /* Long */
1129 wmem_strbuf_append(sb, " ");
1130 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8, 1)); /* Symbol table id */
1131 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8 + 1 + 9, 1)); /* Symbol Code */
1132 }
1133 break;
1134
1135 case '=':
1136 /* Position "with APRS messaging" + Ext APRS message */
1137 wmem_strbuf_append(sb, " (");
1138 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1, 8)); /* Lat */
1139 wmem_strbuf_append(sb, " ");
1140 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8 + 1, 9)); /* Long */
1141 wmem_strbuf_append(sb, " ");
1142 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8, 1)); /* Symbol table id */
1143 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 8 + 1 + 9, 1)); /* Symbol Code */
1144 break;
1145
1146 case '/':
1147 /* Position + timestamp "without APRS messaging" */
1148 wmem_strbuf_append(sb, " (");
1149 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1, 7)); /* Timestamp */
1150 wmem_strbuf_append(sb, " ");
1151 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 1, 8)); /*??*/ /* Lat */
1152 wmem_strbuf_append(sb, " ");
1153 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 8 + 1, 9)); /* Long */
1154 wmem_strbuf_append(sb, " ");
1155 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7, 1)); /* Symbol table id */
1156 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 1 + 9, 1)); /* Symbol Code */
1157 break;
1158
1159 case '@':
1160 /* Position + timestamp "with APRS messaging" + Ext APRS message */
1161 wmem_strbuf_append(sb, " (");
1162 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1, 7)); /* Timestamp */
1163 wmem_strbuf_append(sb, " ");
1164 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 1, 8)); /*??*/ /* Lat */
1165 wmem_strbuf_append(sb, " ");
1166 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 8 + 1, 9)); /* Long */
1167 wmem_strbuf_append(sb, " ");
1168 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7, 1)); /* Symbol table id */
1169 wmem_strbuf_append(sb, tvb_format_text(pinfo->pool, tvb, offset + 1 + 7 + 1 + 9, 1)); /* Symbol Code */
1170 break;
1171 }
1172
1173 col_add_str( pinfo->cinfo, COL_INFO, wmem_strbuf_get_str(sb) );
1174
1175 /* create display subtree for the protocol */
1176 ti = proto_tree_add_protocol_format( parent_tree , proto_aprs, tvb, 0, -1, "%s", wmem_strbuf_get_str(sb) );
1177 aprs_tree = proto_item_add_subtree( ti, ett_aprs );
1178
1179 proto_tree_add_item( aprs_tree, hf_aprs_dti, tvb, offset, 1, ENC_ASCII|ENC_NA );
1180 offset += 1;
1181
1182 switch ( dti )
1183 {
1184 case '<' : /* Station Capabilities */
1185 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_station );
1186 break;
1187 case '>' : /* Status */
1188 offset = aprs_status( aprs_tree, tvb, offset );
1189 break;
1190 case '?' : /* Query */
1191 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_query );
1192 break;
1193 case '$' : /* Raw GPS data or Ultimeter 2000 */
1194 if ( tvb_get_guint8( tvb, offset ) == 'U' )
1195 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_ultimeter_2000 );
1196 else
1197 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_raw );
1198 break;
1199 case '%' : /* Agrelo DFJr / MicroFinder */
1200 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_agrelo );
1201 break;
1202 case 'T' : /* Telemetry data */
1203 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_telemetry );
1204 break;
1205 case '[' : /* Maidenhead grid locator beacon (obsolete) */
1206 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_maidenhead );
1207 break;
1208 case '_' : /* Weather Report (without position) */
1209 offset = aprs_timestamp( aprs_tree, tvb, offset );
1210 offset = dissect_aprs_weather( tvb,
1211 offset,
1212 aprs_tree
1213 );
1214 break;
1215 case ',' : /* Invalid data or test data */
1216 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_invalid_test );
1217 break;
1218 case '{' : /* User-Defined APRS packet format */
1219 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_user_defined );
1220 break;
1221 case '}' : /* Third-party traffic */
1222 offset = aprs_3rd_party( aprs_tree, tvb, offset, -1 );
1223 break;
1224 case ':' : /* Message */
1225 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_message );
1226 break;
1227 case 0x1c : /* Current Mic-E Data (Rev 0 beta) */
1228 offset = dissect_mic_e( tvb,
1229 offset,
1230 pinfo,
1231 aprs_tree,
1232 hf_aprs_mic_e_0_current
1233 );
1234 break;
1235 case 0x1d : /* Old Mic-E Data (Rev 0 beta) */
1236 offset = dissect_mic_e( tvb,
1237 offset,
1238 pinfo,
1239 aprs_tree,
1240 hf_aprs_mic_e_0_old
1241 );
1242 break;
1243 case '\'' : /* Old Mic-E Data (but Current data for TM-D700) */
1244 offset = dissect_mic_e( tvb,
1245 offset,
1246 pinfo,
1247 aprs_tree,
1248 hf_aprs_mic_e_old
1249 );
1250 break;
1251 case '`' : /* Current Mic-E Data (not used in TM-D700) */
1252 offset = dissect_mic_e( tvb,
1253 offset,
1254 pinfo,
1255 aprs_tree,
1256 hf_aprs_mic_e_current
1257 );
1258 break;
1259 case '#' : /* Peet Bros U-II Weather Station */
1260 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_peet_1 );
1261 break;
1262 case '*' : /* Peet Bros U-II Weather Station */
1263 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_peet_2 );
1264 break;
1265 case '&' : /* [Reserved - Map Feature] */
1266 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_map_feature );
1267 break;
1268 case '+' : /* [Reserved - Shelter data with time] */
1269 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_shelter_data );
1270 break;
1271 case '.' : /* [Reserved - Space weather] */
1272 offset = aprs_default_bytes( aprs_tree, tvb, offset, -1, hf_aprs_space_weather );
1273 break;
1274 case ')' : /* Item */
1275 offset = aprs_item( aprs_tree, tvb, offset );
1276 offset = aprs_position( aprs_tree, tvb, offset, TRUE );
1277 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1278 break;
1279 case ';' : /* Object */
1280 offset = aprs_default_string( aprs_tree, tvb, offset, 10, hf_aprs_object );
1281 offset = aprs_timestamp( aprs_tree, tvb, offset );
1282 offset = aprs_position( aprs_tree, tvb, offset, TRUE );
1283 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1284 break;
1285 case '!' : /* Position or Ultimeter 2000 WX Station */
1286 if ( tvb_get_guint8( tvb, offset ) == '!' )
1287 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_ultimeter_2000 );
1288 else
1289 {
1290 offset = aprs_position( aprs_tree, tvb, offset, FALSE );
1291 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1292 }
1293 break;
1294 case '=' : /* Position + Ext APRS message */
1295 offset = aprs_position( aprs_tree, tvb, offset, TRUE );
1296 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1297 break;
1298 case '/' : /* Position + timestamp */
1299 offset = aprs_timestamp( aprs_tree, tvb, offset );
1300 offset = aprs_position( aprs_tree, tvb, offset, FALSE );
1301 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1302 break;
1303 case '@' : /* Position + timestamp + Ext APRS message */
1304 offset = aprs_timestamp( aprs_tree, tvb, offset );
1305 offset = aprs_position( aprs_tree, tvb, offset, TRUE );
1306 offset = aprs_default_string( aprs_tree, tvb, offset, -1, hf_aprs_comment );
1307 break;
1308 default : break;
1309 }
1310 return offset;
1311 }
1312
1313 void
proto_register_aprs(void)1314 proto_register_aprs( void )
1315 {
1316 module_t *aprs_module;
1317
1318 static hf_register_info hf[] = {
1319 { &hf_aprs_dti,
1320 { "Data Type Indicator", "aprs.dti",
1321 FT_STRING, BASE_NONE, NULL, 0x0,
1322 NULL, HFILL }
1323 },
1324 { &hf_aprs_sym_code,
1325 { "Symbol code", "aprs.sym_code",
1326 FT_STRING, BASE_NONE, NULL, 0x0,
1327 NULL, HFILL }
1328 },
1329 { &hf_aprs_sym_id,
1330 { "Symbol table ID", "aprs.sym_id",
1331 FT_STRING, BASE_NONE, NULL, 0x0,
1332 NULL, HFILL }
1333 },
1334
1335 /* Position */
1336 #if 0
1337 { &hf_aprs_position,
1338 { "Position", "aprs.position",
1339 FT_STRING, BASE_NONE, NULL, 0x0,
1340 NULL, HFILL }
1341 },
1342 #endif
1343 { &hf_aprs_lat,
1344 { "Latitude", "aprs.position.lat",
1345 FT_STRING, BASE_NONE, NULL, 0x0,
1346 NULL, HFILL }
1347 },
1348 { &hf_aprs_long,
1349 { "Longitude", "aprs.position.long",
1350 FT_STRING, BASE_NONE, NULL, 0x0,
1351 NULL, HFILL }
1352 },
1353
1354 /* APRS Messages */
1355 { &hf_aprs_comment,
1356 { "Comment", "aprs.comment",
1357 FT_STRING, BASE_NONE, NULL, 0x0,
1358 NULL, HFILL }
1359 },
1360 { &hf_ultimeter_2000,
1361 { "Ultimeter 2000", "aprs.ultimeter_2000",
1362 FT_STRING, BASE_NONE, NULL, 0x0,
1363 NULL, HFILL }
1364 },
1365 { &hf_aprs_status,
1366 { "Status", "aprs.status",
1367 FT_STRING, BASE_NONE, NULL, 0x0,
1368 NULL, HFILL }
1369 },
1370 { &hf_aprs_object,
1371 { "Object", "aprs.object",
1372 FT_STRING, BASE_NONE, NULL, 0x0,
1373 NULL, HFILL }
1374 },
1375 { &hf_aprs_item,
1376 { "Item", "aprs.item",
1377 FT_STRING, BASE_NONE, NULL, 0x0,
1378 NULL, HFILL }
1379 },
1380 { &hf_aprs_query,
1381 { "Query", "aprs.query",
1382 FT_STRING, BASE_NONE, NULL, 0x0,
1383 NULL, HFILL }
1384 },
1385 { &hf_aprs_telemetry,
1386 { "Telemetry", "aprs.telemetry",
1387 FT_STRING, BASE_NONE, NULL, 0x0,
1388 NULL, HFILL }
1389 },
1390 { &hf_aprs_raw,
1391 { "Raw", "aprs.raw",
1392 FT_STRING, BASE_NONE, NULL, 0x0,
1393 "Raw NMEA position report format", HFILL }
1394 },
1395 { &hf_aprs_station,
1396 { "Station", "aprs.station",
1397 FT_STRING, BASE_NONE, NULL, 0x0,
1398 "Station capabilities", HFILL }
1399 },
1400 { &hf_aprs_message,
1401 { "Message", "aprs.message",
1402 FT_STRING, BASE_NONE, NULL, 0x0,
1403 NULL, HFILL }
1404 },
1405 { &hf_aprs_agrelo,
1406 { "Agrelo", "aprs.agrelo",
1407 FT_BYTES, BASE_NONE, NULL, 0x0,
1408 "Agrelo DFJr / MicroFinder", HFILL }
1409 },
1410 { &hf_aprs_maidenhead,
1411 { "Maidenhead", "aprs.maidenhead",
1412 FT_BYTES, BASE_NONE, NULL, 0x0,
1413 "Maidenhead grid locator beacon (obsolete)", HFILL }
1414 },
1415 { &hf_aprs_invalid_test,
1416 { "Invalid or test", "aprs.invalid_test",
1417 FT_BYTES, BASE_NONE, NULL, 0x0,
1418 "Invalid data or test data", HFILL }
1419 },
1420 { &hf_aprs_user_defined,
1421 { "User-Defined", "aprs.user_defined",
1422 FT_BYTES, BASE_NONE, NULL, 0x0,
1423 "User-Defined APRS packet format", HFILL }
1424 },
1425 { &hf_aprs_third_party,
1426 { "Third-party", "aprs.third_party",
1427 FT_BYTES, BASE_NONE, NULL, 0x0,
1428 "Third-party traffic", HFILL }
1429 },
1430 { &hf_aprs_peet_1,
1431 { "Peet U-II (1)", "aprs.peet_1",
1432 FT_BYTES, BASE_NONE, NULL, 0x0,
1433 "Peet Bros U-II Weather Station", HFILL }
1434 },
1435 { &hf_aprs_peet_2,
1436 { "Peet U-II (2)", "aprs.peet_2",
1437 FT_BYTES, BASE_NONE, NULL, 0x0,
1438 "Peet Bros U-II Weather Station", HFILL }
1439 },
1440 { &hf_aprs_map_feature,
1441 { "Map Feature", "aprs.map_feature",
1442 FT_BYTES, BASE_NONE, NULL, 0x0,
1443 "[Reserved - Map Feature", HFILL }
1444 },
1445 { &hf_aprs_shelter_data,
1446 { "Shelter data", "aprs.shelter_data",
1447 FT_BYTES, BASE_NONE, NULL, 0x0,
1448 "[Reserved - Shelter data with time]", HFILL }
1449 },
1450 { &hf_aprs_space_weather,
1451 { "Space weather", "aprs.space_weather",
1452 FT_BYTES, BASE_NONE, NULL, 0x0,
1453 "[Reserved - Space weather]", HFILL }
1454 },
1455 { &hf_aprs_storm,
1456 { "Storm", "aprs.storm",
1457 FT_STRING, BASE_NONE, NULL, 0x0,
1458 NULL, HFILL }
1459 },
1460
1461 /* Time stamp */
1462 { &hf_aprs_dhm,
1463 { "Day/Hour/Minute", "aprs.dhm",
1464 FT_STRING, BASE_NONE, NULL, 0x0,
1465 NULL, HFILL }
1466 },
1467 { &hf_aprs_hms,
1468 { "Hour/Minute/Second", "aprs.hms",
1469 FT_STRING, BASE_NONE, NULL, 0x0,
1470 NULL, HFILL }
1471 },
1472 { &hf_aprs_mdhm,
1473 { "Month/Day/Hour/Minute", "aprs.mdhm",
1474 FT_STRING, BASE_NONE, NULL, 0x0,
1475 NULL, HFILL }
1476 },
1477 { &hf_aprs_tz,
1478 { "Time Zone", "aprs.tz",
1479 FT_STRING, BASE_NONE, NULL, 0x0,
1480 NULL, HFILL }
1481 },
1482
1483 /* Compressed Msg */
1484 { &hf_aprs_compression_type,
1485 { "Compression type", "aprs.ct",
1486 FT_UINT8, BASE_HEX, NULL, 0x0,
1487 NULL, HFILL }
1488 },
1489 { &hf_aprs_ct_gps_fix,
1490 { "GPS fix type", "aprs.ct.gps_fix",
1491 FT_UINT8, BASE_HEX, VALS(gps_vals), 0x20,
1492 NULL, HFILL }
1493 },
1494 { &hf_aprs_ct_nmea_src,
1495 { "NMEA source", "aprs.ct.nmea_src",
1496 FT_UINT8, BASE_HEX, VALS(nmea_vals), 0x18,
1497 NULL, HFILL }
1498 },
1499 { &hf_aprs_ct_origin,
1500 { "Compression origin", "aprs.ct.origin",
1501 FT_UINT8, BASE_HEX, VALS(ctype_vals), 0x07,
1502 NULL, HFILL }
1503 },
1504
1505 /* Ext Msg */
1506 { &hf_aprs_msg,
1507 { "Extended message", "aprs.msg",
1508 FT_STRING, BASE_NONE, NULL, 0x0,
1509 NULL, HFILL }
1510 },
1511 { &hf_aprs_msg_rng,
1512 { "Range", "aprs.msg.rng",
1513 FT_STRING, BASE_NONE, NULL, 0x0,
1514 "Pre-calculated radio range", HFILL }
1515 },
1516 { &hf_aprs_msg_cse,
1517 { "Course", "aprs.msg.cse",
1518 FT_STRING, BASE_NONE, NULL, 0x0,
1519 NULL, HFILL }
1520 },
1521 { &hf_aprs_msg_spd,
1522 { "Speed", "aprs.msg.spd",
1523 FT_STRING, BASE_NONE, NULL, 0x0,
1524 NULL, HFILL }
1525 },
1526 { &hf_aprs_msg_dir,
1527 { "Wind direction", "aprs.msg.dir",
1528 FT_STRING, BASE_NONE, NULL, 0x0,
1529 NULL, HFILL }
1530 },
1531 { &hf_aprs_msg_brg,
1532 { "Bearing", "aprs.msg.brg",
1533 FT_STRING, BASE_NONE, NULL, 0x0,
1534 NULL, HFILL }
1535 },
1536 { &hf_aprs_msg_nrq,
1537 { "Number/Range/Quality", "aprs.msg.nrq",
1538 FT_STRING, BASE_NONE, NULL, 0x0,
1539 NULL, HFILL }
1540 },
1541
1542 /* Msg PHGD */
1543 { &hf_aprs_msg_phg_p,
1544 { "Power", "aprs.msg.phg.p",
1545 FT_STRING, BASE_NONE, NULL, 0x0,
1546 NULL, HFILL }
1547 },
1548 { &hf_aprs_msg_phg_h,
1549 { "Height", "aprs.msg.phg.h",
1550 FT_STRING, BASE_NONE, NULL, 0x0,
1551 NULL, HFILL }
1552 },
1553 { &hf_aprs_msg_phg_g,
1554 { "Gain", "aprs.msg.phg.g",
1555 FT_STRING, BASE_NONE, NULL, 0x0,
1556 NULL, HFILL }
1557 },
1558 { &hf_aprs_msg_phg_d,
1559 { "Directivity", "aprs.msg.phg.d",
1560 FT_STRING, BASE_NONE, NULL, 0x0,
1561 NULL, HFILL }
1562 },
1563
1564 /* Msg DFS */
1565 { &hf_aprs_msg_dfs_s,
1566 { "Strength", "aprs.msg.dfs.s",
1567 FT_STRING, BASE_NONE, NULL, 0x0,
1568 NULL, HFILL }
1569 },
1570 { &hf_aprs_msg_dfs_h,
1571 { "Height", "aprs.msg.dfs.h",
1572 FT_STRING, BASE_NONE, NULL, 0x0,
1573 NULL, HFILL }
1574 },
1575 { &hf_aprs_msg_dfs_g,
1576 { "Gain", "aprs.msg.dfs.g",
1577 FT_STRING, BASE_NONE, NULL, 0x0,
1578 NULL, HFILL }
1579 },
1580 { &hf_aprs_msg_dfs_d,
1581 { "Directivity", "aprs.msg.dfs.d",
1582 FT_STRING, BASE_NONE, NULL, 0x0,
1583 NULL, HFILL }
1584 },
1585
1586 /* Msg AOD */
1587 { &hf_aprs_msg_aod_t,
1588 { "Type", "aprs.msg.aod.t",
1589 FT_STRING, BASE_NONE, NULL, 0x0,
1590 NULL, HFILL }
1591 },
1592 { &hf_aprs_msg_aod_c,
1593 { "Colour", "aprs.msg.aod.c",
1594 FT_STRING, BASE_NONE, NULL, 0x0,
1595 NULL, HFILL }
1596 },
1597
1598 /* Weather */
1599 { &hf_aprs_weather,
1600 { "Weather report", "aprs.weather",
1601 FT_STRING, BASE_NONE, NULL, 0x0,
1602 NULL, HFILL }
1603 },
1604 { &hf_aprs_weather_dir,
1605 { "Wind direction", "aprs.weather.dir",
1606 FT_STRING, BASE_NONE, NULL, 0x0,
1607 NULL, HFILL }
1608 },
1609 { &hf_aprs_weather_spd,
1610 { "Wind speed", "aprs.weather.speed",
1611 FT_STRING, BASE_NONE, NULL, 0x0,
1612 "Wind speed (1 minute)", HFILL }
1613 },
1614 { &hf_aprs_weather_peak,
1615 { "Peak wind speed", "aprs.weather.peak",
1616 FT_STRING, BASE_NONE, NULL, 0x0,
1617 NULL, HFILL }
1618 },
1619 { &hf_aprs_weather_temp,
1620 { "Temperature (F)", "aprs.weather.temp",
1621 FT_STRING, BASE_NONE, NULL, 0x0,
1622 NULL, HFILL }
1623 },
1624 { &hf_aprs_weather_rain_1,
1625 { "Rain (last 1 hour)", "aprs.weather.1_hour",
1626 FT_STRING, BASE_NONE, NULL, 0x0,
1627 NULL, HFILL }
1628 },
1629 { &hf_aprs_weather_rain_24,
1630 { "Rain (last 24 hours)", "aprs.weather.24_hour",
1631 FT_STRING, BASE_NONE, NULL, 0x0,
1632 NULL, HFILL }
1633 },
1634 { &hf_aprs_weather_rain,
1635 { "Rain", "aprs.weather.rain",
1636 FT_STRING, BASE_NONE, NULL, 0x0,
1637 NULL, HFILL }
1638 },
1639 { &hf_aprs_weather_humidty,
1640 { "Humidity", "aprs.weather.humidity",
1641 FT_STRING, BASE_NONE, NULL, 0x0,
1642 NULL, HFILL }
1643 },
1644 { &hf_aprs_weather_press,
1645 { "Pressure", "aprs.weather.pressure",
1646 FT_STRING, BASE_NONE, NULL, 0x0,
1647 NULL, HFILL }
1648 },
1649 { &hf_aprs_weather_luminosity,
1650 { "Luminosity", "aprs.weather.luminosity",
1651 FT_STRING, BASE_NONE, NULL, 0x0,
1652 NULL, HFILL }
1653 },
1654 { &hf_aprs_weather_snow,
1655 { "Snow", "aprs.weather.snow",
1656 FT_STRING, BASE_NONE, NULL, 0x0,
1657 NULL, HFILL }
1658 },
1659 { &hf_aprs_weather_raw_rain,
1660 { "Raw rain", "aprs.weather.raw_rain",
1661 FT_STRING, BASE_NONE, NULL, 0x0,
1662 NULL, HFILL }
1663 },
1664 { &hf_aprs_weather_software,
1665 { "Software", "aprs.weather.software",
1666 FT_STRING, BASE_NONE, NULL, 0x0,
1667 NULL, HFILL }
1668 },
1669 { &hf_aprs_weather_unit,
1670 { "Unit", "aprs.weather.unit",
1671 FT_STRING, BASE_NONE, NULL, 0x0,
1672 NULL, HFILL }
1673 },
1674
1675 /* MIC-E */
1676 { &hf_aprs_mic_e_0_current,
1677 { "Current Mic-E (Rev 0)", "aprs.mic_e_0_current",
1678 FT_STRING, BASE_NONE, NULL, 0x0,
1679 NULL, HFILL }
1680 },
1681 { &hf_aprs_mic_e_0_old,
1682 { "Old Mic-E (Rev 0)", "aprs.mic_e_0_old",
1683 FT_STRING, BASE_NONE, NULL, 0x0,
1684 NULL, HFILL }
1685 },
1686 { &hf_aprs_mic_e_old,
1687 { "Old Mic-E", "aprs.mic_e_old",
1688 FT_STRING, BASE_NONE, NULL, 0x0,
1689 "Old Mic-E Data (but Current data for TM-D700)", HFILL }
1690 },
1691 { &hf_aprs_mic_e_current,
1692 { "Current Mic-E", "aprs.mic_e_current",
1693 FT_STRING, BASE_NONE, NULL, 0x0,
1694 "Current Mic-E Data (not used in TM-D700)", HFILL }
1695 },
1696 { &hf_aprs_mic_e_dst,
1697 { "Destination Address", "aprs.mic_e.dst",
1698 FT_STRING, BASE_NONE, NULL, 0x0,
1699 NULL, HFILL }
1700 },
1701 { &hf_aprs_mic_e_long_d,
1702 { "Longitude degrees", "aprs.mic_e.long_d",
1703 FT_UINT8, BASE_HEX, NULL, 0x0,
1704 NULL, HFILL }
1705 },
1706 { &hf_aprs_mic_e_long_m ,
1707 { "Longitude minutes", "aprs.mic_e.long_m",
1708 FT_UINT8, BASE_HEX, NULL, 0x0,
1709 NULL, HFILL }
1710 },
1711 { &hf_aprs_mic_e_long_h,
1712 { "Longitude hundredths of minutes", "aprs.mic_e.long_h",
1713 FT_UINT8, BASE_HEX, NULL, 0x0,
1714 NULL, HFILL }
1715 },
1716 { &hf_aprs_mic_e_spd_sp,
1717 { "Speed (hundreds & tens)", "aprs.mic_e.speed_sp",
1718 FT_UINT8, BASE_HEX, NULL, 0x0,
1719 NULL, HFILL }
1720 },
1721 { &hf_aprs_mic_e_spd_dc,
1722 { "Speed (tens), Course (hundreds)", "aprs.mic_e.speed_dc",
1723 FT_UINT8, BASE_HEX, NULL, 0x0,
1724 NULL, HFILL }
1725 },
1726 { &hf_aprs_mic_e_spd_se,
1727 { "Course (tens & units)", "aprs.mic_e.speed_se",
1728 FT_UINT8, BASE_HEX, NULL, 0x0,
1729 NULL, HFILL }
1730 },
1731 { &hf_aprs_mic_e_telemetry,
1732 { "Telemetry", "aprs.mic_e.telemetry",
1733 FT_BYTES, BASE_NONE, NULL, 0x0,
1734 NULL, HFILL }
1735 },
1736 { &hf_aprs_mic_e_status,
1737 { "Status", "aprs.mic_e.status",
1738 FT_STRING, BASE_NONE, NULL, 0x0,
1739 NULL, HFILL }
1740 },
1741 { &hf_aprs_storm_dir,
1742 { "Direction", "aprs.storm.direction",
1743 FT_STRING, BASE_NONE, NULL, 0x0,
1744 NULL, HFILL }
1745 },
1746 { &hf_aprs_storm_spd,
1747 { "Speed (knots)", "aprs.storm.speed",
1748 FT_STRING, BASE_NONE, NULL, 0x0,
1749 NULL, HFILL }
1750 },
1751 { &hf_aprs_storm_type,
1752 { "Type", "aprs.storm.type",
1753 FT_STRING, BASE_NONE, NULL, 0x0,
1754 NULL, HFILL }
1755 },
1756 { &hf_aprs_storm_sws,
1757 { "Sustained wind speed (knots)", "aprs.storm.sws",
1758 FT_STRING, BASE_NONE, NULL, 0x0,
1759 NULL, HFILL }
1760 },
1761 { &hf_aprs_storm_pwg,
1762 { "Peak wind gusts (knots)", "aprs.storm.pwg",
1763 FT_STRING, BASE_NONE, NULL, 0x0,
1764 NULL, HFILL }
1765 },
1766 { &hf_aprs_storm_cp,
1767 { "Central pressure (millibars/hPascal)", "aprs.storm.central_pressure",
1768 FT_STRING, BASE_NONE, NULL, 0x0,
1769 NULL, HFILL }
1770 },
1771 { &hf_aprs_storm_rhw,
1772 { "Radius Hurricane Winds (nautical miles)", "aprs.storm.radius_hurricane_winds",
1773 FT_STRING, BASE_NONE, NULL, 0x0,
1774 NULL, HFILL }
1775 },
1776 { &hf_aprs_storm_rtsw,
1777 { "Radius Tropical Storm Winds (nautical miles)", "aprs.storm.radius_tropical_storms_winds",
1778 FT_STRING, BASE_NONE, NULL, 0x0,
1779 NULL, HFILL }
1780 },
1781 { &hf_aprs_storm_rwg,
1782 { "Radius Whole Gale (nautical miles)", "aprs.storm.radius_whole_gale",
1783 FT_STRING, BASE_NONE, NULL, 0x0,
1784 NULL, HFILL }
1785 }
1786 };
1787
1788 static gint *ett[] = {
1789 &ett_aprs,
1790 &ett_aprs_msg,
1791 &ett_aprs_ct,
1792 &ett_aprs_weather,
1793 &ett_aprs_storm,
1794 &ett_aprs_mic_e,
1795 };
1796
1797 proto_aprs = proto_register_protocol("Automatic Position Reporting System", "APRS", "aprs");
1798
1799 register_dissector( "aprs", dissect_aprs, proto_aprs);
1800
1801 proto_register_field_array( proto_aprs, hf, array_length(hf ) );
1802 proto_register_subtree_array( ett, array_length( ett ) );
1803
1804 aprs_module = prefs_register_protocol( proto_aprs, NULL);
1805
1806 prefs_register_bool_preference(aprs_module, "showaprslax",
1807 "Allow APRS violations.",
1808 "Attempt to display common APRS protocol violations correctly",
1809 &gPREF_APRS_LAX );
1810
1811 }
1812
1813 /*
1814 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1815 *
1816 * Local variables:
1817 * c-basic-offset: 8
1818 * tab-width: 8
1819 * indent-tabs-mode: t
1820 * End:
1821 *
1822 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1823 * :indentSize=8:tabSize=8:noTabs=false:
1824 */
1825