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