Sharpen the description of preference names.
[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, FALSE);
438     offset++;
439
440     if (tree)
441         proto_tree_add_item(tree, hf_param_pl, tvb, offset, 1, FALSE);
442     offset++;
443
444     if (len > 0)
445     {
446         if (tree)
447             proto_tree_add_item(tree, hf_param_pv, tvb, offset, len, FALSE);
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, FALSE);
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, FALSE);
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, FALSE);
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, FALSE);
622         proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, FALSE);
623         proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, FALSE);
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, FALSE);
630                 offset += 1 + clen;
631
632                 proto_tree_add_item(tree, hf_iap_attr_name, tvb, offset, 1, FALSE);
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, FALSE);
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, FALSE);
770         proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, FALSE);
771         proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, FALSE);
772         offset++;
773
774         proto_tree_add_item(tree, hf_iap_return, tvb, offset, 1, FALSE);
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, FALSE);
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, FALSE);
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, FALSE);
813                         offset += 2;
814
815                         proto_tree_add_item(entry_tree, hf_iap_attr_type, tvb, offset, 1, FALSE);
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, FALSE);
825                                 break;
826
827                             case IAS_OCT_SEQ:
828                                 proto_tree_add_item(entry_tree, hf_iap_seq_len, tvb, offset, 2, FALSE);
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, FALSE);
834                                 break;
835
836                             case IAS_STRING:
837                                 proto_tree_add_item(entry_tree, hf_iap_char_set, tvb, offset, 1, FALSE);
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, FALSE);
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
890                             default:
891                                 attr_len = 0;
892                         }
893                         offset += attr_len;
894
895                         n++;
896                     }
897                 }
898                 break;
899         }
900     }
901
902     /* If any bytes remain, send it to the generic data dissector */
903     tvb = tvb_new_subset_remaining(tvb, offset);
904     call_dissector(data_handle, tvb, pinfo, root);
905 }
906
907
908 /*
909  * Check if IAP result is octet sequence
910  */
911 gboolean check_iap_octet_result(tvbuff_t* tvb, proto_tree* tree, unsigned offset,
912                                 const char* attr_name, guint8 attr_type)
913 {
914     if (attr_type != IAS_OCT_SEQ)
915     {
916         if (tree)
917         {
918             proto_item* ti = proto_tree_add_item(tree, hf_iap_invaloctet, tvb, offset, 0, FALSE);
919             proto_item_append_text(ti, "%s", attr_name);
920             proto_item_append_text(ti, "\" attribute must be octet sequence!");
921         }
922
923         return FALSE;
924     }
925     else
926         return TRUE;
927 }
928
929
930 /*
931  * Check if IAP result is correct LsapSel
932  */
933 guint8 check_iap_lsap_result(tvbuff_t* tvb, proto_tree* tree, unsigned offset,
934                              const char* attr_name, guint8 attr_type)
935 {
936     guint32 lsap;
937
938
939     if ((attr_type != IAS_INTEGER) || ((lsap = tvb_get_ntohl(tvb, offset)) < 0x01) ||
940         (lsap > 0x6F))
941     {
942         if (tree)
943         {
944             proto_item* ti = proto_tree_add_item(tree, hf_iap_invallsap, tvb, offset, 0, FALSE);
945             proto_item_append_text(ti, "%s", attr_name);
946             proto_item_append_text(ti, "\" attribute must be integer value between 0x01 and 0x6F!");
947         }
948
949         return 0;
950     }
951     else
952         return lsap;
953 }
954
955
956 /*
957  * Dissect IrDA application protocol
958  */
959 static void dissect_appl_proto(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, pdu_type_t pdu_type)
960 {
961     unsigned            offset = 0;
962     guint8              src;
963     address             srcaddr;
964     address             destaddr;
965     conversation_t*     conv;
966     lmp_conversation_t* cur_lmp_conv;
967     lmp_conversation_t* lmp_conv = NULL;
968     guint32             num;
969
970     
971     src = pinfo->circuit_id ^ CMD_FRAME;
972     srcaddr.type  = AT_NONE;
973     srcaddr.len   = 1;
974     srcaddr.data  = (guint8*)&src;
975
976     destaddr.type = AT_NONE;
977     destaddr.len  = 1;
978     destaddr.data = (guint8*)&pinfo->circuit_id;
979
980     /* Find result value dissector */
981     conv = find_conversation(pinfo->fd->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
982     if (conv)
983     {
984         num = pinfo->fd->num;
985
986         lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
987         while (lmp_conv && (lmp_conv->iap_result_frame >= num))
988             lmp_conv = lmp_conv->pnext;
989
990         if (lmp_conv)
991         {
992             cur_lmp_conv = lmp_conv->pnext;
993             while (cur_lmp_conv)
994             {
995                 if ((cur_lmp_conv->iap_result_frame < num) &&
996                     (cur_lmp_conv->iap_result_frame > lmp_conv->iap_result_frame))
997                 {
998                     lmp_conv = cur_lmp_conv;
999                 }
1000
1001                 cur_lmp_conv = cur_lmp_conv->pnext;
1002             }
1003         }
1004     }
1005
1006     if (lmp_conv)
1007     {
1008 /*g_message("%x:%d->%x:%d = %p\n", src, pinfo->srcport, pinfo->circuit_id, pinfo->destport, lmp_conv); */
1009 /*g_message("->%d: %d %d %p\n", pinfo->fd->num, lmp_conv->iap_result_frame, lmp_conv->ttp, lmp_conv->proto_dissector); */
1010         if ((lmp_conv->ttp) && (pdu_type != DISCONNECT_PDU))
1011         {
1012             offset += dissect_ttp(tvb, pinfo, root, (pdu_type == DATA_PDU));
1013
1014             tvb = tvb_new_subset_remaining(tvb, offset);
1015         }
1016
1017         pinfo->private_data = (void *)pdu_type;
1018
1019         lmp_conv->proto_dissector(tvb, pinfo, root);
1020     }
1021     else
1022         call_dissector(data_handle, tvb, pinfo, root);
1023 }
1024
1025
1026 /*
1027  * Dissect LMP
1028  */
1029 static void dissect_irlmp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1030 {
1031     unsigned    offset = 0;
1032     guint8      dlsap;
1033     guint8      slsap;
1034     guint8      cbit;
1035     guint8      opcode = 0;
1036
1037
1038     /* Make entries in Protocol column on summary display */
1039     col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLMP");
1040
1041     dlsap = tvb_get_guint8(tvb, offset);
1042     cbit  = dlsap & CONTROL_BIT;
1043     dlsap &= ~CONTROL_BIT;
1044
1045     slsap = tvb_get_guint8(tvb, offset+1) & ~CONTROL_BIT;
1046
1047     /* save Lsaps in pinfo */
1048     pinfo->srcport  = slsap;
1049     pinfo->destport = dlsap;
1050
1051     if (cbit != 0)
1052     {
1053         opcode = tvb_get_guint8(tvb, offset+2);
1054
1055         col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, ", slsap, dlsap);
1056         col_append_str(pinfo->cinfo, COL_INFO, val_to_str(opcode, lmp_opcode_vals, "0x%02X"));
1057         if ((opcode == ACCESSMODE_CMD) || (opcode == ACCESSMODE_CNF))
1058         {
1059             col_append_str(pinfo->cinfo, COL_INFO, " (");
1060             col_append_str(pinfo->cinfo, COL_INFO,
1061                            val_to_str(tvb_get_guint8(tvb, offset+4), lmp_mode_vals, "0x%02X"));
1062             col_append_str(pinfo->cinfo, COL_INFO, ")");
1063         }
1064     }
1065     else
1066         col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, Len=%d", slsap, dlsap,
1067                      tvb_length(tvb) - 2);
1068
1069     if (root)
1070     {
1071         /* create display subtree for the protocol */
1072         proto_item* ti   = proto_tree_add_item(root, proto_irlmp, tvb, 0, -1, FALSE);
1073         proto_tree* tree = proto_item_add_subtree(ti, ett_irlmp);
1074
1075         proto_tree* dst_tree;
1076         proto_tree* src_tree;
1077
1078
1079         ti       = proto_tree_add_item(tree, hf_lmp_dst, tvb, offset, 1, FALSE);
1080         dst_tree = proto_item_add_subtree(ti, ett_lmp_dst);
1081         proto_tree_add_item(dst_tree, hf_lmp_dst_control, tvb, offset, 1, FALSE);
1082         proto_tree_add_item(dst_tree, hf_lmp_dst_lsap, tvb, offset, 1, FALSE);
1083         offset++;
1084
1085         ti       = proto_tree_add_item(tree, hf_lmp_src, tvb, offset, 1, FALSE);
1086         src_tree = proto_item_add_subtree(ti, ett_lmp_src);
1087         proto_tree_add_item(src_tree, hf_lmp_src_r, tvb, offset, 1, FALSE);
1088         proto_tree_add_item(src_tree, hf_lmp_src_lsap, tvb, offset, 1, FALSE);
1089         offset++;
1090
1091         if (cbit != 0)
1092         {
1093             proto_tree_add_item(tree, hf_lmp_opcode, tvb, offset, 1, FALSE);
1094             offset++;
1095
1096             switch (opcode)
1097             {
1098                 case CONNECT_CMD:
1099                 case CONNECT_CNF:
1100                     if (offset < tvb_length(tvb))
1101                     {
1102                         proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, FALSE);
1103                         offset++;
1104                     }
1105                     break;
1106
1107                 case DISCONNECT:
1108                     proto_tree_add_item(tree, hf_lmp_reason, tvb, offset, 1, FALSE);
1109                     offset++;
1110                     break;
1111
1112                 case ACCESSMODE_CMD:
1113                     proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, FALSE);
1114                     offset++;
1115
1116                     proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, FALSE);
1117                     offset++;
1118                     break;
1119
1120                 case ACCESSMODE_CNF:
1121                     proto_tree_add_item( tree, hf_lmp_status, tvb, offset, 1, FALSE);
1122                     offset++;
1123
1124                     proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, FALSE);
1125                     offset++;
1126                     break;
1127             }
1128         }
1129
1130         tvb = tvb_new_subset_remaining(tvb, offset);
1131         proto_item_set_len(tree, offset);
1132     }
1133     else
1134     {
1135         offset += 2;
1136         if (cbit != 0)
1137         {
1138             offset += 1;
1139
1140             switch (opcode)
1141             {
1142                 case CONNECT_CMD:
1143                 case CONNECT_CNF:
1144                     if (offset < tvb_length(tvb))
1145                         offset++;
1146                     break;
1147
1148                 case DISCONNECT:
1149                     offset++;
1150                     break;
1151
1152                 case ACCESSMODE_CMD:
1153                 case ACCESSMODE_CNF:
1154                     offset += 2;
1155                     break;
1156             }
1157         }
1158
1159         tvb = tvb_new_subset_remaining(tvb, offset);
1160     }
1161
1162     if (cbit == 0)
1163     {
1164         if (dlsap == LSAP_IAS)
1165             dissect_iap_request(tvb, pinfo, root);
1166         else if (slsap == LSAP_IAS)
1167             dissect_iap_result(tvb, pinfo, root);
1168         else
1169             dissect_appl_proto(tvb, pinfo, root, DATA_PDU);
1170     }
1171     else
1172     {
1173         if ((dlsap == LSAP_IAS) || (slsap == LSAP_IAS))
1174             call_dissector(data_handle, tvb, pinfo, root);
1175         else
1176             switch (opcode)
1177             {
1178                 case CONNECT_CMD:
1179                 case CONNECT_CNF:
1180                     dissect_appl_proto(tvb, pinfo, root, CONNECT_PDU);
1181                     break;
1182
1183                 case DISCONNECT:
1184                     dissect_appl_proto(tvb, pinfo, root, DISCONNECT_PDU);
1185                     break;
1186
1187                 default:
1188                     call_dissector(data_handle, tvb, pinfo, root);
1189             }
1190     }
1191 }
1192
1193
1194 /*
1195  * Add LMP conversation
1196  */
1197 void add_lmp_conversation(packet_info* pinfo, guint8 dlsap, gboolean ttp, dissector_t proto_dissector)
1198 {
1199     guint8              dest;
1200     address             srcaddr;
1201     address             destaddr;
1202     conversation_t*     conv;
1203     lmp_conversation_t* lmp_conv = NULL;
1204
1205     
1206 /*g_message("%d: add_lmp_conversation(%p, %d, %d, %p) = ", pinfo->fd->num, pinfo, dlsap, ttp, proto_dissector); */
1207     srcaddr.type  = AT_NONE;
1208     srcaddr.len   = 1;
1209     srcaddr.data  = (guint8*)&pinfo->circuit_id;
1210
1211     dest = pinfo->circuit_id ^ CMD_FRAME;
1212     destaddr.type = AT_NONE;
1213     destaddr.len  = 1;
1214     destaddr.data = (guint8*)&dest;
1215
1216     conv = find_conversation(pinfo->fd->num, &destaddr, &srcaddr, PT_NONE, dlsap, 0, NO_PORT_B);
1217     if (conv)
1218     {
1219         lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
1220         while (1)
1221         {
1222             /* Does entry already exist? */
1223             if (lmp_conv->iap_result_frame == pinfo->fd->num)
1224                 return;
1225
1226             if (lmp_conv->pnext == NULL)
1227             {
1228                 lmp_conv->pnext = se_alloc(sizeof(lmp_conversation_t));
1229                 lmp_conv = lmp_conv->pnext;
1230                 break;
1231             }
1232             lmp_conv = lmp_conv->pnext;
1233         }
1234     }
1235     else
1236     {
1237         conv = conversation_new(pinfo->fd->num, &destaddr, &srcaddr, PT_NONE, dlsap, 0, NO_PORT_B);
1238         lmp_conv = se_alloc(sizeof(lmp_conversation_t));
1239         conversation_add_proto_data(conv, proto_irlmp, (void*)lmp_conv);
1240     }
1241
1242     lmp_conv->pnext            = NULL;
1243     lmp_conv->iap_result_frame = pinfo->fd->num;
1244     lmp_conv->ttp              = ttp;
1245     lmp_conv->proto_dissector  = proto_dissector;
1246
1247 /*g_message("%p\n", lmp_conv); */
1248 }
1249
1250
1251 /*
1252  * Dissect Negotiation Parameters
1253  */
1254 static unsigned dissect_negotiation(tvbuff_t* tvb, proto_tree* tree, unsigned offset)
1255 {
1256     unsigned    n   = 0;
1257     proto_item* ti;
1258     proto_tree* p_tree;
1259     char        buf[256];
1260     guint8      pv;
1261
1262     while (tvb_reported_length_remaining(tvb, offset) > 0)
1263     {
1264         guint8  p_len = tvb_get_guint8(tvb, offset + 1);
1265
1266         if (tree)
1267         {
1268             ti = proto_tree_add_item(tree, hf_negotiation_param, tvb, offset, p_len + 2, FALSE);
1269             p_tree = proto_item_add_subtree(ti, ett_param[n]);
1270
1271             pv = tvb_get_guint8(tvb, offset+2);
1272             buf[0] = 0;
1273
1274             switch (tvb_get_guint8(tvb, offset))
1275             {
1276                 case PI_BAUD_RATE:
1277                     proto_item_append_text(ti, ": Baud Rate (");
1278
1279                     if (pv & 0x01)
1280                         g_strlcat(buf, ", 2400", 256);
1281                     if (pv & 0x02)
1282                         g_strlcat(buf, ", 9600", 256);
1283                     if (pv & 0x04)
1284                         g_strlcat(buf, ", 19200", 256);
1285                     if (pv & 0x08)
1286                         g_strlcat(buf, ", 38400", 256);
1287                     if (pv & 0x10)
1288                         g_strlcat(buf, ", 57600", 256);
1289                     if (pv & 0x20)
1290                         g_strlcat(buf, ", 115200", 256);
1291                     if (pv & 0x40)
1292                         g_strlcat(buf, ", 576000", 256);
1293                     if (pv & 0x80)
1294                         g_strlcat(buf, ", 1152000", 256);
1295                     if ((p_len > 1) && (tvb_get_guint8(tvb, offset+3) & 0x01))
1296                         g_strlcat(buf, ", 4000000", 256);
1297
1298                     g_strlcat(buf, " bps)", 256);
1299
1300                     proto_item_append_text(ti, "%s", buf+2);
1301
1302                     break;
1303
1304                 case PI_MAX_TURN_TIME:
1305                     proto_item_append_text(ti, ": Maximum Turn Time (");
1306
1307                     if (pv & 0x01)
1308                         g_strlcat(buf, ", 500", 256);
1309                     if (pv & 0x02)
1310                         g_strlcat(buf, ", 250", 256);
1311                     if (pv & 0x04)
1312                         g_strlcat(buf, ", 100", 256);
1313                     if (pv & 0x08)
1314                         g_strlcat(buf, ", 50", 256);
1315
1316                     g_strlcat(buf, " ms)", 256);
1317
1318                     proto_item_append_text(ti, "%s", buf+2);
1319
1320                     break;
1321
1322                 case PI_DATA_SIZE:
1323                     proto_item_append_text(ti, ": Data Size (");
1324
1325                     if (pv & 0x01)
1326                         g_strlcat(buf, ", 64", 256);
1327                     if (pv & 0x02)
1328                         g_strlcat(buf, ", 128", 256);
1329                     if (pv & 0x04)
1330                         g_strlcat(buf, ", 256", 256);
1331                     if (pv & 0x08)
1332                         g_strlcat(buf, ", 512", 256);
1333                     if (pv & 0x10)
1334                         g_strlcat(buf, ", 1024", 256);
1335                     if (pv & 0x20)
1336                         g_strlcat(buf, ", 2048", 256);
1337
1338                     g_strlcat(buf, " bytes)", 256);
1339
1340                     proto_item_append_text(ti, "%s", buf+2);
1341
1342                     break;
1343
1344                 case PI_WINDOW_SIZE:
1345                     proto_item_append_text(ti, ": Window Size (");
1346
1347                     if (pv & 0x01)
1348                         g_strlcat(buf, ", 1", 256);
1349                     if (pv & 0x02)
1350                         g_strlcat(buf, ", 2", 256);
1351                     if (pv & 0x04)
1352                         g_strlcat(buf, ", 3", 256);
1353                     if (pv & 0x08)
1354                         g_strlcat(buf, ", 4", 256);
1355                     if (pv & 0x10)
1356                         g_strlcat(buf, ", 5", 256);
1357                     if (pv & 0x20)
1358                         g_strlcat(buf, ", 6", 256);
1359                     if (pv & 0x40)
1360                         g_strlcat(buf, ", 7", 256);
1361
1362                     g_strlcat(buf, " frame window)", 256);
1363
1364                     proto_item_append_text(ti, "%s", buf+2);
1365
1366                     break;
1367
1368                 case PI_ADD_BOFS:
1369                     proto_item_append_text(ti, ": Additional BOFs (");
1370
1371                     if (pv & 0x01)
1372                         g_strlcat(buf, ", 48", 256);
1373                     if (pv & 0x02)
1374                         g_strlcat(buf, ", 24", 256);
1375                     if (pv & 0x04)
1376                         g_strlcat(buf, ", 12", 256);
1377                     if (pv & 0x08)
1378                         g_strlcat(buf, ", 5", 256);
1379                     if (pv & 0x10)
1380                         g_strlcat(buf, ", 3", 256);
1381                     if (pv & 0x20)
1382                         g_strlcat(buf, ", 2", 256);
1383                     if (pv & 0x40)
1384                         g_strlcat(buf, ", 1", 256);
1385                     if (pv & 0x80)
1386                         g_strlcat(buf, ", 0", 256);
1387
1388                     g_strlcat(buf, " additional BOFs at 115200)", 256);
1389
1390                     proto_item_append_text(ti, "%s", buf+2);
1391
1392                     break;
1393
1394                 case PI_MIN_TURN_TIME:
1395                     proto_item_append_text(ti, ": Minimum Turn Time (");
1396
1397                     if (pv & 0x01)
1398                         g_strlcat(buf, ", 10", 256);
1399                     if (pv & 0x02)
1400                         g_strlcat(buf, ", 5", 256);
1401                     if (pv & 0x04)
1402                         g_strlcat(buf, ", 1", 256);
1403                     if (pv & 0x08)
1404                         g_strlcat(buf, ", 0.5", 256);
1405                     if (pv & 0x10)
1406                         g_strlcat(buf, ", 0.1", 256);
1407                     if (pv & 0x20)
1408                         g_strlcat(buf, ", 0.05", 256);
1409                     if (pv & 0x40)
1410                         g_strlcat(buf, ", 0.01", 256);
1411                     if (pv & 0x80)
1412                         g_strlcat(buf, ", 0", 256);
1413
1414                     g_strlcat(buf, " ms)", 256);
1415
1416                     proto_item_append_text(ti, "%s", buf+2);
1417
1418                     break;
1419
1420                 case PI_LINK_DISC:
1421                     proto_item_append_text(ti, ": Link Disconnect/Threshold Time (");
1422
1423                     if (pv & 0x01)
1424                         g_strlcat(buf, ", 3/0", 256);
1425                     if (pv & 0x02)
1426                         g_strlcat(buf, ", 8/3", 256);
1427                     if (pv & 0x04)
1428                         g_strlcat(buf, ", 12/3", 256);
1429                     if (pv & 0x08)
1430                         g_strlcat(buf, ", 16/3", 256);
1431                     if (pv & 0x10)
1432                         g_strlcat(buf, ", 20/3", 256);
1433                     if (pv & 0x20)
1434                         g_strlcat(buf, ", 25/3", 256);
1435                     if (pv & 0x40)
1436                         g_strlcat(buf, ", 30/3", 256);
1437                     if (pv & 0x80)
1438                         g_strlcat(buf, ", 40/3", 256);
1439
1440                     g_strlcat(buf, " s)", 256);
1441
1442                     proto_item_append_text(ti, "%s", buf+2);
1443
1444                     break;
1445
1446                 default:
1447                     proto_item_append_text(ti, ": unknown");
1448             }
1449         } else
1450             p_tree = NULL;
1451
1452         offset = dissect_param_tuple(tvb, p_tree, offset);
1453         n++;
1454     }
1455
1456     return offset;
1457 }
1458
1459
1460 /*
1461  * Dissect XID packet
1462  */
1463 static void dissect_xid(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, proto_tree* lap_tree, gboolean is_command)
1464 {
1465     int         offset = 0;
1466     proto_item* ti = NULL;
1467     proto_tree* i_tree = NULL;
1468     proto_tree* flags_tree;
1469     guint32     saddr, daddr;
1470     guint8      s;
1471     proto_tree* lmp_tree = NULL;
1472
1473     if (lap_tree)
1474     {
1475         ti = proto_tree_add_item(lap_tree, hf_lap_i, tvb, offset, -1, FALSE);
1476         i_tree = proto_item_add_subtree(ti, ett_lap_i);
1477
1478         proto_tree_add_item(i_tree, hf_xid_ident, tvb, offset, 1, FALSE);
1479     }
1480     offset++;
1481
1482     saddr = tvb_get_letohl(tvb, offset);
1483     col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1484     if (lap_tree)
1485         proto_tree_add_uint(i_tree, hf_xid_saddr, tvb, offset, 4, saddr);
1486     offset += 4;
1487
1488     daddr = tvb_get_letohl(tvb, offset);
1489     col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1490     if (lap_tree)
1491         proto_tree_add_uint(i_tree, hf_xid_daddr, tvb, offset, 4, daddr);
1492     offset += 4;
1493
1494     if (lap_tree)
1495     {
1496         ti = proto_tree_add_item(i_tree, hf_xid_flags, tvb, offset, 1, FALSE);
1497         flags_tree = proto_item_add_subtree(ti, ett_xid_flags);
1498         proto_tree_add_item(flags_tree, hf_xid_s, tvb, offset, 1, FALSE);
1499         proto_tree_add_item(flags_tree, hf_xid_conflict, tvb, offset, 1, FALSE);
1500     }
1501     offset++;
1502
1503     if (is_command)
1504     {
1505         s = tvb_get_guint8(tvb, offset);
1506         if (s == 0xFF)
1507             col_append_str(pinfo->cinfo, COL_INFO, ", s=final");
1508         else
1509             col_append_fstr(pinfo->cinfo, COL_INFO, ", s=%u", s);
1510         if (lap_tree)
1511         {
1512             ti = proto_tree_add_uint(i_tree, hf_xid_slotnr, tvb, offset, 1, s);
1513             if (s == 0xFF)
1514                 proto_item_append_text(ti, " (final)");
1515         }
1516     }
1517     offset++;
1518
1519     if (lap_tree)
1520         proto_tree_add_item(i_tree, hf_xid_version, tvb, offset, 1, FALSE);
1521     offset++;
1522
1523     if (lap_tree)
1524     {
1525         proto_item_set_end(lap_tree, tvb, offset);
1526         proto_item_set_end(i_tree, tvb, offset);
1527     }
1528
1529     if (tvb_reported_length_remaining(tvb, offset) > 0)
1530     {
1531         unsigned    hints_len;
1532         guint8      hint1 = 0;
1533         guint8      hint2 = 0;
1534         char buf[23];
1535
1536         if (root)
1537         {
1538             ti = proto_tree_add_item(root, proto_irlmp, tvb, offset, -1, FALSE);
1539             lmp_tree = proto_item_add_subtree(ti, ett_irlmp);
1540         }
1541
1542         for (hints_len = 0;;)
1543         {
1544             guint8 hint = tvb_get_guint8(tvb, offset + hints_len++);
1545
1546             if (hints_len == 1)
1547                 hint1 = hint;
1548             else if (hints_len == 2)
1549                 hint2 = hint;
1550
1551             if ((hint & 0x80) == 0)
1552                 break;
1553         }
1554
1555         if (root)
1556         {
1557             ti = proto_tree_add_item(lmp_tree, hf_lmp_xid_hints, tvb, offset, hints_len, FALSE);
1558             if ((hint1 | hint2) != 0)
1559             {
1560                 char    service_hints[256];
1561
1562                 service_hints[0] = 0;
1563
1564                 if (hint1 & 0x01)                
1565                     g_strlcat(service_hints, ", PnP Compatible", 256);
1566                 if (hint1 & 0x02)
1567                     g_strlcat(service_hints, ", PDA/Palmtop", 256);
1568                 if (hint1 & 0x04)
1569                     g_strlcat(service_hints, ", Computer", 256);
1570                 if (hint1 & 0x08)
1571                     g_strlcat(service_hints, ", Printer", 256);
1572                 if (hint1 & 0x10)
1573                     g_strlcat(service_hints, ", Modem", 256);
1574                 if (hint1 & 0x20)
1575                     g_strlcat(service_hints, ", Fax", 256);
1576                 if (hint1 & 0x40)
1577                     g_strlcat(service_hints, ", LAN Access", 256);
1578                 if (hint2 & 0x01)
1579                     g_strlcat(service_hints, ", Telephony", 256);
1580                 if (hint2 & 0x02)
1581                     g_strlcat(service_hints, ", File Server", 256);
1582                 if (hint2 & 0x04)
1583                     g_strlcat(service_hints, ", IrCOMM", 256);
1584                 if (hint2 & 0x20)
1585                     g_strlcat(service_hints, ", OBEX", 256);
1586
1587                 g_strlcat(service_hints, ")", 256);
1588                 service_hints[0] = ' ';
1589                 service_hints[1] = '(';
1590
1591                 proto_item_append_text(ti, "%s", service_hints);
1592             }
1593         }
1594         offset += hints_len;
1595
1596         if (tvb_reported_length_remaining(tvb, offset) > 0)
1597         {
1598             guint8 cset;
1599             gint name_len;
1600
1601             cset = tvb_get_guint8(tvb, offset);
1602             if (root)
1603                 proto_tree_add_uint(lmp_tree, hf_lmp_xid_charset, tvb, offset, 1, cset);
1604             offset++;
1605             name_len = tvb_reported_length_remaining(tvb, offset);
1606             if (name_len > 0)
1607             {
1608                 if (cset == 0x00)
1609                 {
1610
1611                     if (name_len > 22)
1612                         name_len = 22;
1613                     tvb_memcpy(tvb, buf, offset, name_len);
1614                     buf[name_len] = 0;
1615                     col_append_str(pinfo->cinfo, COL_INFO, ", \"");
1616                     col_append_str(pinfo->cinfo, COL_INFO, buf);
1617                     col_append_str(pinfo->cinfo, COL_INFO, "\"");
1618                     if (root)
1619                         proto_tree_add_item(lmp_tree, hf_lmp_xid_name, tvb, offset,
1620                                             -1, FALSE);
1621                 }
1622                 else
1623                 {
1624                     if (root)
1625                         proto_tree_add_item(lmp_tree, hf_lmp_xid_name_no_ascii, tvb, offset,
1626                                             -1, FALSE);
1627                 }
1628             }
1629         }
1630     }
1631 }
1632
1633
1634 /*
1635  * Dissect Log Messages
1636  */
1637 static void dissect_log(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1638 {
1639     /* Make entries in Protocol column on summary display */
1640     col_set_str(pinfo->cinfo, COL_PROTOCOL, "Log");
1641
1642     /* missed messages? */
1643     if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1644     {
1645         col_set_str(pinfo->cinfo, COL_INFO, "WARNING: Missed one or more messages while capturing!");
1646     }
1647     else 
1648     {
1649         guint   length;
1650         char    buf[256];
1651
1652
1653         length = tvb_length(tvb);
1654         if (length > sizeof(buf)-1)
1655             length = sizeof(buf)-1;
1656         tvb_memcpy(tvb, buf, 0, length);
1657         buf[length] = 0;
1658         if (buf[length-1] == '\n')
1659             buf[length-1] = 0;
1660         else if (buf[length-2] == '\n')
1661             buf[length-2] = 0;
1662
1663         col_add_str(pinfo->cinfo, COL_INFO, buf);
1664     }
1665
1666     if (root)
1667     {
1668         proto_item* ti   = proto_tree_add_item(root, proto_log, tvb, 0, -1, FALSE);
1669         proto_tree* tree = proto_item_add_subtree(ti, ett_log);
1670
1671         if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1672             proto_tree_add_item(tree, hf_log_missed, tvb, 0, 0, FALSE);
1673         else
1674             proto_tree_add_item(tree, hf_log_msg, tvb, 0, -1, FALSE);    
1675     }
1676 }
1677
1678
1679 /*
1680  * Dissect IrLAP
1681  */
1682 static void dissect_irlap(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1683 {
1684     int      offset = 0;
1685     guint8   a, c;
1686     gboolean is_response;
1687     char     addr[9];
1688     proto_item* ti = NULL;
1689     proto_tree* tree = NULL;
1690     proto_tree* i_tree = NULL;
1691     guint32  saddr, daddr;
1692     guint8   ca;
1693
1694     /* Make entries in Protocol column on summary display */
1695     col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLAP");
1696
1697     /* Clear Info column */
1698     col_clear(pinfo->cinfo, COL_INFO);
1699
1700     /* set direction column */
1701     switch (pinfo->pseudo_header->irda.pkttype)
1702     {
1703         case IRDA_OUTGOING:
1704             col_set_str(pinfo->cinfo, COL_IF_DIR, "Out");
1705             break;
1706             
1707         case IRDA_INCOMING:
1708             col_set_str(pinfo->cinfo, COL_IF_DIR, "In");
1709             break;
1710     }
1711
1712     /* decode values used for demuxing */
1713     a = tvb_get_guint8(tvb, 0);
1714
1715     /* save connection address field in pinfo */
1716     pinfo->circuit_id = a;
1717
1718     /* initially set address columns to connection address */
1719     g_snprintf(addr, sizeof(addr)-1, "0x%02X", a >> 1);
1720     col_add_str(pinfo->cinfo, COL_DEF_SRC, addr);
1721     col_add_str(pinfo->cinfo, COL_DEF_DST, addr);
1722
1723     if (root)
1724     {
1725         proto_tree* a_tree;
1726         proto_item* addr_item;
1727
1728         /* create display subtree for the protocol */
1729         ti   = proto_tree_add_item(root, proto_irlap, tvb, 0, -1, FALSE);
1730         tree = proto_item_add_subtree(ti, ett_irlap);
1731
1732         /* create subtree for the address field */
1733         ti     = proto_tree_add_item(tree, hf_lap_a, tvb, offset, 1, FALSE);
1734         a_tree = proto_item_add_subtree(ti, ett_lap_a);
1735         proto_tree_add_item(a_tree, hf_lap_a_cr, tvb, offset, 1, FALSE);
1736         addr_item = proto_tree_add_item(a_tree, hf_lap_a_address, tvb, offset, 1, FALSE);
1737         switch (a & ~CMD_FRAME)
1738         {
1739             case 0:
1740                 proto_item_append_text(addr_item, " (NULL Address)");
1741                 break;
1742             case 0xFE:
1743                 proto_item_append_text(addr_item, " (Broadcast)");
1744                 break;
1745         }
1746     }
1747     is_response = ((a & CMD_FRAME) == 0);
1748     offset++;
1749
1750     /* process the control field */
1751     c = dissect_xdlc_control(tvb, 1, pinfo, tree, hf_lap_c,
1752             ett_lap_c, &irlap_cf_items, NULL, lap_c_u_cmd_abbr_vals,
1753             lap_c_u_rsp_abbr_vals, is_response, FALSE, FALSE);
1754     offset++;
1755
1756     if ((c & XDLC_I_MASK) == XDLC_I) {
1757         /* I frame */
1758         proto_item_set_len(tree, offset);
1759         tvb = tvb_new_subset_remaining(tvb, offset);
1760         dissect_irlmp(tvb, pinfo, root);
1761         return;
1762     }
1763
1764     if ((c & 0x03) == XDLC_U) {
1765         /* U frame */
1766         switch (c & XDLC_U_MODIFIER_MASK)
1767         {
1768             case XDLC_SNRM:
1769                 if (root)
1770                 {
1771                     ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, FALSE);
1772                     i_tree = proto_item_add_subtree(ti, ett_lap_i);
1773                 }
1774
1775                 saddr = tvb_get_letohl(tvb, offset);
1776                 if (!is_response)
1777                 {
1778                     col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1779                 }
1780                 if (root)
1781                     proto_tree_add_uint(i_tree, hf_snrm_saddr, tvb, offset, 4, saddr);
1782                 offset += 4;
1783
1784                 daddr = tvb_get_letohl(tvb, offset);
1785                 if (!is_response)
1786                 {
1787                     col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1788                 }
1789                 if (root)
1790                     proto_tree_add_uint(i_tree, hf_snrm_daddr, tvb, offset, 4, daddr);
1791                 offset += 4;
1792
1793                 ca = tvb_get_guint8(tvb, offset);
1794                 if (!is_response)
1795                 {
1796                     col_append_fstr(pinfo->cinfo, COL_INFO, ", ca=0x%02X",
1797                                         ca >> 1);
1798                 }
1799                 if (root)
1800                     proto_tree_add_uint(i_tree, hf_snrm_ca, tvb, offset, 1, ca >> 1);
1801                 offset++;
1802
1803                 offset = dissect_negotiation(tvb, i_tree, offset);
1804                 if (root)
1805                     proto_item_set_end(ti, tvb, offset);
1806                 break;
1807
1808             case IRDA_XID_CMD:
1809                 tvb = tvb_new_subset_remaining(tvb, offset);
1810                 dissect_xid(tvb, pinfo, root, tree, TRUE);
1811                 return;
1812
1813             case XDLC_UA:
1814                 if (tvb_reported_length_remaining(tvb, offset) > 0)
1815                 {
1816                     if (root)
1817                     {
1818                         ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, FALSE);
1819                         i_tree = proto_item_add_subtree(ti, ett_lap_i);
1820                     }
1821
1822                     saddr = tvb_get_letohl(tvb, offset);
1823                     col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1824                     if (root)
1825                         proto_tree_add_uint(i_tree, hf_ua_saddr, tvb, offset, 4, saddr);
1826                     offset += 4;
1827
1828                     daddr = tvb_get_letohl(tvb, offset);
1829                     col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1830                     if (root)
1831                         proto_tree_add_uint(i_tree, hf_ua_daddr, tvb, offset, 4, daddr);
1832                     offset += 4;
1833
1834                     offset = dissect_negotiation(tvb, i_tree, offset);
1835                     if (root)
1836                         proto_item_set_end(ti, tvb, offset);
1837                 }
1838                 break;
1839
1840             case XDLC_XID:
1841                 tvb = tvb_new_subset_remaining(tvb, offset);
1842                 dissect_xid(tvb, pinfo, root, tree, FALSE);
1843                 return;
1844          }
1845     }
1846
1847     /* If any bytes remain, send it to the generic data dissector */
1848     if (tvb_reported_length_remaining(tvb, offset) > 0)
1849     {
1850         tvb = tvb_new_subset_remaining(tvb, offset);
1851         call_dissector(data_handle, tvb, pinfo, root);
1852     }
1853 }
1854
1855
1856 /*
1857  * Dissect IrDA protocol
1858  */
1859 static void dissect_irda(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1860 {
1861     /* load the display labels */
1862     pinfo->current_proto = "IrDA";
1863
1864     /* check if log message */
1865     if ((pinfo->pseudo_header->irda.pkttype & IRDA_CLASS_MASK) == IRDA_CLASS_LOG)
1866     {
1867         dissect_log(tvb, pinfo, root);
1868         return;
1869     }
1870
1871
1872     dissect_irlap(tvb, pinfo, root);
1873 }
1874
1875
1876 /*
1877  * Register the protocol with Wireshark
1878  * This format is required because a script is used to build the C function
1879  *  that calls all the protocol registrations.
1880  */
1881 void proto_register_irda(void)
1882 {
1883     unsigned i;
1884
1885     /* Setup list of header fields */
1886     static hf_register_info hf_lap[] = {
1887         { &hf_lap_a,
1888             { "Address Field", "irlap.a",
1889                 FT_UINT8, BASE_HEX, NULL, 0,
1890                 NULL, HFILL }},
1891         { &hf_lap_a_cr,
1892             { "C/R", "irlap.a.cr",
1893                 FT_BOOLEAN, 8, TFS(&lap_cr_vals), CMD_FRAME,
1894                 NULL, HFILL }},
1895         { &hf_lap_a_address,
1896             { "Address", "irlap.a.address",
1897                 FT_UINT8, BASE_HEX, NULL, ~CMD_FRAME,
1898                 NULL, HFILL }},
1899         { &hf_lap_c,
1900             { "Control Field", "irlap.c",
1901                 FT_UINT8, BASE_HEX, NULL, 0,
1902                 NULL, HFILL }},
1903         { &hf_lap_c_nr,
1904             { "N(R)", "irlap.c.n_r",
1905                 FT_UINT8, BASE_DEC, NULL, XDLC_N_R_MASK,
1906                 NULL, HFILL }},
1907         { &hf_lap_c_ns,
1908             { "N(S)", "irlap.c.n_s",
1909                 FT_UINT8, BASE_DEC, NULL, XDLC_N_S_MASK,
1910                 NULL, HFILL }},
1911         { &hf_lap_c_p,
1912             { "Poll", "irlap.c.p",
1913                 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1914                 NULL, HFILL }},
1915         { &hf_lap_c_f,
1916             { "Final", "irlap.c.f",
1917                 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1918                 NULL, HFILL }},
1919         { &hf_lap_c_s,
1920             { "Supervisory frame type", "irlap.c.s_ftype",
1921                 FT_UINT8, BASE_HEX, VALS(lap_c_s_vals), XDLC_S_FTYPE_MASK,
1922                 NULL, HFILL }},
1923         { &hf_lap_c_u_cmd,
1924             { "Command", "irlap.c.u_modifier_cmd",
1925                 FT_UINT8, BASE_HEX, VALS(lap_c_u_cmd_vals), XDLC_U_MODIFIER_MASK,
1926                 NULL, HFILL }},
1927         { &hf_lap_c_u_rsp,
1928             { "Response", "irlap.c.u_modifier_resp",
1929                 FT_UINT8, BASE_HEX, VALS(lap_c_u_rsp_vals), XDLC_U_MODIFIER_MASK,
1930                 NULL, HFILL }},
1931         { &hf_lap_c_i,
1932             { "Frame Type", "irlap.c.ftype",
1933                 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_I_MASK,
1934                 NULL, HFILL }},
1935         { &hf_lap_c_s_u,
1936             { "Frame Type", "irlap.c.ftype",
1937                 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_S_U_MASK,
1938                 NULL, HFILL }},
1939         { &hf_lap_i,
1940             { "Information Field", "irlap.i",
1941                 FT_NONE, BASE_NONE, NULL, 0,
1942                 NULL, HFILL }},
1943         { &hf_snrm_saddr,
1944             { "Source Device Address", "irlap.snrm.saddr",
1945                 FT_UINT32, BASE_HEX, NULL, 0,
1946                 NULL, HFILL }},
1947         { &hf_snrm_daddr,
1948             { "Destination Device Address", "irlap.snrm.daddr",
1949                 FT_UINT32, BASE_HEX, NULL, 0,
1950                 NULL, HFILL }},
1951         { &hf_snrm_ca,
1952             { "Connection Address", "irlap.snrm.ca",
1953                 FT_UINT8, BASE_HEX, NULL, 0,
1954                 NULL, HFILL }},
1955         { &hf_negotiation_param,
1956             { "Negotiation Parameter", "irlap.negotiation",
1957                 FT_NONE, BASE_NONE, NULL, 0,
1958                 NULL, HFILL }},
1959         { &hf_param_pi,
1960             { "Parameter Identifier", "irlap.pi",
1961                 FT_UINT8, BASE_HEX, NULL, 0,
1962                 NULL, HFILL }},
1963         { &hf_param_pl,
1964             { "Parameter Length", "irlap.pl",
1965                 FT_UINT8, BASE_HEX, NULL, 0,
1966                 NULL, HFILL }},
1967         { &hf_param_pv,
1968             { "Parameter Value", "irlap.pv",
1969                 FT_BYTES, BASE_NONE, NULL, 0,
1970                 NULL, HFILL }},
1971         { &hf_ua_saddr,
1972             { "Source Device Address", "irlap.ua.saddr",
1973                 FT_UINT32, BASE_HEX, NULL, 0,
1974                 NULL, HFILL }},
1975         { &hf_ua_daddr,
1976             { "Destination Device Address", "irlap.ua.daddr",
1977                 FT_UINT32, BASE_HEX, NULL, 0,
1978                 NULL, HFILL }},
1979         { &hf_xid_ident,
1980             { "Format Identifier", "irlap.xid.fi",
1981                 FT_UINT8, BASE_HEX, NULL, 0,
1982                 NULL, HFILL }},
1983         { &hf_xid_saddr,
1984             { "Source Device Address", "irlap.xid.saddr",
1985                 FT_UINT32, BASE_HEX, NULL, 0,
1986                 NULL, HFILL }},
1987         { &hf_xid_daddr,
1988             { "Destination Device Address", "irlap.xid.daddr",
1989                 FT_UINT32, BASE_HEX, NULL, 0,
1990                 NULL, HFILL }},
1991         { &hf_xid_flags,
1992             { "Discovery Flags", "irlap.xid.flags",
1993                 FT_UINT8, BASE_HEX, NULL, 0,
1994                 NULL, HFILL }},
1995         { &hf_xid_s,
1996             { "Number of Slots", "irlap.xid.s",
1997                 FT_UINT8, BASE_DEC, VALS(xid_slot_numbers), S_MASK,
1998                 NULL, HFILL }},
1999         { &hf_xid_conflict,
2000             { "Conflict", "irlap.xid.conflict",
2001                 FT_BOOLEAN, 8, TFS(&set_notset), CONFLICT,
2002                 NULL, HFILL }},
2003         { &hf_xid_slotnr,
2004             { "Slot Number", "irlap.xid.slotnr",
2005                 FT_UINT8, BASE_DEC, NULL, 0,
2006                 NULL, HFILL }},
2007         { &hf_xid_version,
2008             { "Version Number", "irlap.xid.version",
2009                 FT_UINT8, BASE_HEX, NULL, 0,
2010                 NULL, HFILL }}
2011     };
2012
2013     static hf_register_info hf_log[] = {
2014         { &hf_log_msg,
2015             { "Message", "log.msg",
2016                 FT_STRING, BASE_NONE, NULL, 0,
2017                 NULL, HFILL }},
2018         { &hf_log_missed,
2019             { "WARNING: Missed one or more messages while capturing!", "log.missed",
2020                 FT_NONE, BASE_NONE, NULL, 0,
2021                 NULL, HFILL }}
2022     };
2023
2024     static hf_register_info hf_lmp[] = {
2025         { &hf_lmp_xid_hints,
2026             { "Service Hints", "irlmp.xid.hints",
2027                 FT_BYTES, BASE_NONE, NULL, 0,
2028                 NULL, HFILL }},
2029         { &hf_lmp_xid_charset,
2030             { "Character Set", "irlmp.xid.charset",
2031                 FT_UINT8, BASE_HEX, NULL, 0,
2032                 NULL, HFILL }},
2033         { &hf_lmp_xid_name,
2034             { "Device Nickname", "irlmp.xid.name",
2035                 FT_STRING, BASE_NONE, NULL, 0,
2036                 NULL, HFILL }},
2037         { &hf_lmp_xid_name_no_ascii,
2038             { "Device Nickname (unsupported character set)", "irlmp.xid.name",
2039                 FT_BYTES, BASE_NONE, NULL, 0,
2040                 NULL, HFILL }},
2041         { &hf_lmp_dst,
2042             { "Destination", "irlmp.dst",
2043                 FT_UINT8, BASE_HEX, NULL, 0,
2044                 NULL, HFILL }},
2045         { &hf_lmp_dst_control,
2046             { "Control Bit", "irlmp.dst.c",
2047                 FT_BOOLEAN, 8, TFS(&set_notset), CONTROL_BIT,
2048                 NULL, HFILL }},
2049         { &hf_lmp_dst_lsap,
2050             { "Destination LSAP", "irlmp.dst.lsap",
2051                 FT_UINT8, BASE_DEC, NULL, ~CONTROL_BIT,
2052                 NULL, HFILL }},
2053         { &hf_lmp_src,
2054             { "Source", "irlmp.src",
2055                 FT_UINT8, BASE_HEX, NULL, 0,
2056                 NULL, HFILL }},
2057         { &hf_lmp_src_r,
2058             { "reserved", "irlmp.src.r",
2059                 FT_UINT8, BASE_DEC, NULL, RESERVED_BIT,
2060                 NULL, HFILL }},
2061         { &hf_lmp_src_lsap,
2062             { "Source LSAP", "irlmp.src.lsap",
2063                 FT_UINT8, BASE_DEC, NULL, ~RESERVED_BIT,
2064                 NULL, HFILL }},
2065         { &hf_lmp_opcode,
2066             { "Opcode", "irlmp.opcode",
2067                 FT_UINT8, BASE_HEX, VALS(lmp_opcode_vals), 0x0,
2068                 NULL, HFILL }},
2069         { &hf_lmp_rsvd,
2070             { "Reserved", "irlmp.rsvd",
2071                 FT_UINT8, BASE_HEX, NULL, 0x0,
2072                 NULL, HFILL }},
2073         { &hf_lmp_reason,
2074             { "Reason", "irlmp.reason",
2075                 FT_UINT8, BASE_HEX, VALS(lmp_reason_vals), 0x0,
2076                 NULL, HFILL }},
2077         { &hf_lmp_mode,
2078             { "Mode", "irlmp.mode",
2079                 FT_UINT8, BASE_HEX, VALS(lmp_mode_vals), 0x0,
2080                 NULL, HFILL }},
2081         { &hf_lmp_status,
2082             { "Status", "irlmp.status",
2083                 FT_UINT8, BASE_HEX, VALS(lmp_status_vals), 0x0,
2084                 NULL, HFILL }}
2085     };
2086
2087     static hf_register_info hf_iap[] = {
2088         { &hf_iap_ctl,
2089             { "Control Field", "iap.ctl",
2090                 FT_UINT8, BASE_HEX, NULL, 0,
2091                 NULL, HFILL }},
2092         { &hf_iap_ctl_lst,
2093             { "Last Frame", "iap.ctl.lst",
2094                 FT_BOOLEAN, 8, TFS(&set_notset), IAP_LST,
2095                 NULL, HFILL }},
2096         { &hf_iap_ctl_ack,
2097             { "Acknowledge", "iap.ctl.ack",
2098                 FT_BOOLEAN, 8, TFS(&set_notset), IAP_ACK,
2099                 NULL, HFILL }},
2100         { &hf_iap_ctl_opcode,
2101             { "Opcode", "iap.ctl.opcode",
2102                 FT_UINT8, BASE_HEX, VALS(iap_opcode_vals), IAP_OP,
2103                 NULL, HFILL }},
2104         { &hf_iap_class_name,
2105             { "Class Name", "iap.classname",
2106                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2107                 NULL, HFILL }},
2108         { &hf_iap_attr_name,
2109             { "Attribute Name", "iap.attrname",
2110                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2111                 NULL, HFILL }},
2112         { &hf_iap_return,
2113             { "Return", "iap.return",
2114                 FT_UINT8, BASE_HEX, VALS(iap_return_vals), 0x0,
2115                 NULL, HFILL }},
2116         { &hf_iap_list_len,
2117             { "List Length", "iap.listlen",
2118                 FT_UINT16, BASE_DEC, NULL, 0x0,
2119                 NULL, HFILL }},
2120         { &hf_iap_list_entry,
2121             { "List Entry", "iap.listentry",
2122                 FT_NONE, BASE_NONE, NULL, 0x0,
2123                 NULL, HFILL }},
2124         { &hf_iap_obj_id,
2125             { "Object Identifier", "iap.objectid",
2126                 FT_UINT16, BASE_HEX, NULL, 0x0,
2127                 NULL, HFILL }},
2128         { &hf_iap_attr_type,
2129             { "Type", "iap.attrtype",
2130                 FT_UINT8, BASE_DEC, VALS(iap_attr_type_vals), 0x0,
2131                 NULL, HFILL }},
2132         { &hf_iap_int,
2133             { "Value", "iap.int",
2134                 FT_INT32, BASE_DEC, NULL, 0x0,
2135                 NULL, HFILL }},
2136         { &hf_iap_seq_len,
2137             { "Sequence Length", "iap.seqlen",
2138                 FT_UINT16, BASE_DEC, NULL, 0x0,
2139                 NULL, HFILL }},
2140         { &hf_iap_oct_seq,
2141             { "Sequence", "iap.octseq",
2142                 FT_BYTES, BASE_NONE, NULL, 0x0,
2143                 NULL, HFILL }},
2144         { &hf_iap_char_set,
2145             { "Character Set", "iap.charset",
2146                 FT_UINT8, BASE_HEX, NULL, 0x0,
2147                 NULL, HFILL }},
2148         { &hf_iap_string,
2149             { "String", "iap.string",
2150                 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2151                 NULL, HFILL }},
2152         { &hf_iap_invaloctet,
2153             { "Malformed IAP result: \"", "iap.invaloctet",
2154                 FT_NONE, BASE_NONE, NULL, 0,
2155                 NULL, HFILL }},
2156         { &hf_iap_invallsap,
2157             { "Malformed IAP result: \"", "iap.invallsap",
2158                 FT_NONE, BASE_NONE, NULL, 0,
2159                 NULL, HFILL }}
2160     };
2161
2162     static hf_register_info hf_ttp[] = {
2163         { &hf_ttp_p,
2164             { "Parameter Bit", "ttp.p",
2165                 FT_BOOLEAN, 8, TFS(&set_notset), TTP_PARAMETERS,
2166                 NULL, HFILL }},
2167         { &hf_ttp_icredit,
2168             { "Initial Credit", "ttp.icredit",
2169                 FT_UINT8, BASE_DEC, NULL, ~TTP_PARAMETERS,
2170                 NULL, HFILL }},
2171         { &hf_ttp_m,
2172             { "More Bit", "ttp.m",
2173                 FT_BOOLEAN, 8, TFS(&set_notset), TTP_MORE,
2174                 NULL, HFILL }},
2175         { &hf_ttp_dcredit,
2176             { "Delta Credit", "ttp.dcredit",
2177                 FT_UINT8, BASE_DEC, NULL, ~TTP_MORE,
2178                 NULL, HFILL }}
2179     };
2180
2181     /* Setup protocol subtree arrays */
2182     static gint* ett[] = {
2183         &ett_irlap,
2184         &ett_lap_a,
2185         &ett_lap_c,
2186         &ett_lap_i,
2187         &ett_xid_flags,
2188         &ett_log,
2189         &ett_irlmp,
2190         &ett_lmp_dst,
2191         &ett_lmp_src,
2192         &ett_iap,
2193         &ett_iap_ctl,
2194         &ett_ttp
2195     };
2196
2197     gint* ett_p[MAX_PARAMETERS];
2198     gint* ett_iap_e[MAX_IAP_ENTRIES];
2199
2200
2201     /* Register protocol names and descriptions */
2202     proto_irlap = proto_register_protocol("IrDA Link Access Protocol", "IrLAP", "irlap");
2203     proto_log   = proto_register_protocol("Log Message", "Log", "log");
2204     proto_irlmp = proto_register_protocol("IrDA Link Management Protocol", "IrLMP", "irlmp");
2205     proto_iap   = proto_register_protocol("Information Access Protocol", "IAP", "iap");
2206     proto_ttp   = proto_register_protocol("Tiny Transport Protocol", "TTP", "ttp");
2207
2208     /* Register the dissector */
2209     register_dissector("irda", dissect_irda, proto_irlap);
2210
2211     /* Required function calls to register the header fields */
2212     proto_register_field_array(proto_irlap, hf_lap, array_length(hf_lap));
2213     proto_register_field_array(proto_log, hf_log, array_length(hf_log));
2214     proto_register_field_array(proto_irlmp, hf_lmp, array_length(hf_lmp));
2215     proto_register_field_array(proto_iap, hf_iap, array_length(hf_iap));
2216     proto_register_field_array(proto_ttp, hf_ttp, array_length(hf_ttp));
2217
2218     /* Register subtrees */
2219     proto_register_subtree_array(ett, array_length(ett));
2220     for (i = 0; i < MAX_PARAMETERS; i++)
2221     {
2222         ett_param[i] = -1;
2223         ett_p[i]     = &ett_param[i];
2224     }
2225     proto_register_subtree_array(ett_p, MAX_PARAMETERS);
2226     for (i = 0; i < MAX_IAP_ENTRIES; i++)
2227     {
2228         ett_iap_entry[i] = -1;
2229         ett_iap_e[i]     = &ett_iap_entry[i];
2230     }
2231     proto_register_subtree_array(ett_iap_e, MAX_IAP_ENTRIES);
2232 }
2233
2234
2235 /* If this dissector uses sub-dissector registration add a registration routine.
2236         This format is required because a script is used to find these routines and
2237         create the code that calls these routines.
2238 */
2239
2240 void proto_reg_handoff_irda(void)
2241 {
2242     dissector_handle_t irda_handle;
2243     
2244     irda_handle = find_dissector("irda");
2245     dissector_add_uint("wtap_encap", WTAP_ENCAP_IRDA, irda_handle);
2246     dissector_add_uint("sll.ltype", LINUX_SLL_P_IRDA_LAP, irda_handle);
2247     data_handle = find_dissector("data");
2248 }