Put the value(s) of a parameter into the top-level item for that
[obnox/wireshark/wip.git] / packet-ansi_801.c
1 /* packet-ansi_801.c
2  * Routines for ANSI IS-801 (Location Services (PLD)) dissection
3  *
4  *   Location Services (Position Determination Service)
5  *                      3GPP2 C.S0022-0 v1.0    IS-801
6  *
7  *   Location Services (Position Determination Service)
8  *                      3GPP2 C.S0022-0-1 v1.0  IS-801 Addendum
9  *
10  * Copyright 2004, Michael Lum <mlum [AT] telostech.com>
11  * In association with Telos Technology Inc.
12  *
13  * $Id: packet-ansi_801.c,v 1.1 2004/03/27 11:32:27 guy Exp $
14  *
15  * Ethereal - Network traffic analyzer
16  * By Gerald Combs <gerald@ethereal.com>
17  * Copyright 1998 Gerald Combs
18  *
19  * This program is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU General Public License
21  * as published by the Free Software Foundation; either version 2
22  * of the License, or (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program; if not, write to the Free Software
31  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <gmodule.h>
41
42 #ifdef HAVE_SYS_TYPES_H
43 # include <sys/types.h>
44 #endif
45
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
48 #endif
49
50 #include <string.h>
51
52 #include "epan/packet.h"
53
54
55 static char *ansi_proto_name = "ANSI IS-801 (Location Services (PLD))";
56 static char *ansi_proto_name_short = "IS-801";
57
58 #define ANSI_801_FORWARD        0
59 #define ANSI_801_REVERSE        1
60
61
62 /* Initialize the subtree pointers */
63 static gint ett_ansi_801 = -1;
64
65 /* Initialize the protocol and registered fields */
66 static int proto_ansi_801 = -1;
67 static int hf_ansi_801_for_req_type = -1;
68 static int hf_ansi_801_for_rsp_type = -1;
69 static int hf_ansi_801_rev_req_type = -1;
70 static int hf_ansi_801_rev_rsp_type = -1;
71 static int hf_ansi_801_for_sess_tag = -1;
72 static int hf_ansi_801_rev_sess_tag = -1;
73 static int hf_ansi_801_sess_tag = -1;
74
75 static char bigbuf[1024];
76 static dissector_handle_t data_handle;
77 static packet_info *g_pinfo;
78 static proto_tree *g_tree;
79
80
81 /* FUNCTIONS */
82
83 static gchar *
84 my_match_strval(guint32 val, const value_string *vs, gint *idx)
85 {
86     gint i = 0;
87
88     while (vs[i].strptr)
89     {
90         if (vs[i].value == val)
91         {
92             *idx = i;
93             return(vs[i].strptr);
94         }
95
96         i++;
97     }
98
99     *idx = -1;
100     return(NULL);
101 }
102
103
104 /* PARAM FUNCTIONS */
105
106 #define EXTRANEOUS_DATA_CHECK(edc_len, edc_max_len) \
107     if ((edc_len) > (edc_max_len)) \
108     { \
109         proto_tree_add_text(tree, tvb, \
110             offset, (edc_len) - (edc_max_len), "Extraneous Data"); \
111     }
112
113 #define SHORT_DATA_CHECK(sdc_len, sdc_min_len) \
114     if ((sdc_len) < (sdc_min_len)) \
115     { \
116         proto_tree_add_text(tree, tvb, \
117             offset, (sdc_len), "Short Data (?)"); \
118         return; \
119     }
120
121 #define EXACT_DATA_CHECK(edc_len, edc_eq_len) \
122     if ((edc_len) != (edc_eq_len)) \
123     { \
124         proto_tree_add_text(tree, tvb, \
125             offset, (edc_len), "Unexpected Data Length"); \
126         return; \
127     }
128
129
130 static void
131 for_req_pseudo_meas(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset)
132 {
133     guint32     value;
134     guint32     saved_offset;
135
136     SHORT_DATA_CHECK(len, 3);
137
138     saved_offset = offset;
139
140     value = tvb_get_ntoh24(tvb, offset);
141
142     other_decode_bitfield_value(bigbuf, value >> 16, 0xe0, 8);
143     proto_tree_add_text(tree, tvb, offset, 1,
144         "%s :  Preferred response quality, %u",
145         bigbuf,
146         (value & 0xe00000) >> 21);
147
148     other_decode_bitfield_value(bigbuf, value >> 16, 0x1f, 8);
149     proto_tree_add_text(tree, tvb, offset, 1,
150         "%s :  Number of fixes (MSB), %u",
151         bigbuf,
152         (value & 0x1fe000) >> 13);
153
154     other_decode_bitfield_value(bigbuf, value >> 8, 0xe0, 8);
155     proto_tree_add_text(tree, tvb, offset, 1,
156         "%s :  Number of fixes (LSB)",
157         bigbuf);
158
159     other_decode_bitfield_value(bigbuf, value >> 8, 0x1f, 8);
160     proto_tree_add_text(tree, tvb, offset, 1,
161         "%s :  Time between fixes (MSB), %u",
162         bigbuf,
163         (value & 0x001fe0) >> 5);
164
165     other_decode_bitfield_value(bigbuf, value, 0xe0, 8);
166     proto_tree_add_text(tree, tvb, offset, 1,
167         "%s :  Time between fixes (LSB)",
168         bigbuf);
169
170     other_decode_bitfield_value(bigbuf, value, 0x10, 8);
171     proto_tree_add_text(tree, tvb, offset, 1,
172         "%s :  Offset %srequested",
173         bigbuf,
174         (value & 0x10) ? "" : "not ");
175
176     other_decode_bitfield_value(bigbuf, value, 0x0f, 8);
177     proto_tree_add_text(tree, tvb, offset, 1,
178         "%s :  Reserved",
179         bigbuf);
180
181     offset += 3;
182
183     EXTRANEOUS_DATA_CHECK(len, offset - saved_offset);
184 }
185
186 static const value_string for_req_type_strings[] = {
187     { 0,        "Reserved" },
188     { 2,        "Request MS Information" },
189     { 3,        "Request Autonomous Measurement Weighting Factors" },
190     { 4,        "Request Pseudorange Measurement" },
191     { 5,        "Request Pilot Phase Measurement" },
192     { 1,        "Request Location Response" },
193     { 6,        "Request Time Offset Measurement" },
194     { 7,        "Request Cancellation" },
195     { 0, NULL },
196 };
197 #define NUM_FOR_REQ_TYPE (sizeof(for_req_type_strings)/sizeof(value_string))
198 static gint ett_for_req_type[NUM_FOR_REQ_TYPE];
199 static void (*for_req_type_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset) = {
200     NULL,       /* Reserved */
201     NULL,       /* Request MS Information */
202     NULL,       /* Request Autonomous Measurement Weighting Factors */
203     for_req_pseudo_meas,        /* Request Pseudorange Measurement */
204     NULL,       /* Request Pilot Phase Measurement */
205     NULL,       /* Request Location Response */
206     NULL,       /* Request Time Offset Measurement */
207     NULL,       /* Request Cancellation */
208     NULL,       /* NONE */
209 };
210
211 static const value_string for_rsp_type_strings[] = {
212     { 0,        "Reject" },
213     { 2,        "Provide BS Capabilities" },
214     { 4,        "Provide GPS Acquisition Assistance" },
215     { 6,        "Provide GPS Location Assistance Spherical Coordinates" },
216     { 7,        "Provide GPS Location Assistance Cartesian Coordinates" },
217     { 5,        "Provide GPS Sensitivity Assistance" },
218     { 3,        "Provide Base Station Almanac" },
219     { 8,        "Provide GPS Almanac" },
220     { 9,        "Provide GPS Ephemeris" },
221     { 10,       "Provide GPS Navigation Message Bits" },
222     { 1,        "Provide Location Response" },
223     { 11,       "Provide GPS Almanac Correction" },
224     { 12,       "Provide GPS Satellite Health Information" },
225     { 0, NULL },
226 };
227 #define NUM_FOR_RSP_TYPE (sizeof(for_rsp_type_strings)/sizeof(value_string))
228 static gint ett_for_rsp_type[NUM_FOR_RSP_TYPE];
229 static void (*for_rsp_type_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset) = {
230     NULL,       /* Reject */
231     NULL,       /* Provide BS Capabilities */
232     NULL,       /* Provide GPS Acquisition Assistance */
233     NULL,       /* Provide GPS Location Assistance Spherical Coordinates */
234     NULL,       /* Provide GPS Location Assistance Cartesian Coordinates */
235     NULL,       /* Provide GPS Sensitivity Assistance */
236     NULL,       /* Provide Base Station Almanac */
237     NULL,       /* Provide GPS Almanac */
238     NULL,       /* Provide GPS Ephemeris */
239     NULL,       /* Provide GPS Navigation Message Bits */
240     NULL,       /* Provide Location Response */
241     NULL,       /* Provide GPS Almanac Correction */
242     NULL,       /* Provide GPS Satellite Health Information */
243     NULL,       /* NONE */
244 };
245
246 static const value_string rev_req_type_strings[] = {
247     { 0,        "Reserved" },
248     { 2,        "Request BS Capabilities" },
249     { 4,        "Request GPS Acquisition Assistance" },
250     { 6,        "Request GPS Location Assistance" },
251     { 7,        "Reserved" },
252     { 5,        "Request GPS Sensitivity Assistance" },
253     { 3,        "Request Base Station Almanac" },
254     { 8,        "Request GPS Almanac" },
255     { 9,        "Request GPS Ephemeris" },
256     { 10,       "Request GPS Navigation Message Bits" },
257     { 1,        "Request Location Response" },
258     { 11,       "Request GPS Almanac Correction" },
259     { 12,       "Request GPS Satellite Health Information" },
260     { 0, NULL },
261 };
262 #define NUM_REV_REQ_TYPE (sizeof(rev_req_type_strings)/sizeof(value_string))
263 static gint ett_rev_req_type[NUM_REV_REQ_TYPE];
264 static void (*rev_req_type_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset) = {
265     NULL,       /* Reserved */
266     NULL,       /* Request BS Capabilities */
267     NULL,       /* Request GPS Acquisition Assistance */
268     NULL,       /* Request GPS Location Assistance */
269     NULL,       /* Reserved */
270     NULL,       /* Request GPS Sensitivity Assistance */
271     NULL,       /* Request Base Station Almanac */
272     NULL,       /* Request GPS Almanac */
273     NULL,       /* Request GPS Ephemeris */
274     NULL,       /* Request GPS Navigation Message Bits */
275     NULL,       /* Request Location Response */
276     NULL,       /* Request GPS Almanac Correction */
277     NULL,       /* Request GPS Satellite Health Information */
278     NULL,       /* NONE */
279 };
280
281 static const value_string rev_rsp_type_strings[] = {
282     { 0,        "Reject" },
283     { 2,        "Provide MS Information" },
284     { 3,        "Provide Autonomous Measurement Weighting Factors" },
285     { 4,        "Provide Pseudorange Measurement" },
286     { 5,        "Provide Pilot Phase Measurement" },
287     { 1,        "Provide Location Response" },
288     { 6,        "Provide Time Offset Measurement" },
289     { 7,        "Provide Cancellation Acknowledgement" },
290     { 0, NULL },
291 };
292 #define NUM_REV_RSP_TYPE (sizeof(rev_rsp_type_strings)/sizeof(value_string))
293 static gint ett_rev_rsp_type[NUM_REV_RSP_TYPE];
294 static void (*rev_rsp_type_fcn[])(tvbuff_t *tvb, proto_tree *tree, guint len, guint32 offset) = {
295     NULL,       /* Reject */
296     NULL,       /* Provide MS Information */
297     NULL,       /* Provide Autonomous Measurement Weighting Factors */
298     NULL,       /* Provide Pseudorange Measurement */
299     NULL,       /* Provide Pilot Phase Measurement */
300     NULL,       /* Provide Location Response */
301     NULL,       /* Provide Time Offset Measurement */
302     NULL,       /* Provide Cancellation Acknowledgement */
303     NULL,       /* NONE */
304 };
305
306 static void
307 for_request(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p)
308 {
309     guint32     offset;
310     guint8      oct;
311     gchar       *str = NULL;
312     gint        idx;
313     proto_tree  *subtree;
314     proto_item  *item;
315
316     offset = *offset_p;
317     oct = tvb_get_guint8(tvb, offset);
318
319     other_decode_bitfield_value(bigbuf, oct, 0xf0, 8);
320     proto_tree_add_text(tree, tvb, offset, 1,
321         "%s :  Reserved",
322         bigbuf);
323
324     str = my_match_strval(oct & 0x0f, for_req_type_strings, &idx);
325
326     if (str == NULL)
327     {
328         return;
329     }
330
331     other_decode_bitfield_value(bigbuf, oct, 0x0f, 8);
332     item =
333         proto_tree_add_uint_format(tree, hf_ansi_801_for_req_type, tvb, offset,
334             1, oct & 0x0f,
335             "%s :  Request Type, %s (%u)",
336             bigbuf,
337             str,
338             oct & 0x0f);
339
340     subtree = proto_item_add_subtree(item, ett_for_req_type[idx]);
341
342     offset++;
343     oct = tvb_get_guint8(tvb, offset);
344
345     proto_tree_add_text(subtree, tvb, offset, 1,
346         "Length: %u",
347         oct);
348
349     offset++;
350
351     if (for_req_type_fcn[idx] != NULL)
352     {
353         (*for_req_type_fcn[idx])(tvb, subtree, oct, offset);
354     }
355     else
356     {
357         proto_tree_add_text(subtree, tvb, offset, oct,
358             "Data");
359     }
360
361     *offset_p = offset + oct;
362 }
363
364 static void
365 for_response(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p)
366 {
367     guint32     offset;
368     guint8      oct;
369     gchar       *str = NULL;
370     gint        idx;
371     proto_tree  *subtree;
372     proto_item  *item;
373
374     offset = *offset_p;
375     oct = tvb_get_guint8(tvb, offset);
376
377     other_decode_bitfield_value(bigbuf, oct, 0xe0, 8);
378     proto_tree_add_text(tree, tvb, offset, 1,
379         "%s :  Reserved",
380         bigbuf);
381
382     other_decode_bitfield_value(bigbuf, oct, 0x10, 8);
383     proto_tree_add_text(tree, tvb, offset, 1,
384         "%s :  Unsolicited response indicator",
385         bigbuf);
386
387     str = my_match_strval(oct & 0x0f, for_rsp_type_strings, &idx);
388
389     if (str == NULL)
390     {
391         return;
392     }
393
394     other_decode_bitfield_value(bigbuf, oct, 0x0f, 8);
395     item =
396         proto_tree_add_uint_format(tree, hf_ansi_801_for_rsp_type, tvb, offset,
397             1, oct & 0x0f,
398             "%s :  Response Type, %s (%u)",
399             bigbuf,
400             str,
401             oct & 0x0f);
402
403     subtree = proto_item_add_subtree(item, ett_for_rsp_type[idx]);
404
405     offset++;
406     oct = tvb_get_guint8(tvb, offset);
407
408     proto_tree_add_text(subtree, tvb, offset, 1,
409         "Length: %u",
410         oct);
411
412     offset++;
413
414     if (for_rsp_type_fcn[idx] != NULL)
415     {
416         (*for_rsp_type_fcn[idx])(tvb, subtree, oct, offset);
417     }
418     else
419     {
420         proto_tree_add_text(subtree, tvb, offset, oct,
421             "Data");
422     }
423
424     *offset_p = offset + oct;
425 }
426
427 static void
428 rev_request(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p)
429 {
430     guint32     offset;
431     guint8      oct;
432     gchar       *str = NULL;
433     gint        idx;
434     proto_tree  *subtree;
435     proto_item  *item;
436
437     offset = *offset_p;
438     oct = tvb_get_guint8(tvb, offset);
439
440     other_decode_bitfield_value(bigbuf, oct, 0xf0, 8);
441     proto_tree_add_text(tree, tvb, offset, 1,
442         "%s :  Reserved",
443         bigbuf);
444
445     str = my_match_strval(oct & 0x0f, rev_req_type_strings, &idx);
446
447     if (str == NULL)
448     {
449         return;
450     }
451
452     other_decode_bitfield_value(bigbuf, oct, 0x0f, 8);
453     item =
454         proto_tree_add_uint_format(tree, hf_ansi_801_rev_req_type, tvb, offset,
455             1, oct & 0x0f,
456             "%s :  Request Type, %s (%u)",
457             bigbuf,
458             str,
459             oct & 0x0f);
460
461     subtree = proto_item_add_subtree(item, ett_rev_req_type[idx]);
462
463     offset++;
464     oct = tvb_get_guint8(tvb, offset);
465
466     proto_tree_add_text(subtree, tvb, offset, 1,
467         "Length: %u",
468         oct);
469
470     offset++;
471
472     if (rev_req_type_fcn[idx] != NULL)
473     {
474         (*rev_req_type_fcn[idx])(tvb, subtree, oct, offset);
475     }
476     else
477     {
478         proto_tree_add_text(subtree, tvb, offset, oct,
479             "Data");
480     }
481
482     *offset_p = offset + oct;
483 }
484
485 static void
486 rev_response(tvbuff_t *tvb, proto_tree *tree, guint32 *offset_p)
487 {
488     guint32     offset;
489     guint8      oct;
490     gchar       *str = NULL;
491     gint        idx;
492     proto_tree  *subtree;
493     proto_item  *item;
494
495     offset = *offset_p;
496     oct = tvb_get_guint8(tvb, offset);
497
498     other_decode_bitfield_value(bigbuf, oct, 0xe0, 8);
499     proto_tree_add_text(tree, tvb, offset, 1,
500         "%s :  Reserved",
501         bigbuf);
502
503     other_decode_bitfield_value(bigbuf, oct, 0x10, 8);
504     proto_tree_add_text(tree, tvb, offset, 1,
505         "%s :  Unsolicited response indicator",
506         bigbuf);
507
508     str = my_match_strval(oct & 0x0f, rev_rsp_type_strings, &idx);
509
510     if (str == NULL)
511     {
512         return;
513     }
514
515     other_decode_bitfield_value(bigbuf, oct, 0x0f, 8);
516     item =
517         proto_tree_add_uint_format(tree, hf_ansi_801_rev_rsp_type, tvb, offset,
518             1, oct & 0x0f,
519             "%s :  Response Type, %s (%u)",
520             bigbuf,
521             str,
522             oct & 0x0f);
523
524     subtree = proto_item_add_subtree(item, ett_rev_rsp_type[idx]);
525
526     offset++;
527     oct = tvb_get_guint8(tvb, offset);
528
529     proto_tree_add_text(subtree, tvb, offset, 1,
530         "Length: %u",
531         oct);
532
533     offset++;
534
535     if (rev_rsp_type_fcn[idx] != NULL)
536     {
537         (*rev_rsp_type_fcn[idx])(tvb, subtree, oct, offset);
538     }
539     else
540     {
541         proto_tree_add_text(subtree, tvb, offset, oct,
542             "Data");
543     }
544
545     *offset_p = offset + oct;
546 }
547
548 static void
549 dissect_ansi_801_for_message(tvbuff_t *tvb, proto_tree *tree)
550 {
551     guint32     offset;
552     guint8      oct, num_req, num_rsp;
553     guint       rem_len;
554     gchar       *str = NULL;
555
556     offset = 0;
557     oct = tvb_get_guint8(tvb, offset);
558
559     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
560     proto_tree_add_text(tree, tvb, offset, 1,
561         "%s :  Session Start",
562         bigbuf);
563
564     other_decode_bitfield_value(bigbuf, oct, 0x40, 8);
565     proto_tree_add_text(tree, tvb, offset, 1,
566         "%s :  Session End",
567         bigbuf);
568
569     other_decode_bitfield_value(bigbuf, oct, 0x20, 8);
570     proto_tree_add_text(tree, tvb, offset, 1,
571         "%s :  Session Source",
572         bigbuf);
573
574     other_decode_bitfield_value(bigbuf, oct, 0x1f, 8);
575     proto_tree_add_uint_format(tree, hf_ansi_801_for_sess_tag, tvb, offset,
576         1, oct & 0x1f,
577         "%s :  Session Tag (%u)",
578         bigbuf,
579         oct & 0x1f);
580
581     proto_tree_add_uint_hidden(tree, hf_ansi_801_sess_tag, tvb, offset,
582         1, oct & 0x1f);
583
584     offset++;
585     oct = tvb_get_guint8(tvb, offset);
586
587     switch (oct)
588     {
589     case 0x00: str = "Position Determination Data Message"; break;
590     case 0xff: str = "Reserved"; break;
591     default:
592         if (oct < 0xc0)
593         {
594             str = "Reserved for future standardization";
595         }
596         else
597         {
598             str =
599                 "Available for manufacturer-specific Position Determination "
600                 "Data Message definition as specified in TSB-58";
601         }
602         break;
603     }
604
605     other_decode_bitfield_value(bigbuf, oct, 0xff, 8);
606     proto_tree_add_text(tree, tvb, offset, 1,
607         "%s :  PD Message Type, %s (%u)",
608         bigbuf,
609         str,
610         oct);
611
612     offset++;
613
614     if (oct == 0x00)
615     {
616         oct = tvb_get_guint8(tvb, offset);
617
618         num_req = (oct & 0xf0) >> 4;
619         num_rsp = oct & 0x0f;
620
621         other_decode_bitfield_value(bigbuf, oct, 0xf0, 8);
622         proto_tree_add_text(tree, tvb, offset, 1,
623             "%s :  Number Requests (%u)",
624             bigbuf,
625             num_req);
626
627         other_decode_bitfield_value(bigbuf, oct, 0x0f, 8);
628         proto_tree_add_text(tree, tvb, offset, 1,
629             "%s :  Number Responses (%u)",
630             bigbuf,
631             num_rsp);
632
633         offset++;
634         rem_len = tvb_length_remaining(tvb, offset);
635
636         while ((num_req > 0) &&
637             (rem_len >= 2))
638         {
639             for_request(tvb, tree, &offset);
640
641             rem_len = tvb_length_remaining(tvb, offset);
642             num_req--;
643         }
644
645         if (num_req != 0)
646         {
647             proto_tree_add_text(tree, tvb,
648                 offset, -1, "Short Data (?)");
649             return;
650         }
651
652         while ((num_rsp > 0) &&
653             (rem_len >= 2))
654         {
655             for_response(tvb, tree, &offset);
656
657             rem_len = tvb_length_remaining(tvb, offset);
658             num_rsp--;
659         }
660
661         if (num_rsp != 0)
662         {
663             proto_tree_add_text(tree, tvb,
664                 offset, -1, "Short Data (?)");
665             return;
666         }
667
668         if (rem_len > 0)
669         {
670             proto_tree_add_text(tree, tvb, offset, rem_len,
671                 "Extraneous Data");
672         }
673     }
674     else
675     {
676         proto_tree_add_text(tree, tvb, offset, -1,
677             "Reserved/Proprietary/Future Data");
678     }
679 }
680
681 static void
682 dissect_ansi_801_rev_message(tvbuff_t *tvb, proto_tree *tree)
683 {
684     guint32     offset;
685     guint8      oct, num_req, num_rsp;
686     guint       rem_len;
687     gchar       *str = NULL;
688
689     offset = 0;
690     oct = tvb_get_guint8(tvb, offset);
691
692     other_decode_bitfield_value(bigbuf, oct, 0x80, 8);
693     proto_tree_add_text(tree, tvb, offset, 1,
694         "%s :  Session Start",
695         bigbuf);
696
697     other_decode_bitfield_value(bigbuf, oct, 0x40, 8);
698     proto_tree_add_text(tree, tvb, offset, 1,
699         "%s :  Session End",
700         bigbuf);
701
702     other_decode_bitfield_value(bigbuf, oct, 0x20, 8);
703     proto_tree_add_text(tree, tvb, offset, 1,
704         "%s :  Session Source",
705         bigbuf);
706
707     other_decode_bitfield_value(bigbuf, oct, 0x1f, 8);
708     proto_tree_add_uint_format(tree, hf_ansi_801_rev_sess_tag, tvb, offset,
709         1, oct & 0x1f,
710         "%s :  Session Tag (%u)",
711         bigbuf,
712         oct & 0x1f);
713
714     proto_tree_add_uint_hidden(tree, hf_ansi_801_sess_tag, tvb, offset,
715         1, oct & 0x1f);
716
717     offset++;
718     oct = tvb_get_guint8(tvb, offset);
719
720     switch (oct)
721     {
722     case 0x00: str = "Position Determination Data Message"; break;
723     case 0xff: str = "Reserved"; break;
724     default:
725         if (oct < 0xc0)
726         {
727             str = "Reserved for future standardization";
728         }
729         else
730         {
731             str =
732                 "Available for manufacturer-specific Position Determination "
733                 "Data Message definition as specified in TSB-58";
734         }
735         break;
736     }
737
738     other_decode_bitfield_value(bigbuf, oct, 0xff, 8);
739     proto_tree_add_text(tree, tvb, offset, 1,
740         "%s :  PD Message Type, %s (%u)",
741         bigbuf,
742         str,
743         oct);
744
745     offset++;
746
747     if (oct == 0x00)
748     {
749         oct = tvb_get_guint8(tvb, offset);
750
751         num_req = (oct & 0xf0) >> 4;
752         num_rsp = oct & 0x0f;
753
754         other_decode_bitfield_value(bigbuf, oct, 0xf0, 8);
755         proto_tree_add_text(tree, tvb, offset, 1,
756             "%s :  Number Requests (%u)",
757             bigbuf,
758             num_req);
759
760         other_decode_bitfield_value(bigbuf, oct, 0x0f, 8);
761         proto_tree_add_text(tree, tvb, offset, 1,
762             "%s :  Number Responses (%u)",
763             bigbuf,
764             num_rsp);
765
766         offset++;
767         rem_len = tvb_length_remaining(tvb, offset);
768
769         while ((num_req > 0) &&
770             (rem_len >= 2))
771         {
772             rev_request(tvb, tree, &offset);
773
774             rem_len = tvb_length_remaining(tvb, offset);
775             num_req--;
776         }
777
778         if (num_req != 0)
779         {
780             proto_tree_add_text(tree, tvb,
781                 offset, -1, "Short Data (?)");
782             return;
783         }
784
785         while ((num_rsp > 0) &&
786             (rem_len >= 2))
787         {
788             rev_response(tvb, tree, &offset);
789
790             rem_len = tvb_length_remaining(tvb, offset);
791             num_rsp--;
792         }
793
794         if (num_rsp != 0)
795         {
796             proto_tree_add_text(tree, tvb,
797                 offset, -1, "Short Data (?)");
798             return;
799         }
800
801         if (rem_len > 0)
802         {
803             proto_tree_add_text(tree, tvb, offset, rem_len,
804                 "Extraneous Data");
805         }
806     }
807     else
808     {
809         proto_tree_add_text(tree, tvb, offset, -1,
810             "Reserved/Proprietary/Future Data");
811     }
812 }
813
814 static void
815 dissect_ansi_801(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
816 {
817     proto_item  *ansi_801_item;
818     proto_tree  *ansi_801_tree = NULL;
819
820     g_pinfo = pinfo;
821
822     if (check_col(pinfo->cinfo, COL_PROTOCOL))
823     {
824         col_set_str(pinfo->cinfo, COL_PROTOCOL, ansi_proto_name_short);
825     }
826
827     /* In the interest of speed, if "tree" is NULL, don't do any work not
828      * necessary to generate protocol tree items.
829      */
830     if (tree)
831     {
832         g_tree = tree;
833
834         /*
835          * create the ansi_801 protocol tree
836          */
837         ansi_801_item =
838             proto_tree_add_protocol_format(tree, proto_ansi_801, tvb, 0, -1,
839                 "%s %s Link",
840                 ansi_proto_name,
841                 (pinfo->match_port == ANSI_801_FORWARD) ? "Forward" : "Reverse");
842
843         ansi_801_tree =
844             proto_item_add_subtree(ansi_801_item, ett_ansi_801);
845
846         if (pinfo->match_port == ANSI_801_FORWARD)
847         {
848             dissect_ansi_801_for_message(tvb, ansi_801_tree);
849         }
850         else
851         {
852             dissect_ansi_801_rev_message(tvb, ansi_801_tree);
853         }
854     }
855 }
856
857
858 /* Register the protocol with Ethereal */
859 void
860 proto_register_ansi_801(void)
861 {
862     guint               i;
863     gint                last_offset;
864
865     /* Setup list of header fields */
866     static hf_register_info hf[] =
867     {
868         { &hf_ansi_801_for_req_type,
869             { "Forward Request Type",           "ansi_801.for_req_type",
870             FT_UINT8, BASE_DEC, NULL, 0,
871             "", HFILL }
872         },
873         { &hf_ansi_801_for_rsp_type,
874             { "Forward Response Type",          "ansi_801.for_rsp_type",
875             FT_UINT8, BASE_DEC, NULL, 0,
876             "", HFILL }
877         },
878         { &hf_ansi_801_rev_req_type,
879             { "Reverse Request Type",           "ansi_801.rev_req_type",
880             FT_UINT8, BASE_DEC, NULL, 0,
881             "", HFILL }
882         },
883         { &hf_ansi_801_rev_rsp_type,
884             { "Reverse Response Type",          "ansi_801.rev_rsp_type",
885             FT_UINT8, BASE_DEC, NULL, 0,
886             "", HFILL }
887         },
888         { &hf_ansi_801_for_sess_tag,
889             { "Forward Session Tag",            "ansi_801.for_sess_tag",
890             FT_UINT8, BASE_DEC, NULL, 0,
891             "", HFILL }
892         },
893         { &hf_ansi_801_rev_sess_tag,
894             { "Reverse Session Tag",            "ansi_801.rev_sess_tag",
895             FT_UINT8, BASE_DEC, NULL, 0,
896             "", HFILL }
897         },
898         { &hf_ansi_801_sess_tag,
899             { "Session Tag",                    "ansi_801.sess_tag",
900             FT_UINT8, BASE_DEC, NULL, 0,
901             "", HFILL }
902         },
903     };
904
905     /* Setup protocol subtree array */
906 #define NUM_INDIVIDUAL_PARAMS   1
907     gint *ett[NUM_INDIVIDUAL_PARAMS+NUM_FOR_REQ_TYPE+NUM_FOR_RSP_TYPE+NUM_REV_REQ_TYPE+NUM_REV_RSP_TYPE];
908
909     ett[0] = &ett_ansi_801;
910
911     last_offset = NUM_INDIVIDUAL_PARAMS;
912
913     for (i=0; i < NUM_FOR_REQ_TYPE; i++, last_offset++)
914     {
915         ett[last_offset] = &ett_for_req_type[i];
916     }
917
918     for (i=0; i < NUM_FOR_RSP_TYPE; i++, last_offset++)
919     {
920         ett[last_offset] = &ett_for_rsp_type[i];
921     }
922
923     for (i=0; i < NUM_REV_REQ_TYPE; i++, last_offset++)
924     {
925         ett[last_offset] = &ett_rev_req_type[i];
926     }
927
928     for (i=0; i < NUM_REV_RSP_TYPE; i++, last_offset++)
929     {
930         ett[last_offset] = &ett_rev_rsp_type[i];
931     }
932
933     /* Register the protocol name and description */
934     proto_ansi_801 =
935         proto_register_protocol(ansi_proto_name, "ANSI IS-801 (Location Services (PLD))", "ansi_801");
936
937     /* Required function calls to register the header fields and subtrees used */
938     proto_register_field_array(proto_ansi_801, hf, array_length(hf));
939     proto_register_subtree_array(ett, array_length(ett));
940 }
941
942
943 void
944 proto_reg_handoff_ansi_801(void)
945 {
946     dissector_handle_t  ansi_801_handle;
947
948     ansi_801_handle = create_dissector_handle(dissect_ansi_801, proto_ansi_801);
949
950     dissector_add("ansi_map.pld", ANSI_801_FORWARD, ansi_801_handle);
951     dissector_add("ansi_map.pld", ANSI_801_REVERSE, ansi_801_handle);
952     dissector_add("ansi_a.pld", ANSI_801_FORWARD, ansi_801_handle);
953     dissector_add("ansi_a.pld", ANSI_801_REVERSE, ansi_801_handle);
954
955     data_handle = find_dissector("data");
956 }