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