Fix about 150 warnings new to gcc 4.0 in the error on warning directories.
[obnox/wireshark/wip.git] / plugins / irda / packet-irda.c
1 /* packet-irda.c
2  * Routines for IrDA dissection
3  * By Shaun Jackman <sjackman@pathwayconnect.com>
4  * Copyright 2000 Shaun Jackman
5  *
6  * Extended by Jan Kiszka <jan.kiszka@web.de>
7  * Copyright 2003 Jan Kiszka
8  *
9  * $Id$
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  * 
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  * 
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <glib.h>
39 #include <epan/packet.h>
40 #include <epan/proto.h>
41 #include <epan/conversation.h>
42 #include <epan/xdlc.h>
43
44 #include "irda-appl.h"
45
46 /*
47  * This plugin dissects infrared data transmissions as defined by the IrDA
48  * specification (www.irda.org).  See
49  *
50  *      http://www.irda.org/standards/specifications.asp
51  *
52  * for various IrDA specifications.
53  *
54  * The plugin operates both offline with libpcap files and online on supported
55  * platforms. Live dissection is currently available for Linux-IrDA
56  * (irda.sourceforge.net) and for Windows if the Linux-IrDA port IrCOMM2k
57  * (www.ircomm2k.de) is installed.
58  */
59
60 /*
61  * LAP
62  */
63
64 /* Frame types and templates */
65 #define INVALID   0xff
66
67 /*
68  * XXX - the IrDA spec gives XID as 0x2c; HDLC (and other HDLC-derived
69  * protocolc) use 0xAC.
70  */
71 #define IRDA_XID_CMD   0x2c /* Exchange Station Identification */
72
73 #define CMD_FRAME 0x01
74 #define RSP_FRAME 0x00
75
76 /* Discovery Flags */
77 #define S_MASK    0x03
78 #define CONFLICT  0x04
79
80 /* Negotiation Parameters */
81 #define PI_BAUD_RATE        0x01
82 #define PI_MAX_TURN_TIME    0x82
83 #define PI_DATA_SIZE        0x83
84 #define PI_WINDOW_SIZE      0x84
85 #define PI_ADD_BOFS         0x85
86 #define PI_MIN_TURN_TIME    0x86
87 #define PI_LINK_DISC        0x08
88
89
90 /*
91  * LMP
92  */
93
94 /* IrLMP frame opcodes */
95 #define CONNECT_CMD    0x01
96 #define CONNECT_CNF    0x81
97 #define DISCONNECT     0x02
98 #define ACCESSMODE_CMD 0x03
99 #define ACCESSMODE_CNF 0x83
100
101 #define CONTROL_BIT    0x80
102 #define RESERVED_BIT   0x80
103
104 /* LSAP-SEL's */
105 #define LSAP_MASK     0x7f
106 #define LSAP_IAS      0x00
107 #define LSAP_ANY      0xff
108 #define LSAP_MAX      0x6f /* 0x70-0x7f are reserved */
109 #define LSAP_CONNLESS 0x70 /* Connectionless LSAP, mostly used for Ultra */
110
111
112 /*
113  * IAP
114  */
115
116 /* IrIAP Op-codes */
117 #define GET_INFO_BASE      0x01
118 #define GET_OBJECTS        0x02
119 #define GET_VALUE          0x03
120 #define GET_VALUE_BY_CLASS 0x04
121 #define GET_OBJECT_INFO    0x05
122 #define GET_ATTRIB_NAMES   0x06
123
124 #define IAP_LST            0x80
125 #define IAP_ACK            0x40
126 #define IAP_OP             0x3F
127
128 #define IAS_SUCCESS        0
129 #define IAS_CLASS_UNKNOWN  1
130 #define IAS_ATTRIB_UNKNOWN 2
131 #define IAS_ATTR_TOO_LONG  3
132 #define IAS_DISCONNECT     10
133 #define IAS_UNSUPPORTED    0xFF
134
135
136 /*
137  * TTP
138  */
139
140 #define TTP_PARAMETERS         0x80
141 #define TTP_MORE               0x80
142
143 /* Initialize the protocol and registered fields */
144 static int proto_irlap = -1;
145 static int hf_lap_a = -1;
146 static int hf_lap_a_cr = -1;
147 static int hf_lap_a_address = -1;
148 static int hf_lap_c = -1;
149 static int hf_lap_c_nr = -1;
150 static int hf_lap_c_ns = -1;
151 static int hf_lap_c_p = -1;
152 static int hf_lap_c_f = -1;
153 static int hf_lap_c_s = -1;
154 static int hf_lap_c_u_cmd = -1;
155 static int hf_lap_c_u_rsp = -1;
156 static int hf_lap_c_i = -1;
157 static int hf_lap_c_s_u = -1;
158 static int hf_lap_i = -1;
159 static int hf_snrm_saddr = -1;
160 static int hf_snrm_daddr = -1;
161 static int hf_snrm_ca = -1;
162 static int hf_ua_saddr = -1;
163 static int hf_ua_daddr = -1;
164 static int hf_negotiation_param = -1;
165 static int hf_param_pi = -1;
166 static int hf_param_pl = -1;
167 static int hf_param_pv = -1;
168 static int hf_xid_ident = -1;
169 static int hf_xid_saddr = -1;
170 static int hf_xid_daddr = -1;
171 static int hf_xid_flags = -1;
172 static int hf_xid_s = -1;
173 static int hf_xid_conflict = -1;
174 static int hf_xid_slotnr = -1;
175 static int hf_xid_version = -1;
176
177 static int proto_irlmp = -1;
178 static int hf_lmp_xid_hints = -1;
179 static int hf_lmp_xid_charset = -1;
180 static int hf_lmp_xid_name = -1;
181 static int hf_lmp_xid_name_no_ascii = -1;
182 static int hf_lmp_dst = -1;
183 static int hf_lmp_dst_control = -1;
184 static int hf_lmp_dst_lsap = -1;
185 static int hf_lmp_src = -1;
186 static int hf_lmp_src_r = -1;
187 static int hf_lmp_src_lsap = -1;
188 static int hf_lmp_opcode = -1;
189 static int hf_lmp_rsvd = -1;
190 static int hf_lmp_reason = -1;
191 static int hf_lmp_mode = -1;
192 static int hf_lmp_status = -1;
193
194 static int proto_iap = -1;
195 static int hf_iap_ctl = -1;
196 static int hf_iap_ctl_lst = -1;
197 static int hf_iap_ctl_ack = -1;
198 static int hf_iap_ctl_opcode = -1;
199 static int hf_iap_class_name = -1;
200 static int hf_iap_attr_name = -1;
201 static int hf_iap_return = -1;
202 static int hf_iap_list_len = -1;
203 static int hf_iap_list_entry = -1;
204 static int hf_iap_obj_id = -1;
205 static int hf_iap_attr_type = -1;
206 static int hf_iap_int = -1;
207 static int hf_iap_seq_len = -1;
208 static int hf_iap_oct_seq = -1;
209 static int hf_iap_char_set = -1;
210 static int hf_iap_string = -1;
211 static int hf_iap_invaloctet = -1;
212 static int hf_iap_invallsap = -1;
213
214 static int proto_ttp = -1;
215 static int hf_ttp_p = -1;
216 static int hf_ttp_icredit = -1;
217 static int hf_ttp_m = -1;
218 static int hf_ttp_dcredit = -1;
219
220 static int proto_log = -1;
221 static int hf_log_msg = -1;
222 static int hf_log_missed = -1;
223
224 /* Initialize the subtree pointers */
225 static gint ett_irlap = -1;
226 static gint ett_lap_a = -1;
227 static gint ett_lap_c = -1;
228 static gint ett_lap_i = -1;
229 static gint ett_xid_flags = -1;
230 static gint ett_log = -1;
231 static gint ett_irlmp = -1;
232 static gint ett_lmp_dst = -1;
233 static gint ett_lmp_src = -1;
234 static gint ett_iap = -1;
235 static gint ett_iap_ctl = -1;
236 static gint ett_ttp = -1;
237
238 #define MAX_PARAMETERS      32
239 static gint ett_param[MAX_PARAMETERS];
240
241 static gint ett_iap_entry[MAX_IAP_ENTRIES];
242
243 static const xdlc_cf_items irlap_cf_items = {
244         &hf_lap_c_nr,
245         &hf_lap_c_ns,
246         &hf_lap_c_p,
247         &hf_lap_c_f,
248         &hf_lap_c_s,
249         &hf_lap_c_u_cmd,
250         &hf_lap_c_u_rsp,
251         &hf_lap_c_i,
252         &hf_lap_c_s_u
253 };
254
255 /* IAP conversation type */
256 typedef struct iap_conversation {
257     struct iap_conversation*    pnext;
258     guint32                     iap_query_frame;
259     ias_attr_dissector_t* pattr_dissector;
260 } iap_conversation_t;
261
262 /* IrLMP conversation type */
263 typedef struct lmp_conversation {
264     struct lmp_conversation*    pnext;
265     guint32                     iap_result_frame;
266     gboolean                    ttp;
267     dissector_t                 proto_dissector;
268 } lmp_conversation_t;
269
270 static GMemChunk* iap_conv_chunk = NULL;
271 static GMemChunk* lmp_conv_chunk = NULL;
272
273 static const true_false_string lap_cr_vals = {
274     "Command",
275     "Response"
276 };
277
278 static const true_false_string set_notset = {
279     "Set",
280     "Not set"
281 };
282
283 static const value_string lap_c_ftype_vals[] = {
284     { XDLC_I, "Information frame" },
285     { XDLC_S, "Supervisory frame" },
286     { XDLC_U, "Unnumbered frame" },
287     { 0,      NULL }
288 };
289
290 static const value_string lap_c_u_cmd_abbr_vals[] = {
291     { XDLC_SNRM,    "SNRM" },
292     { XDLC_DISC,    "DISC" },
293     { XDLC_UI,      "UI" },
294     { IRDA_XID_CMD, "XID" },
295     { XDLC_TEST,    "TEST" },
296     { 0,            NULL }
297 };
298
299 static const value_string lap_c_u_rsp_abbr_vals[] = {
300     { XDLC_SNRM, "RNRM" },
301     { XDLC_UA,   "UA" },
302     { XDLC_FRMR, "FRMR" },
303     { XDLC_DM,   "DM" },
304     { XDLC_RD,   "RD" },
305     { XDLC_UI,   "UI" },
306     { XDLC_XID,  "XID" },
307     { XDLC_TEST, "TEST" },
308     { 0,         NULL }
309 };
310
311 static const value_string lap_c_u_cmd_vals[] = {
312     { XDLC_SNRM>>2,    "Set Normal Response Mode" },
313     { XDLC_DISC>>2,    "Disconnect" },
314     { XDLC_UI>>2,      "Unnumbered Information" },
315     { IRDA_XID_CMD>>2, "Exchange Station Identification" },
316     { XDLC_TEST>>2,    "Test" },
317     { 0,               NULL }
318 };
319
320 static const value_string lap_c_u_rsp_vals[] = {
321     { XDLC_SNRM>>2,  "Request Normal Response Mode" },
322     { XDLC_UA>>2,    "Unnumbered Acknowledge" },
323     { XDLC_FRMR>>2,  "Frame Reject" },
324     { XDLC_DM>>2,    "Disconnect Mode" },
325     { XDLC_RD>>2,    "Request Disconnect" },
326     { XDLC_UI>>2,    "Unnumbered Information" },
327     { XDLC_XID>>2,   "Exchange Station Identification" },
328     { XDLC_TEST>>2,  "Test" },
329     { 0,             NULL }
330 };
331
332 static const value_string lap_c_s_vals[] = {
333     { XDLC_RR>>2,   "Receiver ready" },
334     { XDLC_RNR>>2,  "Receiver not ready" },
335     { XDLC_REJ>>2,  "Reject" },
336     { XDLC_SREJ>>2, "Selective reject" },
337     { 0,            NULL }
338 };
339
340 static const value_string xid_slot_numbers[] = {
341 /* Number of XID slots */
342     { 0, "1" },
343     { 1, "6" },
344     { 2, "8" },
345     { 3, "16" },
346     { 0, NULL }
347 };
348
349 static const value_string lmp_opcode_vals[] = {
350 /* IrLMP frame opcodes */
351     { CONNECT_CMD,    "Connect Command" },
352     { CONNECT_CNF,    "Connect Confirm" },
353     { DISCONNECT,     "Disconnect" },
354     { ACCESSMODE_CMD, "Access Mode Command" },
355     { ACCESSMODE_CNF, "Access Mode Confirm" },
356     { 0,              NULL }
357 };
358
359 static const value_string lmp_reason_vals[] = {
360 /* IrLMP disconnect reasons */
361     { 0x01, "User Request" },
362     { 0x02, "Unexpected IrLAP Disconnect" },
363     { 0x03, "Failed to establish IrLAP connection" },
364     { 0x04, "IrLAP Reset" },
365     { 0x05, "Link Management Initiated Disconnect" },
366     { 0x06, "Data delivered on disconnected LSAP-Connection"},
367     { 0x07, "Non Responsive LM-MUX Client" },
368     { 0x08, "No available LM-MUX Client" },
369     { 0x09, "Connection Half Open" },
370     { 0x0A, "Illegal Source Address" },
371     { 0xFF, "Unspecified Disconnect Reason" },
372     { 0,    NULL }
373 };
374
375 static const value_string lmp_mode_vals[] = {
376 /* IrLMP modes */
377     { 0x00, "Multiplexed" },
378     { 0x01, "Exclusive" },
379     { 0,    NULL }
380 };
381
382 static const value_string lmp_status_vals[] = {
383 /* IrLMP status */
384     { 0x00, "Success" },
385     { 0x01, "Failure" },
386     { 0xFF, "Unsupported" },
387     { 0,    NULL }
388 };
389
390 static const value_string iap_opcode_vals[] = {
391 /* IrIAP Op-codes */
392     { GET_INFO_BASE,      "GetInfoBase" },
393     { GET_OBJECTS,        "GetObjects" },
394     { GET_VALUE,          "GetValue" },
395     { GET_VALUE_BY_CLASS, "GetValueByClass" },
396     { GET_OBJECT_INFO,    "GetObjectInfo" },
397     { GET_ATTRIB_NAMES,   "GetAttributeNames" },
398     { 0,                  NULL }
399 };
400
401 static const value_string iap_return_vals[] = {
402 /* IrIAP Return-codes */
403     { IAS_SUCCESS,        "Success" },
404     { IAS_CLASS_UNKNOWN,  "Class/Object Unknown" },
405     { IAS_ATTRIB_UNKNOWN, "Attribute Unknown" },
406     { IAS_ATTR_TOO_LONG,  "Attribute List Too Long" },
407     { IAS_DISCONNECT,     "Disconnect (Linux-IrDA only)" },
408     { IAS_UNSUPPORTED,    "Unsupported Optional Operation" },
409     { 0,                  NULL }
410 };
411
412 static const value_string iap_attr_type_vals[] = {
413 /* LM-IAS Attribute types */
414     { IAS_MISSING, "Missing" },
415     { IAS_INTEGER, "Integer" },
416     { IAS_OCT_SEQ, "Octet Sequence" },
417     { IAS_STRING,  "String" },
418     { 0,           NULL }
419 };
420
421 static ias_attr_dissector_t device_attr_dissector[] = {
422 /* Device attribute dissectors */
423 /*    { "IrLMPSupport", xxx },  not implemented yet... */
424     { NULL, NULL }
425 };
426
427 /* IAS class dissectors */
428 static ias_class_dissector_t class_dissector[] = { CLASS_DISSECTORS };
429
430
431 /*
432  * Dissect parameter tuple
433  */
434 unsigned dissect_param_tuple(tvbuff_t* tvb, proto_tree* tree, unsigned offset)
435 {
436     guint8  len = tvb_get_guint8(tvb, offset + 1);
437
438     if (tree)
439         proto_tree_add_item(tree, hf_param_pi, tvb, offset, 1, FALSE);
440     offset++;
441
442     if (tree)
443         proto_tree_add_item(tree, hf_param_pl, tvb, offset, 1, FALSE);
444     offset++;
445
446     if (len > 0)
447     {
448         if (tree)
449             proto_tree_add_item(tree, hf_param_pv, tvb, offset, len, FALSE);
450         offset += len;
451     }
452
453     return offset;
454 }
455
456
457 /*
458  * Dissect TTP
459  */
460 static unsigned dissect_ttp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, gboolean data)
461 {
462     unsigned    offset = 0;
463     guint8      head;
464
465
466     if (tvb_length(tvb) == 0)
467         return 0;
468
469     /* Make entries in Protocol column on summary display */
470     if (check_col(pinfo->cinfo, COL_PROTOCOL))
471         col_set_str(pinfo->cinfo, COL_PROTOCOL, "TTP");
472
473     head = tvb_get_guint8(tvb, offset);
474
475     if (check_col(pinfo->cinfo, COL_INFO))
476     {
477         char    buf[128];
478
479
480         sprintf(buf, ", Credit=%d", head & ~TTP_PARAMETERS);
481         col_append_str(pinfo->cinfo, COL_INFO, buf);
482     }
483
484     if (root)
485     {
486         /* create display subtree for the protocol */
487         proto_item* ti   = proto_tree_add_item(root, proto_ttp, tvb, 0, -1, FALSE);
488         proto_tree* tree = proto_item_add_subtree(ti, ett_ttp);
489
490         if (data)
491         {
492             proto_tree_add_item(tree, hf_ttp_m, tvb, offset, 1, FALSE);
493             proto_tree_add_item(tree, hf_ttp_dcredit, tvb, offset, 1, FALSE);
494             offset++;
495         }
496         else
497         {
498             proto_tree_add_item(tree, hf_ttp_p, tvb, offset, 1, FALSE);
499             proto_tree_add_item(tree, hf_ttp_icredit, tvb, offset, 1, FALSE);
500             offset++;
501         }
502         proto_item_set_len(tree, offset);
503     }
504     else
505         offset++;
506
507     return offset;
508 }
509
510
511 /*
512  * Dissect IAP request
513  */
514 static void dissect_iap_request(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
515 {
516     unsigned            offset = 0;
517     guint8              op;
518     guint8              clen = 0;
519     guint8              alen = 0;
520     guint8              src;
521     address             srcaddr;
522     address             destaddr;
523     conversation_t*     conv;
524     iap_conversation_t* iap_conv;
525
526
527     if (tvb_length(tvb) == 0)
528         return;
529
530     /* Make entries in Protocol column on summary display */
531     if (check_col(pinfo->cinfo, COL_PROTOCOL))
532         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAP");
533
534     op = tvb_get_guint8(tvb, offset) & IAP_OP;
535
536     switch (op)
537     {
538         case GET_VALUE_BY_CLASS:
539             clen = MIN(tvb_get_guint8(tvb, offset + 1), 60);
540             alen = MIN(tvb_get_guint8(tvb, offset + 1 + 1 + clen), 60);
541
542             /* create conversation entry */
543             src = pinfo->circuit_id ^ CMD_FRAME;
544             srcaddr.type  = AT_NONE;
545             srcaddr.len   = 1;
546             srcaddr.data  = (guint8*)&src;
547
548             destaddr.type = AT_NONE;
549             destaddr.len  = 1;
550             destaddr.data = (guint8*)&pinfo->circuit_id;
551
552             conv = find_conversation(pinfo->fd->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
553             if (conv)
554             {
555                 iap_conv = (iap_conversation_t*)conversation_get_proto_data(conv, proto_iap);
556                 while (1)
557                 {
558                     if (iap_conv->iap_query_frame == pinfo->fd->num)
559                     {
560                         iap_conv = NULL;
561                         break;
562                     }
563                     if (iap_conv->pnext == NULL)
564                     {
565                         iap_conv->pnext = g_mem_chunk_alloc(iap_conv_chunk);
566                         iap_conv = iap_conv->pnext;
567                         break;
568                     }
569                     iap_conv = iap_conv->pnext;
570                 }
571             }
572             else
573             {
574                 conv = conversation_new(pinfo->fd->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
575                 iap_conv = g_mem_chunk_alloc(iap_conv_chunk);
576                 conversation_add_proto_data(conv, proto_iap, (void*)iap_conv);
577             }
578
579             /* Dissect IAP query if it is new */
580             if (iap_conv)
581             {
582                 int     i, j;
583                 char    class_name[256];
584                 char    attr_name[256];
585
586
587                 iap_conv->pnext           = NULL;
588                 iap_conv->iap_query_frame = pinfo->fd->num;
589                 iap_conv->pattr_dissector = NULL;
590
591                 tvb_memcpy(tvb, (guint8*)class_name, offset + 1 + 1, clen);
592                 class_name[clen] = 0;
593                 tvb_memcpy(tvb, (guint8*)attr_name, offset + 1 + 1 + clen + 1, alen);
594                 attr_name[alen] = 0;
595
596                 /* Find the attribute dissector */
597                 for (i = 0; class_dissector[i].class_name != NULL; i++)
598                     if (strcmp(class_name, class_dissector[i].class_name) == 0)
599                     {
600                         for (j = 0; class_dissector[i].pattr_dissector[j].attr_name != NULL; j++)
601                             if (strcmp(attr_name, class_dissector[i].pattr_dissector[j].attr_name) == 0)
602                             {
603                                 iap_conv->pattr_dissector = &class_dissector[i].pattr_dissector[j];
604                                 break;
605                             }
606                         break;
607                     }
608             }
609
610             if (check_col(pinfo->cinfo, COL_INFO))
611             {
612                 char    buf[128];
613
614
615                 col_add_str(pinfo->cinfo, COL_INFO, "GetValueByClass: \"");
616
617                 tvb_memcpy(tvb, (guint8*)buf, offset + 1 + 1, clen);
618                 memcpy(&buf[clen], "\" \"", 3);
619                 tvb_memcpy(tvb, (guint8*)buf + clen + 3, offset + 1 + 1 + clen + 1, alen);
620                 buf[clen + 3 + alen] = '\"';
621                 buf[clen + 3 + alen + 1] = 0;
622                 col_append_str(pinfo->cinfo, COL_INFO, buf);
623             }
624     }
625
626     if (root)
627     {
628         /* create display subtree for the protocol */
629         proto_item* ti   = proto_tree_add_item(root, proto_iap, tvb, 0, -1, FALSE);
630         proto_tree* tree = proto_item_add_subtree(ti, ett_iap);
631
632         proto_tree* ctl_tree;
633
634
635         ti       = proto_tree_add_item(tree, hf_iap_ctl, tvb, offset, 1, FALSE);
636         ctl_tree = proto_item_add_subtree(ti, ett_iap_ctl);
637         proto_tree_add_item(ctl_tree, hf_iap_ctl_lst, tvb, offset, 1, FALSE);
638         proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, FALSE);
639         proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, FALSE);
640         offset++;
641
642         switch (op)
643         {
644             case GET_VALUE_BY_CLASS:
645                 proto_tree_add_item(tree, hf_iap_class_name, tvb, offset, 1, FALSE);
646                 offset += 1 + clen;
647
648                 proto_tree_add_item(tree, hf_iap_attr_name, tvb, offset, 1, FALSE);
649                 offset += 1 + alen;
650                 break;
651         }
652     }
653     else
654     {
655         offset++;
656         switch (op)
657         {
658             case GET_VALUE_BY_CLASS:
659                 offset += 1 + clen + 1 + alen;
660                 break;
661         }
662     }
663
664     /* If any bytes remain, send it to the generic data dissector */
665     tvb = tvb_new_subset(tvb, offset, -1, -1);
666     call_dissector(data_handle, tvb, pinfo, root);
667 }
668
669
670 /*
671  * Dissect IAP result
672  */
673 static void dissect_iap_result(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
674 {
675     unsigned            offset = 0;
676     unsigned            len    = tvb_length(tvb);
677     unsigned            n      = 0;
678     unsigned            list_len;
679     guint8              op;
680     guint8              retcode;
681     guint8              type;
682     guint16             attr_len;
683     char                buf[300];
684     guint8              src;
685     address             srcaddr;
686     address             destaddr;
687     conversation_t*     conv;
688     iap_conversation_t* cur_iap_conv;
689     iap_conversation_t* iap_conv = NULL;
690     guint32             num;
691
692
693     if (tvb_length(tvb) == 0)
694         return;
695
696     /* Make entries in Protocol column on summary display */
697     if (check_col(pinfo->cinfo, COL_PROTOCOL))
698         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAP");
699
700     op      = tvb_get_guint8(tvb, offset) & IAP_OP;
701     retcode = tvb_get_guint8(tvb, offset + 1);
702
703     src = pinfo->circuit_id ^ CMD_FRAME;
704     srcaddr.type  = AT_NONE;
705     srcaddr.len   = 1;
706     srcaddr.data  = (guint8*)&src;
707
708     destaddr.type = AT_NONE;
709     destaddr.len  = 1;
710     destaddr.data = (guint8*)&pinfo->circuit_id;
711
712     /* Find result value dissector */
713     conv = find_conversation(pinfo->fd->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
714     if (conv)
715     {
716         num = pinfo->fd->num;
717
718         iap_conv = (iap_conversation_t*)conversation_get_proto_data(conv, proto_iap);
719         while (iap_conv && (iap_conv->iap_query_frame >= num))
720             iap_conv = iap_conv->pnext;
721
722         if (iap_conv)
723         {
724             cur_iap_conv = iap_conv->pnext;
725             while (cur_iap_conv)
726             {
727                 if ((cur_iap_conv->iap_query_frame < num) &&
728                     (cur_iap_conv->iap_query_frame > iap_conv->iap_query_frame))
729                 {
730                     iap_conv = cur_iap_conv;
731                 }
732
733                 cur_iap_conv = cur_iap_conv->pnext;
734             }
735         }
736     }
737
738     if (check_col(pinfo->cinfo, COL_INFO))
739     {
740         col_add_str(pinfo->cinfo, COL_INFO, "Result: ");
741         col_append_str(pinfo->cinfo, COL_INFO, val_to_str(retcode, iap_return_vals, "0x%02X"));
742
743         switch (op)
744         {
745             case GET_VALUE_BY_CLASS:
746                 if (retcode == 0)
747                 {
748                     switch (tvb_get_guint8(tvb, offset + 6))
749                     {
750                         case IAS_MISSING:
751                             strcpy(buf, ", Missing");
752                             break;
753
754                         case IAS_INTEGER:
755                             sprintf(buf, ", Integer: %d", tvb_get_ntohl(tvb, offset + 7));
756                             break;
757
758                         case IAS_OCT_SEQ:
759                             sprintf(buf, ", %d Octets", tvb_get_ntohs(tvb, offset + 7));
760                             break;
761
762                         case IAS_STRING:
763                             strcpy(buf, ", \"");
764                             n = tvb_get_guint8(tvb, offset + 8);
765                             tvb_memcpy(tvb, (guint8*)buf + 3, offset + 9, n);
766                             strcpy(buf + 3 + n, "\"");
767                             break;
768                     }
769                     col_append_str(pinfo->cinfo, COL_INFO, buf);
770                     if (tvb_get_ntohs(tvb, offset + 2) > 1)
771                         col_append_str(pinfo->cinfo, COL_INFO, ", ...");
772                 }
773                 break;
774         }
775     }
776
777     if (root)
778     {
779         /* create display subtree for the protocol */
780         proto_item* ti   = proto_tree_add_item(root, proto_iap, tvb, 0, -1, FALSE);
781         proto_tree* tree = proto_item_add_subtree(ti, ett_iap);
782
783         proto_tree* ctl_tree;
784         proto_tree* entry_tree;
785
786
787         ti       = proto_tree_add_item(tree, hf_iap_ctl, tvb, offset, 1, FALSE);
788         ctl_tree = proto_item_add_subtree(ti, ett_iap_ctl);
789         proto_tree_add_item(ctl_tree, hf_iap_ctl_lst, tvb, offset, 1, FALSE);
790         proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, FALSE);
791         proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, FALSE);
792         offset++;
793
794         proto_tree_add_item(tree, hf_iap_return, tvb, offset, 1, FALSE);
795         offset++;
796
797         switch (op)
798         {
799             case GET_VALUE_BY_CLASS:
800                 if (retcode == 0)
801                 {
802                     list_len = tvb_get_ntohs(tvb, offset);
803
804                     proto_tree_add_item(tree, hf_iap_list_len, tvb, offset, 2, FALSE);
805                     offset += 2;
806
807                     while ((offset < len) && (n < list_len))
808                     {
809                         type = tvb_get_guint8(tvb, offset + 2);
810                         switch (type)
811                         {
812                             case IAS_INTEGER:
813                                 attr_len = 4;
814                                 break;
815
816                             case IAS_OCT_SEQ:
817                                 attr_len = tvb_get_ntohs(tvb, offset + 2 + 1) + 2;
818                                 break;
819
820                             case IAS_STRING:
821                                 attr_len = tvb_get_guint8(tvb, offset + 2 + 1 + 1) + 2;
822                                 break;
823
824                             default:
825                                 attr_len = 0;
826                         }
827
828                         ti = proto_tree_add_item(tree, hf_iap_list_entry, tvb, offset, 2 + 1 + attr_len, FALSE);
829                         g_snprintf(buf, sizeof(buf) - 1, "%d", n + 1);
830                         proto_item_append_text(ti, buf);
831                         entry_tree = proto_item_add_subtree(ti, ett_iap_entry[n]);
832
833                         proto_tree_add_item(entry_tree, hf_iap_obj_id, tvb, offset, 2, FALSE);
834                         offset += 2;
835
836                         proto_tree_add_item(entry_tree, hf_iap_attr_type, tvb, offset, 1, FALSE);
837                         offset++;
838
839                         switch (type)
840                         {
841                             case IAS_INTEGER:
842                                 if (!iap_conv || !iap_conv->pattr_dissector ||
843                                     !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
844                                                                                 n, type))
845                                     proto_tree_add_item(entry_tree, hf_iap_int, tvb, offset, 4, FALSE);
846                                 break;
847
848                             case IAS_OCT_SEQ:
849                                 proto_tree_add_item(entry_tree, hf_iap_seq_len, tvb, offset, 2, FALSE);
850                                 if (!iap_conv || !iap_conv->pattr_dissector ||
851                                     !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
852                                                                                 n, type))
853                                     proto_tree_add_item(entry_tree, hf_iap_oct_seq, tvb, offset + 2,
854                                                         attr_len - 2, FALSE);
855                                 break;
856
857                             case IAS_STRING:
858                                 proto_tree_add_item(entry_tree, hf_iap_char_set, tvb, offset, 1, FALSE);
859                                 if (!iap_conv || !iap_conv->pattr_dissector ||
860                                     !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
861                                                                                 n, type))
862                                     proto_tree_add_item(entry_tree, hf_iap_string, tvb, offset + 1, 1, FALSE);
863                                 break;
864                         }
865                         offset += attr_len;
866
867                         n++;
868                     }
869                 }
870                 break;
871         }
872     }
873     else
874     {
875         offset += 2;
876         switch (op)
877         {
878             case GET_VALUE_BY_CLASS:
879                 if (retcode == 0)
880                 {
881                     offset += 2;
882
883                     while (offset < len)
884                     {
885                         offset += 2;
886                         type = tvb_get_guint8(tvb, offset);
887                         offset++;
888
889                         switch (type)
890                         {
891                             case IAS_INTEGER:
892                                 attr_len = 4;
893                                 if (iap_conv && iap_conv->pattr_dissector)
894                                     iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
895                                                                                n, type);
896                                 break;
897
898                             case IAS_OCT_SEQ:
899                                 attr_len = tvb_get_ntohs(tvb, offset) + 2;
900                                 if (iap_conv && iap_conv->pattr_dissector)
901                                     iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
902                                                                                n, type);
903                                 break;
904
905                             case IAS_STRING:
906                                 attr_len = tvb_get_guint8(tvb, offset + 1) + 2;
907                                 if (iap_conv && iap_conv->pattr_dissector)
908                                     iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
909                                                                                n, type);
910
911                             default:
912                                 attr_len = 0;
913                         }
914                         offset += attr_len;
915
916                         n++;
917                     }
918                 }
919                 break;
920         }
921     }
922
923     /* If any bytes remain, send it to the generic data dissector */
924     tvb = tvb_new_subset(tvb, offset, -1, -1);
925     call_dissector(data_handle, tvb, pinfo, root);
926 }
927
928
929 /*
930  * Check if IAP result is octet sequence
931  */
932 gboolean check_iap_octet_result(tvbuff_t* tvb, proto_tree* tree, unsigned offset,
933                                 const char* attr_name, guint8 attr_type)
934 {
935     if (attr_type != IAS_OCT_SEQ)
936     {
937         if (tree)
938         {
939             proto_item* ti = proto_tree_add_item(tree, hf_iap_invaloctet, tvb, offset, 0, FALSE);
940             proto_item_append_text(ti, "%s", attr_name);
941             proto_item_append_text(ti, "\" attribute must be octet sequence!");
942         }
943
944         return FALSE;
945     }
946     else
947         return TRUE;
948 }
949
950
951 /*
952  * Check if IAP result is correct LsapSel
953  */
954 guint8 check_iap_lsap_result(tvbuff_t* tvb, proto_tree* tree, unsigned offset,
955                              const char* attr_name, guint8 attr_type)
956 {
957     guint32 lsap;
958
959
960     if ((attr_type != IAS_INTEGER) || ((lsap = tvb_get_ntohl(tvb, offset)) < 0x01) ||
961         (lsap > 0x6F))
962     {
963         if (tree)
964         {
965             proto_item* ti = proto_tree_add_item(tree, hf_iap_invallsap, tvb, offset, 0, FALSE);
966             proto_item_append_text(ti, "%s", attr_name);
967             proto_item_append_text(ti, "\" attribute must be integer value between 0x01 and 0x6F!");
968         }
969
970         return 0;
971     }
972     else
973         return lsap;
974 }
975
976
977 /*
978  * Dissect IrDA application protocol
979  */
980 static void dissect_appl_proto(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, pdu_type_t pdu_type)
981 {
982     unsigned            offset = 0;
983     guint8              src;
984     address             srcaddr;
985     address             destaddr;
986     conversation_t*     conv;
987     lmp_conversation_t* cur_lmp_conv;
988     lmp_conversation_t* lmp_conv = NULL;
989     guint32             num;
990
991     
992     src = pinfo->circuit_id ^ CMD_FRAME;
993     srcaddr.type  = AT_NONE;
994     srcaddr.len   = 1;
995     srcaddr.data  = (guint8*)&src;
996
997     destaddr.type = AT_NONE;
998     destaddr.len  = 1;
999     destaddr.data = (guint8*)&pinfo->circuit_id;
1000
1001     /* Find result value dissector */
1002     conv = find_conversation(pinfo->fd->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
1003     if (conv)
1004     {
1005         num = pinfo->fd->num;
1006
1007         lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
1008         while (lmp_conv && (lmp_conv->iap_result_frame >= num))
1009             lmp_conv = lmp_conv->pnext;
1010
1011         if (lmp_conv)
1012         {
1013             cur_lmp_conv = lmp_conv->pnext;
1014             while (cur_lmp_conv)
1015             {
1016                 if ((cur_lmp_conv->iap_result_frame < num) &&
1017                     (cur_lmp_conv->iap_result_frame > lmp_conv->iap_result_frame))
1018                 {
1019                     lmp_conv = cur_lmp_conv;
1020                 }
1021
1022                 cur_lmp_conv = cur_lmp_conv->pnext;
1023             }
1024         }
1025     }
1026
1027     if (lmp_conv)
1028     {
1029 /*g_message("%x:%d->%x:%d = %p\n", src, pinfo->srcport, pinfo->circuit_id, pinfo->destport, lmp_conv); */
1030 /*g_message("->%d: %d %d %p\n", pinfo->fd->num, lmp_conv->iap_result_frame, lmp_conv->ttp, lmp_conv->proto_dissector); */
1031         if ((lmp_conv->ttp) && (pdu_type != DISCONNECT_PDU))
1032         {
1033             offset += dissect_ttp(tvb, pinfo, root, (pdu_type == DATA_PDU));
1034
1035             tvb = tvb_new_subset(tvb, offset, -1, -1);
1036         }
1037
1038         pinfo->private_data = (void *)pdu_type;
1039
1040         lmp_conv->proto_dissector(tvb, pinfo, root);
1041     }
1042     else
1043         call_dissector(data_handle, tvb, pinfo, root);
1044 }
1045
1046
1047 /*
1048  * Dissect LMP
1049  */
1050 static void dissect_irlmp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1051 {
1052     unsigned    offset = 0;
1053     guint8      dlsap;
1054     guint8      slsap;
1055     guint8      cbit;
1056     guint8      opcode = 0;
1057
1058
1059     /* Make entries in Protocol column on summary display */
1060     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1061         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLMP");
1062
1063     dlsap = tvb_get_guint8(tvb, offset);
1064     cbit  = dlsap & CONTROL_BIT;
1065     dlsap &= ~CONTROL_BIT;
1066
1067     slsap = tvb_get_guint8(tvb, offset+1) & ~CONTROL_BIT;
1068
1069     /* save Lsaps in pinfo */
1070     pinfo->srcport  = slsap;
1071     pinfo->destport = dlsap;
1072
1073     if (cbit != 0)
1074     {
1075         opcode = tvb_get_guint8(tvb, offset+2);
1076
1077         if (check_col(pinfo->cinfo, COL_INFO))
1078         {
1079             col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, ", slsap, dlsap);
1080             col_append_str(pinfo->cinfo, COL_INFO, val_to_str(opcode, lmp_opcode_vals, "0x%02X"));
1081             if ((opcode == ACCESSMODE_CMD) || (opcode == ACCESSMODE_CNF))
1082             {
1083                 col_append_str(pinfo->cinfo, COL_INFO, " (");
1084                 col_append_str(pinfo->cinfo, COL_INFO,
1085                                val_to_str(tvb_get_guint8(tvb, offset+4), lmp_mode_vals, "0x%02X"));
1086                 col_append_str(pinfo->cinfo, COL_INFO, ")");
1087             }
1088         }
1089     }
1090     else
1091         if (check_col(pinfo->cinfo, COL_INFO))
1092             col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, Len=%d", slsap, dlsap,
1093                          tvb_length(tvb) - 2);
1094
1095     if (root)
1096     {
1097         /* create display subtree for the protocol */
1098         proto_item* ti   = proto_tree_add_item(root, proto_irlmp, tvb, 0, -1, FALSE);
1099         proto_tree* tree = proto_item_add_subtree(ti, ett_irlmp);
1100
1101         proto_tree* dst_tree;
1102         proto_tree* src_tree;
1103
1104
1105         ti       = proto_tree_add_item(tree, hf_lmp_dst, tvb, offset, 1, FALSE);
1106         dst_tree = proto_item_add_subtree(ti, ett_lmp_dst);
1107         proto_tree_add_item(dst_tree, hf_lmp_dst_control, tvb, offset, 1, FALSE);
1108         proto_tree_add_item(dst_tree, hf_lmp_dst_lsap, tvb, offset, 1, FALSE);
1109         offset++;
1110
1111         ti       = proto_tree_add_item(tree, hf_lmp_src, tvb, offset, 1, FALSE);
1112         src_tree = proto_item_add_subtree(ti, ett_lmp_src);
1113         proto_tree_add_item(src_tree, hf_lmp_src_r, tvb, offset, 1, FALSE);
1114         proto_tree_add_item(src_tree, hf_lmp_src_lsap, tvb, offset, 1, FALSE);
1115         offset++;
1116
1117         if (cbit != 0)
1118         {
1119             proto_tree_add_item(tree, hf_lmp_opcode, tvb, offset, 1, FALSE);
1120             offset++;
1121
1122             switch (opcode)
1123             {
1124                 case CONNECT_CMD:
1125                 case CONNECT_CNF:
1126                     if (offset < tvb_length(tvb))
1127                     {
1128                         proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, FALSE);
1129                         offset++;
1130                     }
1131                     break;
1132
1133                 case DISCONNECT:
1134                     proto_tree_add_item(tree, hf_lmp_reason, tvb, offset, 1, FALSE);
1135                     offset++;
1136                     break;
1137
1138                 case ACCESSMODE_CMD:
1139                     proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, FALSE);
1140                     offset++;
1141
1142                     proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, FALSE);
1143                     offset++;
1144                     break;
1145
1146                 case ACCESSMODE_CNF:
1147                     proto_tree_add_item( tree, hf_lmp_status, tvb, offset, 1, FALSE);
1148                     offset++;
1149
1150                     proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, FALSE);
1151                     offset++;
1152                     break;
1153             }
1154         }
1155
1156         tvb = tvb_new_subset(tvb, offset, -1, -1);
1157         proto_item_set_len(tree, offset);
1158     }
1159     else
1160     {
1161         offset += 2;
1162         if (cbit != 0)
1163         {
1164             offset += 1;
1165
1166             switch (opcode)
1167             {
1168                 case CONNECT_CMD:
1169                 case CONNECT_CNF:
1170                     if (offset < tvb_length(tvb))
1171                         offset++;
1172                     break;
1173
1174                 case DISCONNECT:
1175                     offset++;
1176                     break;
1177
1178                 case ACCESSMODE_CMD:
1179                 case ACCESSMODE_CNF:
1180                     offset += 2;
1181                     break;
1182             }
1183         }
1184
1185         tvb = tvb_new_subset(tvb, offset, -1, -1);
1186     }
1187
1188     if (cbit == 0)
1189     {
1190         if (dlsap == LSAP_IAS)
1191             dissect_iap_request(tvb, pinfo, root);
1192         else if (slsap == LSAP_IAS)
1193             dissect_iap_result(tvb, pinfo, root);
1194         else
1195             dissect_appl_proto(tvb, pinfo, root, DATA_PDU);
1196     }
1197     else
1198     {
1199         if ((dlsap == LSAP_IAS) || (slsap == LSAP_IAS))
1200             call_dissector(data_handle, tvb, pinfo, root);
1201         else
1202             switch (opcode)
1203             {
1204                 case CONNECT_CMD:
1205                 case CONNECT_CNF:
1206                     dissect_appl_proto(tvb, pinfo, root, CONNECT_PDU);
1207                     break;
1208
1209                 case DISCONNECT:
1210                     dissect_appl_proto(tvb, pinfo, root, DISCONNECT_PDU);
1211                     break;
1212
1213                 default:
1214                     call_dissector(data_handle, tvb, pinfo, root);
1215             }
1216     }
1217 }
1218
1219
1220 /*
1221  * Add LMP conversation
1222  */
1223 void add_lmp_conversation(packet_info* pinfo, guint8 dlsap, gboolean ttp, dissector_t proto_dissector)
1224 {
1225     guint8              dest;
1226     address             srcaddr;
1227     address             destaddr;
1228     conversation_t*     conv;
1229     lmp_conversation_t* lmp_conv = NULL;
1230
1231     
1232 /*g_message("%d: add_lmp_conversation(%p, %d, %d, %p) = ", pinfo->fd->num, pinfo, dlsap, ttp, proto_dissector); */
1233     srcaddr.type  = AT_NONE;
1234     srcaddr.len   = 1;
1235     srcaddr.data  = (guint8*)&pinfo->circuit_id;
1236
1237     dest = pinfo->circuit_id ^ CMD_FRAME;
1238     destaddr.type = AT_NONE;
1239     destaddr.len  = 1;
1240     destaddr.data = (guint8*)&dest;
1241
1242     conv = find_conversation(pinfo->fd->num, &destaddr, &srcaddr, PT_NONE, dlsap, 0, NO_PORT_B);
1243     if (conv)
1244     {
1245         lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
1246         while (1)
1247         {
1248             /* Does entry already exist? */
1249             if (lmp_conv->iap_result_frame == pinfo->fd->num)
1250                 return;
1251
1252             if (lmp_conv->pnext == NULL)
1253             {
1254                 lmp_conv->pnext = g_mem_chunk_alloc(lmp_conv_chunk);
1255                 lmp_conv = lmp_conv->pnext;
1256                 break;
1257             }
1258             lmp_conv = lmp_conv->pnext;
1259         }
1260     }
1261     else
1262     {
1263         conv = conversation_new(pinfo->fd->num, &destaddr, &srcaddr, PT_NONE, dlsap, 0, NO_PORT_B);
1264         lmp_conv = g_mem_chunk_alloc(lmp_conv_chunk);
1265         conversation_add_proto_data(conv, proto_irlmp, (void*)lmp_conv);
1266     }
1267
1268     lmp_conv->pnext            = NULL;
1269     lmp_conv->iap_result_frame = pinfo->fd->num;
1270     lmp_conv->ttp              = ttp;
1271     lmp_conv->proto_dissector  = proto_dissector;
1272
1273 /*g_message("%p\n", lmp_conv); */
1274 }
1275
1276
1277 /*
1278  * Dissect Negotiation Parameters
1279  */
1280 static unsigned dissect_negotiation(tvbuff_t* tvb, proto_tree* tree, unsigned offset)
1281 {
1282     unsigned    n   = 0;
1283     proto_item* ti;
1284     proto_tree* p_tree;
1285     char        buf[256];
1286     guint8      pv;
1287
1288     while (tvb_reported_length_remaining(tvb, offset) > 0)
1289     {
1290         guint8  p_len = tvb_get_guint8(tvb, offset + 1);
1291
1292         if (tree)
1293         {
1294             ti = proto_tree_add_item(tree, hf_negotiation_param, tvb, offset, p_len + 2, FALSE);
1295             p_tree = proto_item_add_subtree(ti, ett_param[n]);
1296
1297             pv = tvb_get_guint8(tvb, offset+2);
1298             buf[0] = 0;
1299
1300             switch (tvb_get_guint8(tvb, offset))
1301             {
1302                 case PI_BAUD_RATE:
1303                     proto_item_append_text(ti, ": Baud Rate (");
1304
1305                     if (pv & 0x01)
1306                         strcat(buf, ", 2400");
1307                     if (pv & 0x02)
1308                         strcat(buf, ", 9600");
1309                     if (pv & 0x04)
1310                         strcat(buf, ", 19200");
1311                     if (pv & 0x08)
1312                         strcat(buf, ", 38400");
1313                     if (pv & 0x10)
1314                         strcat(buf, ", 57600");
1315                     if (pv & 0x20)
1316                         strcat(buf, ", 115200");
1317                     if (pv & 0x40)
1318                         strcat(buf, ", 576000");
1319                     if (pv & 0x80)
1320                         strcat(buf, ", 1152000");
1321                     if ((p_len > 1) && (tvb_get_guint8(tvb, offset+3) & 0x01))
1322                         strcat(buf, ", 4000000");
1323
1324                     strcat(buf, " bps)");
1325
1326                     proto_item_append_text(ti, buf+2);
1327
1328                     break;
1329
1330                 case PI_MAX_TURN_TIME:
1331                     proto_item_append_text(ti, ": Maximum Turn Time (");
1332
1333                     if (pv & 0x01)
1334                         strcat(buf, ", 500");
1335                     if (pv & 0x02)
1336                         strcat(buf, ", 250");
1337                     if (pv & 0x04)
1338                         strcat(buf, ", 100");
1339                     if (pv & 0x08)
1340                         strcat(buf, ", 50");
1341
1342                     strcat(buf, " ms)");
1343
1344                     proto_item_append_text(ti, buf+2);
1345
1346                     break;
1347
1348                 case PI_DATA_SIZE:
1349                     proto_item_append_text(ti, ": Data Size (");
1350
1351                     if (pv & 0x01)
1352                         strcat(buf, ", 64");
1353                     if (pv & 0x02)
1354                         strcat(buf, ", 128");
1355                     if (pv & 0x04)
1356                         strcat(buf, ", 256");
1357                     if (pv & 0x08)
1358                         strcat(buf, ", 512");
1359                     if (pv & 0x10)
1360                         strcat(buf, ", 1024");
1361                     if (pv & 0x20)
1362                         strcat(buf, ", 2048");
1363
1364                     strcat(buf, " bytes)");
1365
1366                     proto_item_append_text(ti, buf+2);
1367
1368                     break;
1369
1370                 case PI_WINDOW_SIZE:
1371                     proto_item_append_text(ti, ": Window Size (");
1372
1373                     if (pv & 0x01)
1374                         strcat(buf, ", 1");
1375                     if (pv & 0x02)
1376                         strcat(buf, ", 2");
1377                     if (pv & 0x04)
1378                         strcat(buf, ", 3");
1379                     if (pv & 0x08)
1380                         strcat(buf, ", 4");
1381                     if (pv & 0x10)
1382                         strcat(buf, ", 5");
1383                     if (pv & 0x20)
1384                         strcat(buf, ", 6");
1385                     if (pv & 0x40)
1386                         strcat(buf, ", 7");
1387
1388                     strcat(buf, " frame window)");
1389
1390                     proto_item_append_text(ti, buf+2);
1391
1392                     break;
1393
1394                 case PI_ADD_BOFS:
1395                     proto_item_append_text(ti, ": Additional BOFs (");
1396
1397                     if (pv & 0x01)
1398                         strcat(buf, ", 48");
1399                     if (pv & 0x02)
1400                         strcat(buf, ", 24");
1401                     if (pv & 0x04)
1402                         strcat(buf, ", 12");
1403                     if (pv & 0x08)
1404                         strcat(buf, ", 5");
1405                     if (pv & 0x10)
1406                         strcat(buf, ", 3");
1407                     if (pv & 0x20)
1408                         strcat(buf, ", 2");
1409                     if (pv & 0x40)
1410                         strcat(buf, ", 1");
1411                     if (pv & 0x80)
1412                         strcat(buf, ", 0");
1413
1414                     strcat(buf, " additional BOFs at 115200)");
1415
1416                     proto_item_append_text(ti, buf+2);
1417
1418                     break;
1419
1420                 case PI_MIN_TURN_TIME:
1421                     proto_item_append_text(ti, ": Minimum Turn Time (");
1422
1423                     if (pv & 0x01)
1424                         strcat(buf, ", 10");
1425                     if (pv & 0x02)
1426                         strcat(buf, ", 5");
1427                     if (pv & 0x04)
1428                         strcat(buf, ", 1");
1429                     if (pv & 0x08)
1430                         strcat(buf, ", 0.5");
1431                     if (pv & 0x10)
1432                         strcat(buf, ", 0.1");
1433                     if (pv & 0x20)
1434                         strcat(buf, ", 0.05");
1435                     if (pv & 0x40)
1436                         strcat(buf, ", 0.01");
1437                     if (pv & 0x80)
1438                         strcat(buf, ", 0");
1439
1440                     strcat(buf, " ms)");
1441
1442                     proto_item_append_text(ti, buf+2);
1443
1444                     break;
1445
1446                 case PI_LINK_DISC:
1447                     proto_item_append_text(ti, ": Link Disconnect/Threshold Time (");
1448
1449                     if (pv & 0x01)
1450                         strcat(buf, ", 3/0");
1451                     if (pv & 0x02)
1452                         strcat(buf, ", 8/3");
1453                     if (pv & 0x04)
1454                         strcat(buf, ", 12/3");
1455                     if (pv & 0x08)
1456                         strcat(buf, ", 16/3");
1457                     if (pv & 0x10)
1458                         strcat(buf, ", 20/3");
1459                     if (pv & 0x20)
1460                         strcat(buf, ", 25/3");
1461                     if (pv & 0x40)
1462                         strcat(buf, ", 30/3");
1463                     if (pv & 0x80)
1464                         strcat(buf, ", 40/3");
1465
1466                     strcat(buf, " s)");
1467
1468                     proto_item_append_text(ti, buf+2);
1469
1470                     break;
1471
1472                 default:
1473                     proto_item_append_text(ti, ": unknown");
1474             }
1475         } else
1476             p_tree = NULL;
1477
1478         offset = dissect_param_tuple(tvb, p_tree, offset);
1479         n++;
1480     }
1481
1482     return offset;
1483 }
1484
1485
1486 /*
1487  * Dissect XID packet
1488  */
1489 static void dissect_xid(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, proto_tree* lap_tree, gboolean is_command)
1490 {
1491     int         offset = 0;
1492     proto_item* ti = NULL;
1493     proto_tree* i_tree = NULL;
1494     proto_tree* flags_tree;
1495     guint32     saddr, daddr;
1496     guint8      s;
1497     proto_tree* lmp_tree = NULL;
1498
1499     if (lap_tree)
1500     {
1501         ti = proto_tree_add_item(lap_tree, hf_lap_i, tvb, offset, -1, FALSE);
1502         i_tree = proto_item_add_subtree(ti, ett_lap_i);
1503
1504         proto_tree_add_item(i_tree, hf_xid_ident, tvb, offset, 1, FALSE);
1505     }
1506     offset++;
1507
1508     saddr = tvb_get_letohl(tvb, offset);
1509     if (check_col(pinfo->cinfo, COL_DEF_SRC))
1510         col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1511     if (lap_tree)
1512         proto_tree_add_uint(i_tree, hf_xid_saddr, tvb, offset, 4, saddr);
1513     offset += 4;
1514
1515     daddr = tvb_get_letohl(tvb, offset);
1516     if (check_col(pinfo->cinfo, COL_DEF_DST))
1517         col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1518     if (lap_tree)
1519         proto_tree_add_uint(i_tree, hf_xid_daddr, tvb, offset, 4, daddr);
1520     offset += 4;
1521
1522     if (lap_tree)
1523     {
1524         ti = proto_tree_add_item(i_tree, hf_xid_flags, tvb, offset, 1, FALSE);
1525         flags_tree = proto_item_add_subtree(ti, ett_xid_flags);
1526         proto_tree_add_item(flags_tree, hf_xid_s, tvb, offset, 1, FALSE);
1527         proto_tree_add_item(flags_tree, hf_xid_conflict, tvb, offset, 1, FALSE);
1528     }
1529     offset++;
1530
1531     if (is_command)
1532     {
1533         s = tvb_get_guint8(tvb, offset);
1534         if (check_col(pinfo->cinfo, COL_INFO))
1535         {
1536             if (s == 0xFF)
1537                 col_append_str(pinfo->cinfo, COL_INFO, ", s=final");
1538             else
1539                 col_append_fstr(pinfo->cinfo, COL_INFO, ", s=%u", s);
1540         }
1541         if (lap_tree)
1542         {
1543             ti = proto_tree_add_uint(i_tree, hf_xid_slotnr, tvb, offset, 1, s);
1544             if (s == 0xFF)
1545                 proto_item_append_text(ti, " (final)");
1546         }
1547     }
1548     offset++;
1549
1550     if (lap_tree)
1551         proto_tree_add_item(i_tree, hf_xid_version, tvb, offset, 1, FALSE);
1552     offset++;
1553
1554     if (lap_tree)
1555     {
1556         proto_item_set_end(lap_tree, tvb, offset);
1557         proto_item_set_end(i_tree, tvb, offset);
1558     }
1559
1560     if (tvb_reported_length_remaining(tvb, offset) > 0)
1561     {
1562         unsigned    hints_len;
1563         guint8      hint1 = 0;
1564         guint8      hint2 = 0;
1565
1566         if (root)
1567         {
1568             ti = proto_tree_add_item(root, proto_irlmp, tvb, offset, -1, FALSE);
1569             lmp_tree = proto_item_add_subtree(ti, ett_irlmp);
1570         }
1571
1572         for (hints_len = 0;;)
1573         {
1574             guint8 hint = tvb_get_guint8(tvb, offset + hints_len++);
1575
1576             if (hints_len == 1)
1577                 hint1 = hint;
1578             else if (hints_len == 2)
1579                 hint2 = hint;
1580
1581             if ((hint & 0x80) == 0)
1582                 break;
1583         }
1584
1585         if (root)
1586         {
1587             ti = proto_tree_add_item(lmp_tree, hf_lmp_xid_hints, tvb, offset, hints_len, FALSE);
1588             if ((hint1 | hint2) != 0)
1589             {
1590                 char    service_hints[256];
1591
1592                 service_hints[0] = 0;
1593
1594                 if (hint1 & 0x01)                
1595                     strcat(service_hints, ", PnP Compatible");
1596                 if (hint1 & 0x02)
1597                     strcat(service_hints, ", PDA/Palmtop");
1598                 if (hint1 & 0x04)
1599                     strcat(service_hints, ", Computer");
1600                 if (hint1 & 0x08)
1601                     strcat(service_hints, ", Printer");
1602                 if (hint1 & 0x10)
1603                     strcat(service_hints, ", Modem");
1604                 if (hint1 & 0x20)
1605                     strcat(service_hints, ", Fax");
1606                 if (hint1 & 0x40)
1607                     strcat(service_hints, ", LAN Access");
1608                 if (hint2 & 0x01)
1609                     strcat(service_hints, ", Telephony");
1610                 if (hint2 & 0x02)
1611                     strcat(service_hints, ", File Server");
1612                 if (hint2 & 0x04)
1613                     strcat(service_hints, ", IrCOMM");
1614                 if (hint2 & 0x20)
1615                     strcat(service_hints, ", OBEX");
1616
1617                 strcat(service_hints, ")");
1618                 service_hints[0] = ' ';
1619                 service_hints[1] = '(';
1620
1621                 proto_item_append_text(ti, service_hints);
1622             }
1623         }
1624         offset += hints_len;
1625
1626         if (tvb_reported_length_remaining(tvb, offset) > 0)
1627         {
1628             guint8 cset;
1629             gint name_len;
1630
1631             cset = tvb_get_guint8(tvb, offset);
1632             if (root)
1633                 proto_tree_add_uint(lmp_tree, hf_lmp_xid_charset, tvb, offset, 1, cset);
1634             offset++;
1635             name_len = tvb_reported_length_remaining(tvb, offset);
1636             if (name_len > 0)
1637             {
1638                 if (cset == 0x00)
1639                 {
1640                     if (check_col(pinfo->cinfo, COL_INFO))
1641                     {
1642                         char buf[23];
1643
1644                         if (name_len > 22)
1645                             name_len = 22;
1646                         tvb_memcpy(tvb, (guint8*)buf, offset, name_len);
1647                         buf[name_len] = 0;
1648                         col_append_str(pinfo->cinfo, COL_INFO, ", \"");
1649                         col_append_str(pinfo->cinfo, COL_INFO, buf);
1650                         col_append_str(pinfo->cinfo, COL_INFO, "\"");
1651                     }
1652                     if (root)
1653                         proto_tree_add_item(lmp_tree, hf_lmp_xid_name, tvb, offset,
1654                                             -1, FALSE);
1655                 }
1656                 else
1657                 {
1658                     if (root)
1659                         proto_tree_add_item(lmp_tree, hf_lmp_xid_name_no_ascii, tvb, offset,
1660                                             -1, FALSE);
1661                 }
1662             }
1663         }
1664     }
1665 }
1666
1667
1668 /*
1669  * Dissect Log Messages
1670  */
1671 static void dissect_log(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1672 {
1673     /* Make entries in Protocol column on summary display */
1674     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1675         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Log");
1676
1677     /* missed messages? */
1678     if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1679     {
1680         if (check_col(pinfo->cinfo, COL_INFO))
1681             col_set_str(pinfo->cinfo, COL_INFO,
1682                 "WARNING: Missed one or more messages while capturing!");
1683     }
1684     else if (check_col(pinfo->cinfo, COL_INFO))
1685     {
1686         guint   length;
1687         char    buf[256];
1688
1689
1690         length = tvb_length(tvb);
1691         if (length > sizeof(buf)-1)
1692             length = sizeof(buf)-1;
1693         tvb_memcpy(tvb, (guint8*)buf, 0, length);
1694         buf[length] = 0;
1695         if (buf[length-1] == '\n')
1696             buf[length-1] = 0;
1697         else if (buf[length-2] == '\n')
1698             buf[length-2] = 0;
1699
1700         col_add_str(pinfo->cinfo, COL_INFO, buf);
1701     }
1702
1703     if (root)
1704     {
1705         proto_item* ti   = proto_tree_add_item(root, proto_log, tvb, 0, -1, FALSE);
1706         proto_tree* tree = proto_item_add_subtree(ti, ett_log);
1707
1708         if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1709             proto_tree_add_item(tree, hf_log_missed, tvb, 0, 0, FALSE);
1710         else
1711             proto_tree_add_item(tree, hf_log_msg, tvb, 0, -1, FALSE);    
1712     }
1713 }
1714
1715
1716 /*
1717  * Dissect IrLAP
1718  */
1719 static void dissect_irlap(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1720 {
1721     int      offset = 0;
1722     guint8   a, c;
1723     gboolean is_response;
1724     char     addr[9];
1725     proto_item* ti = NULL;
1726     proto_tree* tree = NULL;
1727     proto_tree* i_tree = NULL;
1728     guint32  saddr, daddr;
1729     guint8   ca;
1730
1731     /* Make entries in Protocol column on summary display */
1732     if (check_col(pinfo->cinfo, COL_PROTOCOL))
1733         col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLAP");
1734
1735     /* Clear Info column */
1736     if (check_col(pinfo->cinfo, COL_INFO))
1737         col_clear(pinfo->cinfo, COL_INFO);
1738
1739     /* set direction column */
1740     if (check_col(pinfo->cinfo, COL_IF_DIR))
1741     {
1742         switch (pinfo->pseudo_header->irda.pkttype)
1743         {
1744             case IRDA_OUTGOING:
1745                 col_set_str(pinfo->cinfo, COL_IF_DIR, "Out");
1746                 break;
1747                 
1748             case IRDA_INCOMING:
1749                 col_set_str(pinfo->cinfo, COL_IF_DIR, "In");
1750                 break;
1751         }
1752     }
1753
1754     /* decode values used for demuxing */
1755     a = tvb_get_guint8(tvb, 0);
1756
1757     /* save connection address field in pinfo */
1758     pinfo->circuit_id = a;
1759
1760     /* initially set address columns to connection address */
1761     g_snprintf(addr, sizeof(addr)-1, "0x%02X", a >> 1);
1762     if (check_col(pinfo->cinfo, COL_DEF_SRC))
1763         col_add_str(pinfo->cinfo, COL_DEF_SRC, addr);
1764     if (check_col(pinfo->cinfo, COL_DEF_DST))
1765         col_add_str(pinfo->cinfo, COL_DEF_DST, addr);
1766
1767     if (root)
1768     {
1769         proto_tree* a_tree;
1770         proto_item* addr_item;
1771
1772         /* create display subtree for the protocol */
1773         ti   = proto_tree_add_item(root, proto_irlap, tvb, 0, -1, FALSE);
1774         tree = proto_item_add_subtree(ti, ett_irlap);
1775
1776         /* create subtree for the address field */
1777         ti     = proto_tree_add_item(tree, hf_lap_a, tvb, offset, 1, FALSE);
1778         a_tree = proto_item_add_subtree(ti, ett_lap_a);
1779         proto_tree_add_item(a_tree, hf_lap_a_cr, tvb, offset, 1, FALSE);
1780         addr_item = proto_tree_add_item(a_tree, hf_lap_a_address, tvb, offset, 1, FALSE);
1781         switch (a & ~CMD_FRAME)
1782         {
1783             case 0:
1784                 proto_item_append_text(addr_item, " (NULL Address)");
1785                 break;
1786             case 0xFE:
1787                 proto_item_append_text(addr_item, " (Broadcast)");
1788                 break;
1789         }
1790     }
1791     is_response = ((a & CMD_FRAME) == 0);
1792     offset++;
1793
1794     /* process the control field */
1795     c = dissect_xdlc_control(tvb, 1, pinfo, tree, hf_lap_c,
1796             ett_lap_c, &irlap_cf_items, NULL, lap_c_u_cmd_abbr_vals,
1797             lap_c_u_rsp_abbr_vals, is_response, FALSE, FALSE);
1798     offset++;
1799
1800     if ((c & XDLC_I_MASK) == XDLC_I) {
1801         /* I frame */
1802         proto_item_set_len(tree, offset);
1803         tvb = tvb_new_subset(tvb, offset, -1, -1);
1804         dissect_irlmp(tvb, pinfo, root);
1805         return;
1806     }
1807
1808     if ((c & 0x03) == XDLC_U) {
1809         /* U frame */
1810         switch (c & XDLC_U_MODIFIER_MASK)
1811         {
1812             case XDLC_SNRM:
1813                 if (root)
1814                 {
1815                     ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, FALSE);
1816                     i_tree = proto_item_add_subtree(ti, ett_lap_i);
1817                 }
1818
1819                 saddr = tvb_get_letohl(tvb, offset);
1820                 if (!is_response)
1821                 {
1822                     if (check_col(pinfo->cinfo, COL_DEF_SRC))
1823                         col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1824                 }
1825                 if (root)
1826                     proto_tree_add_uint(i_tree, hf_snrm_saddr, tvb, offset, 4, saddr);
1827                 offset += 4;
1828
1829                 daddr = tvb_get_letohl(tvb, offset);
1830                 if (!is_response)
1831                 {
1832                     if (check_col(pinfo->cinfo, COL_DEF_DST))
1833                         col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1834                 }
1835                 if (root)
1836                     proto_tree_add_uint(i_tree, hf_snrm_daddr, tvb, offset, 4, daddr);
1837                 offset += 4;
1838
1839                 ca = tvb_get_guint8(tvb, offset);
1840                 if (!is_response)
1841                 {
1842                     if (check_col(pinfo->cinfo, COL_INFO))
1843                         col_append_fstr(pinfo->cinfo, COL_INFO, ", ca=0x%02X",
1844                                         ca >> 1);
1845                 }
1846                 if (root)
1847                     proto_tree_add_uint(i_tree, hf_snrm_ca, tvb, offset, 1, ca >> 1);
1848                 offset++;
1849
1850                 offset = dissect_negotiation(tvb, i_tree, offset);
1851                 if (root)
1852                     proto_item_set_end(ti, tvb, offset);
1853                 break;
1854
1855             case IRDA_XID_CMD:
1856                 tvb = tvb_new_subset(tvb, offset, -1, -1);
1857                 dissect_xid(tvb, pinfo, root, tree, TRUE);
1858                 return;
1859
1860             case XDLC_UA:
1861                 if (tvb_reported_length_remaining(tvb, offset) > 0)
1862                 {
1863                     if (root)
1864                     {
1865                         ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, FALSE);
1866                         i_tree = proto_item_add_subtree(ti, ett_lap_i);
1867                     }
1868
1869                     saddr = tvb_get_letohl(tvb, offset);
1870                     if (check_col(pinfo->cinfo, COL_DEF_SRC))
1871                         col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1872                     if (root)
1873                         proto_tree_add_uint(i_tree, hf_ua_saddr, tvb, offset, 4, saddr);
1874                     offset += 4;
1875
1876                     daddr = tvb_get_letohl(tvb, offset);
1877                     if (check_col(pinfo->cinfo, COL_DEF_DST))
1878                         col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1879                     if (root)
1880                         proto_tree_add_uint(i_tree, hf_ua_daddr, tvb, offset, 4, daddr);
1881                     offset += 4;
1882
1883                     offset = dissect_negotiation(tvb, i_tree, offset);
1884                     if (root)
1885                         proto_item_set_end(ti, tvb, offset);
1886                 }
1887                 break;
1888
1889             case XDLC_XID:
1890                 tvb = tvb_new_subset(tvb, offset, -1, -1);
1891                 dissect_xid(tvb, pinfo, root, tree, FALSE);
1892                 return;
1893          }
1894     }
1895
1896     /* If any bytes remain, send it to the generic data dissector */
1897     if (tvb_reported_length_remaining(tvb, offset) > 0)
1898     {
1899         tvb = tvb_new_subset(tvb, offset, -1, -1);
1900         call_dissector(data_handle, tvb, pinfo, root);
1901     }
1902 }
1903
1904
1905 /*
1906  * Dissect IrDA protocol
1907  */
1908 static void dissect_irda(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1909 {
1910     /* load the display labels */
1911     pinfo->current_proto = "IrDA";
1912
1913     /* check if log message */
1914     if ((pinfo->pseudo_header->irda.pkttype & IRDA_CLASS_MASK) == IRDA_CLASS_LOG)
1915     {
1916         dissect_log(tvb, pinfo, root);
1917         return;
1918     }
1919
1920
1921     dissect_irlap(tvb, pinfo, root);
1922 }
1923
1924
1925 /*
1926  * Re-initialize the IrDA dissector
1927  */
1928 static void init_irda(void)
1929 {
1930     if (iap_conv_chunk)
1931         g_mem_chunk_destroy(iap_conv_chunk);
1932     if (lmp_conv_chunk)
1933         g_mem_chunk_destroy(lmp_conv_chunk);
1934
1935     iap_conv_chunk = g_mem_chunk_new("iap_conversation", sizeof(iap_conversation_t),
1936                                      10 * sizeof(iap_conversation_t), G_ALLOC_AND_FREE);
1937     lmp_conv_chunk = g_mem_chunk_new("lmp_conversation", sizeof(lmp_conversation_t),
1938                                      10 * sizeof(lmp_conversation_t), G_ALLOC_AND_FREE);
1939 }
1940
1941
1942 /*
1943  * Register the protocol with Wireshark
1944  * This format is required because a script is used to build the C function
1945  *  that calls all the protocol registrations.
1946  */
1947 void proto_register_irda(void)
1948 {
1949     unsigned i;
1950
1951     /* Setup list of header fields */
1952     static hf_register_info hf_lap[] = {
1953         { &hf_lap_a,
1954             { "Address Field", "irlap.a",
1955                 FT_UINT8, BASE_HEX, NULL, 0,
1956                 "", HFILL }},
1957         { &hf_lap_a_cr,
1958             { "C/R", "irlap.a.cr",
1959                 FT_BOOLEAN, 8, TFS(&lap_cr_vals), CMD_FRAME,
1960                 "", HFILL }},
1961         { &hf_lap_a_address,
1962             { "Address", "irlap.a.address",
1963                 FT_UINT8, BASE_HEX, NULL, ~CMD_FRAME,
1964                 "", HFILL }},
1965         { &hf_lap_c,
1966             { "Control Field", "irlap.c",
1967                 FT_UINT8, BASE_HEX, NULL, 0,
1968                 "", HFILL }},
1969         { &hf_lap_c_nr,
1970             { "N(R)", "irlap.c.n_r",
1971                 FT_UINT8, BASE_DEC, NULL, XDLC_N_R_MASK,
1972                 "", HFILL }},
1973         { &hf_lap_c_ns,
1974             { "N(S)", "irlap.c.n_s",
1975                 FT_UINT8, BASE_DEC, NULL, XDLC_N_S_MASK,
1976                 "", HFILL }},
1977         { &hf_lap_c_p,
1978             { "Poll", "irlap.c.p",
1979                 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1980                 "", HFILL }},
1981         { &hf_lap_c_f,
1982             { "Final", "irlap.c.f",
1983                 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1984                 "", HFILL }},
1985         { &hf_lap_c_s,
1986             { "Supervisory frame type", "irlap.c.s_ftype",
1987                 FT_UINT8, BASE_HEX, VALS(lap_c_s_vals), XDLC_S_FTYPE_MASK,
1988                 "", HFILL }},
1989         { &hf_lap_c_u_cmd,
1990             { "Command", "irlap.c.u_modifier_cmd",
1991                 FT_UINT8, BASE_HEX, VALS(lap_c_u_cmd_vals), XDLC_U_MODIFIER_MASK,
1992                 "", HFILL }},
1993         { &hf_lap_c_u_rsp,
1994             { "Response", "irlap.c.u_modifier_resp",
1995                 FT_UINT8, BASE_HEX, VALS(lap_c_u_rsp_vals), XDLC_U_MODIFIER_MASK,
1996                 "", HFILL }},
1997         { &hf_lap_c_i,
1998             { "Frame Type", "irlap.c.ftype",
1999                 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_I_MASK,
2000                 "", HFILL }},
2001         { &hf_lap_c_s_u,
2002             { "Frame Type", "irlap.c.ftype",
2003                 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_S_U_MASK,
2004                 "", HFILL }},
2005         { &hf_lap_i,
2006             { "Information Field", "irlap.i",
2007                 FT_NONE, BASE_NONE, NULL, 0,
2008                 "", HFILL }},
2009         { &hf_snrm_saddr,
2010             { "Source Device Address", "irlap.snrm.saddr",
2011                 FT_UINT32, BASE_HEX, NULL, 0,
2012                 "", HFILL }},
2013         { &hf_snrm_daddr,
2014             { "Destination Device Address", "irlap.snrm.daddr",
2015                 FT_UINT32, BASE_HEX, NULL, 0,
2016                 "", HFILL }},
2017         { &hf_snrm_ca,
2018             { "Connection Address", "irlap.snrm.ca",
2019                 FT_UINT8, BASE_HEX, NULL, 0,
2020                 "", HFILL }},
2021         { &hf_negotiation_param,
2022             { "Negotiation Parameter", "irlap.negotiation",
2023                 FT_NONE, BASE_NONE, NULL, 0,
2024                 "", HFILL }},
2025         { &hf_param_pi,
2026             { "Parameter Identifier", "irlap.pi",
2027                 FT_UINT8, BASE_HEX, NULL, 0,
2028                 "", HFILL }},
2029         { &hf_param_pl,
2030             { "Parameter Length", "irlap.pl",
2031                 FT_UINT8, BASE_HEX, NULL, 0,
2032                 "", HFILL }},
2033         { &hf_param_pv,
2034             { "Parameter Value", "irlap.pv",
2035                 FT_BYTES, BASE_HEX, NULL, 0,
2036                 "", HFILL }},
2037         { &hf_ua_saddr,
2038             { "Source Device Address", "irlap.ua.saddr",
2039                 FT_UINT32, BASE_HEX, NULL, 0,
2040                 "", HFILL }},
2041         { &hf_ua_daddr,
2042             { "Destination Device Address", "irlap.ua.daddr",
2043                 FT_UINT32, BASE_HEX, NULL, 0,
2044                 "", HFILL }},
2045         { &hf_xid_ident,
2046             { "Format Identifier", "irlap.xid.fi",
2047                 FT_UINT8, BASE_HEX, NULL, 0,
2048                 "", HFILL }},
2049         { &hf_xid_saddr,
2050             { "Source Device Address", "irlap.xid.saddr",
2051                 FT_UINT32, BASE_HEX, NULL, 0,
2052                 "", HFILL }},
2053         { &hf_xid_daddr,
2054             { "Destination Device Address", "irlap.xid.daddr",
2055                 FT_UINT32, BASE_HEX, NULL, 0,
2056                 "", HFILL }},
2057         { &hf_xid_flags,
2058             { "Discovery Flags", "irlap.xid.flags",
2059                 FT_UINT8, BASE_HEX, NULL, 0,
2060                 "", HFILL }},
2061         { &hf_xid_s,
2062             { "Number of Slots", "irlap.xid.s",
2063                 FT_UINT8, BASE_DEC, VALS(&xid_slot_numbers), S_MASK,
2064                 "", HFILL }},
2065         { &hf_xid_conflict,
2066             { "Conflict", "irlap.xid.conflict",
2067                 FT_BOOLEAN, 8, TFS(&set_notset), CONFLICT,
2068                 "", HFILL }},
2069         { &hf_xid_slotnr,
2070             { "Slot Number", "irlap.xid.slotnr",
2071                 FT_UINT8, BASE_DEC, NULL, 0,
2072                 "", HFILL }},
2073         { &hf_xid_version,
2074             { "Version Number", "irlap.xid.version",
2075                 FT_UINT8, BASE_HEX, NULL, 0,
2076                 "", HFILL }}
2077     };
2078
2079     static hf_register_info hf_log[] = {
2080         { &hf_log_msg,
2081             { "Message", "log.msg",
2082                 FT_STRING, BASE_NONE, NULL, 0,
2083                 "", HFILL }},
2084         { &hf_log_missed,
2085             { "WARNING: Missed one or more messages while capturing!", "log.missed",
2086                 FT_NONE, BASE_NONE, NULL, 0,
2087                 "", HFILL }}
2088     };
2089
2090     static hf_register_info hf_lmp[] = {
2091         { &hf_lmp_xid_hints,
2092             { "Service Hints", "irlmp.xid.hints",
2093                 FT_BYTES, BASE_HEX, NULL, 0,
2094                 "", HFILL }},
2095         { &hf_lmp_xid_charset,
2096             { "Character Set", "irlmp.xid.charset",
2097                 FT_UINT8, BASE_HEX, NULL, 0,
2098                 "", HFILL }},
2099         { &hf_lmp_xid_name,
2100             { "Device Nickname", "irlmp.xid.name",
2101                 FT_STRING, BASE_NONE, NULL, 0,
2102                 "", HFILL }},
2103         { &hf_lmp_xid_name_no_ascii,
2104             { "Device Nickname (unsupported character set)", "irlmp.xid.name",
2105                 FT_BYTES, BASE_NONE, NULL, 0,
2106                 "", HFILL }},
2107         { &hf_lmp_dst,
2108             { "Destination", "irlmp.dst",
2109                 FT_UINT8, BASE_HEX, NULL, 0,
2110                 "", HFILL }},
2111         { &hf_lmp_dst_control,
2112             { "Control Bit", "irlmp.dst.c",
2113                 FT_BOOLEAN, 8, TFS(&set_notset), CONTROL_BIT,
2114                 "", HFILL }},
2115         { &hf_lmp_dst_lsap,
2116             { "Destination LSAP", "irlmp.dst.lsap",
2117                 FT_UINT8, BASE_DEC, NULL, ~CONTROL_BIT,
2118                 "", HFILL }},
2119         { &hf_lmp_src,
2120             { "Source", "irlmp.src",
2121                 FT_UINT8, BASE_HEX, NULL, 0,
2122                 "", HFILL }},
2123         { &hf_lmp_src_r,
2124             { "reserved", "irlmp.src.r",
2125                 FT_UINT8, BASE_DEC, NULL, RESERVED_BIT,
2126                 "", HFILL }},
2127         { &hf_lmp_src_lsap,
2128             { "Source LSAP", "irlmp.src.lsap",
2129                 FT_UINT8, BASE_DEC, NULL, ~RESERVED_BIT,
2130                 "", HFILL }},
2131         { &hf_lmp_opcode,
2132             { "Opcode", "irlmp.opcode",
2133                 FT_UINT8, BASE_HEX, VALS(lmp_opcode_vals), 0x0,
2134                 "", HFILL }},
2135         { &hf_lmp_rsvd,
2136             { "Reserved", "irlmp.rsvd",
2137                 FT_UINT8, BASE_HEX, NULL, 0x0,
2138                 "", HFILL }},
2139         { &hf_lmp_reason,
2140             { "Reason", "irlmp.reason",
2141                 FT_UINT8, BASE_HEX, VALS(lmp_reason_vals), 0x0,
2142                 "", HFILL }},
2143         { &hf_lmp_mode,
2144             { "Mode", "irlmp.mode",
2145                 FT_UINT8, BASE_HEX, VALS(lmp_mode_vals), 0x0,
2146                 "", HFILL }},
2147         { &hf_lmp_status,
2148             { "Status", "irlmp.status",
2149                 FT_UINT8, BASE_HEX, VALS(lmp_status_vals), 0x0,
2150                 "", HFILL }}
2151     };
2152
2153     static hf_register_info hf_iap[] = {
2154         { &hf_iap_ctl,
2155             { "Control Field", "iap.ctl",
2156                 FT_UINT8, BASE_HEX, NULL, 0,
2157                 "", HFILL }},
2158         { &hf_iap_ctl_lst,
2159             { "Last Frame", "iap.ctl.lst",
2160                 FT_BOOLEAN, 8, TFS(&set_notset), IAP_LST,
2161                 "", HFILL }},
2162         { &hf_iap_ctl_ack,
2163             { "Acknowledge", "iap.ctl.ack",
2164                 FT_BOOLEAN, 8, TFS(&set_notset), IAP_ACK,
2165                 "", HFILL }},
2166         { &hf_iap_ctl_opcode,
2167             { "Opcode", "iap.ctl.opcode",
2168                 FT_UINT8, BASE_HEX, VALS(iap_opcode_vals), IAP_OP,
2169                 "", HFILL }},
2170         { &hf_iap_class_name,
2171             { "Class Name", "iap.classname",
2172                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2173                 "", HFILL }},
2174         { &hf_iap_attr_name,
2175             { "Attribute Name", "iap.attrname",
2176                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2177                 "", HFILL }},
2178         { &hf_iap_return,
2179             { "Return", "iap.return",
2180                 FT_UINT8, BASE_HEX, VALS(iap_return_vals), 0x0,
2181                 "", HFILL }},
2182         { &hf_iap_list_len,
2183             { "List Length", "iap.listlen",
2184                 FT_UINT16, BASE_DEC, NULL, 0x0,
2185                 "", HFILL }},
2186         { &hf_iap_list_entry,
2187             { "List Entry ", "iap.listentry",
2188                 FT_NONE, BASE_NONE, NULL, 0x0,
2189                 "", HFILL }},
2190         { &hf_iap_obj_id,
2191             { "Object Identifier", "iap.objectid",
2192                 FT_UINT16, BASE_HEX, NULL, 0x0,
2193                 "", HFILL }},
2194         { &hf_iap_attr_type,
2195             { "Type", "iap.attrtype",
2196                 FT_UINT8, BASE_DEC, VALS(iap_attr_type_vals), 0x0,
2197                 "", HFILL }},
2198         { &hf_iap_int,
2199             { "Value", "iap.int",
2200                 FT_INT32, BASE_DEC, NULL, 0x0,
2201                 "", HFILL }},
2202         { &hf_iap_seq_len,
2203             { "Sequence Length", "iap.seqlen",
2204                 FT_UINT16, BASE_DEC, NULL, 0x0,
2205                 "", HFILL }},
2206         { &hf_iap_oct_seq,
2207             { "Sequence", "iap.octseq",
2208                 FT_BYTES, BASE_HEX, NULL, 0x0,
2209                 "", HFILL }},
2210         { &hf_iap_char_set,
2211             { "Character Set", "iap.charset",
2212                 FT_UINT8, BASE_HEX, NULL, 0x0,
2213                 "", HFILL }},
2214         { &hf_iap_string,
2215             { "String", "iap.string",
2216                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2217                 "", HFILL }},
2218         { &hf_iap_invaloctet,
2219             { "Mailformed IAP result: \"", "iap.invaloctet",
2220                 FT_NONE, BASE_NONE, NULL, 0,
2221                 "", HFILL }},
2222         { &hf_iap_invallsap,
2223             { "Mailformed IAP result: \"", "iap.invallsap",
2224                 FT_NONE, BASE_NONE, NULL, 0,
2225                 "", HFILL }}
2226     };
2227
2228     static hf_register_info hf_ttp[] = {
2229         { &hf_ttp_p,
2230             { "Parameter Bit", "ttp.p",
2231                 FT_BOOLEAN, 8, TFS(&set_notset), TTP_PARAMETERS,
2232                 "", HFILL }},
2233         { &hf_ttp_icredit,
2234             { "Initial Credit", "ttp.icredit",
2235                 FT_UINT8, BASE_DEC, NULL, ~TTP_PARAMETERS,
2236                 "", HFILL }},
2237         { &hf_ttp_m,
2238             { "More Bit", "ttp.m",
2239                 FT_BOOLEAN, 8, TFS(&set_notset), TTP_MORE,
2240                 "", HFILL }},
2241         { &hf_ttp_dcredit,
2242             { "Delta Credit", "ttp.dcredit",
2243                 FT_UINT8, BASE_DEC, NULL, ~TTP_MORE,
2244                 "", HFILL }}
2245     };
2246
2247     /* Setup protocol subtree arrays */
2248     static gint* ett[] = {
2249         &ett_irlap,
2250         &ett_lap_a,
2251         &ett_lap_c,
2252         &ett_lap_i,
2253         &ett_xid_flags,
2254         &ett_log,
2255         &ett_irlmp,
2256         &ett_lmp_dst,
2257         &ett_lmp_src,
2258         &ett_iap,
2259         &ett_iap_ctl,
2260         &ett_ttp
2261     };
2262
2263     static gint* ett_p[MAX_PARAMETERS];
2264     static gint* ett_iap_e[MAX_IAP_ENTRIES];
2265
2266
2267     /* Register re-init routine */
2268     register_init_routine(init_irda);
2269
2270     /* Register protocol names and descriptions */
2271     proto_irlap = proto_register_protocol("IrDA Link Access Protocol", "IrLAP", "irlap");
2272     proto_log   = proto_register_protocol("Log Message", "Log", "log");
2273     proto_irlmp = proto_register_protocol("IrDA Link Management Protocol", "IrLMP", "irlmp");
2274     proto_iap   = proto_register_protocol("Information Access Protocol", "IAP", "iap");
2275     proto_ttp   = proto_register_protocol("Tiny Transport Protocol", "TTP", "ttp");
2276
2277     /* Register the dissector */
2278     register_dissector("irda", dissect_irda, proto_irlap);
2279
2280     /* Required function calls to register the header fields */
2281     proto_register_field_array(proto_irlap, hf_lap, array_length(hf_lap));
2282     proto_register_field_array(proto_log, hf_log, array_length(hf_log));
2283     proto_register_field_array(proto_irlmp, hf_lmp, array_length(hf_lmp));
2284     proto_register_field_array(proto_iap, hf_iap, array_length(hf_iap));
2285     proto_register_field_array(proto_ttp, hf_ttp, array_length(hf_ttp));
2286
2287     /* Register subtrees */
2288     proto_register_subtree_array(ett, array_length(ett));
2289     for (i = 0; i < MAX_PARAMETERS; i++)
2290     {
2291         ett_param[i] = -1;
2292         ett_p[i]     = &ett_param[i];
2293     }
2294     proto_register_subtree_array(ett_p, MAX_PARAMETERS);
2295     for (i = 0; i < MAX_IAP_ENTRIES; i++)
2296     {
2297         ett_iap_entry[i] = -1;
2298         ett_iap_e[i]     = &ett_iap_entry[i];
2299     }
2300     proto_register_subtree_array(ett_iap_e, MAX_IAP_ENTRIES);
2301 }
2302
2303
2304 /* If this dissector uses sub-dissector registration add a registration routine.
2305         This format is required because a script is used to find these routines and
2306         create the code that calls these routines.
2307 */
2308
2309 void proto_reg_handoff_irda(void)
2310 {
2311     dissector_handle_t irda_handle;
2312
2313     irda_handle = find_dissector("irda");
2314     dissector_add("wtap_encap", WTAP_ENCAP_IRDA, irda_handle);
2315     data_handle = find_dissector("data");
2316 }