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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include <epan/packet.h>
36 #include <epan/conversation.h>
37 #include <epan/wmem/wmem.h>
38 #include <epan/xdlc.h>
40 #include "irda-appl.h"
41 #include <epan/dissectors/packet-sll.h>
44 * This plugin dissects infrared data transmissions as defined by the IrDA
45 * specification (www.irda.org). See
47 * http://www.irda.org/standards/specifications.asp
49 * for various IrDA specifications.
51 * The plugin operates both offline with libpcap files and online on supported
52 * platforms. Live dissection is currently available for Linux-IrDA
53 * (irda.sourceforge.net) and for Windows if the Linux-IrDA port IrCOMM2k
54 * (www.ircomm2k.de) is installed.
61 /* Frame types and templates */
65 * XXX - the IrDA spec gives XID as 0x2c; HDLC (and other HDLC-derived
66 * protocolc) use 0xAC.
68 #define IRDA_XID_CMD 0x2c /* Exchange Station Identification */
70 #define CMD_FRAME 0x01
71 #define RSP_FRAME 0x00
77 /* Negotiation Parameters */
78 #define PI_BAUD_RATE 0x01
79 #define PI_MAX_TURN_TIME 0x82
80 #define PI_DATA_SIZE 0x83
81 #define PI_WINDOW_SIZE 0x84
82 #define PI_ADD_BOFS 0x85
83 #define PI_MIN_TURN_TIME 0x86
84 #define PI_LINK_DISC 0x08
91 /* IrLMP frame opcodes */
92 #define CONNECT_CMD 0x01
93 #define CONNECT_CNF 0x81
94 #define DISCONNECT 0x02
95 #define ACCESSMODE_CMD 0x03
96 #define ACCESSMODE_CNF 0x83
98 #define CONTROL_BIT 0x80
99 #define RESERVED_BIT 0x80
102 #define LSAP_MASK 0x7f
103 #define LSAP_IAS 0x00
104 #define LSAP_ANY 0xff
105 #define LSAP_MAX 0x6f /* 0x70-0x7f are reserved */
106 #define LSAP_CONNLESS 0x70 /* Connectionless LSAP, mostly used for Ultra */
114 #define GET_INFO_BASE 0x01
115 #define GET_OBJECTS 0x02
116 #define GET_VALUE 0x03
117 #define GET_VALUE_BY_CLASS 0x04
118 #define GET_OBJECT_INFO 0x05
119 #define GET_ATTRIB_NAMES 0x06
125 #define IAS_SUCCESS 0
126 #define IAS_CLASS_UNKNOWN 1
127 #define IAS_ATTRIB_UNKNOWN 2
128 #define IAS_ATTR_TOO_LONG 3
129 #define IAS_DISCONNECT 10
130 #define IAS_UNSUPPORTED 0xFF
137 #define TTP_PARAMETERS 0x80
138 #define TTP_MORE 0x80
140 static dissector_handle_t data_handle
;
142 /* Initialize the protocol and registered fields */
143 static int proto_irlap
= -1;
144 static int hf_lap_a
= -1;
145 static int hf_lap_a_cr
= -1;
146 static int hf_lap_a_address
= -1;
147 static int hf_lap_c
= -1;
148 static int hf_lap_c_nr
= -1;
149 static int hf_lap_c_ns
= -1;
150 static int hf_lap_c_p
= -1;
151 static int hf_lap_c_f
= -1;
152 static int hf_lap_c_s
= -1;
153 static int hf_lap_c_u_cmd
= -1;
154 static int hf_lap_c_u_rsp
= -1;
155 static int hf_lap_c_i
= -1;
156 static int hf_lap_c_s_u
= -1;
157 static int hf_lap_i
= -1;
158 static int hf_snrm_saddr
= -1;
159 static int hf_snrm_daddr
= -1;
160 static int hf_snrm_ca
= -1;
161 static int hf_ua_saddr
= -1;
162 static int hf_ua_daddr
= -1;
163 static int hf_negotiation_param
= -1;
164 static int hf_param_pi
= -1;
165 static int hf_param_pl
= -1;
166 static int hf_param_pv
= -1;
167 static int hf_xid_ident
= -1;
168 static int hf_xid_saddr
= -1;
169 static int hf_xid_daddr
= -1;
170 static int hf_xid_flags
= -1;
171 static int hf_xid_s
= -1;
172 static int hf_xid_conflict
= -1;
173 static int hf_xid_slotnr
= -1;
174 static int hf_xid_version
= -1;
176 static int proto_irlmp
= -1;
177 static int hf_lmp_xid_hints
= -1;
178 static int hf_lmp_xid_charset
= -1;
179 static int hf_lmp_xid_name
= -1;
180 static int hf_lmp_xid_name_no_ascii
= -1;
181 static int hf_lmp_dst
= -1;
182 static int hf_lmp_dst_control
= -1;
183 static int hf_lmp_dst_lsap
= -1;
184 static int hf_lmp_src
= -1;
185 static int hf_lmp_src_r
= -1;
186 static int hf_lmp_src_lsap
= -1;
187 static int hf_lmp_opcode
= -1;
188 static int hf_lmp_rsvd
= -1;
189 static int hf_lmp_reason
= -1;
190 static int hf_lmp_mode
= -1;
191 static int hf_lmp_status
= -1;
193 static int proto_iap
= -1;
194 static int hf_iap_ctl
= -1;
195 static int hf_iap_ctl_lst
= -1;
196 static int hf_iap_ctl_ack
= -1;
197 static int hf_iap_ctl_opcode
= -1;
198 static int hf_iap_class_name
= -1;
199 static int hf_iap_attr_name
= -1;
200 static int hf_iap_return
= -1;
201 static int hf_iap_list_len
= -1;
202 static int hf_iap_list_entry
= -1;
203 static int hf_iap_obj_id
= -1;
204 static int hf_iap_attr_type
= -1;
205 static int hf_iap_int
= -1;
206 static int hf_iap_seq_len
= -1;
207 static int hf_iap_oct_seq
= -1;
208 static int hf_iap_char_set
= -1;
209 static int hf_iap_string
= -1;
210 static int hf_iap_invaloctet
= -1;
211 static int hf_iap_invallsap
= -1;
213 static int proto_ttp
= -1;
214 static int hf_ttp_p
= -1;
215 static int hf_ttp_icredit
= -1;
216 static int hf_ttp_m
= -1;
217 static int hf_ttp_dcredit
= -1;
219 static int proto_log
= -1;
220 static int hf_log_msg
= -1;
221 static int hf_log_missed
= -1;
223 /* Initialize the subtree pointers */
224 static gint ett_irlap
= -1;
225 static gint ett_lap_a
= -1;
226 static gint ett_lap_c
= -1;
227 static gint ett_lap_i
= -1;
228 static gint ett_xid_flags
= -1;
229 static gint ett_log
= -1;
230 static gint ett_irlmp
= -1;
231 static gint ett_lmp_dst
= -1;
232 static gint ett_lmp_src
= -1;
233 static gint ett_iap
= -1;
234 static gint ett_iap_ctl
= -1;
235 static gint ett_ttp
= -1;
237 #define MAX_PARAMETERS 32
238 static gint ett_param
[MAX_PARAMETERS
];
240 static gint ett_iap_entry
[MAX_IAP_ENTRIES
];
242 static const xdlc_cf_items irlap_cf_items
= {
254 /* IAP conversation type */
255 typedef struct iap_conversation
{
256 struct iap_conversation
* pnext
;
257 guint32 iap_query_frame
;
258 ias_attr_dissector_t
* pattr_dissector
;
259 } iap_conversation_t
;
261 /* IrLMP conversation type */
262 typedef struct lmp_conversation
{
263 struct lmp_conversation
* pnext
;
264 guint32 iap_result_frame
;
266 dissector_t proto_dissector
;
267 } lmp_conversation_t
;
269 static const true_false_string lap_cr_vals
= {
274 static const true_false_string set_notset
= {
279 static const value_string lap_c_ftype_vals
[] = {
280 { XDLC_I
, "Information frame" },
281 { XDLC_S
, "Supervisory frame" },
282 { XDLC_U
, "Unnumbered frame" },
286 static const value_string lap_c_u_cmd_abbr_vals
[] = {
287 { XDLC_SNRM
, "SNRM" },
288 { XDLC_DISC
, "DISC" },
290 { IRDA_XID_CMD
, "XID" },
291 { XDLC_TEST
, "TEST" },
295 static const value_string lap_c_u_rsp_abbr_vals
[] = {
296 { XDLC_SNRM
, "RNRM" },
298 { XDLC_FRMR
, "FRMR" },
303 { XDLC_TEST
, "TEST" },
307 static const value_string lap_c_u_cmd_vals
[] = {
308 { XDLC_SNRM
>>2, "Set Normal Response Mode" },
309 { XDLC_DISC
>>2, "Disconnect" },
310 { XDLC_UI
>>2, "Unnumbered Information" },
311 { IRDA_XID_CMD
>>2, "Exchange Station Identification" },
312 { XDLC_TEST
>>2, "Test" },
316 static const value_string lap_c_u_rsp_vals
[] = {
317 { XDLC_SNRM
>>2, "Request Normal Response Mode" },
318 { XDLC_UA
>>2, "Unnumbered Acknowledge" },
319 { XDLC_FRMR
>>2, "Frame Reject" },
320 { XDLC_DM
>>2, "Disconnect Mode" },
321 { XDLC_RD
>>2, "Request Disconnect" },
322 { XDLC_UI
>>2, "Unnumbered Information" },
323 { XDLC_XID
>>2, "Exchange Station Identification" },
324 { XDLC_TEST
>>2, "Test" },
328 static const value_string lap_c_s_vals
[] = {
329 { XDLC_RR
>>2, "Receiver ready" },
330 { XDLC_RNR
>>2, "Receiver not ready" },
331 { XDLC_REJ
>>2, "Reject" },
332 { XDLC_SREJ
>>2, "Selective reject" },
336 static const value_string xid_slot_numbers
[] = {
337 /* Number of XID slots */
345 static const value_string lmp_opcode_vals
[] = {
346 /* IrLMP frame opcodes */
347 { CONNECT_CMD
, "Connect Command" },
348 { CONNECT_CNF
, "Connect Confirm" },
349 { DISCONNECT
, "Disconnect" },
350 { ACCESSMODE_CMD
, "Access Mode Command" },
351 { ACCESSMODE_CNF
, "Access Mode Confirm" },
355 static const value_string lmp_reason_vals
[] = {
356 /* IrLMP disconnect reasons */
357 { 0x01, "User Request" },
358 { 0x02, "Unexpected IrLAP Disconnect" },
359 { 0x03, "Failed to establish IrLAP connection" },
360 { 0x04, "IrLAP Reset" },
361 { 0x05, "Link Management Initiated Disconnect" },
362 { 0x06, "Data delivered on disconnected LSAP-Connection"},
363 { 0x07, "Non Responsive LM-MUX Client" },
364 { 0x08, "No available LM-MUX Client" },
365 { 0x09, "Connection Half Open" },
366 { 0x0A, "Illegal Source Address" },
367 { 0xFF, "Unspecified Disconnect Reason" },
371 static const value_string lmp_mode_vals
[] = {
373 { 0x00, "Multiplexed" },
374 { 0x01, "Exclusive" },
378 static const value_string lmp_status_vals
[] = {
382 { 0xFF, "Unsupported" },
386 static const value_string iap_opcode_vals
[] = {
388 { GET_INFO_BASE
, "GetInfoBase" },
389 { GET_OBJECTS
, "GetObjects" },
390 { GET_VALUE
, "GetValue" },
391 { GET_VALUE_BY_CLASS
, "GetValueByClass" },
392 { GET_OBJECT_INFO
, "GetObjectInfo" },
393 { GET_ATTRIB_NAMES
, "GetAttributeNames" },
397 static const value_string iap_return_vals
[] = {
398 /* IrIAP Return-codes */
399 { IAS_SUCCESS
, "Success" },
400 { IAS_CLASS_UNKNOWN
, "Class/Object Unknown" },
401 { IAS_ATTRIB_UNKNOWN
, "Attribute Unknown" },
402 { IAS_ATTR_TOO_LONG
, "Attribute List Too Long" },
403 { IAS_DISCONNECT
, "Disconnect (Linux-IrDA only)" },
404 { IAS_UNSUPPORTED
, "Unsupported Optional Operation" },
408 static const value_string iap_attr_type_vals
[] = {
409 /* LM-IAS Attribute types */
410 { IAS_MISSING
, "Missing" },
411 { IAS_INTEGER
, "Integer" },
412 { IAS_OCT_SEQ
, "Octet Sequence" },
413 { IAS_STRING
, "String" },
417 static ias_attr_dissector_t device_attr_dissector
[] = {
418 /* Device attribute dissectors */
419 /* { "IrLMPSupport", xxx }, not implemented yet... */
423 /* IAS class dissectors */
424 static ias_class_dissector_t class_dissector
[] = { CLASS_DISSECTORS
};
428 * Dissect parameter tuple
430 guint
dissect_param_tuple(tvbuff_t
* tvb
, proto_tree
* tree
, guint offset
)
432 guint8 len
= tvb_get_guint8(tvb
, offset
+ 1);
435 proto_tree_add_item(tree
, hf_param_pi
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
439 proto_tree_add_item(tree
, hf_param_pl
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
445 proto_tree_add_item(tree
, hf_param_pv
, tvb
, offset
, len
, ENC_NA
);
456 static guint
dissect_ttp(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* root
, gboolean data
)
462 if (tvb_length(tvb
) == 0)
465 /* Make entries in Protocol column on summary display */
466 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "TTP");
468 head
= tvb_get_guint8(tvb
, offset
);
470 g_snprintf(buf
, 128, ", Credit=%d", head
& ~TTP_PARAMETERS
);
471 col_append_str(pinfo
->cinfo
, COL_INFO
, buf
);
475 /* create display subtree for the protocol */
476 proto_item
* ti
= proto_tree_add_item(root
, proto_ttp
, tvb
, 0, -1, ENC_NA
);
477 proto_tree
* tree
= proto_item_add_subtree(ti
, ett_ttp
);
481 proto_tree_add_item(tree
, hf_ttp_m
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
482 proto_tree_add_item(tree
, hf_ttp_dcredit
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
487 proto_tree_add_item(tree
, hf_ttp_p
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
488 proto_tree_add_item(tree
, hf_ttp_icredit
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
491 proto_item_set_len(tree
, offset
);
501 * Dissect IAP request
503 static void dissect_iap_request(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* root
)
512 conversation_t
* conv
;
513 iap_conversation_t
* iap_conv
;
516 if (tvb_length(tvb
) == 0)
519 /* Make entries in Protocol column on summary display */
520 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IAP");
522 op
= tvb_get_guint8(tvb
, offset
) & IAP_OP
;
526 case GET_VALUE_BY_CLASS
:
527 clen
= MIN(tvb_get_guint8(tvb
, offset
+ 1), 60);
528 alen
= MIN(tvb_get_guint8(tvb
, offset
+ 1 + 1 + clen
), 60);
530 /* create conversation entry */
531 src
= pinfo
->circuit_id
^ CMD_FRAME
;
532 srcaddr
.type
= AT_NONE
;
534 srcaddr
.data
= (guint8
*)&src
;
536 destaddr
.type
= AT_NONE
;
538 destaddr
.data
= (guint8
*)&pinfo
->circuit_id
;
540 conv
= find_conversation(pinfo
->fd
->num
, &srcaddr
, &destaddr
, PT_NONE
, pinfo
->srcport
, pinfo
->destport
, 0);
543 iap_conv
= (iap_conversation_t
*)conversation_get_proto_data(conv
, proto_iap
);
546 if (iap_conv
->iap_query_frame
== pinfo
->fd
->num
)
551 if (iap_conv
->pnext
== NULL
)
553 iap_conv
->pnext
= wmem_new(wmem_file_scope(), iap_conversation_t
);
554 iap_conv
= iap_conv
->pnext
;
557 iap_conv
= iap_conv
->pnext
;
562 conv
= conversation_new(pinfo
->fd
->num
, &srcaddr
, &destaddr
, PT_NONE
, pinfo
->srcport
, pinfo
->destport
, 0);
563 iap_conv
= wmem_new(wmem_file_scope(), iap_conversation_t
);
564 conversation_add_proto_data(conv
, proto_iap
, (void*)iap_conv
);
567 /* Dissect IAP query if it is new */
571 char class_name
[256];
575 iap_conv
->pnext
= NULL
;
576 iap_conv
->iap_query_frame
= pinfo
->fd
->num
;
577 iap_conv
->pattr_dissector
= NULL
;
579 tvb_memcpy(tvb
, class_name
, offset
+ 1 + 1, clen
);
580 class_name
[clen
] = 0;
581 tvb_memcpy(tvb
, attr_name
, offset
+ 1 + 1 + clen
+ 1, alen
);
584 /* Find the attribute dissector */
585 for (i
= 0; class_dissector
[i
].class_name
!= NULL
; i
++)
586 if (strcmp(class_name
, class_dissector
[i
].class_name
) == 0)
588 for (j
= 0; class_dissector
[i
].pattr_dissector
[j
].attr_name
!= NULL
; j
++)
589 if (strcmp(attr_name
, class_dissector
[i
].pattr_dissector
[j
].attr_name
) == 0)
591 iap_conv
->pattr_dissector
= &class_dissector
[i
].pattr_dissector
[j
];
598 col_set_str(pinfo
->cinfo
, COL_INFO
, "GetValueByClass: \"");
600 tvb_memcpy(tvb
, buf
, offset
+ 1 + 1, clen
);
601 memcpy(&buf
[clen
], "\" \"", 3);
602 tvb_memcpy(tvb
, buf
+ clen
+ 3, offset
+ 1 + 1 + clen
+ 1, alen
);
603 buf
[clen
+ 3 + alen
] = '\"';
604 buf
[clen
+ 3 + alen
+ 1] = 0;
605 col_append_str(pinfo
->cinfo
, COL_INFO
, buf
);
610 /* create display subtree for the protocol */
611 proto_item
* ti
= proto_tree_add_item(root
, proto_iap
, tvb
, 0, -1, ENC_NA
);
612 proto_tree
* tree
= proto_item_add_subtree(ti
, ett_iap
);
614 proto_tree
* ctl_tree
;
617 ti
= proto_tree_add_item(tree
, hf_iap_ctl
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
618 ctl_tree
= proto_item_add_subtree(ti
, ett_iap_ctl
);
619 proto_tree_add_item(ctl_tree
, hf_iap_ctl_lst
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
620 proto_tree_add_item(ctl_tree
, hf_iap_ctl_ack
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
621 proto_tree_add_item(ctl_tree
, hf_iap_ctl_opcode
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
626 case GET_VALUE_BY_CLASS
:
627 proto_tree_add_item(tree
, hf_iap_class_name
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
630 proto_tree_add_item(tree
, hf_iap_attr_name
, tvb
, offset
, 1, ENC_ASCII
|ENC_NA
);
640 case GET_VALUE_BY_CLASS
:
641 offset
+= 1 + clen
+ 1 + alen
;
646 /* If any bytes remain, send it to the generic data dissector */
647 tvb
= tvb_new_subset_remaining(tvb
, offset
);
648 call_dissector(data_handle
, tvb
, pinfo
, root
);
655 static void dissect_iap_result(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* root
)
658 guint len
= tvb_length(tvb
);
669 conversation_t
* conv
;
670 iap_conversation_t
* cur_iap_conv
;
671 iap_conversation_t
* iap_conv
= NULL
;
675 if (tvb_length(tvb
) == 0)
678 /* Make entries in Protocol column on summary display */
679 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IAP");
681 op
= tvb_get_guint8(tvb
, offset
) & IAP_OP
;
682 retcode
= tvb_get_guint8(tvb
, offset
+ 1);
684 src
= pinfo
->circuit_id
^ CMD_FRAME
;
685 srcaddr
.type
= AT_NONE
;
687 srcaddr
.data
= (guint8
*)&src
;
689 destaddr
.type
= AT_NONE
;
691 destaddr
.data
= (guint8
*)&pinfo
->circuit_id
;
693 /* Find result value dissector */
694 conv
= find_conversation(pinfo
->fd
->num
, &srcaddr
, &destaddr
, PT_NONE
, pinfo
->srcport
, pinfo
->destport
, 0);
697 num
= pinfo
->fd
->num
;
699 iap_conv
= (iap_conversation_t
*)conversation_get_proto_data(conv
, proto_iap
);
700 while (iap_conv
&& (iap_conv
->iap_query_frame
>= num
))
701 iap_conv
= iap_conv
->pnext
;
705 cur_iap_conv
= iap_conv
->pnext
;
708 if ((cur_iap_conv
->iap_query_frame
< num
) &&
709 (cur_iap_conv
->iap_query_frame
> iap_conv
->iap_query_frame
))
711 iap_conv
= cur_iap_conv
;
714 cur_iap_conv
= cur_iap_conv
->pnext
;
719 col_set_str(pinfo
->cinfo
, COL_INFO
, "Result: ");
720 col_append_str(pinfo
->cinfo
, COL_INFO
, val_to_str(retcode
, iap_return_vals
, "0x%02X"));
724 case GET_VALUE_BY_CLASS
:
728 switch (tvb_get_guint8(tvb
, offset
+ 6))
731 g_snprintf(buf
, 300, ", Missing");
735 g_snprintf(buf
, 300, ", Integer: %d", tvb_get_ntohl(tvb
, offset
+ 7));
739 g_snprintf(buf
, 300, ", %d Octets", tvb_get_ntohs(tvb
, offset
+ 7));
743 n
= tvb_get_guint8(tvb
, offset
+ 8);
744 string
= tvb_get_string(wmem_packet_scope(), tvb
, offset
+ 9, n
);
745 g_snprintf(buf
, 300, ", \"%s\"", string
);
748 col_append_str(pinfo
->cinfo
, COL_INFO
, buf
);
749 if (tvb_get_ntohs(tvb
, offset
+ 2) > 1)
750 col_append_str(pinfo
->cinfo
, COL_INFO
, ", ...");
757 /* create display subtree for the protocol */
758 proto_item
* ti
= proto_tree_add_item(root
, proto_iap
, tvb
, 0, -1, ENC_NA
);
759 proto_tree
* tree
= proto_item_add_subtree(ti
, ett_iap
);
761 proto_tree
* ctl_tree
;
762 proto_tree
* entry_tree
;
765 ti
= proto_tree_add_item(tree
, hf_iap_ctl
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
766 ctl_tree
= proto_item_add_subtree(ti
, ett_iap_ctl
);
767 proto_tree_add_item(ctl_tree
, hf_iap_ctl_lst
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
768 proto_tree_add_item(ctl_tree
, hf_iap_ctl_ack
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
769 proto_tree_add_item(ctl_tree
, hf_iap_ctl_opcode
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
772 proto_tree_add_item(tree
, hf_iap_return
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
777 case GET_VALUE_BY_CLASS
:
780 list_len
= tvb_get_ntohs(tvb
, offset
);
782 proto_tree_add_item(tree
, hf_iap_list_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
785 while ((offset
< len
) && (n
< list_len
))
787 type
= tvb_get_guint8(tvb
, offset
+ 2);
795 attr_len
= tvb_get_ntohs(tvb
, offset
+ 2 + 1) + 2;
799 attr_len
= tvb_get_guint8(tvb
, offset
+ 2 + 1 + 1) + 2;
806 ti
= proto_tree_add_item(tree
, hf_iap_list_entry
, tvb
, offset
, 2 + 1 + attr_len
, ENC_NA
);
807 proto_item_append_text(ti
, "%d", n
+ 1);
808 entry_tree
= proto_item_add_subtree(ti
, ett_iap_entry
[n
]);
810 proto_tree_add_item(entry_tree
, hf_iap_obj_id
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
813 proto_tree_add_item(entry_tree
, hf_iap_attr_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
819 if (!iap_conv
|| !iap_conv
->pattr_dissector
||
820 !iap_conv
->pattr_dissector
->value_dissector(tvb
, offset
, pinfo
, entry_tree
,
822 proto_tree_add_item(entry_tree
, hf_iap_int
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
826 proto_tree_add_item(entry_tree
, hf_iap_seq_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
827 if (!iap_conv
|| !iap_conv
->pattr_dissector
||
828 !iap_conv
->pattr_dissector
->value_dissector(tvb
, offset
, pinfo
, entry_tree
,
830 proto_tree_add_item(entry_tree
, hf_iap_oct_seq
, tvb
, offset
+ 2,
831 attr_len
- 2, ENC_NA
);
835 proto_tree_add_item(entry_tree
, hf_iap_char_set
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
836 if (!iap_conv
|| !iap_conv
->pattr_dissector
||
837 !iap_conv
->pattr_dissector
->value_dissector(tvb
, offset
, pinfo
, entry_tree
,
839 proto_tree_add_item(entry_tree
, hf_iap_string
, tvb
, offset
+ 1, 1, ENC_ASCII
|ENC_NA
);
855 case GET_VALUE_BY_CLASS
:
863 type
= tvb_get_guint8(tvb
, offset
);
870 if (iap_conv
&& iap_conv
->pattr_dissector
)
871 iap_conv
->pattr_dissector
->value_dissector(tvb
, offset
, pinfo
, 0,
876 attr_len
= tvb_get_ntohs(tvb
, offset
) + 2;
877 if (iap_conv
&& iap_conv
->pattr_dissector
)
878 iap_conv
->pattr_dissector
->value_dissector(tvb
, offset
, pinfo
, 0,
883 attr_len
= tvb_get_guint8(tvb
, offset
+ 1) + 2;
884 if (iap_conv
&& iap_conv
->pattr_dissector
)
885 iap_conv
->pattr_dissector
->value_dissector(tvb
, offset
, pinfo
, 0,
901 /* If any bytes remain, send it to the generic data dissector */
902 tvb
= tvb_new_subset_remaining(tvb
, offset
);
903 call_dissector(data_handle
, tvb
, pinfo
, root
);
908 * Check if IAP result is octet sequence
910 gboolean
check_iap_octet_result(tvbuff_t
* tvb
, proto_tree
* tree
, guint offset
,
911 const char* attr_name
, guint8 attr_type
)
913 if (attr_type
!= IAS_OCT_SEQ
)
917 proto_item
* ti
= proto_tree_add_item(tree
, hf_iap_invaloctet
, tvb
, offset
, 0, ENC_NA
);
918 proto_item_append_text(ti
, "%s", attr_name
);
919 proto_item_append_text(ti
, "\" attribute must be octet sequence!");
930 * Check if IAP result is correct LsapSel
932 guint8
check_iap_lsap_result(tvbuff_t
* tvb
, proto_tree
* tree
, guint offset
,
933 const char* attr_name
, guint8 attr_type
)
938 if ((attr_type
!= IAS_INTEGER
) || ((lsap
= tvb_get_ntohl(tvb
, offset
)) < 0x01) ||
943 proto_item
* ti
= proto_tree_add_item(tree
, hf_iap_invallsap
, tvb
, offset
, 0, ENC_NA
);
944 proto_item_append_text(ti
, "%s", attr_name
);
945 proto_item_append_text(ti
, "\" attribute must be integer value between 0x01 and 0x6F!");
956 * Dissect IrDA application protocol
958 static void dissect_appl_proto(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* root
, pdu_type_t pdu_type
)
964 conversation_t
* conv
;
965 lmp_conversation_t
* cur_lmp_conv
;
966 lmp_conversation_t
* lmp_conv
= NULL
;
970 src
= pinfo
->circuit_id
^ CMD_FRAME
;
971 srcaddr
.type
= AT_NONE
;
973 srcaddr
.data
= (guint8
*)&src
;
975 destaddr
.type
= AT_NONE
;
977 destaddr
.data
= (guint8
*)&pinfo
->circuit_id
;
979 /* Find result value dissector */
980 conv
= find_conversation(pinfo
->fd
->num
, &srcaddr
, &destaddr
, PT_NONE
, pinfo
->srcport
, pinfo
->destport
, 0);
983 num
= pinfo
->fd
->num
;
985 lmp_conv
= (lmp_conversation_t
*)conversation_get_proto_data(conv
, proto_irlmp
);
986 while (lmp_conv
&& (lmp_conv
->iap_result_frame
>= num
))
987 lmp_conv
= lmp_conv
->pnext
;
991 cur_lmp_conv
= lmp_conv
->pnext
;
994 if ((cur_lmp_conv
->iap_result_frame
< num
) &&
995 (cur_lmp_conv
->iap_result_frame
> lmp_conv
->iap_result_frame
))
997 lmp_conv
= cur_lmp_conv
;
1000 cur_lmp_conv
= cur_lmp_conv
->pnext
;
1007 /*g_message("%x:%d->%x:%d = %p\n", src, pinfo->srcport, pinfo->circuit_id, pinfo->destport, lmp_conv); */
1008 /*g_message("->%d: %d %d %p\n", pinfo->fd->num, lmp_conv->iap_result_frame, lmp_conv->ttp, lmp_conv->proto_dissector); */
1009 if ((lmp_conv
->ttp
) && (pdu_type
!= DISCONNECT_PDU
))
1011 offset
+= dissect_ttp(tvb
, pinfo
, root
, (pdu_type
== DATA_PDU
));
1013 tvb
= tvb_new_subset_remaining(tvb
, offset
);
1016 pinfo
->private_data
= (void *)pdu_type
;
1018 lmp_conv
->proto_dissector(tvb
, pinfo
, root
);
1021 call_dissector(data_handle
, tvb
, pinfo
, root
);
1028 static void dissect_irlmp(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* root
)
1037 /* Make entries in Protocol column on summary display */
1038 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IrLMP");
1040 dlsap
= tvb_get_guint8(tvb
, offset
);
1041 cbit
= dlsap
& CONTROL_BIT
;
1042 dlsap
&= ~CONTROL_BIT
;
1044 slsap
= tvb_get_guint8(tvb
, offset
+1) & ~CONTROL_BIT
;
1046 /* save Lsaps in pinfo */
1047 pinfo
->srcport
= slsap
;
1048 pinfo
->destport
= dlsap
;
1052 opcode
= tvb_get_guint8(tvb
, offset
+2);
1054 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%d > %d, ", slsap
, dlsap
);
1055 col_append_str(pinfo
->cinfo
, COL_INFO
, val_to_str(opcode
, lmp_opcode_vals
, "0x%02X"));
1056 if ((opcode
== ACCESSMODE_CMD
) || (opcode
== ACCESSMODE_CNF
))
1058 col_append_str(pinfo
->cinfo
, COL_INFO
, " (");
1059 col_append_str(pinfo
->cinfo
, COL_INFO
,
1060 val_to_str(tvb_get_guint8(tvb
, offset
+4), lmp_mode_vals
, "0x%02X"));
1061 col_append_str(pinfo
->cinfo
, COL_INFO
, ")");
1065 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "%d > %d, Len=%d", slsap
, dlsap
,
1066 tvb_length(tvb
) - 2);
1070 /* create display subtree for the protocol */
1071 proto_item
* ti
= proto_tree_add_item(root
, proto_irlmp
, tvb
, 0, -1, ENC_NA
);
1072 proto_tree
* tree
= proto_item_add_subtree(ti
, ett_irlmp
);
1074 proto_tree
* dst_tree
;
1075 proto_tree
* src_tree
;
1078 ti
= proto_tree_add_item(tree
, hf_lmp_dst
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1079 dst_tree
= proto_item_add_subtree(ti
, ett_lmp_dst
);
1080 proto_tree_add_item(dst_tree
, hf_lmp_dst_control
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1081 proto_tree_add_item(dst_tree
, hf_lmp_dst_lsap
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1084 ti
= proto_tree_add_item(tree
, hf_lmp_src
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1085 src_tree
= proto_item_add_subtree(ti
, ett_lmp_src
);
1086 proto_tree_add_item(src_tree
, hf_lmp_src_r
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1087 proto_tree_add_item(src_tree
, hf_lmp_src_lsap
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1092 proto_tree_add_item(tree
, hf_lmp_opcode
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1099 if (offset
< tvb_length(tvb
))
1101 proto_tree_add_item(tree
, hf_lmp_rsvd
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1107 proto_tree_add_item(tree
, hf_lmp_reason
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1111 case ACCESSMODE_CMD
:
1112 proto_tree_add_item(tree
, hf_lmp_rsvd
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1115 proto_tree_add_item(tree
, hf_lmp_mode
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1119 case ACCESSMODE_CNF
:
1120 proto_tree_add_item( tree
, hf_lmp_status
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1123 proto_tree_add_item(tree
, hf_lmp_mode
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1129 tvb
= tvb_new_subset_remaining(tvb
, offset
);
1130 proto_item_set_len(tree
, offset
);
1143 if (offset
< tvb_length(tvb
))
1151 case ACCESSMODE_CMD
:
1152 case ACCESSMODE_CNF
:
1158 tvb
= tvb_new_subset_remaining(tvb
, offset
);
1163 if (dlsap
== LSAP_IAS
)
1164 dissect_iap_request(tvb
, pinfo
, root
);
1165 else if (slsap
== LSAP_IAS
)
1166 dissect_iap_result(tvb
, pinfo
, root
);
1168 dissect_appl_proto(tvb
, pinfo
, root
, DATA_PDU
);
1172 if ((dlsap
== LSAP_IAS
) || (slsap
== LSAP_IAS
))
1173 call_dissector(data_handle
, tvb
, pinfo
, root
);
1179 dissect_appl_proto(tvb
, pinfo
, root
, CONNECT_PDU
);
1183 dissect_appl_proto(tvb
, pinfo
, root
, DISCONNECT_PDU
);
1187 call_dissector(data_handle
, tvb
, pinfo
, root
);
1194 * Add LMP conversation
1196 void add_lmp_conversation(packet_info
* pinfo
, guint8 dlsap
, gboolean ttp
, dissector_t proto_dissector
)
1201 conversation_t
* conv
;
1202 lmp_conversation_t
* lmp_conv
= NULL
;
1205 /*g_message("%d: add_lmp_conversation(%p, %d, %d, %p) = ", pinfo->fd->num, pinfo, dlsap, ttp, proto_dissector); */
1206 srcaddr
.type
= AT_NONE
;
1208 srcaddr
.data
= (guint8
*)&pinfo
->circuit_id
;
1210 dest
= pinfo
->circuit_id
^ CMD_FRAME
;
1211 destaddr
.type
= AT_NONE
;
1213 destaddr
.data
= (guint8
*)&dest
;
1215 conv
= find_conversation(pinfo
->fd
->num
, &destaddr
, &srcaddr
, PT_NONE
, dlsap
, 0, NO_PORT_B
);
1218 lmp_conv
= (lmp_conversation_t
*)conversation_get_proto_data(conv
, proto_irlmp
);
1221 /* Does entry already exist? */
1222 if (lmp_conv
->iap_result_frame
== pinfo
->fd
->num
)
1225 if (lmp_conv
->pnext
== NULL
)
1227 lmp_conv
->pnext
= wmem_new(wmem_file_scope(), lmp_conversation_t
);
1228 lmp_conv
= lmp_conv
->pnext
;
1231 lmp_conv
= lmp_conv
->pnext
;
1236 conv
= conversation_new(pinfo
->fd
->num
, &destaddr
, &srcaddr
, PT_NONE
, dlsap
, 0, NO_PORT_B
);
1237 lmp_conv
= wmem_new(wmem_file_scope(), lmp_conversation_t
);
1238 conversation_add_proto_data(conv
, proto_irlmp
, (void*)lmp_conv
);
1241 lmp_conv
->pnext
= NULL
;
1242 lmp_conv
->iap_result_frame
= pinfo
->fd
->num
;
1243 lmp_conv
->ttp
= ttp
;
1244 lmp_conv
->proto_dissector
= proto_dissector
;
1246 /*g_message("%p\n", lmp_conv); */
1251 * Dissect Negotiation Parameters
1253 static guint
dissect_negotiation(tvbuff_t
* tvb
, proto_tree
* tree
, guint offset
)
1261 while (tvb_reported_length_remaining(tvb
, offset
) > 0)
1263 guint8 p_len
= tvb_get_guint8(tvb
, offset
+ 1);
1267 ti
= proto_tree_add_item(tree
, hf_negotiation_param
, tvb
, offset
, p_len
+ 2, ENC_NA
);
1268 p_tree
= proto_item_add_subtree(ti
, ett_param
[n
]);
1270 pv
= tvb_get_guint8(tvb
, offset
+2);
1273 switch (tvb_get_guint8(tvb
, offset
))
1276 proto_item_append_text(ti
, ": Baud Rate (");
1279 g_strlcat(buf
, ", 2400", 256);
1281 g_strlcat(buf
, ", 9600", 256);
1283 g_strlcat(buf
, ", 19200", 256);
1285 g_strlcat(buf
, ", 38400", 256);
1287 g_strlcat(buf
, ", 57600", 256);
1289 g_strlcat(buf
, ", 115200", 256);
1291 g_strlcat(buf
, ", 576000", 256);
1293 g_strlcat(buf
, ", 1152000", 256);
1294 if ((p_len
> 1) && (tvb_get_guint8(tvb
, offset
+3) & 0x01))
1295 g_strlcat(buf
, ", 4000000", 256);
1297 g_strlcat(buf
, " bps)", 256);
1299 proto_item_append_text(ti
, "%s", buf
+2);
1303 case PI_MAX_TURN_TIME
:
1304 proto_item_append_text(ti
, ": Maximum Turn Time (");
1307 g_strlcat(buf
, ", 500", 256);
1309 g_strlcat(buf
, ", 250", 256);
1311 g_strlcat(buf
, ", 100", 256);
1313 g_strlcat(buf
, ", 50", 256);
1315 g_strlcat(buf
, " ms)", 256);
1317 proto_item_append_text(ti
, "%s", buf
+2);
1322 proto_item_append_text(ti
, ": Data Size (");
1325 g_strlcat(buf
, ", 64", 256);
1327 g_strlcat(buf
, ", 128", 256);
1329 g_strlcat(buf
, ", 256", 256);
1331 g_strlcat(buf
, ", 512", 256);
1333 g_strlcat(buf
, ", 1024", 256);
1335 g_strlcat(buf
, ", 2048", 256);
1337 g_strlcat(buf
, " bytes)", 256);
1339 proto_item_append_text(ti
, "%s", buf
+2);
1343 case PI_WINDOW_SIZE
:
1344 proto_item_append_text(ti
, ": Window Size (");
1347 g_strlcat(buf
, ", 1", 256);
1349 g_strlcat(buf
, ", 2", 256);
1351 g_strlcat(buf
, ", 3", 256);
1353 g_strlcat(buf
, ", 4", 256);
1355 g_strlcat(buf
, ", 5", 256);
1357 g_strlcat(buf
, ", 6", 256);
1359 g_strlcat(buf
, ", 7", 256);
1361 g_strlcat(buf
, " frame window)", 256);
1363 proto_item_append_text(ti
, "%s", buf
+2);
1368 proto_item_append_text(ti
, ": Additional BOFs (");
1371 g_strlcat(buf
, ", 48", 256);
1373 g_strlcat(buf
, ", 24", 256);
1375 g_strlcat(buf
, ", 12", 256);
1377 g_strlcat(buf
, ", 5", 256);
1379 g_strlcat(buf
, ", 3", 256);
1381 g_strlcat(buf
, ", 2", 256);
1383 g_strlcat(buf
, ", 1", 256);
1385 g_strlcat(buf
, ", 0", 256);
1387 g_strlcat(buf
, " additional BOFs at 115200)", 256);
1389 proto_item_append_text(ti
, "%s", buf
+2);
1393 case PI_MIN_TURN_TIME
:
1394 proto_item_append_text(ti
, ": Minimum Turn Time (");
1397 g_strlcat(buf
, ", 10", 256);
1399 g_strlcat(buf
, ", 5", 256);
1401 g_strlcat(buf
, ", 1", 256);
1403 g_strlcat(buf
, ", 0.5", 256);
1405 g_strlcat(buf
, ", 0.1", 256);
1407 g_strlcat(buf
, ", 0.05", 256);
1409 g_strlcat(buf
, ", 0.01", 256);
1411 g_strlcat(buf
, ", 0", 256);
1413 g_strlcat(buf
, " ms)", 256);
1415 proto_item_append_text(ti
, "%s", buf
+2);
1420 proto_item_append_text(ti
, ": Link Disconnect/Threshold Time (");
1423 g_strlcat(buf
, ", 3/0", 256);
1425 g_strlcat(buf
, ", 8/3", 256);
1427 g_strlcat(buf
, ", 12/3", 256);
1429 g_strlcat(buf
, ", 16/3", 256);
1431 g_strlcat(buf
, ", 20/3", 256);
1433 g_strlcat(buf
, ", 25/3", 256);
1435 g_strlcat(buf
, ", 30/3", 256);
1437 g_strlcat(buf
, ", 40/3", 256);
1439 g_strlcat(buf
, " s)", 256);
1441 proto_item_append_text(ti
, "%s", buf
+2);
1446 proto_item_append_text(ti
, ": unknown");
1451 offset
= dissect_param_tuple(tvb
, p_tree
, offset
);
1460 * Dissect XID packet
1462 static void dissect_xid(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* root
, proto_tree
* lap_tree
, gboolean is_command
)
1465 proto_item
* ti
= NULL
;
1466 proto_tree
* i_tree
= NULL
;
1467 proto_tree
* flags_tree
;
1468 guint32 saddr
, daddr
;
1470 proto_tree
* lmp_tree
= NULL
;
1474 ti
= proto_tree_add_item(lap_tree
, hf_lap_i
, tvb
, offset
, -1, ENC_NA
);
1475 i_tree
= proto_item_add_subtree(ti
, ett_lap_i
);
1477 proto_tree_add_item(i_tree
, hf_xid_ident
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1481 saddr
= tvb_get_letohl(tvb
, offset
);
1482 col_add_fstr(pinfo
->cinfo
, COL_DEF_SRC
, "0x%08X", saddr
);
1484 proto_tree_add_uint(i_tree
, hf_xid_saddr
, tvb
, offset
, 4, saddr
);
1487 daddr
= tvb_get_letohl(tvb
, offset
);
1488 col_add_fstr(pinfo
->cinfo
, COL_DEF_DST
, "0x%08X", daddr
);
1490 proto_tree_add_uint(i_tree
, hf_xid_daddr
, tvb
, offset
, 4, daddr
);
1495 ti
= proto_tree_add_item(i_tree
, hf_xid_flags
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1496 flags_tree
= proto_item_add_subtree(ti
, ett_xid_flags
);
1497 proto_tree_add_item(flags_tree
, hf_xid_s
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1498 proto_tree_add_item(flags_tree
, hf_xid_conflict
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1504 s
= tvb_get_guint8(tvb
, offset
);
1506 col_append_str(pinfo
->cinfo
, COL_INFO
, ", s=final");
1508 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", s=%u", s
);
1511 ti
= proto_tree_add_uint(i_tree
, hf_xid_slotnr
, tvb
, offset
, 1, s
);
1513 proto_item_append_text(ti
, " (final)");
1519 proto_tree_add_item(i_tree
, hf_xid_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1524 proto_item_set_end(lap_tree
, tvb
, offset
);
1525 proto_item_set_end(i_tree
, tvb
, offset
);
1528 if (tvb_reported_length_remaining(tvb
, offset
) > 0)
1537 ti
= proto_tree_add_item(root
, proto_irlmp
, tvb
, offset
, -1, ENC_NA
);
1538 lmp_tree
= proto_item_add_subtree(ti
, ett_irlmp
);
1541 for (hints_len
= 0;;)
1543 guint8 hint
= tvb_get_guint8(tvb
, offset
+ hints_len
++);
1547 else if (hints_len
== 2)
1550 if ((hint
& 0x80) == 0)
1556 ti
= proto_tree_add_item(lmp_tree
, hf_lmp_xid_hints
, tvb
, offset
, hints_len
, ENC_NA
);
1557 if ((hint1
| hint2
) != 0)
1559 char service_hints
[256];
1561 service_hints
[0] = 0;
1564 g_strlcat(service_hints
, ", PnP Compatible", 256);
1566 g_strlcat(service_hints
, ", PDA/Palmtop", 256);
1568 g_strlcat(service_hints
, ", Computer", 256);
1570 g_strlcat(service_hints
, ", Printer", 256);
1572 g_strlcat(service_hints
, ", Modem", 256);
1574 g_strlcat(service_hints
, ", Fax", 256);
1576 g_strlcat(service_hints
, ", LAN Access", 256);
1578 g_strlcat(service_hints
, ", Telephony", 256);
1580 g_strlcat(service_hints
, ", File Server", 256);
1582 g_strlcat(service_hints
, ", IrCOMM", 256);
1584 g_strlcat(service_hints
, ", OBEX", 256);
1586 g_strlcat(service_hints
, ")", 256);
1587 service_hints
[0] = ' ';
1588 service_hints
[1] = '(';
1590 proto_item_append_text(ti
, "%s", service_hints
);
1593 offset
+= hints_len
;
1595 if (tvb_reported_length_remaining(tvb
, offset
) > 0)
1600 cset
= tvb_get_guint8(tvb
, offset
);
1602 proto_tree_add_uint(lmp_tree
, hf_lmp_xid_charset
, tvb
, offset
, 1, cset
);
1604 name_len
= tvb_reported_length_remaining(tvb
, offset
);
1612 tvb_memcpy(tvb
, buf
, offset
, name_len
);
1614 col_append_str(pinfo
->cinfo
, COL_INFO
, ", \"");
1615 col_append_str(pinfo
->cinfo
, COL_INFO
, buf
);
1616 col_append_str(pinfo
->cinfo
, COL_INFO
, "\"");
1618 proto_tree_add_item(lmp_tree
, hf_lmp_xid_name
, tvb
, offset
,
1619 -1, ENC_ASCII
|ENC_NA
);
1624 proto_tree_add_item(lmp_tree
, hf_lmp_xid_name_no_ascii
, tvb
, offset
,
1634 * Dissect Log Messages
1636 static void dissect_log(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* root
)
1638 /* Make entries in Protocol column on summary display */
1639 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Log");
1641 /* missed messages? */
1642 if (pinfo
->pseudo_header
->irda
.pkttype
== IRDA_MISSED_MSG
)
1644 col_set_str(pinfo
->cinfo
, COL_INFO
, "WARNING: Missed one or more messages while capturing!");
1652 length
= tvb_length(tvb
);
1653 if (length
> sizeof(buf
)-1)
1654 length
= sizeof(buf
)-1;
1655 tvb_memcpy(tvb
, buf
, 0, length
);
1657 if (buf
[length
-1] == '\n')
1659 else if (buf
[length
-2] == '\n')
1662 col_add_str(pinfo
->cinfo
, COL_INFO
, buf
);
1667 proto_item
* ti
= proto_tree_add_item(root
, proto_log
, tvb
, 0, -1, ENC_NA
);
1668 proto_tree
* tree
= proto_item_add_subtree(ti
, ett_log
);
1670 if (pinfo
->pseudo_header
->irda
.pkttype
== IRDA_MISSED_MSG
)
1671 proto_tree_add_item(tree
, hf_log_missed
, tvb
, 0, 0, ENC_NA
);
1673 proto_tree_add_item(tree
, hf_log_msg
, tvb
, 0, -1, ENC_ASCII
|ENC_NA
);
1681 static void dissect_irlap(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* root
)
1685 gboolean is_response
;
1687 proto_item
* ti
= NULL
;
1688 proto_tree
* tree
= NULL
;
1689 proto_tree
* i_tree
= NULL
;
1690 guint32 saddr
, daddr
;
1693 /* Make entries in Protocol column on summary display */
1694 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "IrLAP");
1696 /* Clear Info column */
1697 col_clear(pinfo
->cinfo
, COL_INFO
);
1699 /* set direction column */
1700 switch (pinfo
->pseudo_header
->irda
.pkttype
)
1703 col_set_str(pinfo
->cinfo
, COL_IF_DIR
, "Out");
1707 col_set_str(pinfo
->cinfo
, COL_IF_DIR
, "In");
1711 /* decode values used for demuxing */
1712 a
= tvb_get_guint8(tvb
, 0);
1714 /* save connection address field in pinfo */
1715 pinfo
->circuit_id
= a
;
1717 /* initially set address columns to connection address */
1718 g_snprintf(addr
, sizeof(addr
)-1, "0x%02X", a
>> 1);
1719 col_add_str(pinfo
->cinfo
, COL_DEF_SRC
, addr
);
1720 col_add_str(pinfo
->cinfo
, COL_DEF_DST
, addr
);
1725 proto_item
* addr_item
;
1727 /* create display subtree for the protocol */
1728 ti
= proto_tree_add_item(root
, proto_irlap
, tvb
, 0, -1, ENC_NA
);
1729 tree
= proto_item_add_subtree(ti
, ett_irlap
);
1731 /* create subtree for the address field */
1732 ti
= proto_tree_add_item(tree
, hf_lap_a
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1733 a_tree
= proto_item_add_subtree(ti
, ett_lap_a
);
1734 proto_tree_add_item(a_tree
, hf_lap_a_cr
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1735 addr_item
= proto_tree_add_item(a_tree
, hf_lap_a_address
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1736 switch (a
& ~CMD_FRAME
)
1739 proto_item_append_text(addr_item
, " (NULL Address)");
1742 proto_item_append_text(addr_item
, " (Broadcast)");
1746 is_response
= ((a
& CMD_FRAME
) == 0);
1749 /* process the control field */
1750 c
= dissect_xdlc_control(tvb
, 1, pinfo
, tree
, hf_lap_c
,
1751 ett_lap_c
, &irlap_cf_items
, NULL
, lap_c_u_cmd_abbr_vals
,
1752 lap_c_u_rsp_abbr_vals
, is_response
, FALSE
, FALSE
);
1755 if ((c
& XDLC_I_MASK
) == XDLC_I
) {
1757 proto_item_set_len(tree
, offset
);
1758 tvb
= tvb_new_subset_remaining(tvb
, offset
);
1759 dissect_irlmp(tvb
, pinfo
, root
);
1763 if ((c
& 0x03) == XDLC_U
) {
1765 switch (c
& XDLC_U_MODIFIER_MASK
)
1770 ti
= proto_tree_add_item(tree
, hf_lap_i
, tvb
, offset
, -1, ENC_NA
);
1771 i_tree
= proto_item_add_subtree(ti
, ett_lap_i
);
1774 saddr
= tvb_get_letohl(tvb
, offset
);
1777 col_add_fstr(pinfo
->cinfo
, COL_DEF_SRC
, "0x%08X", saddr
);
1780 proto_tree_add_uint(i_tree
, hf_snrm_saddr
, tvb
, offset
, 4, saddr
);
1783 daddr
= tvb_get_letohl(tvb
, offset
);
1786 col_add_fstr(pinfo
->cinfo
, COL_DEF_DST
, "0x%08X", daddr
);
1789 proto_tree_add_uint(i_tree
, hf_snrm_daddr
, tvb
, offset
, 4, daddr
);
1792 ca
= tvb_get_guint8(tvb
, offset
);
1795 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", ca=0x%02X",
1799 proto_tree_add_uint(i_tree
, hf_snrm_ca
, tvb
, offset
, 1, ca
>> 1);
1802 offset
= dissect_negotiation(tvb
, i_tree
, offset
);
1804 proto_item_set_end(ti
, tvb
, offset
);
1808 tvb
= tvb_new_subset_remaining(tvb
, offset
);
1809 dissect_xid(tvb
, pinfo
, root
, tree
, TRUE
);
1813 if (tvb_reported_length_remaining(tvb
, offset
) > 0)
1817 ti
= proto_tree_add_item(tree
, hf_lap_i
, tvb
, offset
, -1, ENC_NA
);
1818 i_tree
= proto_item_add_subtree(ti
, ett_lap_i
);
1821 saddr
= tvb_get_letohl(tvb
, offset
);
1822 col_add_fstr(pinfo
->cinfo
, COL_DEF_SRC
, "0x%08X", saddr
);
1824 proto_tree_add_uint(i_tree
, hf_ua_saddr
, tvb
, offset
, 4, saddr
);
1827 daddr
= tvb_get_letohl(tvb
, offset
);
1828 col_add_fstr(pinfo
->cinfo
, COL_DEF_DST
, "0x%08X", daddr
);
1830 proto_tree_add_uint(i_tree
, hf_ua_daddr
, tvb
, offset
, 4, daddr
);
1833 offset
= dissect_negotiation(tvb
, i_tree
, offset
);
1835 proto_item_set_end(ti
, tvb
, offset
);
1840 tvb
= tvb_new_subset_remaining(tvb
, offset
);
1841 dissect_xid(tvb
, pinfo
, root
, tree
, FALSE
);
1846 /* If any bytes remain, send it to the generic data dissector */
1847 if (tvb_reported_length_remaining(tvb
, offset
) > 0)
1849 tvb
= tvb_new_subset_remaining(tvb
, offset
);
1850 call_dissector(data_handle
, tvb
, pinfo
, root
);
1856 * Dissect IrDA protocol
1858 static void dissect_irda(tvbuff_t
* tvb
, packet_info
* pinfo
, proto_tree
* root
)
1860 /* load the display labels */
1861 pinfo
->current_proto
= "IrDA";
1863 /* check if log message */
1864 if ((pinfo
->pseudo_header
->irda
.pkttype
& IRDA_CLASS_MASK
) == IRDA_CLASS_LOG
)
1866 dissect_log(tvb
, pinfo
, root
);
1871 dissect_irlap(tvb
, pinfo
, root
);
1876 * Register the protocol with Wireshark
1877 * This format is required because a script is used to build the C function
1878 * that calls all the protocol registrations.
1880 void proto_register_irda(void)
1884 /* Setup list of header fields */
1885 static hf_register_info hf_lap
[] = {
1887 { "Address Field", "irlap.a",
1888 FT_UINT8
, BASE_HEX
, NULL
, 0,
1891 { "C/R", "irlap.a.cr",
1892 FT_BOOLEAN
, 8, TFS(&lap_cr_vals
), CMD_FRAME
,
1894 { &hf_lap_a_address
,
1895 { "Address", "irlap.a.address",
1896 FT_UINT8
, BASE_HEX
, NULL
, ~CMD_FRAME
,
1899 { "Control Field", "irlap.c",
1900 FT_UINT8
, BASE_HEX
, NULL
, 0,
1903 { "N(R)", "irlap.c.n_r",
1904 FT_UINT8
, BASE_DEC
, NULL
, XDLC_N_R_MASK
,
1907 { "N(S)", "irlap.c.n_s",
1908 FT_UINT8
, BASE_DEC
, NULL
, XDLC_N_S_MASK
,
1911 { "Poll", "irlap.c.p",
1912 FT_BOOLEAN
, 8, TFS(&set_notset
), XDLC_P_F
,
1915 { "Final", "irlap.c.f",
1916 FT_BOOLEAN
, 8, TFS(&set_notset
), XDLC_P_F
,
1919 { "Supervisory frame type", "irlap.c.s_ftype",
1920 FT_UINT8
, BASE_HEX
, VALS(lap_c_s_vals
), XDLC_S_FTYPE_MASK
,
1923 { "Command", "irlap.c.u_modifier_cmd",
1924 FT_UINT8
, BASE_HEX
, VALS(lap_c_u_cmd_vals
), XDLC_U_MODIFIER_MASK
,
1927 { "Response", "irlap.c.u_modifier_resp",
1928 FT_UINT8
, BASE_HEX
, VALS(lap_c_u_rsp_vals
), XDLC_U_MODIFIER_MASK
,
1931 { "Frame Type", "irlap.c.ftype",
1932 FT_UINT8
, BASE_HEX
, VALS(lap_c_ftype_vals
), XDLC_I_MASK
,
1935 { "Frame Type", "irlap.c.ftype",
1936 FT_UINT8
, BASE_HEX
, VALS(lap_c_ftype_vals
), XDLC_S_U_MASK
,
1939 { "Information Field", "irlap.i",
1940 FT_NONE
, BASE_NONE
, NULL
, 0,
1943 { "Source Device Address", "irlap.snrm.saddr",
1944 FT_UINT32
, BASE_HEX
, NULL
, 0,
1947 { "Destination Device Address", "irlap.snrm.daddr",
1948 FT_UINT32
, BASE_HEX
, NULL
, 0,
1951 { "Connection Address", "irlap.snrm.ca",
1952 FT_UINT8
, BASE_HEX
, NULL
, 0,
1954 { &hf_negotiation_param
,
1955 { "Negotiation Parameter", "irlap.negotiation",
1956 FT_NONE
, BASE_NONE
, NULL
, 0,
1959 { "Parameter Identifier", "irlap.pi",
1960 FT_UINT8
, BASE_HEX
, NULL
, 0,
1963 { "Parameter Length", "irlap.pl",
1964 FT_UINT8
, BASE_HEX
, NULL
, 0,
1967 { "Parameter Value", "irlap.pv",
1968 FT_BYTES
, BASE_NONE
, NULL
, 0,
1971 { "Source Device Address", "irlap.ua.saddr",
1972 FT_UINT32
, BASE_HEX
, NULL
, 0,
1975 { "Destination Device Address", "irlap.ua.daddr",
1976 FT_UINT32
, BASE_HEX
, NULL
, 0,
1979 { "Format Identifier", "irlap.xid.fi",
1980 FT_UINT8
, BASE_HEX
, NULL
, 0,
1983 { "Source Device Address", "irlap.xid.saddr",
1984 FT_UINT32
, BASE_HEX
, NULL
, 0,
1987 { "Destination Device Address", "irlap.xid.daddr",
1988 FT_UINT32
, BASE_HEX
, NULL
, 0,
1991 { "Discovery Flags", "irlap.xid.flags",
1992 FT_UINT8
, BASE_HEX
, NULL
, 0,
1995 { "Number of Slots", "irlap.xid.s",
1996 FT_UINT8
, BASE_DEC
, VALS(xid_slot_numbers
), S_MASK
,
1999 { "Conflict", "irlap.xid.conflict",
2000 FT_BOOLEAN
, 8, TFS(&set_notset
), CONFLICT
,
2003 { "Slot Number", "irlap.xid.slotnr",
2004 FT_UINT8
, BASE_DEC
, NULL
, 0,
2007 { "Version Number", "irlap.xid.version",
2008 FT_UINT8
, BASE_HEX
, NULL
, 0,
2012 static hf_register_info hf_log
[] = {
2014 { "Message", "log.msg",
2015 FT_STRING
, BASE_NONE
, NULL
, 0,
2018 { "WARNING: Missed one or more messages while capturing!", "log.missed",
2019 FT_NONE
, BASE_NONE
, NULL
, 0,
2023 static hf_register_info hf_lmp
[] = {
2024 { &hf_lmp_xid_hints
,
2025 { "Service Hints", "irlmp.xid.hints",
2026 FT_BYTES
, BASE_NONE
, NULL
, 0,
2028 { &hf_lmp_xid_charset
,
2029 { "Character Set", "irlmp.xid.charset",
2030 FT_UINT8
, BASE_HEX
, NULL
, 0,
2033 { "Device Nickname", "irlmp.xid.name",
2034 FT_STRING
, BASE_NONE
, NULL
, 0,
2036 { &hf_lmp_xid_name_no_ascii
,
2037 { "Device Nickname (unsupported character set)", "irlmp.xid.name",
2038 FT_BYTES
, BASE_NONE
, NULL
, 0,
2041 { "Destination", "irlmp.dst",
2042 FT_UINT8
, BASE_HEX
, NULL
, 0,
2044 { &hf_lmp_dst_control
,
2045 { "Control Bit", "irlmp.dst.c",
2046 FT_BOOLEAN
, 8, TFS(&set_notset
), CONTROL_BIT
,
2049 { "Destination LSAP", "irlmp.dst.lsap",
2050 FT_UINT8
, BASE_DEC
, NULL
, ~CONTROL_BIT
,
2053 { "Source", "irlmp.src",
2054 FT_UINT8
, BASE_HEX
, NULL
, 0,
2057 { "reserved", "irlmp.src.r",
2058 FT_UINT8
, BASE_DEC
, NULL
, RESERVED_BIT
,
2061 { "Source LSAP", "irlmp.src.lsap",
2062 FT_UINT8
, BASE_DEC
, NULL
, ~RESERVED_BIT
,
2065 { "Opcode", "irlmp.opcode",
2066 FT_UINT8
, BASE_HEX
, VALS(lmp_opcode_vals
), 0x0,
2069 { "Reserved", "irlmp.rsvd",
2070 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
2073 { "Reason", "irlmp.reason",
2074 FT_UINT8
, BASE_HEX
, VALS(lmp_reason_vals
), 0x0,
2077 { "Mode", "irlmp.mode",
2078 FT_UINT8
, BASE_HEX
, VALS(lmp_mode_vals
), 0x0,
2081 { "Status", "irlmp.status",
2082 FT_UINT8
, BASE_HEX
, VALS(lmp_status_vals
), 0x0,
2086 static hf_register_info hf_iap
[] = {
2088 { "Control Field", "iap.ctl",
2089 FT_UINT8
, BASE_HEX
, NULL
, 0,
2092 { "Last Frame", "iap.ctl.lst",
2093 FT_BOOLEAN
, 8, TFS(&set_notset
), IAP_LST
,
2096 { "Acknowledge", "iap.ctl.ack",
2097 FT_BOOLEAN
, 8, TFS(&set_notset
), IAP_ACK
,
2099 { &hf_iap_ctl_opcode
,
2100 { "Opcode", "iap.ctl.opcode",
2101 FT_UINT8
, BASE_HEX
, VALS(iap_opcode_vals
), IAP_OP
,
2103 { &hf_iap_class_name
,
2104 { "Class Name", "iap.classname",
2105 FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0,
2107 { &hf_iap_attr_name
,
2108 { "Attribute Name", "iap.attrname",
2109 FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0,
2112 { "Return", "iap.return",
2113 FT_UINT8
, BASE_HEX
, VALS(iap_return_vals
), 0x0,
2116 { "List Length", "iap.listlen",
2117 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
2119 { &hf_iap_list_entry
,
2120 { "List Entry", "iap.listentry",
2121 FT_NONE
, BASE_NONE
, NULL
, 0x0,
2124 { "Object Identifier", "iap.objectid",
2125 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
2127 { &hf_iap_attr_type
,
2128 { "Type", "iap.attrtype",
2129 FT_UINT8
, BASE_DEC
, VALS(iap_attr_type_vals
), 0x0,
2132 { "Value", "iap.int",
2133 FT_INT32
, BASE_DEC
, NULL
, 0x0,
2136 { "Sequence Length", "iap.seqlen",
2137 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
2140 { "Sequence", "iap.octseq",
2141 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
2144 { "Character Set", "iap.charset",
2145 FT_UINT8
, BASE_HEX
, NULL
, 0x0,
2148 { "String", "iap.string",
2149 FT_UINT_STRING
, BASE_NONE
, NULL
, 0x0,
2151 { &hf_iap_invaloctet
,
2152 { "Malformed IAP result: \"", "iap.invaloctet",
2153 FT_NONE
, BASE_NONE
, NULL
, 0,
2155 { &hf_iap_invallsap
,
2156 { "Malformed IAP result: \"", "iap.invallsap",
2157 FT_NONE
, BASE_NONE
, NULL
, 0,
2161 static hf_register_info hf_ttp
[] = {
2163 { "Parameter Bit", "ttp.p",
2164 FT_BOOLEAN
, 8, TFS(&set_notset
), TTP_PARAMETERS
,
2167 { "Initial Credit", "ttp.icredit",
2168 FT_UINT8
, BASE_DEC
, NULL
, ~TTP_PARAMETERS
,
2171 { "More Bit", "ttp.m",
2172 FT_BOOLEAN
, 8, TFS(&set_notset
), TTP_MORE
,
2175 { "Delta Credit", "ttp.dcredit",
2176 FT_UINT8
, BASE_DEC
, NULL
, ~TTP_MORE
,
2180 /* Setup protocol subtree arrays */
2181 static gint
* ett
[] = {
2196 gint
* ett_p
[MAX_PARAMETERS
];
2197 gint
* ett_iap_e
[MAX_IAP_ENTRIES
];
2200 /* Register protocol names and descriptions */
2201 proto_irlap
= proto_register_protocol("IrDA Link Access Protocol", "IrLAP", "irlap");
2202 proto_log
= proto_register_protocol("Log Message", "Log", "log");
2203 proto_irlmp
= proto_register_protocol("IrDA Link Management Protocol", "IrLMP", "irlmp");
2204 proto_iap
= proto_register_protocol("Information Access Protocol", "IAP", "iap");
2205 proto_ttp
= proto_register_protocol("Tiny Transport Protocol", "TTP", "ttp");
2207 /* Register the dissector */
2208 register_dissector("irda", dissect_irda
, proto_irlap
);
2210 /* Required function calls to register the header fields */
2211 proto_register_field_array(proto_irlap
, hf_lap
, array_length(hf_lap
));
2212 proto_register_field_array(proto_log
, hf_log
, array_length(hf_log
));
2213 proto_register_field_array(proto_irlmp
, hf_lmp
, array_length(hf_lmp
));
2214 proto_register_field_array(proto_iap
, hf_iap
, array_length(hf_iap
));
2215 proto_register_field_array(proto_ttp
, hf_ttp
, array_length(hf_ttp
));
2217 /* Register subtrees */
2218 proto_register_subtree_array(ett
, array_length(ett
));
2219 for (i
= 0; i
< MAX_PARAMETERS
; i
++)
2222 ett_p
[i
] = &ett_param
[i
];
2224 proto_register_subtree_array(ett_p
, MAX_PARAMETERS
);
2225 for (i
= 0; i
< MAX_IAP_ENTRIES
; i
++)
2227 ett_iap_entry
[i
] = -1;
2228 ett_iap_e
[i
] = &ett_iap_entry
[i
];
2230 proto_register_subtree_array(ett_iap_e
, MAX_IAP_ENTRIES
);
2234 /* If this dissector uses sub-dissector registration add a registration routine.
2235 This format is required because a script is used to find these routines and
2236 create the code that calls these routines.
2239 void proto_reg_handoff_irda(void)
2241 dissector_handle_t irda_handle
;
2243 irda_handle
= find_dissector("irda");
2244 dissector_add_uint("wtap_encap", WTAP_ENCAP_IRDA
, irda_handle
);
2245 dissector_add_uint("sll.ltype", LINUX_SLL_P_IRDA_LAP
, irda_handle
);
2246 data_handle
= find_dissector("data");