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