2 * Routines for IrDA dissection
3 * By Shaun Jackman <sjackman@pathwayconnect.com>
4 * Copyright 2000 Shaun Jackman
6 * Extended by Jan Kiszka <jan.kiszka@web.de>
7 * Copyright 2003 Jan Kiszka
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
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.
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.
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.
39 #include <epan/packet.h>
40 #include <epan/proto.h>
41 #include <epan/conversation.h>
42 #include <epan/xdlc.h>
44 #include "irda-appl.h"
47 * This plugin dissects infrared data transmissions as defined by the IrDA
48 * specification (www.irda.org). See
50 * http://www.irda.org/standards/specifications.asp
52 * for various IrDA specifications.
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.
64 /* Frame types and templates */
68 * XXX - the IrDA spec gives XID as 0x2c; HDLC (and other HDLC-derived
69 * protocolc) use 0xAC.
71 #define IRDA_XID_CMD 0x2c /* Exchange Station Identification */
73 #define CMD_FRAME 0x01
74 #define RSP_FRAME 0x00
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
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
101 #define CONTROL_BIT 0x80
102 #define RESERVED_BIT 0x80
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 */
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
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
140 #define TTP_PARAMETERS 0x80
141 #define TTP_MORE 0x80
143 static dissector_handle_t data_handle;
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;
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;
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;
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;
222 static int proto_log = -1;
223 static int hf_log_msg = -1;
224 static int hf_log_missed = -1;
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;
240 #define MAX_PARAMETERS 32
241 static gint ett_param[MAX_PARAMETERS];
243 static gint ett_iap_entry[MAX_IAP_ENTRIES];
245 static const xdlc_cf_items irlap_cf_items = {
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;
264 /* IrLMP conversation type */
265 typedef struct lmp_conversation {
266 struct lmp_conversation* pnext;
267 guint32 iap_result_frame;
269 dissector_t proto_dissector;
270 } lmp_conversation_t;
272 static GMemChunk* iap_conv_chunk = NULL;
273 static GMemChunk* lmp_conv_chunk = NULL;
275 static const true_false_string lap_cr_vals = {
280 static const true_false_string set_notset = {
285 static const value_string lap_c_ftype_vals[] = {
286 { XDLC_I, "Information frame" },
287 { XDLC_S, "Supervisory frame" },
288 { XDLC_U, "Unnumbered frame" },
292 static const value_string lap_c_u_cmd_abbr_vals[] = {
293 { XDLC_SNRM, "SNRM" },
294 { XDLC_DISC, "DISC" },
296 { IRDA_XID_CMD, "XID" },
297 { XDLC_TEST, "TEST" },
301 static const value_string lap_c_u_rsp_abbr_vals[] = {
302 { XDLC_SNRM, "RNRM" },
304 { XDLC_FRMR, "FRMR" },
309 { XDLC_TEST, "TEST" },
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" },
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" },
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" },
342 static const value_string xid_slot_numbers[] = {
343 /* Number of XID slots */
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" },
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" },
377 static const value_string lmp_mode_vals[] = {
379 { 0x00, "Multiplexed" },
380 { 0x01, "Exclusive" },
384 static const value_string lmp_status_vals[] = {
388 { 0xFF, "Unsupported" },
392 static const value_string iap_opcode_vals[] = {
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" },
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" },
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" },
423 static ias_attr_dissector_t device_attr_dissector[] = {
424 /* Device attribute dissectors */
425 /* { "IrLMPSupport", xxx }, not implemented yet... */
429 /* IAS class dissectors */
430 static ias_class_dissector_t class_dissector[] = { CLASS_DISSECTORS };
434 * Dissect parameter tuple
436 unsigned dissect_param_tuple(tvbuff_t* tvb, proto_tree* tree, unsigned offset)
438 guint8 len = tvb_get_guint8(tvb, offset + 1);
441 proto_tree_add_item(tree, hf_param_pi, tvb, offset, 1, FALSE);
445 proto_tree_add_item(tree, hf_param_pl, tvb, offset, 1, FALSE);
451 proto_tree_add_item(tree, hf_param_pv, tvb, offset, len, FALSE);
462 static unsigned dissect_ttp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, gboolean data)
468 if (tvb_length(tvb) == 0)
471 /* Make entries in Protocol column on summary display */
472 if (check_col(pinfo->cinfo, COL_PROTOCOL))
473 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TTP");
475 head = tvb_get_guint8(tvb, offset);
477 if (check_col(pinfo->cinfo, COL_INFO))
482 g_snprintf(buf, 128, ", Credit=%d", head & ~TTP_PARAMETERS);
483 col_append_str(pinfo->cinfo, COL_INFO, buf);
488 /* create display subtree for the protocol */
489 proto_item* ti = proto_tree_add_item(root, proto_ttp, tvb, 0, -1, FALSE);
490 proto_tree* tree = proto_item_add_subtree(ti, ett_ttp);
494 proto_tree_add_item(tree, hf_ttp_m, tvb, offset, 1, FALSE);
495 proto_tree_add_item(tree, hf_ttp_dcredit, tvb, offset, 1, FALSE);
500 proto_tree_add_item(tree, hf_ttp_p, tvb, offset, 1, FALSE);
501 proto_tree_add_item(tree, hf_ttp_icredit, tvb, offset, 1, FALSE);
504 proto_item_set_len(tree, offset);
514 * Dissect IAP request
516 static void dissect_iap_request(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
525 conversation_t* conv;
526 iap_conversation_t* iap_conv;
529 if (tvb_length(tvb) == 0)
532 /* Make entries in Protocol column on summary display */
533 if (check_col(pinfo->cinfo, COL_PROTOCOL))
534 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAP");
536 op = tvb_get_guint8(tvb, offset) & IAP_OP;
540 case GET_VALUE_BY_CLASS:
541 clen = MIN(tvb_get_guint8(tvb, offset + 1), 60);
542 alen = MIN(tvb_get_guint8(tvb, offset + 1 + 1 + clen), 60);
544 /* create conversation entry */
545 src = pinfo->circuit_id ^ CMD_FRAME;
546 srcaddr.type = AT_NONE;
548 srcaddr.data = (guint8*)&src;
550 destaddr.type = AT_NONE;
552 destaddr.data = (guint8*)&pinfo->circuit_id;
554 conv = find_conversation(pinfo->fd->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
557 iap_conv = (iap_conversation_t*)conversation_get_proto_data(conv, proto_iap);
560 if (iap_conv->iap_query_frame == pinfo->fd->num)
565 if (iap_conv->pnext == NULL)
567 iap_conv->pnext = g_mem_chunk_alloc(iap_conv_chunk);
568 iap_conv = iap_conv->pnext;
571 iap_conv = iap_conv->pnext;
576 conv = conversation_new(pinfo->fd->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
577 iap_conv = g_mem_chunk_alloc(iap_conv_chunk);
578 conversation_add_proto_data(conv, proto_iap, (void*)iap_conv);
581 /* Dissect IAP query if it is new */
585 char class_name[256];
589 iap_conv->pnext = NULL;
590 iap_conv->iap_query_frame = pinfo->fd->num;
591 iap_conv->pattr_dissector = NULL;
593 tvb_memcpy(tvb, class_name, offset + 1 + 1, clen);
594 class_name[clen] = 0;
595 tvb_memcpy(tvb, attr_name, offset + 1 + 1 + clen + 1, alen);
598 /* Find the attribute dissector */
599 for (i = 0; class_dissector[i].class_name != NULL; i++)
600 if (strcmp(class_name, class_dissector[i].class_name) == 0)
602 for (j = 0; class_dissector[i].pattr_dissector[j].attr_name != NULL; j++)
603 if (strcmp(attr_name, class_dissector[i].pattr_dissector[j].attr_name) == 0)
605 iap_conv->pattr_dissector = &class_dissector[i].pattr_dissector[j];
612 if (check_col(pinfo->cinfo, COL_INFO))
617 col_add_str(pinfo->cinfo, COL_INFO, "GetValueByClass: \"");
619 tvb_memcpy(tvb, buf, offset + 1 + 1, clen);
620 memcpy(&buf[clen], "\" \"", 3);
621 tvb_memcpy(tvb, buf + clen + 3, offset + 1 + 1 + clen + 1, alen);
622 buf[clen + 3 + alen] = '\"';
623 buf[clen + 3 + alen + 1] = 0;
624 col_append_str(pinfo->cinfo, COL_INFO, buf);
630 /* create display subtree for the protocol */
631 proto_item* ti = proto_tree_add_item(root, proto_iap, tvb, 0, -1, FALSE);
632 proto_tree* tree = proto_item_add_subtree(ti, ett_iap);
634 proto_tree* ctl_tree;
637 ti = proto_tree_add_item(tree, hf_iap_ctl, tvb, offset, 1, FALSE);
638 ctl_tree = proto_item_add_subtree(ti, ett_iap_ctl);
639 proto_tree_add_item(ctl_tree, hf_iap_ctl_lst, tvb, offset, 1, FALSE);
640 proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, FALSE);
641 proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, FALSE);
646 case GET_VALUE_BY_CLASS:
647 proto_tree_add_item(tree, hf_iap_class_name, tvb, offset, 1, FALSE);
650 proto_tree_add_item(tree, hf_iap_attr_name, tvb, offset, 1, FALSE);
660 case GET_VALUE_BY_CLASS:
661 offset += 1 + clen + 1 + alen;
666 /* If any bytes remain, send it to the generic data dissector */
667 tvb = tvb_new_subset(tvb, offset, -1, -1);
668 call_dissector(data_handle, tvb, pinfo, root);
675 static void dissect_iap_result(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
678 unsigned len = tvb_length(tvb);
689 conversation_t* conv;
690 iap_conversation_t* cur_iap_conv;
691 iap_conversation_t* iap_conv = NULL;
695 if (tvb_length(tvb) == 0)
698 /* Make entries in Protocol column on summary display */
699 if (check_col(pinfo->cinfo, COL_PROTOCOL))
700 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAP");
702 op = tvb_get_guint8(tvb, offset) & IAP_OP;
703 retcode = tvb_get_guint8(tvb, offset + 1);
705 src = pinfo->circuit_id ^ CMD_FRAME;
706 srcaddr.type = AT_NONE;
708 srcaddr.data = (guint8*)&src;
710 destaddr.type = AT_NONE;
712 destaddr.data = (guint8*)&pinfo->circuit_id;
714 /* Find result value dissector */
715 conv = find_conversation(pinfo->fd->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
718 num = pinfo->fd->num;
720 iap_conv = (iap_conversation_t*)conversation_get_proto_data(conv, proto_iap);
721 while (iap_conv && (iap_conv->iap_query_frame >= num))
722 iap_conv = iap_conv->pnext;
726 cur_iap_conv = iap_conv->pnext;
729 if ((cur_iap_conv->iap_query_frame < num) &&
730 (cur_iap_conv->iap_query_frame > iap_conv->iap_query_frame))
732 iap_conv = cur_iap_conv;
735 cur_iap_conv = cur_iap_conv->pnext;
740 if (check_col(pinfo->cinfo, COL_INFO))
742 col_add_str(pinfo->cinfo, COL_INFO, "Result: ");
743 col_append_str(pinfo->cinfo, COL_INFO, val_to_str(retcode, iap_return_vals, "0x%02X"));
747 case GET_VALUE_BY_CLASS:
751 switch (tvb_get_guint8(tvb, offset + 6))
754 g_snprintf(buf, 300, ", Missing");
758 g_snprintf(buf, 300, ", Integer: %d", tvb_get_ntohl(tvb, offset + 7));
762 g_snprintf(buf, 300, ", %d Octets", tvb_get_ntohs(tvb, offset + 7));
766 n = tvb_get_guint8(tvb, offset + 8);
767 string = tvb_get_ephemeral_string(tvb, offset + 9, n);
768 g_snprintf(buf, 300, ", \"%s\"", string);
771 col_append_str(pinfo->cinfo, COL_INFO, buf);
772 if (tvb_get_ntohs(tvb, offset + 2) > 1)
773 col_append_str(pinfo->cinfo, COL_INFO, ", ...");
781 /* create display subtree for the protocol */
782 proto_item* ti = proto_tree_add_item(root, proto_iap, tvb, 0, -1, FALSE);
783 proto_tree* tree = proto_item_add_subtree(ti, ett_iap);
785 proto_tree* ctl_tree;
786 proto_tree* entry_tree;
789 ti = proto_tree_add_item(tree, hf_iap_ctl, tvb, offset, 1, FALSE);
790 ctl_tree = proto_item_add_subtree(ti, ett_iap_ctl);
791 proto_tree_add_item(ctl_tree, hf_iap_ctl_lst, tvb, offset, 1, FALSE);
792 proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, FALSE);
793 proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, FALSE);
796 proto_tree_add_item(tree, hf_iap_return, tvb, offset, 1, FALSE);
801 case GET_VALUE_BY_CLASS:
804 list_len = tvb_get_ntohs(tvb, offset);
806 proto_tree_add_item(tree, hf_iap_list_len, tvb, offset, 2, FALSE);
809 while ((offset < len) && (n < list_len))
811 type = tvb_get_guint8(tvb, offset + 2);
819 attr_len = tvb_get_ntohs(tvb, offset + 2 + 1) + 2;
823 attr_len = tvb_get_guint8(tvb, offset + 2 + 1 + 1) + 2;
830 ti = proto_tree_add_item(tree, hf_iap_list_entry, tvb, offset, 2 + 1 + attr_len, FALSE);
831 proto_item_append_text(ti, "%d", n + 1);
832 entry_tree = proto_item_add_subtree(ti, ett_iap_entry[n]);
834 proto_tree_add_item(entry_tree, hf_iap_obj_id, tvb, offset, 2, FALSE);
837 proto_tree_add_item(entry_tree, hf_iap_attr_type, tvb, offset, 1, FALSE);
843 if (!iap_conv || !iap_conv->pattr_dissector ||
844 !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
846 proto_tree_add_item(entry_tree, hf_iap_int, tvb, offset, 4, FALSE);
850 proto_tree_add_item(entry_tree, hf_iap_seq_len, tvb, offset, 2, FALSE);
851 if (!iap_conv || !iap_conv->pattr_dissector ||
852 !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
854 proto_tree_add_item(entry_tree, hf_iap_oct_seq, tvb, offset + 2,
855 attr_len - 2, FALSE);
859 proto_tree_add_item(entry_tree, hf_iap_char_set, tvb, offset, 1, FALSE);
860 if (!iap_conv || !iap_conv->pattr_dissector ||
861 !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
863 proto_tree_add_item(entry_tree, hf_iap_string, tvb, offset + 1, 1, FALSE);
879 case GET_VALUE_BY_CLASS:
887 type = tvb_get_guint8(tvb, offset);
894 if (iap_conv && iap_conv->pattr_dissector)
895 iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
900 attr_len = tvb_get_ntohs(tvb, offset) + 2;
901 if (iap_conv && iap_conv->pattr_dissector)
902 iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
907 attr_len = tvb_get_guint8(tvb, offset + 1) + 2;
908 if (iap_conv && iap_conv->pattr_dissector)
909 iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
924 /* If any bytes remain, send it to the generic data dissector */
925 tvb = tvb_new_subset(tvb, offset, -1, -1);
926 call_dissector(data_handle, tvb, pinfo, root);
931 * Check if IAP result is octet sequence
933 gboolean check_iap_octet_result(tvbuff_t* tvb, proto_tree* tree, unsigned offset,
934 const char* attr_name, guint8 attr_type)
936 if (attr_type != IAS_OCT_SEQ)
940 proto_item* ti = proto_tree_add_item(tree, hf_iap_invaloctet, tvb, offset, 0, FALSE);
941 proto_item_append_text(ti, "%s", attr_name);
942 proto_item_append_text(ti, "\" attribute must be octet sequence!");
953 * Check if IAP result is correct LsapSel
955 guint8 check_iap_lsap_result(tvbuff_t* tvb, proto_tree* tree, unsigned offset,
956 const char* attr_name, guint8 attr_type)
961 if ((attr_type != IAS_INTEGER) || ((lsap = tvb_get_ntohl(tvb, offset)) < 0x01) ||
966 proto_item* ti = proto_tree_add_item(tree, hf_iap_invallsap, tvb, offset, 0, FALSE);
967 proto_item_append_text(ti, "%s", attr_name);
968 proto_item_append_text(ti, "\" attribute must be integer value between 0x01 and 0x6F!");
979 * Dissect IrDA application protocol
981 static void dissect_appl_proto(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, pdu_type_t pdu_type)
987 conversation_t* conv;
988 lmp_conversation_t* cur_lmp_conv;
989 lmp_conversation_t* lmp_conv = NULL;
993 src = pinfo->circuit_id ^ CMD_FRAME;
994 srcaddr.type = AT_NONE;
996 srcaddr.data = (guint8*)&src;
998 destaddr.type = AT_NONE;
1000 destaddr.data = (guint8*)&pinfo->circuit_id;
1002 /* Find result value dissector */
1003 conv = find_conversation(pinfo->fd->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
1006 num = pinfo->fd->num;
1008 lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
1009 while (lmp_conv && (lmp_conv->iap_result_frame >= num))
1010 lmp_conv = lmp_conv->pnext;
1014 cur_lmp_conv = lmp_conv->pnext;
1015 while (cur_lmp_conv)
1017 if ((cur_lmp_conv->iap_result_frame < num) &&
1018 (cur_lmp_conv->iap_result_frame > lmp_conv->iap_result_frame))
1020 lmp_conv = cur_lmp_conv;
1023 cur_lmp_conv = cur_lmp_conv->pnext;
1030 /*g_message("%x:%d->%x:%d = %p\n", src, pinfo->srcport, pinfo->circuit_id, pinfo->destport, lmp_conv); */
1031 /*g_message("->%d: %d %d %p\n", pinfo->fd->num, lmp_conv->iap_result_frame, lmp_conv->ttp, lmp_conv->proto_dissector); */
1032 if ((lmp_conv->ttp) && (pdu_type != DISCONNECT_PDU))
1034 offset += dissect_ttp(tvb, pinfo, root, (pdu_type == DATA_PDU));
1036 tvb = tvb_new_subset(tvb, offset, -1, -1);
1039 pinfo->private_data = (void *)pdu_type;
1041 lmp_conv->proto_dissector(tvb, pinfo, root);
1044 call_dissector(data_handle, tvb, pinfo, root);
1051 static void dissect_irlmp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1053 unsigned offset = 0;
1060 /* Make entries in Protocol column on summary display */
1061 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1062 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLMP");
1064 dlsap = tvb_get_guint8(tvb, offset);
1065 cbit = dlsap & CONTROL_BIT;
1066 dlsap &= ~CONTROL_BIT;
1068 slsap = tvb_get_guint8(tvb, offset+1) & ~CONTROL_BIT;
1070 /* save Lsaps in pinfo */
1071 pinfo->srcport = slsap;
1072 pinfo->destport = dlsap;
1076 opcode = tvb_get_guint8(tvb, offset+2);
1078 if (check_col(pinfo->cinfo, COL_INFO))
1080 col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, ", slsap, dlsap);
1081 col_append_str(pinfo->cinfo, COL_INFO, val_to_str(opcode, lmp_opcode_vals, "0x%02X"));
1082 if ((opcode == ACCESSMODE_CMD) || (opcode == ACCESSMODE_CNF))
1084 col_append_str(pinfo->cinfo, COL_INFO, " (");
1085 col_append_str(pinfo->cinfo, COL_INFO,
1086 val_to_str(tvb_get_guint8(tvb, offset+4), lmp_mode_vals, "0x%02X"));
1087 col_append_str(pinfo->cinfo, COL_INFO, ")");
1092 if (check_col(pinfo->cinfo, COL_INFO))
1093 col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, Len=%d", slsap, dlsap,
1094 tvb_length(tvb) - 2);
1098 /* create display subtree for the protocol */
1099 proto_item* ti = proto_tree_add_item(root, proto_irlmp, tvb, 0, -1, FALSE);
1100 proto_tree* tree = proto_item_add_subtree(ti, ett_irlmp);
1102 proto_tree* dst_tree;
1103 proto_tree* src_tree;
1106 ti = proto_tree_add_item(tree, hf_lmp_dst, tvb, offset, 1, FALSE);
1107 dst_tree = proto_item_add_subtree(ti, ett_lmp_dst);
1108 proto_tree_add_item(dst_tree, hf_lmp_dst_control, tvb, offset, 1, FALSE);
1109 proto_tree_add_item(dst_tree, hf_lmp_dst_lsap, tvb, offset, 1, FALSE);
1112 ti = proto_tree_add_item(tree, hf_lmp_src, tvb, offset, 1, FALSE);
1113 src_tree = proto_item_add_subtree(ti, ett_lmp_src);
1114 proto_tree_add_item(src_tree, hf_lmp_src_r, tvb, offset, 1, FALSE);
1115 proto_tree_add_item(src_tree, hf_lmp_src_lsap, tvb, offset, 1, FALSE);
1120 proto_tree_add_item(tree, hf_lmp_opcode, tvb, offset, 1, FALSE);
1127 if (offset < tvb_length(tvb))
1129 proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, FALSE);
1135 proto_tree_add_item(tree, hf_lmp_reason, tvb, offset, 1, FALSE);
1139 case ACCESSMODE_CMD:
1140 proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, FALSE);
1143 proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, FALSE);
1147 case ACCESSMODE_CNF:
1148 proto_tree_add_item( tree, hf_lmp_status, tvb, offset, 1, FALSE);
1151 proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, FALSE);
1157 tvb = tvb_new_subset(tvb, offset, -1, -1);
1158 proto_item_set_len(tree, offset);
1171 if (offset < tvb_length(tvb))
1179 case ACCESSMODE_CMD:
1180 case ACCESSMODE_CNF:
1186 tvb = tvb_new_subset(tvb, offset, -1, -1);
1191 if (dlsap == LSAP_IAS)
1192 dissect_iap_request(tvb, pinfo, root);
1193 else if (slsap == LSAP_IAS)
1194 dissect_iap_result(tvb, pinfo, root);
1196 dissect_appl_proto(tvb, pinfo, root, DATA_PDU);
1200 if ((dlsap == LSAP_IAS) || (slsap == LSAP_IAS))
1201 call_dissector(data_handle, tvb, pinfo, root);
1207 dissect_appl_proto(tvb, pinfo, root, CONNECT_PDU);
1211 dissect_appl_proto(tvb, pinfo, root, DISCONNECT_PDU);
1215 call_dissector(data_handle, tvb, pinfo, root);
1222 * Add LMP conversation
1224 void add_lmp_conversation(packet_info* pinfo, guint8 dlsap, gboolean ttp, dissector_t proto_dissector)
1229 conversation_t* conv;
1230 lmp_conversation_t* lmp_conv = NULL;
1233 /*g_message("%d: add_lmp_conversation(%p, %d, %d, %p) = ", pinfo->fd->num, pinfo, dlsap, ttp, proto_dissector); */
1234 srcaddr.type = AT_NONE;
1236 srcaddr.data = (guint8*)&pinfo->circuit_id;
1238 dest = pinfo->circuit_id ^ CMD_FRAME;
1239 destaddr.type = AT_NONE;
1241 destaddr.data = (guint8*)&dest;
1243 conv = find_conversation(pinfo->fd->num, &destaddr, &srcaddr, PT_NONE, dlsap, 0, NO_PORT_B);
1246 lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
1249 /* Does entry already exist? */
1250 if (lmp_conv->iap_result_frame == pinfo->fd->num)
1253 if (lmp_conv->pnext == NULL)
1255 lmp_conv->pnext = g_mem_chunk_alloc(lmp_conv_chunk);
1256 lmp_conv = lmp_conv->pnext;
1259 lmp_conv = lmp_conv->pnext;
1264 conv = conversation_new(pinfo->fd->num, &destaddr, &srcaddr, PT_NONE, dlsap, 0, NO_PORT_B);
1265 lmp_conv = g_mem_chunk_alloc(lmp_conv_chunk);
1266 conversation_add_proto_data(conv, proto_irlmp, (void*)lmp_conv);
1269 lmp_conv->pnext = NULL;
1270 lmp_conv->iap_result_frame = pinfo->fd->num;
1271 lmp_conv->ttp = ttp;
1272 lmp_conv->proto_dissector = proto_dissector;
1274 /*g_message("%p\n", lmp_conv); */
1279 * Dissect Negotiation Parameters
1281 static unsigned dissect_negotiation(tvbuff_t* tvb, proto_tree* tree, unsigned offset)
1289 while (tvb_reported_length_remaining(tvb, offset) > 0)
1291 guint8 p_len = tvb_get_guint8(tvb, offset + 1);
1295 ti = proto_tree_add_item(tree, hf_negotiation_param, tvb, offset, p_len + 2, FALSE);
1296 p_tree = proto_item_add_subtree(ti, ett_param[n]);
1298 pv = tvb_get_guint8(tvb, offset+2);
1301 switch (tvb_get_guint8(tvb, offset))
1304 proto_item_append_text(ti, ": Baud Rate (");
1307 g_strlcat(buf, ", 2400", 256);
1309 g_strlcat(buf, ", 9600", 256);
1311 g_strlcat(buf, ", 19200", 256);
1313 g_strlcat(buf, ", 38400", 256);
1315 g_strlcat(buf, ", 57600", 256);
1317 g_strlcat(buf, ", 115200", 256);
1319 g_strlcat(buf, ", 576000", 256);
1321 g_strlcat(buf, ", 1152000", 256);
1322 if ((p_len > 1) && (tvb_get_guint8(tvb, offset+3) & 0x01))
1323 g_strlcat(buf, ", 4000000", 256);
1325 g_strlcat(buf, " bps)", 256);
1327 proto_item_append_text(ti, "%s", buf+2);
1331 case PI_MAX_TURN_TIME:
1332 proto_item_append_text(ti, ": Maximum Turn Time (");
1335 g_strlcat(buf, ", 500", 256);
1337 g_strlcat(buf, ", 250", 256);
1339 g_strlcat(buf, ", 100", 256);
1341 g_strlcat(buf, ", 50", 256);
1343 g_strlcat(buf, " ms)", 256);
1345 proto_item_append_text(ti, "%s", buf+2);
1350 proto_item_append_text(ti, ": Data Size (");
1353 g_strlcat(buf, ", 64", 256);
1355 g_strlcat(buf, ", 128", 256);
1357 g_strlcat(buf, ", 256", 256);
1359 g_strlcat(buf, ", 512", 256);
1361 g_strlcat(buf, ", 1024", 256);
1363 g_strlcat(buf, ", 2048", 256);
1365 g_strlcat(buf, " bytes)", 256);
1367 proto_item_append_text(ti, "%s", buf+2);
1371 case PI_WINDOW_SIZE:
1372 proto_item_append_text(ti, ": Window Size (");
1375 g_strlcat(buf, ", 1", 256);
1377 g_strlcat(buf, ", 2", 256);
1379 g_strlcat(buf, ", 3", 256);
1381 g_strlcat(buf, ", 4", 256);
1383 g_strlcat(buf, ", 5", 256);
1385 g_strlcat(buf, ", 6", 256);
1387 g_strlcat(buf, ", 7", 256);
1389 g_strlcat(buf, " frame window)", 256);
1391 proto_item_append_text(ti, "%s", buf+2);
1396 proto_item_append_text(ti, ": Additional BOFs (");
1399 g_strlcat(buf, ", 48", 256);
1401 g_strlcat(buf, ", 24", 256);
1403 g_strlcat(buf, ", 12", 256);
1405 g_strlcat(buf, ", 5", 256);
1407 g_strlcat(buf, ", 3", 256);
1409 g_strlcat(buf, ", 2", 256);
1411 g_strlcat(buf, ", 1", 256);
1413 g_strlcat(buf, ", 0", 256);
1415 g_strlcat(buf, " additional BOFs at 115200)", 256);
1417 proto_item_append_text(ti, "%s", buf+2);
1421 case PI_MIN_TURN_TIME:
1422 proto_item_append_text(ti, ": Minimum Turn Time (");
1425 g_strlcat(buf, ", 10", 256);
1427 g_strlcat(buf, ", 5", 256);
1429 g_strlcat(buf, ", 1", 256);
1431 g_strlcat(buf, ", 0.5", 256);
1433 g_strlcat(buf, ", 0.1", 256);
1435 g_strlcat(buf, ", 0.05", 256);
1437 g_strlcat(buf, ", 0.01", 256);
1439 g_strlcat(buf, ", 0", 256);
1441 g_strlcat(buf, " ms)", 256);
1443 proto_item_append_text(ti, "%s", buf+2);
1448 proto_item_append_text(ti, ": Link Disconnect/Threshold Time (");
1451 g_strlcat(buf, ", 3/0", 256);
1453 g_strlcat(buf, ", 8/3", 256);
1455 g_strlcat(buf, ", 12/3", 256);
1457 g_strlcat(buf, ", 16/3", 256);
1459 g_strlcat(buf, ", 20/3", 256);
1461 g_strlcat(buf, ", 25/3", 256);
1463 g_strlcat(buf, ", 30/3", 256);
1465 g_strlcat(buf, ", 40/3", 256);
1467 g_strlcat(buf, " s)", 256);
1469 proto_item_append_text(ti, "%s", buf+2);
1474 proto_item_append_text(ti, ": unknown");
1479 offset = dissect_param_tuple(tvb, p_tree, offset);
1488 * Dissect XID packet
1490 static void dissect_xid(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, proto_tree* lap_tree, gboolean is_command)
1493 proto_item* ti = NULL;
1494 proto_tree* i_tree = NULL;
1495 proto_tree* flags_tree;
1496 guint32 saddr, daddr;
1498 proto_tree* lmp_tree = NULL;
1502 ti = proto_tree_add_item(lap_tree, hf_lap_i, tvb, offset, -1, FALSE);
1503 i_tree = proto_item_add_subtree(ti, ett_lap_i);
1505 proto_tree_add_item(i_tree, hf_xid_ident, tvb, offset, 1, FALSE);
1509 saddr = tvb_get_letohl(tvb, offset);
1510 if (check_col(pinfo->cinfo, COL_DEF_SRC))
1511 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1513 proto_tree_add_uint(i_tree, hf_xid_saddr, tvb, offset, 4, saddr);
1516 daddr = tvb_get_letohl(tvb, offset);
1517 if (check_col(pinfo->cinfo, COL_DEF_DST))
1518 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1520 proto_tree_add_uint(i_tree, hf_xid_daddr, tvb, offset, 4, daddr);
1525 ti = proto_tree_add_item(i_tree, hf_xid_flags, tvb, offset, 1, FALSE);
1526 flags_tree = proto_item_add_subtree(ti, ett_xid_flags);
1527 proto_tree_add_item(flags_tree, hf_xid_s, tvb, offset, 1, FALSE);
1528 proto_tree_add_item(flags_tree, hf_xid_conflict, tvb, offset, 1, FALSE);
1534 s = tvb_get_guint8(tvb, offset);
1535 if (check_col(pinfo->cinfo, COL_INFO))
1538 col_append_str(pinfo->cinfo, COL_INFO, ", s=final");
1540 col_append_fstr(pinfo->cinfo, COL_INFO, ", s=%u", s);
1544 ti = proto_tree_add_uint(i_tree, hf_xid_slotnr, tvb, offset, 1, s);
1546 proto_item_append_text(ti, " (final)");
1552 proto_tree_add_item(i_tree, hf_xid_version, tvb, offset, 1, FALSE);
1557 proto_item_set_end(lap_tree, tvb, offset);
1558 proto_item_set_end(i_tree, tvb, offset);
1561 if (tvb_reported_length_remaining(tvb, offset) > 0)
1569 ti = proto_tree_add_item(root, proto_irlmp, tvb, offset, -1, FALSE);
1570 lmp_tree = proto_item_add_subtree(ti, ett_irlmp);
1573 for (hints_len = 0;;)
1575 guint8 hint = tvb_get_guint8(tvb, offset + hints_len++);
1579 else if (hints_len == 2)
1582 if ((hint & 0x80) == 0)
1588 ti = proto_tree_add_item(lmp_tree, hf_lmp_xid_hints, tvb, offset, hints_len, FALSE);
1589 if ((hint1 | hint2) != 0)
1591 char service_hints[256];
1593 service_hints[0] = 0;
1596 g_strlcat(service_hints, ", PnP Compatible", 256);
1598 g_strlcat(service_hints, ", PDA/Palmtop", 256);
1600 g_strlcat(service_hints, ", Computer", 256);
1602 g_strlcat(service_hints, ", Printer", 256);
1604 g_strlcat(service_hints, ", Modem", 256);
1606 g_strlcat(service_hints, ", Fax", 256);
1608 g_strlcat(service_hints, ", LAN Access", 256);
1610 g_strlcat(service_hints, ", Telephony", 256);
1612 g_strlcat(service_hints, ", File Server", 256);
1614 g_strlcat(service_hints, ", IrCOMM", 256);
1616 g_strlcat(service_hints, ", OBEX", 256);
1618 g_strlcat(service_hints, ")", 256);
1619 service_hints[0] = ' ';
1620 service_hints[1] = '(';
1622 proto_item_append_text(ti, "%s", service_hints);
1625 offset += hints_len;
1627 if (tvb_reported_length_remaining(tvb, offset) > 0)
1632 cset = tvb_get_guint8(tvb, offset);
1634 proto_tree_add_uint(lmp_tree, hf_lmp_xid_charset, tvb, offset, 1, cset);
1636 name_len = tvb_reported_length_remaining(tvb, offset);
1641 if (check_col(pinfo->cinfo, COL_INFO))
1647 tvb_memcpy(tvb, buf, offset, name_len);
1649 col_append_str(pinfo->cinfo, COL_INFO, ", \"");
1650 col_append_str(pinfo->cinfo, COL_INFO, buf);
1651 col_append_str(pinfo->cinfo, COL_INFO, "\"");
1654 proto_tree_add_item(lmp_tree, hf_lmp_xid_name, tvb, offset,
1660 proto_tree_add_item(lmp_tree, hf_lmp_xid_name_no_ascii, tvb, offset,
1670 * Dissect Log Messages
1672 static void dissect_log(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1674 /* Make entries in Protocol column on summary display */
1675 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1676 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Log");
1678 /* missed messages? */
1679 if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1681 if (check_col(pinfo->cinfo, COL_INFO))
1682 col_set_str(pinfo->cinfo, COL_INFO,
1683 "WARNING: Missed one or more messages while capturing!");
1685 else if (check_col(pinfo->cinfo, COL_INFO))
1691 length = tvb_length(tvb);
1692 if (length > sizeof(buf)-1)
1693 length = sizeof(buf)-1;
1694 tvb_memcpy(tvb, buf, 0, length);
1696 if (buf[length-1] == '\n')
1698 else if (buf[length-2] == '\n')
1701 col_add_str(pinfo->cinfo, COL_INFO, buf);
1706 proto_item* ti = proto_tree_add_item(root, proto_log, tvb, 0, -1, FALSE);
1707 proto_tree* tree = proto_item_add_subtree(ti, ett_log);
1709 if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1710 proto_tree_add_item(tree, hf_log_missed, tvb, 0, 0, FALSE);
1712 proto_tree_add_item(tree, hf_log_msg, tvb, 0, -1, FALSE);
1720 static void dissect_irlap(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1724 gboolean is_response;
1726 proto_item* ti = NULL;
1727 proto_tree* tree = NULL;
1728 proto_tree* i_tree = NULL;
1729 guint32 saddr, daddr;
1732 /* Make entries in Protocol column on summary display */
1733 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1734 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLAP");
1736 /* Clear Info column */
1737 if (check_col(pinfo->cinfo, COL_INFO))
1738 col_clear(pinfo->cinfo, COL_INFO);
1740 /* set direction column */
1741 if (check_col(pinfo->cinfo, COL_IF_DIR))
1743 switch (pinfo->pseudo_header->irda.pkttype)
1746 col_set_str(pinfo->cinfo, COL_IF_DIR, "Out");
1750 col_set_str(pinfo->cinfo, COL_IF_DIR, "In");
1755 /* decode values used for demuxing */
1756 a = tvb_get_guint8(tvb, 0);
1758 /* save connection address field in pinfo */
1759 pinfo->circuit_id = a;
1761 /* initially set address columns to connection address */
1762 g_snprintf(addr, sizeof(addr)-1, "0x%02X", a >> 1);
1763 if (check_col(pinfo->cinfo, COL_DEF_SRC))
1764 col_add_str(pinfo->cinfo, COL_DEF_SRC, addr);
1765 if (check_col(pinfo->cinfo, COL_DEF_DST))
1766 col_add_str(pinfo->cinfo, COL_DEF_DST, addr);
1771 proto_item* addr_item;
1773 /* create display subtree for the protocol */
1774 ti = proto_tree_add_item(root, proto_irlap, tvb, 0, -1, FALSE);
1775 tree = proto_item_add_subtree(ti, ett_irlap);
1777 /* create subtree for the address field */
1778 ti = proto_tree_add_item(tree, hf_lap_a, tvb, offset, 1, FALSE);
1779 a_tree = proto_item_add_subtree(ti, ett_lap_a);
1780 proto_tree_add_item(a_tree, hf_lap_a_cr, tvb, offset, 1, FALSE);
1781 addr_item = proto_tree_add_item(a_tree, hf_lap_a_address, tvb, offset, 1, FALSE);
1782 switch (a & ~CMD_FRAME)
1785 proto_item_append_text(addr_item, " (NULL Address)");
1788 proto_item_append_text(addr_item, " (Broadcast)");
1792 is_response = ((a & CMD_FRAME) == 0);
1795 /* process the control field */
1796 c = dissect_xdlc_control(tvb, 1, pinfo, tree, hf_lap_c,
1797 ett_lap_c, &irlap_cf_items, NULL, lap_c_u_cmd_abbr_vals,
1798 lap_c_u_rsp_abbr_vals, is_response, FALSE, FALSE);
1801 if ((c & XDLC_I_MASK) == XDLC_I) {
1803 proto_item_set_len(tree, offset);
1804 tvb = tvb_new_subset(tvb, offset, -1, -1);
1805 dissect_irlmp(tvb, pinfo, root);
1809 if ((c & 0x03) == XDLC_U) {
1811 switch (c & XDLC_U_MODIFIER_MASK)
1816 ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, FALSE);
1817 i_tree = proto_item_add_subtree(ti, ett_lap_i);
1820 saddr = tvb_get_letohl(tvb, offset);
1823 if (check_col(pinfo->cinfo, COL_DEF_SRC))
1824 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1827 proto_tree_add_uint(i_tree, hf_snrm_saddr, tvb, offset, 4, saddr);
1830 daddr = tvb_get_letohl(tvb, offset);
1833 if (check_col(pinfo->cinfo, COL_DEF_DST))
1834 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1837 proto_tree_add_uint(i_tree, hf_snrm_daddr, tvb, offset, 4, daddr);
1840 ca = tvb_get_guint8(tvb, offset);
1843 if (check_col(pinfo->cinfo, COL_INFO))
1844 col_append_fstr(pinfo->cinfo, COL_INFO, ", ca=0x%02X",
1848 proto_tree_add_uint(i_tree, hf_snrm_ca, tvb, offset, 1, ca >> 1);
1851 offset = dissect_negotiation(tvb, i_tree, offset);
1853 proto_item_set_end(ti, tvb, offset);
1857 tvb = tvb_new_subset(tvb, offset, -1, -1);
1858 dissect_xid(tvb, pinfo, root, tree, TRUE);
1862 if (tvb_reported_length_remaining(tvb, offset) > 0)
1866 ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, FALSE);
1867 i_tree = proto_item_add_subtree(ti, ett_lap_i);
1870 saddr = tvb_get_letohl(tvb, offset);
1871 if (check_col(pinfo->cinfo, COL_DEF_SRC))
1872 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1874 proto_tree_add_uint(i_tree, hf_ua_saddr, tvb, offset, 4, saddr);
1877 daddr = tvb_get_letohl(tvb, offset);
1878 if (check_col(pinfo->cinfo, COL_DEF_DST))
1879 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1881 proto_tree_add_uint(i_tree, hf_ua_daddr, tvb, offset, 4, daddr);
1884 offset = dissect_negotiation(tvb, i_tree, offset);
1886 proto_item_set_end(ti, tvb, offset);
1891 tvb = tvb_new_subset(tvb, offset, -1, -1);
1892 dissect_xid(tvb, pinfo, root, tree, FALSE);
1897 /* If any bytes remain, send it to the generic data dissector */
1898 if (tvb_reported_length_remaining(tvb, offset) > 0)
1900 tvb = tvb_new_subset(tvb, offset, -1, -1);
1901 call_dissector(data_handle, tvb, pinfo, root);
1907 * Dissect IrDA protocol
1909 static void dissect_irda(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1911 /* load the display labels */
1912 pinfo->current_proto = "IrDA";
1914 /* check if log message */
1915 if ((pinfo->pseudo_header->irda.pkttype & IRDA_CLASS_MASK) == IRDA_CLASS_LOG)
1917 dissect_log(tvb, pinfo, root);
1922 dissect_irlap(tvb, pinfo, root);
1927 * Re-initialize the IrDA dissector
1929 static void init_irda(void)
1932 g_mem_chunk_destroy(iap_conv_chunk);
1934 g_mem_chunk_destroy(lmp_conv_chunk);
1936 iap_conv_chunk = g_mem_chunk_new("iap_conversation", sizeof(iap_conversation_t),
1937 10 * sizeof(iap_conversation_t), G_ALLOC_AND_FREE);
1938 lmp_conv_chunk = g_mem_chunk_new("lmp_conversation", sizeof(lmp_conversation_t),
1939 10 * sizeof(lmp_conversation_t), G_ALLOC_AND_FREE);
1944 * Register the protocol with Wireshark
1945 * This format is required because a script is used to build the C function
1946 * that calls all the protocol registrations.
1948 void proto_register_irda(void)
1952 /* Setup list of header fields */
1953 static hf_register_info hf_lap[] = {
1955 { "Address Field", "irlap.a",
1956 FT_UINT8, BASE_HEX, NULL, 0,
1959 { "C/R", "irlap.a.cr",
1960 FT_BOOLEAN, 8, TFS(&lap_cr_vals), CMD_FRAME,
1962 { &hf_lap_a_address,
1963 { "Address", "irlap.a.address",
1964 FT_UINT8, BASE_HEX, NULL, ~CMD_FRAME,
1967 { "Control Field", "irlap.c",
1968 FT_UINT8, BASE_HEX, NULL, 0,
1971 { "N(R)", "irlap.c.n_r",
1972 FT_UINT8, BASE_DEC, NULL, XDLC_N_R_MASK,
1975 { "N(S)", "irlap.c.n_s",
1976 FT_UINT8, BASE_DEC, NULL, XDLC_N_S_MASK,
1979 { "Poll", "irlap.c.p",
1980 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1983 { "Final", "irlap.c.f",
1984 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1987 { "Supervisory frame type", "irlap.c.s_ftype",
1988 FT_UINT8, BASE_HEX, VALS(lap_c_s_vals), XDLC_S_FTYPE_MASK,
1991 { "Command", "irlap.c.u_modifier_cmd",
1992 FT_UINT8, BASE_HEX, VALS(lap_c_u_cmd_vals), XDLC_U_MODIFIER_MASK,
1995 { "Response", "irlap.c.u_modifier_resp",
1996 FT_UINT8, BASE_HEX, VALS(lap_c_u_rsp_vals), XDLC_U_MODIFIER_MASK,
1999 { "Frame Type", "irlap.c.ftype",
2000 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_I_MASK,
2003 { "Frame Type", "irlap.c.ftype",
2004 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_S_U_MASK,
2007 { "Information Field", "irlap.i",
2008 FT_NONE, BASE_NONE, NULL, 0,
2011 { "Source Device Address", "irlap.snrm.saddr",
2012 FT_UINT32, BASE_HEX, NULL, 0,
2015 { "Destination Device Address", "irlap.snrm.daddr",
2016 FT_UINT32, BASE_HEX, NULL, 0,
2019 { "Connection Address", "irlap.snrm.ca",
2020 FT_UINT8, BASE_HEX, NULL, 0,
2022 { &hf_negotiation_param,
2023 { "Negotiation Parameter", "irlap.negotiation",
2024 FT_NONE, BASE_NONE, NULL, 0,
2027 { "Parameter Identifier", "irlap.pi",
2028 FT_UINT8, BASE_HEX, NULL, 0,
2031 { "Parameter Length", "irlap.pl",
2032 FT_UINT8, BASE_HEX, NULL, 0,
2035 { "Parameter Value", "irlap.pv",
2036 FT_BYTES, BASE_HEX, NULL, 0,
2039 { "Source Device Address", "irlap.ua.saddr",
2040 FT_UINT32, BASE_HEX, NULL, 0,
2043 { "Destination Device Address", "irlap.ua.daddr",
2044 FT_UINT32, BASE_HEX, NULL, 0,
2047 { "Format Identifier", "irlap.xid.fi",
2048 FT_UINT8, BASE_HEX, NULL, 0,
2051 { "Source Device Address", "irlap.xid.saddr",
2052 FT_UINT32, BASE_HEX, NULL, 0,
2055 { "Destination Device Address", "irlap.xid.daddr",
2056 FT_UINT32, BASE_HEX, NULL, 0,
2059 { "Discovery Flags", "irlap.xid.flags",
2060 FT_UINT8, BASE_HEX, NULL, 0,
2063 { "Number of Slots", "irlap.xid.s",
2064 FT_UINT8, BASE_DEC, VALS(&xid_slot_numbers), S_MASK,
2067 { "Conflict", "irlap.xid.conflict",
2068 FT_BOOLEAN, 8, TFS(&set_notset), CONFLICT,
2071 { "Slot Number", "irlap.xid.slotnr",
2072 FT_UINT8, BASE_DEC, NULL, 0,
2075 { "Version Number", "irlap.xid.version",
2076 FT_UINT8, BASE_HEX, NULL, 0,
2080 static hf_register_info hf_log[] = {
2082 { "Message", "log.msg",
2083 FT_STRING, BASE_NONE, NULL, 0,
2086 { "WARNING: Missed one or more messages while capturing!", "log.missed",
2087 FT_NONE, BASE_NONE, NULL, 0,
2091 static hf_register_info hf_lmp[] = {
2092 { &hf_lmp_xid_hints,
2093 { "Service Hints", "irlmp.xid.hints",
2094 FT_BYTES, BASE_HEX, NULL, 0,
2096 { &hf_lmp_xid_charset,
2097 { "Character Set", "irlmp.xid.charset",
2098 FT_UINT8, BASE_HEX, NULL, 0,
2101 { "Device Nickname", "irlmp.xid.name",
2102 FT_STRING, BASE_NONE, NULL, 0,
2104 { &hf_lmp_xid_name_no_ascii,
2105 { "Device Nickname (unsupported character set)", "irlmp.xid.name",
2106 FT_BYTES, BASE_NONE, NULL, 0,
2109 { "Destination", "irlmp.dst",
2110 FT_UINT8, BASE_HEX, NULL, 0,
2112 { &hf_lmp_dst_control,
2113 { "Control Bit", "irlmp.dst.c",
2114 FT_BOOLEAN, 8, TFS(&set_notset), CONTROL_BIT,
2117 { "Destination LSAP", "irlmp.dst.lsap",
2118 FT_UINT8, BASE_DEC, NULL, ~CONTROL_BIT,
2121 { "Source", "irlmp.src",
2122 FT_UINT8, BASE_HEX, NULL, 0,
2125 { "reserved", "irlmp.src.r",
2126 FT_UINT8, BASE_DEC, NULL, RESERVED_BIT,
2129 { "Source LSAP", "irlmp.src.lsap",
2130 FT_UINT8, BASE_DEC, NULL, ~RESERVED_BIT,
2133 { "Opcode", "irlmp.opcode",
2134 FT_UINT8, BASE_HEX, VALS(lmp_opcode_vals), 0x0,
2137 { "Reserved", "irlmp.rsvd",
2138 FT_UINT8, BASE_HEX, NULL, 0x0,
2141 { "Reason", "irlmp.reason",
2142 FT_UINT8, BASE_HEX, VALS(lmp_reason_vals), 0x0,
2145 { "Mode", "irlmp.mode",
2146 FT_UINT8, BASE_HEX, VALS(lmp_mode_vals), 0x0,
2149 { "Status", "irlmp.status",
2150 FT_UINT8, BASE_HEX, VALS(lmp_status_vals), 0x0,
2154 static hf_register_info hf_iap[] = {
2156 { "Control Field", "iap.ctl",
2157 FT_UINT8, BASE_HEX, NULL, 0,
2160 { "Last Frame", "iap.ctl.lst",
2161 FT_BOOLEAN, 8, TFS(&set_notset), IAP_LST,
2164 { "Acknowledge", "iap.ctl.ack",
2165 FT_BOOLEAN, 8, TFS(&set_notset), IAP_ACK,
2167 { &hf_iap_ctl_opcode,
2168 { "Opcode", "iap.ctl.opcode",
2169 FT_UINT8, BASE_HEX, VALS(iap_opcode_vals), IAP_OP,
2171 { &hf_iap_class_name,
2172 { "Class Name", "iap.classname",
2173 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2175 { &hf_iap_attr_name,
2176 { "Attribute Name", "iap.attrname",
2177 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2180 { "Return", "iap.return",
2181 FT_UINT8, BASE_HEX, VALS(iap_return_vals), 0x0,
2184 { "List Length", "iap.listlen",
2185 FT_UINT16, BASE_DEC, NULL, 0x0,
2187 { &hf_iap_list_entry,
2188 { "List Entry ", "iap.listentry",
2189 FT_NONE, BASE_NONE, NULL, 0x0,
2192 { "Object Identifier", "iap.objectid",
2193 FT_UINT16, BASE_HEX, NULL, 0x0,
2195 { &hf_iap_attr_type,
2196 { "Type", "iap.attrtype",
2197 FT_UINT8, BASE_DEC, VALS(iap_attr_type_vals), 0x0,
2200 { "Value", "iap.int",
2201 FT_INT32, BASE_DEC, NULL, 0x0,
2204 { "Sequence Length", "iap.seqlen",
2205 FT_UINT16, BASE_DEC, NULL, 0x0,
2208 { "Sequence", "iap.octseq",
2209 FT_BYTES, BASE_HEX, NULL, 0x0,
2212 { "Character Set", "iap.charset",
2213 FT_UINT8, BASE_HEX, NULL, 0x0,
2216 { "String", "iap.string",
2217 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2219 { &hf_iap_invaloctet,
2220 { "Malformed IAP result: \"", "iap.invaloctet",
2221 FT_NONE, BASE_NONE, NULL, 0,
2223 { &hf_iap_invallsap,
2224 { "Malformed IAP result: \"", "iap.invallsap",
2225 FT_NONE, BASE_NONE, NULL, 0,
2229 static hf_register_info hf_ttp[] = {
2231 { "Parameter Bit", "ttp.p",
2232 FT_BOOLEAN, 8, TFS(&set_notset), TTP_PARAMETERS,
2235 { "Initial Credit", "ttp.icredit",
2236 FT_UINT8, BASE_DEC, NULL, ~TTP_PARAMETERS,
2239 { "More Bit", "ttp.m",
2240 FT_BOOLEAN, 8, TFS(&set_notset), TTP_MORE,
2243 { "Delta Credit", "ttp.dcredit",
2244 FT_UINT8, BASE_DEC, NULL, ~TTP_MORE,
2248 /* Setup protocol subtree arrays */
2249 static gint* ett[] = {
2264 static gint* ett_p[MAX_PARAMETERS];
2265 static gint* ett_iap_e[MAX_IAP_ENTRIES];
2268 /* Register re-init routine */
2269 register_init_routine(init_irda);
2271 /* Register protocol names and descriptions */
2272 proto_irlap = proto_register_protocol("IrDA Link Access Protocol", "IrLAP", "irlap");
2273 proto_log = proto_register_protocol("Log Message", "Log", "log");
2274 proto_irlmp = proto_register_protocol("IrDA Link Management Protocol", "IrLMP", "irlmp");
2275 proto_iap = proto_register_protocol("Information Access Protocol", "IAP", "iap");
2276 proto_ttp = proto_register_protocol("Tiny Transport Protocol", "TTP", "ttp");
2278 /* Register the dissector */
2279 register_dissector("irda", dissect_irda, proto_irlap);
2281 /* Required function calls to register the header fields */
2282 proto_register_field_array(proto_irlap, hf_lap, array_length(hf_lap));
2283 proto_register_field_array(proto_log, hf_log, array_length(hf_log));
2284 proto_register_field_array(proto_irlmp, hf_lmp, array_length(hf_lmp));
2285 proto_register_field_array(proto_iap, hf_iap, array_length(hf_iap));
2286 proto_register_field_array(proto_ttp, hf_ttp, array_length(hf_ttp));
2288 /* Register subtrees */
2289 proto_register_subtree_array(ett, array_length(ett));
2290 for (i = 0; i < MAX_PARAMETERS; i++)
2293 ett_p[i] = &ett_param[i];
2295 proto_register_subtree_array(ett_p, MAX_PARAMETERS);
2296 for (i = 0; i < MAX_IAP_ENTRIES; i++)
2298 ett_iap_entry[i] = -1;
2299 ett_iap_e[i] = &ett_iap_entry[i];
2301 proto_register_subtree_array(ett_iap_e, MAX_IAP_ENTRIES);
2305 /* If this dissector uses sub-dissector registration add a registration routine.
2306 This format is required because a script is used to find these routines and
2307 create the code that calls these routines.
2310 void proto_reg_handoff_irda(void)
2312 dissector_handle_t irda_handle;
2314 irda_handle = find_dissector("irda");
2315 dissector_add("wtap_encap", WTAP_ENCAP_IRDA, irda_handle);
2316 data_handle = find_dissector("data");