Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / plugins / epan / irda / packet-irda.c
bloba3d096fcc986888f61d1b1a1a5f36bb4e8d7ade1
1 /* packet-irda.c
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
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
16 #include "config.h"
18 #include <string.h>
20 #include <epan/packet.h>
21 #include <epan/address_types.h>
22 #include <epan/to_str.h>
23 #include <epan/strutil.h>
24 #include <epan/conversation.h>
25 #include <epan/xdlc.h>
26 #include <epan/tfs.h>
27 #include <wsutil/array.h>
28 #include <wiretap/wtap.h>
30 #include <epan/dissectors/packet-sll.h>
31 #include "irda-appl.h"
34 * This plugin dissects infrared data transmissions as defined by IrDA
35 * specifications. See
37 * https://web.archive.org/web/20040405053146/http://www.irda.org/standards/specifications.asp
39 * or
41 * https://archive.org/search?query=creator%3A%22Infrared+Data+Association%22
43 * for various IrDA specifications, including a zip archive of the IrPHY
44 * 1.4, IrLAP 1.1, IrLMP 1.1, IrDA Tiny TP 1.1, and IrDA Point and Shoot
45 * Profile 1.1 and Test Specification 1.0 at
47 * https://web.archive.org/web/20040405053146/http://www.irda.org/standards/pubs/IrData.zip
49 * or the the IrLAP 1.1 specification at
51 * https://archive.org/details/ir-lap-11
53 * The plugin operates both offline with libpcap files and online on supported
54 * platforms. Live dissection is currently available for Linux-IrDA
55 * (irda.sourceforge.net) and for Windows if the Linux-IrDA port IrCOMM2k
56 * (www.ircomm2k.de) is installed.
60 * LAP
63 /* Frame types and templates */
64 #define INVALID 0xff
67 * XXX - the IrDA spec gives XID as 0x2c; HDLC (and other HDLC-derived
68 * protocolc) use 0xAC.
70 #define IRDA_XID_CMD 0x2c /* Exchange Station Identification */
72 #define CMD_FRAME 0x01
73 #define RSP_FRAME 0x00
75 /* Discovery Flags */
76 #define S_MASK 0x03
77 #define CONFLICT 0x04
79 /* Negotiation Parameters */
80 #define PI_BAUD_RATE 0x01
81 #define PI_MAX_TURN_TIME 0x82
82 #define PI_DATA_SIZE 0x83
83 #define PI_WINDOW_SIZE 0x84
84 #define PI_ADD_BOFS 0x85
85 #define PI_MIN_TURN_TIME 0x86
86 #define PI_LINK_DISC 0x08
90 * LMP
93 /* IrLMP frame opcodes */
94 #define CONNECT_CMD 0x01
95 #define CONNECT_CNF 0x81
96 #define DISCONNECT 0x02
97 #define ACCESSMODE_CMD 0x03
98 #define ACCESSMODE_CNF 0x83
100 #define CONTROL_BIT 0x80
101 #define RESERVED_BIT 0x80
103 /* LSAP-SEL's */
104 #define LSAP_MASK 0x7f
105 #define LSAP_IAS 0x00
106 #define LSAP_ANY 0xff
107 #define LSAP_MAX 0x6f /* 0x70-0x7f are reserved */
108 #define LSAP_CONNLESS 0x70 /* Connectionless LSAP, mostly used for Ultra */
112 * IAP
115 /* IrIAP Op-codes */
116 #define GET_INFO_BASE 0x01
117 #define GET_OBJECTS 0x02
118 #define GET_VALUE 0x03
119 #define GET_VALUE_BY_CLASS 0x04
120 #define GET_OBJECT_INFO 0x05
121 #define GET_ATTRIB_NAMES 0x06
123 #define IAP_LST 0x80
124 #define IAP_ACK 0x40
125 #define IAP_OP 0x3F
127 #define IAS_SUCCESS 0
128 #define IAS_CLASS_UNKNOWN 1
129 #define IAS_ATTRIB_UNKNOWN 2
130 #define IAS_ATTR_TOO_LONG 3
131 #define IAS_DISCONNECT 10
132 #define IAS_UNSUPPORTED 0xFF
136 * TTP
139 #define TTP_PARAMETERS 0x80
140 #define TTP_MORE 0x80
142 void proto_reg_handoff_irda(void);
143 void proto_register_irda(void);
145 /* Initialize the protocol and registered fields */
146 static int proto_irlap;
147 static int hf_lap_a;
148 static int hf_lap_a_cr;
149 static int hf_lap_a_address;
150 static int hf_lap_c;
151 static int hf_lap_c_nr;
152 static int hf_lap_c_ns;
153 static int hf_lap_c_p;
154 static int hf_lap_c_f;
155 static int hf_lap_c_s;
156 static int hf_lap_c_u_cmd;
157 static int hf_lap_c_u_rsp;
158 static int hf_lap_c_i;
159 static int hf_lap_c_s_u;
160 static int hf_lap_i;
161 static int hf_snrm_saddr;
162 static int hf_snrm_daddr;
163 static int hf_snrm_ca;
164 static int hf_ua_saddr;
165 static int hf_ua_daddr;
166 static int hf_negotiation_param;
167 static int hf_param_pi;
168 static int hf_param_pl;
169 static int hf_param_pv;
170 static int hf_xid_ident;
171 static int hf_xid_saddr;
172 static int hf_xid_daddr;
173 static int hf_xid_flags;
174 static int hf_xid_s;
175 static int hf_xid_conflict;
176 static int hf_xid_slotnr;
177 static int hf_xid_version;
179 static int proto_irlmp;
180 static int hf_lmp_xid_hints;
181 static int hf_lmp_xid_charset;
182 static int hf_lmp_xid_name;
183 static int hf_lmp_xid_name_no_encoding;
184 static int hf_lmp_dst;
185 static int hf_lmp_dst_control;
186 static int hf_lmp_dst_lsap;
187 static int hf_lmp_src;
188 static int hf_lmp_src_r;
189 static int hf_lmp_src_lsap;
190 static int hf_lmp_opcode;
191 static int hf_lmp_rsvd;
192 static int hf_lmp_reason;
193 static int hf_lmp_mode;
194 static int hf_lmp_status;
196 static int proto_iap;
197 static int hf_iap_ctl;
198 static int hf_iap_ctl_lst;
199 static int hf_iap_ctl_ack;
200 static int hf_iap_ctl_opcode;
201 static int hf_iap_class_name;
202 static int hf_iap_attr_name;
203 static int hf_iap_return;
204 static int hf_iap_list_len;
205 static int hf_iap_list_entry;
206 static int hf_iap_obj_id;
207 static int hf_iap_attr_type;
208 static int hf_iap_int;
209 static int hf_iap_seq_len;
210 static int hf_iap_oct_seq;
211 static int hf_iap_char_set;
212 static int hf_iap_string;
213 static int hf_iap_invaloctet;
214 static int hf_iap_invallsap;
216 static int proto_ttp;
217 static int hf_ttp_p;
218 static int hf_ttp_icredit;
219 static int hf_ttp_m;
220 static int hf_ttp_dcredit;
222 static int proto_log;
223 static int hf_log_msg;
224 static int hf_log_missed;
226 /* Initialize the subtree pointers */
227 static int ett_irlap;
228 static int ett_lap_a;
229 static int ett_lap_c;
230 static int ett_lap_i;
231 static int ett_xid_flags;
232 static int ett_log;
233 static int ett_irlmp;
234 static int ett_lmp_dst;
235 static int ett_lmp_src;
236 static int ett_iap;
237 static int ett_iap_ctl;
238 static int ett_ttp;
240 #define MAX_PARAMETERS 32
241 static int ett_param[MAX_PARAMETERS];
243 static int ett_iap_entry[MAX_IAP_ENTRIES];
245 static int irda_address_type = -1;
247 static dissector_handle_t irda_handle;
249 static const xdlc_cf_items irlap_cf_items = {
250 &hf_lap_c_nr,
251 &hf_lap_c_ns,
252 &hf_lap_c_p,
253 &hf_lap_c_f,
254 &hf_lap_c_s,
255 &hf_lap_c_u_cmd,
256 &hf_lap_c_u_rsp,
257 &hf_lap_c_i,
258 &hf_lap_c_s_u
261 /* IAP conversation type */
262 typedef struct iap_conversation {
263 struct iap_conversation* pnext;
264 uint32_t iap_query_frame;
265 ias_attr_dissector_t* pattr_dissector;
266 } iap_conversation_t;
268 /* IrLMP conversation type */
269 typedef struct lmp_conversation {
270 struct lmp_conversation* pnext;
271 uint32_t iap_result_frame;
272 bool ttp;
273 dissector_handle_t dissector;
274 } lmp_conversation_t;
276 static const true_false_string lap_cr_vals = {
277 "Command",
278 "Response"
281 static const true_false_string set_notset = {
282 "Set",
283 "Not set"
286 static const value_string lap_c_ftype_vals[] = {
287 { XDLC_I, "Information frame" },
288 { XDLC_S, "Supervisory frame" },
289 { XDLC_U, "Unnumbered frame" },
290 { 0, NULL }
293 static const value_string lap_c_u_cmd_abbr_vals[] = {
294 { XDLC_SNRM, "SNRM" },
295 { XDLC_DISC, "DISC" },
296 { XDLC_UI, "UI" },
297 { IRDA_XID_CMD, "XID" },
298 { XDLC_TEST, "TEST" },
299 { 0, NULL }
302 static const value_string lap_c_u_rsp_abbr_vals[] = {
303 { XDLC_SNRM, "RNRM" },
304 { XDLC_UA, "UA" },
305 { XDLC_FRMR, "FRMR" },
306 { XDLC_DM, "DM" },
307 { XDLC_RD, "RD" },
308 { XDLC_UI, "UI" },
309 { XDLC_XID, "XID" },
310 { XDLC_TEST, "TEST" },
311 { 0, NULL }
314 static const value_string lap_c_u_cmd_vals[] = {
315 { XDLC_SNRM>>2, "Set Normal Response Mode" },
316 { XDLC_DISC>>2, "Disconnect" },
317 { XDLC_UI>>2, "Unnumbered Information" },
318 { IRDA_XID_CMD>>2, "Exchange Station Identification" },
319 { XDLC_TEST>>2, "Test" },
320 { 0, NULL }
323 static const value_string lap_c_u_rsp_vals[] = {
324 { XDLC_SNRM>>2, "Request Normal Response Mode" },
325 { XDLC_UA>>2, "Unnumbered Acknowledge" },
326 { XDLC_FRMR>>2, "Frame Reject" },
327 { XDLC_DM>>2, "Disconnect Mode" },
328 { XDLC_RD>>2, "Request Disconnect" },
329 { XDLC_UI>>2, "Unnumbered Information" },
330 { XDLC_XID>>2, "Exchange Station Identification" },
331 { XDLC_TEST>>2, "Test" },
332 { 0, NULL }
335 static const value_string lap_c_s_vals[] = {
336 { XDLC_RR>>2, "Receiver ready" },
337 { XDLC_RNR>>2, "Receiver not ready" },
338 { XDLC_REJ>>2, "Reject" },
339 { XDLC_SREJ>>2, "Selective reject" },
340 { 0, NULL }
343 static const value_string xid_slot_numbers[] = {
344 /* Number of XID slots */
345 { 0, "1" },
346 { 1, "6" },
347 { 2, "8" },
348 { 3, "16" },
349 { 0, NULL }
352 static const value_string lmp_opcode_vals[] = {
353 /* IrLMP frame opcodes */
354 { CONNECT_CMD, "Connect Command" },
355 { CONNECT_CNF, "Connect Confirm" },
356 { DISCONNECT, "Disconnect" },
357 { ACCESSMODE_CMD, "Access Mode Command" },
358 { ACCESSMODE_CNF, "Access Mode Confirm" },
359 { 0, NULL }
362 static const value_string lmp_reason_vals[] = {
363 /* IrLMP disconnect reasons */
364 { 0x01, "User Request" },
365 { 0x02, "Unexpected IrLAP Disconnect" },
366 { 0x03, "Failed to establish IrLAP connection" },
367 { 0x04, "IrLAP Reset" },
368 { 0x05, "Link Management Initiated Disconnect" },
369 { 0x06, "Data delivered on disconnected LSAP-Connection"},
370 { 0x07, "Non Responsive LM-MUX Client" },
371 { 0x08, "No available LM-MUX Client" },
372 { 0x09, "Connection Half Open" },
373 { 0x0A, "Illegal Source Address" },
374 { 0xFF, "Unspecified Disconnect Reason" },
375 { 0, NULL }
378 static const value_string lmp_mode_vals[] = {
379 /* IrLMP modes */
380 { 0x00, "Multiplexed" },
381 { 0x01, "Exclusive" },
382 { 0, NULL }
385 static const value_string lmp_status_vals[] = {
386 /* IrLMP status */
387 { 0x00, "Success" },
388 { 0x01, "Failure" },
389 { 0xFF, "Unsupported" },
390 { 0, NULL }
393 #define LMP_CHARSET_ASCII 0
394 #define LMP_CHARSET_ISO_8859_1 1
395 #define LMP_CHARSET_ISO_8859_2 2
396 #define LMP_CHARSET_ISO_8859_3 3
397 #define LMP_CHARSET_ISO_8859_4 4
398 #define LMP_CHARSET_ISO_8859_5 5
399 #define LMP_CHARSET_ISO_8859_6 6
400 #define LMP_CHARSET_ISO_8859_7 7
401 #define LMP_CHARSET_ISO_8859_8 8
402 #define LMP_CHARSET_ISO_8859_9 9
403 #define LMP_CHARSET_UNICODE 0xFF /* UCS-2 (byte order?) */
405 static const value_string lmp_charset_vals[] = {
406 /* IrLMP character set */
407 { LMP_CHARSET_ASCII, "ASCII" },
408 { LMP_CHARSET_ISO_8859_1, "ISO 8859-1" },
409 { LMP_CHARSET_ISO_8859_2, "ISO 8859-2" },
410 { LMP_CHARSET_ISO_8859_3, "ISO 8859-3" },
411 { LMP_CHARSET_ISO_8859_4, "ISO 8859-4" },
412 { LMP_CHARSET_ISO_8859_5, "ISO 8859-5" },
413 { LMP_CHARSET_ISO_8859_6, "ISO 8859-6" },
414 { LMP_CHARSET_ISO_8859_7, "ISO 8859-7" },
415 { LMP_CHARSET_ISO_8859_8, "ISO 8859-8" },
416 { LMP_CHARSET_ISO_8859_9, "ISO 8859-9" },
417 { LMP_CHARSET_UNICODE, "Unicode" },
418 { 0, NULL }
421 static const value_string iap_opcode_vals[] = {
422 /* IrIAP Op-codes */
423 { GET_INFO_BASE, "GetInfoBase" },
424 { GET_OBJECTS, "GetObjects" },
425 { GET_VALUE, "GetValue" },
426 { GET_VALUE_BY_CLASS, "GetValueByClass" },
427 { GET_OBJECT_INFO, "GetObjectInfo" },
428 { GET_ATTRIB_NAMES, "GetAttributeNames" },
429 { 0, NULL }
432 static const value_string iap_return_vals[] = {
433 /* IrIAP Return-codes */
434 { IAS_SUCCESS, "Success" },
435 { IAS_CLASS_UNKNOWN, "Class/Object Unknown" },
436 { IAS_ATTRIB_UNKNOWN, "Attribute Unknown" },
437 { IAS_ATTR_TOO_LONG, "Attribute List Too Long" },
438 { IAS_DISCONNECT, "Disconnect (Linux-IrDA only)" },
439 { IAS_UNSUPPORTED, "Unsupported Optional Operation" },
440 { 0, NULL }
443 static const value_string iap_attr_type_vals[] = {
444 /* LM-IAS Attribute types */
445 { IAS_MISSING, "Missing" },
446 { IAS_INTEGER, "Integer" },
447 { IAS_OCT_SEQ, "Octet Sequence" },
448 { IAS_STRING, "String" },
449 { 0, NULL }
452 static ias_attr_dissector_t device_attr_dissector[] = {
453 /* Device attribute dissectors */
454 /* { "IrLMPSupport", xxx }, not implemented yet... */
455 { NULL, NULL }
458 /* IAS class dissectors */
459 static ias_class_dissector_t class_dissector[] = { CLASS_DISSECTORS };
463 * Dissect parameter tuple
465 unsigned dissect_param_tuple(tvbuff_t* tvb, proto_tree* tree, unsigned offset)
467 uint8_t len = tvb_get_uint8(tvb, offset + 1);
469 if (tree)
470 proto_tree_add_item(tree, hf_param_pi, tvb, offset, 1, ENC_BIG_ENDIAN);
471 offset++;
473 if (tree)
474 proto_tree_add_item(tree, hf_param_pl, tvb, offset, 1, ENC_BIG_ENDIAN);
475 offset++;
477 if (len > 0)
479 if (tree)
480 proto_tree_add_item(tree, hf_param_pv, tvb, offset, len, ENC_NA);
481 offset += len;
484 return offset;
489 * Dissect TTP
491 static unsigned dissect_ttp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, bool data)
493 unsigned offset = 0;
494 uint8_t head;
495 char buf[128];
497 if (tvb_reported_length(tvb) == 0)
498 return 0;
500 /* Make entries in Protocol column on summary display */
501 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TTP");
503 head = tvb_get_uint8(tvb, offset);
505 snprintf(buf, 128, ", Credit=%d", head & ~TTP_PARAMETERS);
506 col_append_str(pinfo->cinfo, COL_INFO, buf);
508 if (root)
510 /* create display subtree for the protocol */
511 proto_item* ti = proto_tree_add_item(root, proto_ttp, tvb, 0, -1, ENC_NA);
512 proto_tree* tree = proto_item_add_subtree(ti, ett_ttp);
514 if (data)
516 proto_tree_add_item(tree, hf_ttp_m, tvb, offset, 1, ENC_BIG_ENDIAN);
517 proto_tree_add_item(tree, hf_ttp_dcredit, tvb, offset, 1, ENC_BIG_ENDIAN);
518 offset++;
520 else
522 proto_tree_add_item(tree, hf_ttp_p, tvb, offset, 1, ENC_BIG_ENDIAN);
523 proto_tree_add_item(tree, hf_ttp_icredit, tvb, offset, 1, ENC_BIG_ENDIAN);
524 offset++;
526 proto_item_set_len(tree, offset);
528 else
529 offset++;
531 return offset;
536 * Dissect IAP request
538 static void dissect_iap_request(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, uint8_t circuit_id)
540 unsigned offset = 0;
541 uint8_t op;
542 uint8_t clen = 0;
543 uint8_t alen = 0;
544 uint8_t src;
545 address srcaddr;
546 address destaddr;
547 conversation_t* conv;
548 iap_conversation_t* iap_conv;
550 if (tvb_reported_length(tvb) == 0)
551 return;
553 /* Make entries in Protocol column on summary display */
554 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAP");
556 op = tvb_get_uint8(tvb, offset) & IAP_OP;
558 switch (op)
560 case GET_VALUE_BY_CLASS:
561 clen = MIN(tvb_get_uint8(tvb, offset + 1), 60);
562 alen = MIN(tvb_get_uint8(tvb, offset + 1 + 1 + clen), 60);
564 /* create conversation entry */
565 src = circuit_id ^ CMD_FRAME;
566 set_address(&srcaddr, irda_address_type, 1, &src);
568 set_address(&destaddr, irda_address_type, 1, &circuit_id);
570 conv = find_conversation(pinfo->num, &srcaddr, &destaddr, CONVERSATION_NONE, pinfo->srcport, pinfo->destport, 0);
571 if (conv)
573 iap_conv = (iap_conversation_t*)conversation_get_proto_data(conv, proto_iap);
574 while (1)
576 if (iap_conv->iap_query_frame == pinfo->num)
578 iap_conv = NULL;
579 break;
581 if (iap_conv->pnext == NULL)
583 iap_conv->pnext = wmem_new(wmem_file_scope(), iap_conversation_t);
584 iap_conv = iap_conv->pnext;
585 break;
587 iap_conv = iap_conv->pnext;
590 else
592 conv = conversation_new(pinfo->num, &srcaddr, &destaddr, CONVERSATION_NONE, pinfo->srcport, pinfo->destport, 0);
593 iap_conv = wmem_new(wmem_file_scope(), iap_conversation_t);
594 conversation_add_proto_data(conv, proto_iap, (void*)iap_conv);
596 if (iap_conv)
598 iap_conv->pnext = NULL;
599 iap_conv->iap_query_frame = pinfo->num;
600 iap_conv->pattr_dissector = NULL;
603 char *class_name = (char *) tvb_get_string_enc(pinfo->pool, tvb, offset + 1 + 1, clen, ENC_ASCII|ENC_NA);
604 char *attr_name = (char *) tvb_get_string_enc(pinfo->pool, tvb, offset + 1 + 1 + clen + 1, alen, ENC_ASCII|ENC_NA);
606 col_add_fstr(pinfo->cinfo, COL_INFO, "GetValueByClass: \"%s\" \"%s\"",
607 format_text(pinfo->pool, (unsigned char *) class_name, strlen(class_name)),
608 format_text(pinfo->pool, (unsigned char *) attr_name, strlen(attr_name)));
610 /* Dissect IAP query if it is new */
611 if (iap_conv)
613 int i, j;
615 /* Find the attribute dissector */
616 for (i = 0; class_dissector[i].class_name != NULL; i++)
617 if (strcmp(class_name, class_dissector[i].class_name) == 0)
619 for (j = 0; class_dissector[i].pattr_dissector[j].attr_name != NULL; j++)
620 if (strcmp(attr_name, class_dissector[i].pattr_dissector[j].attr_name) == 0)
622 iap_conv->pattr_dissector = &class_dissector[i].pattr_dissector[j];
623 break;
625 break;
630 if (root)
632 /* create display subtree for the protocol */
633 proto_item* ti = proto_tree_add_item(root, proto_iap, tvb, 0, -1, ENC_NA);
634 proto_tree* tree = proto_item_add_subtree(ti, ett_iap);
636 proto_tree* ctl_tree;
639 ti = proto_tree_add_item(tree, hf_iap_ctl, tvb, offset, 1, ENC_BIG_ENDIAN);
640 ctl_tree = proto_item_add_subtree(ti, ett_iap_ctl);
641 proto_tree_add_item(ctl_tree, hf_iap_ctl_lst, tvb, offset, 1, ENC_BIG_ENDIAN);
642 proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, ENC_BIG_ENDIAN);
643 proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
644 offset++;
646 switch (op)
648 case GET_VALUE_BY_CLASS:
649 proto_tree_add_item(tree, hf_iap_class_name, tvb, offset, 1, ENC_ASCII|ENC_BIG_ENDIAN);
650 offset += 1 + clen;
652 proto_tree_add_item(tree, hf_iap_attr_name, tvb, offset, 1, ENC_ASCII|ENC_BIG_ENDIAN);
653 offset += 1 + alen;
654 break;
657 else
659 offset++;
660 switch (op)
662 case GET_VALUE_BY_CLASS:
663 offset += 1 + clen + 1 + alen;
664 break;
668 /* If any bytes remain, send it to the generic data dissector */
669 tvb = tvb_new_subset_remaining(tvb, offset);
670 call_data_dissector(tvb, pinfo, root);
675 * Dissect IAP result
677 static void dissect_iap_result(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, uint8_t circuit_id)
679 unsigned offset = 0;
680 unsigned len = tvb_reported_length(tvb);
681 unsigned n = 0;
682 unsigned list_len;
683 uint8_t op;
684 uint8_t retcode;
685 uint8_t type;
686 uint16_t attr_len;
687 char buf[300];
688 uint8_t src;
689 address srcaddr;
690 address destaddr;
691 conversation_t* conv;
692 iap_conversation_t* cur_iap_conv;
693 iap_conversation_t* iap_conv = NULL;
694 uint32_t num;
697 if (len == 0)
698 return;
700 /* Make entries in Protocol column on summary display */
701 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAP");
703 op = tvb_get_uint8(tvb, offset) & IAP_OP;
704 retcode = tvb_get_uint8(tvb, offset + 1);
706 src = circuit_id ^ CMD_FRAME;
707 set_address(&srcaddr, irda_address_type, 1, &src);
709 set_address(&destaddr, irda_address_type, 1, &circuit_id);
711 /* Find result value dissector */
712 conv = find_conversation(pinfo->num, &srcaddr, &destaddr, CONVERSATION_NONE, pinfo->srcport, pinfo->destport, 0);
713 if (conv)
715 num = pinfo->num;
717 iap_conv = (iap_conversation_t*)conversation_get_proto_data(conv, proto_iap);
718 while (iap_conv && (iap_conv->iap_query_frame >= num))
719 iap_conv = iap_conv->pnext;
721 if (iap_conv)
723 cur_iap_conv = iap_conv->pnext;
724 while (cur_iap_conv)
726 if ((cur_iap_conv->iap_query_frame < num) &&
727 (cur_iap_conv->iap_query_frame > iap_conv->iap_query_frame))
729 iap_conv = cur_iap_conv;
732 cur_iap_conv = cur_iap_conv->pnext;
737 col_set_str(pinfo->cinfo, COL_INFO, "Result: ");
738 col_append_str(pinfo->cinfo, COL_INFO, val_to_str(retcode, iap_return_vals, "0x%02X"));
740 switch (op)
742 case GET_VALUE_BY_CLASS:
743 if (retcode == 0)
745 switch (tvb_get_uint8(tvb, offset + 6))
747 case IAS_MISSING:
748 col_append_str(pinfo->cinfo, COL_INFO, ", Missing");
749 break;
751 case IAS_INTEGER:
752 col_append_fstr(pinfo->cinfo, COL_INFO, ", Integer: %d", tvb_get_ntohl(tvb, offset + 7));
753 break;
755 case IAS_OCT_SEQ:
756 snprintf(buf, 300, ", %d Octets", tvb_get_ntohs(tvb, offset + 7));
757 break;
759 case IAS_STRING:
760 n = tvb_get_uint8(tvb, offset + 8);
761 col_append_fstr(pinfo->cinfo, COL_INFO, ", \"%s\"", tvb_get_string_enc(pinfo->pool, tvb, offset + 9, n, ENC_ASCII));
762 break;
763 default:
764 break;
766 if (tvb_get_ntohs(tvb, offset + 2) > 1)
767 col_append_str(pinfo->cinfo, COL_INFO, ", ...");
769 break;
772 if (root)
774 /* create display subtree for the protocol */
775 proto_item* ti = proto_tree_add_item(root, proto_iap, tvb, 0, -1, ENC_NA);
776 proto_tree* tree = proto_item_add_subtree(ti, ett_iap);
778 proto_tree* ctl_tree;
779 proto_tree* entry_tree;
782 ti = proto_tree_add_item(tree, hf_iap_ctl, tvb, offset, 1, ENC_BIG_ENDIAN);
783 ctl_tree = proto_item_add_subtree(ti, ett_iap_ctl);
784 proto_tree_add_item(ctl_tree, hf_iap_ctl_lst, tvb, offset, 1, ENC_BIG_ENDIAN);
785 proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, ENC_BIG_ENDIAN);
786 proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
787 offset++;
789 proto_tree_add_item(tree, hf_iap_return, tvb, offset, 1, ENC_BIG_ENDIAN);
790 offset++;
792 switch (op)
794 case GET_VALUE_BY_CLASS:
795 if (retcode == 0)
797 list_len = tvb_get_ntohs(tvb, offset);
799 proto_tree_add_item(tree, hf_iap_list_len, tvb, offset, 2, ENC_BIG_ENDIAN);
800 offset += 2;
802 while ((offset < len) && (n < list_len))
804 type = tvb_get_uint8(tvb, offset + 2);
805 switch (type)
807 case IAS_INTEGER:
808 attr_len = 4;
809 break;
811 case IAS_OCT_SEQ:
812 attr_len = tvb_get_ntohs(tvb, offset + 2 + 1) + 2;
813 break;
815 case IAS_STRING:
816 attr_len = tvb_get_uint8(tvb, offset + 2 + 1 + 1) + 2;
817 break;
819 default:
820 attr_len = 0;
823 ti = proto_tree_add_item(tree, hf_iap_list_entry, tvb, offset, 2 + 1 + attr_len, ENC_NA);
824 proto_item_append_text(ti, "%d", n + 1);
825 entry_tree = proto_item_add_subtree(ti, ett_iap_entry[n]);
827 proto_tree_add_item(entry_tree, hf_iap_obj_id, tvb, offset, 2, ENC_BIG_ENDIAN);
828 offset += 2;
830 proto_tree_add_item(entry_tree, hf_iap_attr_type, tvb, offset, 1, ENC_BIG_ENDIAN);
831 offset++;
833 switch (type)
835 case IAS_INTEGER:
836 if (!iap_conv || !iap_conv->pattr_dissector ||
837 !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
838 n, type, circuit_id))
839 proto_tree_add_item(entry_tree, hf_iap_int, tvb, offset, 4, ENC_BIG_ENDIAN);
840 break;
842 case IAS_OCT_SEQ:
843 proto_tree_add_item(entry_tree, hf_iap_seq_len, tvb, offset, 2, ENC_BIG_ENDIAN);
844 if (!iap_conv || !iap_conv->pattr_dissector ||
845 !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
846 n, type, circuit_id))
847 proto_tree_add_item(entry_tree, hf_iap_oct_seq, tvb, offset + 2,
848 attr_len - 2, ENC_NA);
849 break;
851 case IAS_STRING:
852 proto_tree_add_item(entry_tree, hf_iap_char_set, tvb, offset, 1, ENC_BIG_ENDIAN);
853 if (!iap_conv || !iap_conv->pattr_dissector ||
854 !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
855 n, type, circuit_id))
856 proto_tree_add_item(entry_tree, hf_iap_string, tvb, offset + 1, 1, ENC_ASCII|ENC_BIG_ENDIAN);
857 break;
859 offset += attr_len;
861 n++;
864 break;
867 else
869 offset += 2;
870 switch (op)
872 case GET_VALUE_BY_CLASS:
873 if (retcode == 0)
875 offset += 2;
877 while (offset < len)
879 offset += 2;
880 type = tvb_get_uint8(tvb, offset);
881 offset++;
883 switch (type)
885 case IAS_INTEGER:
886 attr_len = 4;
887 if (iap_conv && iap_conv->pattr_dissector)
888 iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
889 n, type, circuit_id);
890 break;
892 case IAS_OCT_SEQ:
893 attr_len = tvb_get_ntohs(tvb, offset) + 2;
894 if (iap_conv && iap_conv->pattr_dissector)
895 iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
896 n, type, circuit_id);
897 break;
899 case IAS_STRING:
900 attr_len = tvb_get_uint8(tvb, offset + 1) + 2;
901 if (iap_conv && iap_conv->pattr_dissector)
902 iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
903 n, type, circuit_id);
904 break;
906 default:
907 attr_len = 0;
909 offset += attr_len;
911 n++;
914 break;
918 /* If any bytes remain, send it to the generic data dissector */
919 tvb = tvb_new_subset_remaining(tvb, offset);
920 call_data_dissector(tvb, pinfo, root);
925 * Check if IAP result is octet sequence
927 bool check_iap_octet_result(tvbuff_t* tvb, proto_tree* tree, unsigned offset,
928 const char* attr_name, uint8_t attr_type)
930 if (attr_type != IAS_OCT_SEQ)
932 if (tree)
934 proto_item* ti = proto_tree_add_item(tree, hf_iap_invaloctet, tvb, offset, 0, ENC_NA);
935 proto_item_append_text(ti, "%s", attr_name);
936 proto_item_append_text(ti, "\" attribute must be octet sequence!");
939 return false;
941 else
942 return true;
947 * Check if IAP result is correct LsapSel
949 uint8_t check_iap_lsap_result(tvbuff_t* tvb, proto_tree* tree, unsigned offset,
950 const char* attr_name, uint8_t attr_type)
952 uint32_t lsap;
955 if ((attr_type != IAS_INTEGER) || ((lsap = tvb_get_ntohl(tvb, offset)) < 0x01) ||
956 (lsap > 0x6F))
958 if (tree)
960 proto_item* ti = proto_tree_add_item(tree, hf_iap_invallsap, tvb, offset, 0, ENC_NA);
961 proto_item_append_text(ti, "%s", attr_name);
962 proto_item_append_text(ti, "\" attribute must be integer value between 0x01 and 0x6F!");
965 return 0;
967 else
968 return lsap;
973 * Dissect IrDA application protocol
975 static void dissect_appl_proto(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, pdu_type_t pdu_type, uint8_t circuit_id)
977 unsigned offset = 0;
978 uint8_t src;
979 address srcaddr;
980 address destaddr;
981 conversation_t* conv;
982 lmp_conversation_t* cur_lmp_conv;
983 lmp_conversation_t* lmp_conv = NULL;
984 uint32_t num;
987 src = circuit_id ^ CMD_FRAME;
988 set_address(&srcaddr, irda_address_type, 1, &src);
990 set_address(&destaddr, irda_address_type, 1, &circuit_id);
992 /* Find result value dissector */
993 conv = find_conversation(pinfo->num, &srcaddr, &destaddr, CONVERSATION_NONE, pinfo->srcport, pinfo->destport, 0);
994 if (conv)
996 num = pinfo->num;
998 lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
999 while (lmp_conv && (lmp_conv->iap_result_frame >= num))
1000 lmp_conv = lmp_conv->pnext;
1002 if (lmp_conv)
1004 cur_lmp_conv = lmp_conv->pnext;
1005 while (cur_lmp_conv)
1007 if ((cur_lmp_conv->iap_result_frame < num) &&
1008 (cur_lmp_conv->iap_result_frame > lmp_conv->iap_result_frame))
1010 lmp_conv = cur_lmp_conv;
1013 cur_lmp_conv = cur_lmp_conv->pnext;
1018 if (lmp_conv)
1020 /*ws_message("%x:%d->%x:%d = %p\n", src, pinfo->srcport, circuit_id, pinfo->destport, lmp_conv); */
1021 /*ws_message("->%d: %d %d %p\n", pinfo->num, lmp_conv->iap_result_frame, lmp_conv->ttp, lmp_conv->proto_dissector); */
1022 if ((lmp_conv->ttp) && (pdu_type != DISCONNECT_PDU))
1024 offset += dissect_ttp(tvb, pinfo, root, (pdu_type == DATA_PDU));
1026 tvb = tvb_new_subset_remaining(tvb, offset);
1029 call_dissector_with_data(lmp_conv->dissector, tvb, pinfo, root, GUINT_TO_POINTER(pdu_type));
1031 else
1032 call_data_dissector(tvb, pinfo, root);
1037 * Dissect LMP
1039 static void dissect_irlmp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, uint8_t circuit_id)
1041 unsigned offset = 0;
1042 uint8_t dlsap;
1043 uint8_t slsap;
1044 uint8_t cbit;
1045 uint8_t opcode = 0;
1048 /* Make entries in Protocol column on summary display */
1049 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLMP");
1051 dlsap = tvb_get_uint8(tvb, offset);
1052 cbit = dlsap & CONTROL_BIT;
1053 dlsap &= ~CONTROL_BIT;
1055 slsap = tvb_get_uint8(tvb, offset+1) & ~CONTROL_BIT;
1057 /* save Lsaps in pinfo */
1058 pinfo->srcport = slsap;
1059 pinfo->destport = dlsap;
1061 if (cbit != 0)
1063 opcode = tvb_get_uint8(tvb, offset+2);
1065 col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, ", slsap, dlsap);
1066 col_append_str(pinfo->cinfo, COL_INFO, val_to_str(opcode, lmp_opcode_vals, "0x%02X"));
1067 if ((opcode == ACCESSMODE_CMD) || (opcode == ACCESSMODE_CNF))
1069 col_append_str(pinfo->cinfo, COL_INFO, " (");
1070 col_append_str(pinfo->cinfo, COL_INFO,
1071 val_to_str(tvb_get_uint8(tvb, offset+4), lmp_mode_vals, "0x%02X"));
1072 col_append_str(pinfo->cinfo, COL_INFO, ")");
1075 else
1076 col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, Len=%d", slsap, dlsap,
1077 tvb_reported_length(tvb) - 2);
1079 if (root)
1081 /* create display subtree for the protocol */
1082 proto_item* ti = proto_tree_add_item(root, proto_irlmp, tvb, 0, -1, ENC_NA);
1083 proto_tree* tree = proto_item_add_subtree(ti, ett_irlmp);
1085 proto_tree* dst_tree;
1086 proto_tree* src_tree;
1089 ti = proto_tree_add_item(tree, hf_lmp_dst, tvb, offset, 1, ENC_BIG_ENDIAN);
1090 dst_tree = proto_item_add_subtree(ti, ett_lmp_dst);
1091 proto_tree_add_item(dst_tree, hf_lmp_dst_control, tvb, offset, 1, ENC_BIG_ENDIAN);
1092 proto_tree_add_item(dst_tree, hf_lmp_dst_lsap, tvb, offset, 1, ENC_BIG_ENDIAN);
1093 offset++;
1095 ti = proto_tree_add_item(tree, hf_lmp_src, tvb, offset, 1, ENC_BIG_ENDIAN);
1096 src_tree = proto_item_add_subtree(ti, ett_lmp_src);
1097 proto_tree_add_item(src_tree, hf_lmp_src_r, tvb, offset, 1, ENC_BIG_ENDIAN);
1098 proto_tree_add_item(src_tree, hf_lmp_src_lsap, tvb, offset, 1, ENC_BIG_ENDIAN);
1099 offset++;
1101 if (cbit != 0)
1103 proto_tree_add_item(tree, hf_lmp_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
1104 offset++;
1106 switch (opcode)
1108 case CONNECT_CMD:
1109 case CONNECT_CNF:
1110 if (offset < tvb_reported_length(tvb))
1112 proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, ENC_BIG_ENDIAN);
1113 offset++;
1115 break;
1117 case DISCONNECT:
1118 proto_tree_add_item(tree, hf_lmp_reason, tvb, offset, 1, ENC_BIG_ENDIAN);
1119 offset++;
1120 break;
1122 case ACCESSMODE_CMD:
1123 proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, ENC_BIG_ENDIAN);
1124 offset++;
1126 proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
1127 offset++;
1128 break;
1130 case ACCESSMODE_CNF:
1131 proto_tree_add_item( tree, hf_lmp_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1132 offset++;
1134 proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
1135 offset++;
1136 break;
1140 tvb = tvb_new_subset_remaining(tvb, offset);
1141 proto_item_set_len(tree, offset);
1143 else
1145 offset += 2;
1146 if (cbit != 0)
1148 offset += 1;
1150 switch (opcode)
1152 case CONNECT_CMD:
1153 case CONNECT_CNF:
1154 if (offset < tvb_reported_length(tvb))
1155 offset++;
1156 break;
1158 case DISCONNECT:
1159 offset++;
1160 break;
1162 case ACCESSMODE_CMD:
1163 case ACCESSMODE_CNF:
1164 offset += 2;
1165 break;
1169 tvb = tvb_new_subset_remaining(tvb, offset);
1172 if (cbit == 0)
1174 if (dlsap == LSAP_IAS)
1175 dissect_iap_request(tvb, pinfo, root, circuit_id);
1176 else if (slsap == LSAP_IAS)
1177 dissect_iap_result(tvb, pinfo, root, circuit_id);
1178 else
1179 dissect_appl_proto(tvb, pinfo, root, DATA_PDU, circuit_id);
1181 else
1183 if ((dlsap == LSAP_IAS) || (slsap == LSAP_IAS))
1184 call_data_dissector(tvb, pinfo, root);
1185 else
1186 switch (opcode)
1188 case CONNECT_CMD:
1189 case CONNECT_CNF:
1190 dissect_appl_proto(tvb, pinfo, root, CONNECT_PDU, circuit_id);
1191 break;
1193 case DISCONNECT:
1194 dissect_appl_proto(tvb, pinfo, root, DISCONNECT_PDU, circuit_id);
1195 break;
1197 default:
1198 call_data_dissector(tvb, pinfo, root);
1205 * Add LMP conversation
1207 void add_lmp_conversation(packet_info* pinfo, uint8_t dlsap, bool ttp, dissector_handle_t dissector, uint8_t circuit_id)
1209 uint8_t dest;
1210 address srcaddr;
1211 address destaddr;
1212 conversation_t* conv;
1213 lmp_conversation_t* lmp_conv = NULL;
1216 /*ws_message("%d: add_lmp_conversation(%p, %d, %d, %p) = ", pinfo->num, pinfo, dlsap, ttp, proto_dissector); */
1217 set_address(&srcaddr, irda_address_type, 1, &circuit_id);
1218 dest = circuit_id ^ CMD_FRAME;
1219 set_address(&destaddr, irda_address_type, 1, &dest);
1221 conv = find_conversation(pinfo->num, &destaddr, &srcaddr, CONVERSATION_NONE, dlsap, 0, NO_PORT_B);
1222 if (conv)
1224 lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
1225 while (1)
1227 /* Does entry already exist? */
1228 if (lmp_conv->iap_result_frame == pinfo->num)
1229 return;
1231 if (lmp_conv->pnext == NULL)
1233 lmp_conv->pnext = wmem_new(wmem_file_scope(), lmp_conversation_t);
1234 lmp_conv = lmp_conv->pnext;
1235 break;
1237 lmp_conv = lmp_conv->pnext;
1240 else
1242 conv = conversation_new(pinfo->num, &destaddr, &srcaddr, CONVERSATION_NONE, dlsap, 0, NO_PORT2);
1243 lmp_conv = wmem_new(wmem_file_scope(), lmp_conversation_t);
1244 conversation_add_proto_data(conv, proto_irlmp, (void*)lmp_conv);
1247 lmp_conv->pnext = NULL;
1248 lmp_conv->iap_result_frame = pinfo->num;
1249 lmp_conv->ttp = ttp;
1250 lmp_conv->dissector = dissector;
1252 /*ws_message("%p\n", lmp_conv); */
1257 * Dissect Negotiation Parameters
1259 static unsigned dissect_negotiation(tvbuff_t* tvb, proto_tree* tree, unsigned offset)
1261 unsigned n = 0;
1262 proto_item* ti;
1263 proto_tree* p_tree;
1264 char buf[256];
1265 uint8_t pv;
1267 while (tvb_reported_length_remaining(tvb, offset) > 0)
1269 uint8_t p_len = tvb_get_uint8(tvb, offset + 1);
1271 if (tree)
1273 ti = proto_tree_add_item(tree, hf_negotiation_param, tvb, offset, p_len + 2, ENC_NA);
1274 p_tree = proto_item_add_subtree(ti, ett_param[n]);
1276 pv = tvb_get_uint8(tvb, offset+2);
1277 buf[0] = 0;
1279 switch (tvb_get_uint8(tvb, offset))
1281 case PI_BAUD_RATE:
1282 proto_item_append_text(ti, ": Baud Rate (");
1284 if (pv & 0x01)
1285 (void) g_strlcat(buf, ", 2400", 256);
1286 if (pv & 0x02)
1287 (void) g_strlcat(buf, ", 9600", 256);
1288 if (pv & 0x04)
1289 (void) g_strlcat(buf, ", 19200", 256);
1290 if (pv & 0x08)
1291 (void) g_strlcat(buf, ", 38400", 256);
1292 if (pv & 0x10)
1293 (void) g_strlcat(buf, ", 57600", 256);
1294 if (pv & 0x20)
1295 (void) g_strlcat(buf, ", 115200", 256);
1296 if (pv & 0x40)
1297 (void) g_strlcat(buf, ", 576000", 256);
1298 if (pv & 0x80)
1299 (void) g_strlcat(buf, ", 1152000", 256);
1300 if ((p_len > 1) && (tvb_get_uint8(tvb, offset+3) & 0x01))
1301 (void) g_strlcat(buf, ", 4000000", 256);
1303 (void) g_strlcat(buf, " bps)", 256);
1305 proto_item_append_text(ti, "%s", buf+2);
1307 break;
1309 case PI_MAX_TURN_TIME:
1310 proto_item_append_text(ti, ": Maximum Turn Time (");
1312 if (pv & 0x01)
1313 (void) g_strlcat(buf, ", 500", 256);
1314 if (pv & 0x02)
1315 (void) g_strlcat(buf, ", 250", 256);
1316 if (pv & 0x04)
1317 (void) g_strlcat(buf, ", 100", 256);
1318 if (pv & 0x08)
1319 (void) g_strlcat(buf, ", 50", 256);
1321 (void) g_strlcat(buf, " ms)", 256);
1323 proto_item_append_text(ti, "%s", buf+2);
1325 break;
1327 case PI_DATA_SIZE:
1328 proto_item_append_text(ti, ": Data Size (");
1330 if (pv & 0x01)
1331 (void) g_strlcat(buf, ", 64", 256);
1332 if (pv & 0x02)
1333 (void) g_strlcat(buf, ", 128", 256);
1334 if (pv & 0x04)
1335 (void) g_strlcat(buf, ", 256", 256);
1336 if (pv & 0x08)
1337 (void) g_strlcat(buf, ", 512", 256);
1338 if (pv & 0x10)
1339 (void) g_strlcat(buf, ", 1024", 256);
1340 if (pv & 0x20)
1341 (void) g_strlcat(buf, ", 2048", 256);
1343 (void) g_strlcat(buf, " bytes)", 256);
1345 proto_item_append_text(ti, "%s", buf+2);
1347 break;
1349 case PI_WINDOW_SIZE:
1350 proto_item_append_text(ti, ": Window Size (");
1352 if (pv & 0x01)
1353 (void) g_strlcat(buf, ", 1", 256);
1354 if (pv & 0x02)
1355 (void) g_strlcat(buf, ", 2", 256);
1356 if (pv & 0x04)
1357 (void) g_strlcat(buf, ", 3", 256);
1358 if (pv & 0x08)
1359 (void) g_strlcat(buf, ", 4", 256);
1360 if (pv & 0x10)
1361 (void) g_strlcat(buf, ", 5", 256);
1362 if (pv & 0x20)
1363 (void) g_strlcat(buf, ", 6", 256);
1364 if (pv & 0x40)
1365 (void) g_strlcat(buf, ", 7", 256);
1367 (void) g_strlcat(buf, " frame window)", 256);
1369 proto_item_append_text(ti, "%s", buf+2);
1371 break;
1373 case PI_ADD_BOFS:
1374 proto_item_append_text(ti, ": Additional BOFs (");
1376 if (pv & 0x01)
1377 (void) g_strlcat(buf, ", 48", 256);
1378 if (pv & 0x02)
1379 (void) g_strlcat(buf, ", 24", 256);
1380 if (pv & 0x04)
1381 (void) g_strlcat(buf, ", 12", 256);
1382 if (pv & 0x08)
1383 (void) g_strlcat(buf, ", 5", 256);
1384 if (pv & 0x10)
1385 (void) g_strlcat(buf, ", 3", 256);
1386 if (pv & 0x20)
1387 (void) g_strlcat(buf, ", 2", 256);
1388 if (pv & 0x40)
1389 (void) g_strlcat(buf, ", 1", 256);
1390 if (pv & 0x80)
1391 (void) g_strlcat(buf, ", 0", 256);
1393 (void) g_strlcat(buf, " additional BOFs at 115200)", 256);
1395 proto_item_append_text(ti, "%s", buf+2);
1397 break;
1399 case PI_MIN_TURN_TIME:
1400 proto_item_append_text(ti, ": Minimum Turn Time (");
1402 if (pv & 0x01)
1403 (void) g_strlcat(buf, ", 10", 256);
1404 if (pv & 0x02)
1405 (void) g_strlcat(buf, ", 5", 256);
1406 if (pv & 0x04)
1407 (void) g_strlcat(buf, ", 1", 256);
1408 if (pv & 0x08)
1409 (void) g_strlcat(buf, ", 0.5", 256);
1410 if (pv & 0x10)
1411 (void) g_strlcat(buf, ", 0.1", 256);
1412 if (pv & 0x20)
1413 (void) g_strlcat(buf, ", 0.05", 256);
1414 if (pv & 0x40)
1415 (void) g_strlcat(buf, ", 0.01", 256);
1416 if (pv & 0x80)
1417 (void) g_strlcat(buf, ", 0", 256);
1419 (void) g_strlcat(buf, " ms)", 256);
1421 proto_item_append_text(ti, "%s", buf+2);
1423 break;
1425 case PI_LINK_DISC:
1426 proto_item_append_text(ti, ": Link Disconnect/Threshold Time (");
1428 if (pv & 0x01)
1429 (void) g_strlcat(buf, ", 3/0", 256);
1430 if (pv & 0x02)
1431 (void) g_strlcat(buf, ", 8/3", 256);
1432 if (pv & 0x04)
1433 (void) g_strlcat(buf, ", 12/3", 256);
1434 if (pv & 0x08)
1435 (void) g_strlcat(buf, ", 16/3", 256);
1436 if (pv & 0x10)
1437 (void) g_strlcat(buf, ", 20/3", 256);
1438 if (pv & 0x20)
1439 (void) g_strlcat(buf, ", 25/3", 256);
1440 if (pv & 0x40)
1441 (void) g_strlcat(buf, ", 30/3", 256);
1442 if (pv & 0x80)
1443 (void) g_strlcat(buf, ", 40/3", 256);
1445 (void) g_strlcat(buf, " s)", 256);
1447 proto_item_append_text(ti, "%s", buf+2);
1449 break;
1451 default:
1452 proto_item_append_text(ti, ": unknown");
1454 } else
1455 p_tree = NULL;
1457 offset = dissect_param_tuple(tvb, p_tree, offset);
1458 n++;
1461 return offset;
1466 * Dissect XID packet
1468 static void dissect_xid(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, proto_tree* lap_tree, bool is_command)
1470 int offset = 0;
1471 proto_item* ti = NULL;
1472 proto_tree* i_tree = NULL;
1473 proto_tree* flags_tree;
1474 uint32_t saddr, daddr;
1475 uint8_t s;
1476 proto_tree* lmp_tree = NULL;
1478 if (lap_tree)
1480 ti = proto_tree_add_item(lap_tree, hf_lap_i, tvb, offset, -1, ENC_NA);
1481 i_tree = proto_item_add_subtree(ti, ett_lap_i);
1483 proto_tree_add_item(i_tree, hf_xid_ident, tvb, offset, 1, ENC_BIG_ENDIAN);
1485 offset++;
1487 saddr = tvb_get_letohl(tvb, offset);
1488 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1489 if (lap_tree)
1490 proto_tree_add_uint(i_tree, hf_xid_saddr, tvb, offset, 4, saddr);
1491 offset += 4;
1493 daddr = tvb_get_letohl(tvb, offset);
1494 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1495 if (lap_tree)
1496 proto_tree_add_uint(i_tree, hf_xid_daddr, tvb, offset, 4, daddr);
1497 offset += 4;
1499 if (lap_tree)
1501 /* Discovery flags */
1502 ti = proto_tree_add_item(i_tree, hf_xid_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
1503 flags_tree = proto_item_add_subtree(ti, ett_xid_flags);
1504 proto_tree_add_item(flags_tree, hf_xid_s, tvb, offset, 1, ENC_BIG_ENDIAN);
1505 proto_tree_add_item(flags_tree, hf_xid_conflict, tvb, offset, 1, ENC_BIG_ENDIAN);
1507 offset++;
1509 if (is_command)
1511 s = tvb_get_uint8(tvb, offset);
1512 if (s == 0xFF)
1513 col_append_str(pinfo->cinfo, COL_INFO, ", s=final");
1514 else
1515 col_append_fstr(pinfo->cinfo, COL_INFO, ", s=%u", s);
1516 if (lap_tree)
1518 ti = proto_tree_add_uint(i_tree, hf_xid_slotnr, tvb, offset, 1, s);
1519 if (s == 0xFF)
1520 proto_item_append_text(ti, " (final)");
1523 /* Skip (empty?) byte even if no command.. Have seen non-zero values in a capture */
1524 offset++;
1526 if (lap_tree)
1527 proto_tree_add_item(i_tree, hf_xid_version, tvb, offset, 1, ENC_BIG_ENDIAN);
1528 offset++;
1530 if (lap_tree)
1532 proto_item_set_end(lap_tree, tvb, offset);
1533 proto_item_set_end(i_tree, tvb, offset);
1536 if (tvb_reported_length_remaining(tvb, offset) > 0)
1538 unsigned hints_len;
1539 uint8_t hint1 = 0;
1540 uint8_t hint2 = 0;
1542 if (root)
1544 ti = proto_tree_add_item(root, proto_irlmp, tvb, offset, -1, ENC_NA);
1545 lmp_tree = proto_item_add_subtree(ti, ett_irlmp);
1548 for (hints_len = 0;;)
1550 uint8_t hint = tvb_get_uint8(tvb, offset + hints_len++);
1552 if (hints_len == 1)
1553 hint1 = hint;
1554 else if (hints_len == 2)
1555 hint2 = hint;
1557 if ((hint & 0x80) == 0)
1558 break;
1561 if (root)
1563 ti = proto_tree_add_item(lmp_tree, hf_lmp_xid_hints, tvb, offset, hints_len, ENC_NA);
1564 if ((hint1 | hint2) != 0)
1566 char service_hints[256];
1568 service_hints[0] = 0;
1570 if (hint1 & 0x01)
1571 (void) g_strlcat(service_hints, ", PnP Compatible", 256);
1572 if (hint1 & 0x02)
1573 (void) g_strlcat(service_hints, ", PDA/Palmtop", 256);
1574 if (hint1 & 0x04)
1575 (void) g_strlcat(service_hints, ", Computer", 256);
1576 if (hint1 & 0x08)
1577 (void) g_strlcat(service_hints, ", Printer", 256);
1578 if (hint1 & 0x10)
1579 (void) g_strlcat(service_hints, ", Modem", 256);
1580 if (hint1 & 0x20)
1581 (void) g_strlcat(service_hints, ", Fax", 256);
1582 if (hint1 & 0x40)
1583 (void) g_strlcat(service_hints, ", LAN Access", 256);
1584 if (hint2 & 0x01)
1585 (void) g_strlcat(service_hints, ", Telephony", 256);
1586 if (hint2 & 0x02)
1587 (void) g_strlcat(service_hints, ", File Server", 256);
1588 if (hint2 & 0x04)
1589 (void) g_strlcat(service_hints, ", IrCOMM", 256);
1590 if (hint2 & 0x20)
1591 (void) g_strlcat(service_hints, ", OBEX", 256);
1593 (void) g_strlcat(service_hints, ")", 256);
1594 service_hints[0] = ' ';
1595 service_hints[1] = '(';
1597 proto_item_append_text(ti, "%s", service_hints);
1600 offset += hints_len;
1602 if (tvb_reported_length_remaining(tvb, offset) > 0)
1604 uint8_t cset;
1605 int name_len;
1606 char *name;
1607 bool have_encoding;
1608 unsigned encoding;
1610 cset = tvb_get_uint8(tvb, offset);
1611 if (root)
1612 proto_tree_add_uint(lmp_tree, hf_lmp_xid_charset, tvb, offset, 1, cset);
1613 offset++;
1614 name_len = tvb_reported_length_remaining(tvb, offset);
1615 if (name_len > 0)
1617 switch (cset) {
1619 case LMP_CHARSET_ASCII:
1620 encoding = ENC_ASCII|ENC_NA;
1621 have_encoding = true;
1622 break;
1624 case LMP_CHARSET_ISO_8859_1:
1625 encoding = ENC_ISO_8859_1|ENC_NA;
1626 have_encoding = true;
1627 break;
1629 case LMP_CHARSET_ISO_8859_2:
1630 encoding = ENC_ISO_8859_2|ENC_NA;
1631 have_encoding = true;
1632 break;
1634 case LMP_CHARSET_ISO_8859_3:
1635 encoding = ENC_ISO_8859_3|ENC_NA;
1636 have_encoding = true;
1637 break;
1639 case LMP_CHARSET_ISO_8859_4:
1640 encoding = ENC_ISO_8859_4|ENC_NA;
1641 have_encoding = true;
1642 break;
1644 case LMP_CHARSET_ISO_8859_5:
1645 encoding = ENC_ISO_8859_5|ENC_NA;
1646 have_encoding = true;
1647 break;
1649 case LMP_CHARSET_ISO_8859_6:
1650 encoding = ENC_ISO_8859_6|ENC_NA;
1651 have_encoding = true;
1652 break;
1654 case LMP_CHARSET_ISO_8859_7:
1655 encoding = ENC_ISO_8859_7|ENC_NA;
1656 have_encoding = true;
1657 break;
1659 case LMP_CHARSET_ISO_8859_8:
1660 encoding = ENC_ISO_8859_8|ENC_NA;
1661 have_encoding = true;
1662 break;
1664 case LMP_CHARSET_ISO_8859_9:
1665 encoding = ENC_ISO_8859_9|ENC_NA;
1666 have_encoding = true;
1667 break;
1669 case LMP_CHARSET_UNICODE:
1670 /* Presumably big-endian; assume just UCS-2 for now */
1671 encoding = ENC_UCS_2|ENC_BIG_ENDIAN;
1672 have_encoding = true;
1673 break;
1675 default:
1676 encoding = 0;
1677 have_encoding = false;
1678 break;
1681 if (have_encoding)
1683 name = (char *) tvb_get_string_enc(pinfo->pool, tvb, offset, name_len, encoding);
1684 col_append_fstr(pinfo->cinfo, COL_INFO, ", \"%s\"", format_text(pinfo->pool, (unsigned char *) name, strlen(name)));
1685 if (root)
1686 proto_tree_add_item(lmp_tree, hf_lmp_xid_name, tvb, offset,
1687 -1, encoding);
1689 else
1691 if (root)
1692 proto_tree_add_item(lmp_tree, hf_lmp_xid_name_no_encoding, tvb, offset,
1693 -1, ENC_NA);
1702 * Dissect Log Messages
1704 static void dissect_log(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1706 /* Make entries in Protocol column on summary display */
1707 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Log");
1709 /* missed messages? */
1710 if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1712 col_set_str(pinfo->cinfo, COL_INFO, "WARNING: Missed one or more messages while capturing!");
1714 else
1716 unsigned length;
1717 char *buf;
1719 length = tvb_captured_length(tvb);
1720 buf = (char *) tvb_get_string_enc(pinfo->pool, tvb, 0, length, ENC_ASCII|ENC_NA);
1721 if (length > 0 && buf[length-1] == '\n')
1722 buf[length-1] = 0;
1723 else if (length > 1 && buf[length-2] == '\n')
1724 buf[length-2] = 0;
1726 col_add_str(pinfo->cinfo, COL_INFO, format_text(pinfo->pool, (unsigned char *) buf, strlen(buf)));
1729 if (root)
1731 proto_item* ti = proto_tree_add_item(root, proto_log, tvb, 0, -1, ENC_NA);
1732 proto_tree* tree = proto_item_add_subtree(ti, ett_log);
1734 if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1735 proto_tree_add_item(tree, hf_log_missed, tvb, 0, 0, ENC_NA);
1736 else
1737 proto_tree_add_item(tree, hf_log_msg, tvb, 0, -1, ENC_ASCII|ENC_NA);
1743 * Dissect IrLAP
1745 static void dissect_irlap(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1747 int offset = 0;
1748 uint8_t circuit_id, c;
1749 bool is_response;
1750 char addr[9];
1751 proto_item* ti = NULL;
1752 proto_tree* tree = NULL;
1753 proto_tree* i_tree = NULL;
1754 uint32_t saddr, daddr;
1755 uint8_t ca;
1757 /* Make entries in Protocol column on summary display */
1758 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLAP");
1760 /* Clear Info column */
1761 col_clear(pinfo->cinfo, COL_INFO);
1763 /* set direction column */
1764 switch (pinfo->pseudo_header->irda.pkttype)
1766 case IRDA_OUTGOING:
1767 col_set_str(pinfo->cinfo, COL_IF_DIR, "Out");
1768 break;
1770 case IRDA_INCOMING:
1771 col_set_str(pinfo->cinfo, COL_IF_DIR, "In");
1772 break;
1775 /* decode values used for demuxing */
1776 circuit_id = tvb_get_uint8(tvb, 0);
1778 /* initially set address columns to connection address */
1779 snprintf(addr, sizeof(addr)-1, "0x%02X", circuit_id >> 1);
1780 col_add_str(pinfo->cinfo, COL_DEF_SRC, addr);
1781 col_add_str(pinfo->cinfo, COL_DEF_DST, addr);
1783 if (root)
1785 proto_tree* a_tree;
1786 proto_item* addr_item;
1788 /* create display subtree for the protocol */
1789 ti = proto_tree_add_item(root, proto_irlap, tvb, 0, -1, ENC_NA);
1790 tree = proto_item_add_subtree(ti, ett_irlap);
1792 /* create subtree for the address field */
1793 ti = proto_tree_add_item(tree, hf_lap_a, tvb, offset, 1, ENC_BIG_ENDIAN);
1794 a_tree = proto_item_add_subtree(ti, ett_lap_a);
1795 proto_tree_add_item(a_tree, hf_lap_a_cr, tvb, offset, 1, ENC_BIG_ENDIAN);
1796 addr_item = proto_tree_add_item(a_tree, hf_lap_a_address, tvb, offset, 1, ENC_BIG_ENDIAN);
1797 switch (circuit_id & ~CMD_FRAME)
1799 case 0:
1800 proto_item_append_text(addr_item, " (NULL Address)");
1801 break;
1802 case 0xFE:
1803 proto_item_append_text(addr_item, " (Broadcast)");
1804 break;
1807 is_response = ((circuit_id & CMD_FRAME) == 0);
1808 offset++;
1810 /* process the control field */
1811 c = dissect_xdlc_control(tvb, offset, pinfo, tree, hf_lap_c,
1812 ett_lap_c, &irlap_cf_items, NULL, lap_c_u_cmd_abbr_vals,
1813 lap_c_u_rsp_abbr_vals, is_response, false, false);
1814 offset++;
1816 if ((c & XDLC_I_MASK) == XDLC_I) {
1817 /* I frame */
1818 proto_item_set_len(tree, offset);
1819 tvb = tvb_new_subset_remaining(tvb, offset);
1820 dissect_irlmp(tvb, pinfo, root, circuit_id);
1821 return;
1824 if ((c & XDLC_S_U_MASK) == XDLC_U) {
1825 /* U frame */
1826 switch (c & XDLC_U_MODIFIER_MASK)
1828 case XDLC_SNRM:
1829 if (root)
1831 ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, ENC_NA);
1832 i_tree = proto_item_add_subtree(ti, ett_lap_i);
1835 saddr = tvb_get_letohl(tvb, offset);
1836 if (!is_response)
1838 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1840 if (root)
1841 proto_tree_add_uint(i_tree, hf_snrm_saddr, tvb, offset, 4, saddr);
1842 offset += 4;
1844 daddr = tvb_get_letohl(tvb, offset);
1845 if (!is_response)
1847 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1849 if (root)
1850 proto_tree_add_uint(i_tree, hf_snrm_daddr, tvb, offset, 4, daddr);
1851 offset += 4;
1853 ca = tvb_get_uint8(tvb, offset);
1854 if (!is_response)
1856 col_append_fstr(pinfo->cinfo, COL_INFO, ", ca=0x%02X",
1857 ca >> 1);
1859 if (root)
1860 proto_tree_add_uint(i_tree, hf_snrm_ca, tvb, offset, 1, ca >> 1);
1861 offset++;
1863 offset = dissect_negotiation(tvb, i_tree, offset);
1864 if (root)
1865 proto_item_set_end(ti, tvb, offset);
1866 break;
1868 case IRDA_XID_CMD:
1869 tvb = tvb_new_subset_remaining(tvb, offset);
1870 dissect_xid(tvb, pinfo, root, tree, true);
1871 return;
1873 case XDLC_UA:
1874 if (tvb_reported_length_remaining(tvb, offset) > 0)
1876 if (root)
1878 ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, ENC_NA);
1879 i_tree = proto_item_add_subtree(ti, ett_lap_i);
1882 saddr = tvb_get_letohl(tvb, offset);
1883 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1884 if (root)
1885 proto_tree_add_uint(i_tree, hf_ua_saddr, tvb, offset, 4, saddr);
1886 offset += 4;
1888 daddr = tvb_get_letohl(tvb, offset);
1889 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1890 if (root)
1891 proto_tree_add_uint(i_tree, hf_ua_daddr, tvb, offset, 4, daddr);
1892 offset += 4;
1894 offset = dissect_negotiation(tvb, i_tree, offset);
1895 if (root)
1896 proto_item_set_end(ti, tvb, offset);
1898 break;
1900 case XDLC_XID:
1901 tvb = tvb_new_subset_remaining(tvb, offset);
1902 dissect_xid(tvb, pinfo, root, tree, false);
1903 return;
1907 /* If any bytes remain, send it to the generic data dissector */
1908 if (tvb_reported_length_remaining(tvb, offset) > 0)
1910 tvb = tvb_new_subset_remaining(tvb, offset);
1911 call_data_dissector(tvb, pinfo, root);
1917 * Dissect IrDA protocol
1919 static int dissect_irda(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, void* data _U_)
1921 /* check if log message */
1922 if ((pinfo->pseudo_header->irda.pkttype & IRDA_CLASS_MASK) == IRDA_CLASS_LOG)
1924 dissect_log(tvb, pinfo, root);
1925 return tvb_captured_length(tvb);
1929 dissect_irlap(tvb, pinfo, root);
1930 return tvb_captured_length(tvb);
1933 static int irda_addr_to_str(const address* addr, char *buf, int buf_len _U_)
1935 const uint8_t *addrdata = (const uint8_t *)addr->data;
1937 uint32_to_str_buf(*addrdata, buf, buf_len);
1938 return (int)strlen(buf);
1941 static int irda_addr_str_len(const address* addr _U_)
1943 return 11; /* Leaves required space (10 bytes) for uint_to_str_back() */
1946 static const char* irda_col_filter_str(const address* addr _U_, bool is_src _U_)
1948 return "irlap.a";
1951 static int irda_addr_len(void)
1953 return 1;
1957 * Register the protocol with Wireshark
1958 * This format is required because a script is used to build the C function
1959 * that calls all the protocol registrations.
1961 void proto_register_irda(void)
1963 unsigned i;
1965 /* Setup list of header fields */
1966 static hf_register_info hf_lap[] = {
1967 { &hf_lap_a,
1968 { "Address Field", "irlap.a",
1969 FT_UINT8, BASE_HEX, NULL, 0,
1970 NULL, HFILL }},
1971 { &hf_lap_a_cr,
1972 { "C/R", "irlap.a.cr",
1973 FT_BOOLEAN, 8, TFS(&lap_cr_vals), CMD_FRAME,
1974 NULL, HFILL }},
1975 { &hf_lap_a_address,
1976 { "Address", "irlap.a.address",
1977 FT_UINT8, BASE_HEX, NULL, ~CMD_FRAME,
1978 NULL, HFILL }},
1979 { &hf_lap_c,
1980 { "Control Field", "irlap.c",
1981 FT_UINT8, BASE_HEX, NULL, 0,
1982 NULL, HFILL }},
1983 { &hf_lap_c_nr,
1984 { "N(R)", "irlap.c.n_r",
1985 FT_UINT8, BASE_DEC, NULL, XDLC_N_R_MASK,
1986 NULL, HFILL }},
1987 { &hf_lap_c_ns,
1988 { "N(S)", "irlap.c.n_s",
1989 FT_UINT8, BASE_DEC, NULL, XDLC_N_S_MASK,
1990 NULL, HFILL }},
1991 { &hf_lap_c_p,
1992 { "Poll", "irlap.c.p",
1993 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1994 NULL, HFILL }},
1995 { &hf_lap_c_f,
1996 { "Final", "irlap.c.f",
1997 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1998 NULL, HFILL }},
1999 { &hf_lap_c_s,
2000 { "Supervisory frame type", "irlap.c.s_ftype",
2001 FT_UINT8, BASE_HEX, VALS(lap_c_s_vals), XDLC_S_FTYPE_MASK,
2002 NULL, HFILL }},
2003 { &hf_lap_c_u_cmd,
2004 { "Command", "irlap.c.u_modifier_cmd",
2005 FT_UINT8, BASE_HEX, VALS(lap_c_u_cmd_vals), XDLC_U_MODIFIER_MASK,
2006 NULL, HFILL }},
2007 { &hf_lap_c_u_rsp,
2008 { "Response", "irlap.c.u_modifier_resp",
2009 FT_UINT8, BASE_HEX, VALS(lap_c_u_rsp_vals), XDLC_U_MODIFIER_MASK,
2010 NULL, HFILL }},
2011 { &hf_lap_c_i,
2012 { "Frame Type", "irlap.c.ftype",
2013 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_I_MASK,
2014 NULL, HFILL }},
2015 { &hf_lap_c_s_u,
2016 { "Frame Type", "irlap.c.ftype",
2017 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_S_U_MASK,
2018 NULL, HFILL }},
2019 { &hf_lap_i,
2020 { "Information Field", "irlap.i",
2021 FT_NONE, BASE_NONE, NULL, 0,
2022 NULL, HFILL }},
2023 { &hf_snrm_saddr,
2024 { "Source Device Address", "irlap.snrm.saddr",
2025 FT_UINT32, BASE_HEX, NULL, 0,
2026 NULL, HFILL }},
2027 { &hf_snrm_daddr,
2028 { "Destination Device Address", "irlap.snrm.daddr",
2029 FT_UINT32, BASE_HEX, NULL, 0,
2030 NULL, HFILL }},
2031 { &hf_snrm_ca,
2032 { "Connection Address", "irlap.snrm.ca",
2033 FT_UINT8, BASE_HEX, NULL, 0,
2034 NULL, HFILL }},
2035 { &hf_negotiation_param,
2036 { "Negotiation Parameter", "irlap.negotiation",
2037 FT_NONE, BASE_NONE, NULL, 0,
2038 NULL, HFILL }},
2039 { &hf_param_pi,
2040 { "Parameter Identifier", "irlap.pi",
2041 FT_UINT8, BASE_HEX, NULL, 0,
2042 NULL, HFILL }},
2043 { &hf_param_pl,
2044 { "Parameter Length", "irlap.pl",
2045 FT_UINT8, BASE_HEX, NULL, 0,
2046 NULL, HFILL }},
2047 { &hf_param_pv,
2048 { "Parameter Value", "irlap.pv",
2049 FT_BYTES, BASE_NONE, NULL, 0,
2050 NULL, HFILL }},
2051 { &hf_ua_saddr,
2052 { "Source Device Address", "irlap.ua.saddr",
2053 FT_UINT32, BASE_HEX, NULL, 0,
2054 NULL, HFILL }},
2055 { &hf_ua_daddr,
2056 { "Destination Device Address", "irlap.ua.daddr",
2057 FT_UINT32, BASE_HEX, NULL, 0,
2058 NULL, HFILL }},
2059 { &hf_xid_ident,
2060 { "Format Identifier", "irlap.xid.fi",
2061 FT_UINT8, BASE_HEX, NULL, 0,
2062 NULL, HFILL }},
2063 { &hf_xid_saddr,
2064 { "Source Device Address", "irlap.xid.saddr",
2065 FT_UINT32, BASE_HEX, NULL, 0,
2066 NULL, HFILL }},
2067 { &hf_xid_daddr,
2068 { "Destination Device Address", "irlap.xid.daddr",
2069 FT_UINT32, BASE_HEX, NULL, 0,
2070 NULL, HFILL }},
2071 { &hf_xid_flags,
2072 { "Discovery Flags", "irlap.xid.flags",
2073 FT_UINT8, BASE_HEX, NULL, 0,
2074 NULL, HFILL }},
2075 { &hf_xid_s,
2076 { "Number of Slots", "irlap.xid.s",
2077 FT_UINT8, BASE_DEC, VALS(xid_slot_numbers), S_MASK,
2078 NULL, HFILL }},
2079 { &hf_xid_conflict,
2080 { "Conflict", "irlap.xid.conflict",
2081 FT_BOOLEAN, 8, TFS(&set_notset), CONFLICT,
2082 NULL, HFILL }},
2083 { &hf_xid_slotnr,
2084 { "Slot Number", "irlap.xid.slotnr",
2085 FT_UINT8, BASE_DEC, NULL, 0,
2086 NULL, HFILL }},
2087 { &hf_xid_version,
2088 { "Version Number", "irlap.xid.version",
2089 FT_UINT8, BASE_HEX, NULL, 0,
2090 NULL, HFILL }}
2093 static hf_register_info hf_log[] = {
2094 { &hf_log_msg,
2095 { "Message", "log.msg",
2096 FT_STRING, BASE_NONE, NULL, 0,
2097 NULL, HFILL }},
2098 { &hf_log_missed,
2099 { "WARNING: Missed one or more messages while capturing!", "log.missed",
2100 FT_NONE, BASE_NONE, NULL, 0,
2101 NULL, HFILL }}
2104 static hf_register_info hf_lmp[] = {
2105 { &hf_lmp_xid_hints,
2106 { "Service Hints", "irlmp.xid.hints",
2107 FT_BYTES, BASE_NONE, NULL, 0,
2108 NULL, HFILL }},
2109 { &hf_lmp_xid_charset,
2110 { "Character Set", "irlmp.xid.charset",
2111 FT_UINT8, BASE_HEX, VALS(lmp_charset_vals), 0,
2112 NULL, HFILL }},
2113 { &hf_lmp_xid_name,
2114 { "Device Nickname", "irlmp.xid.name",
2115 FT_STRING, BASE_NONE, NULL, 0,
2116 NULL, HFILL }},
2117 { &hf_lmp_xid_name_no_encoding,
2118 { "Device Nickname (unsupported character set)", "irlmp.xid.name.no_encoding",
2119 FT_BYTES, BASE_NONE, NULL, 0,
2120 NULL, HFILL }},
2121 { &hf_lmp_dst,
2122 { "Destination", "irlmp.dst",
2123 FT_UINT8, BASE_HEX, NULL, 0,
2124 NULL, HFILL }},
2125 { &hf_lmp_dst_control,
2126 { "Control Bit", "irlmp.dst.c",
2127 FT_BOOLEAN, 8, TFS(&set_notset), CONTROL_BIT,
2128 NULL, HFILL }},
2129 { &hf_lmp_dst_lsap,
2130 { "Destination LSAP", "irlmp.dst.lsap",
2131 FT_UINT8, BASE_DEC, NULL, ~CONTROL_BIT,
2132 NULL, HFILL }},
2133 { &hf_lmp_src,
2134 { "Source", "irlmp.src",
2135 FT_UINT8, BASE_HEX, NULL, 0,
2136 NULL, HFILL }},
2137 { &hf_lmp_src_r,
2138 { "reserved", "irlmp.src.r",
2139 FT_UINT8, BASE_DEC, NULL, RESERVED_BIT,
2140 NULL, HFILL }},
2141 { &hf_lmp_src_lsap,
2142 { "Source LSAP", "irlmp.src.lsap",
2143 FT_UINT8, BASE_DEC, NULL, ~RESERVED_BIT,
2144 NULL, HFILL }},
2145 { &hf_lmp_opcode,
2146 { "Opcode", "irlmp.opcode",
2147 FT_UINT8, BASE_HEX, VALS(lmp_opcode_vals), 0x0,
2148 NULL, HFILL }},
2149 { &hf_lmp_rsvd,
2150 { "Reserved", "irlmp.rsvd",
2151 FT_UINT8, BASE_HEX, NULL, 0x0,
2152 NULL, HFILL }},
2153 { &hf_lmp_reason,
2154 { "Reason", "irlmp.reason",
2155 FT_UINT8, BASE_HEX, VALS(lmp_reason_vals), 0x0,
2156 NULL, HFILL }},
2157 { &hf_lmp_mode,
2158 { "Mode", "irlmp.mode",
2159 FT_UINT8, BASE_HEX, VALS(lmp_mode_vals), 0x0,
2160 NULL, HFILL }},
2161 { &hf_lmp_status,
2162 { "Status", "irlmp.status",
2163 FT_UINT8, BASE_HEX, VALS(lmp_status_vals), 0x0,
2164 NULL, HFILL }}
2167 static hf_register_info hf_iap[] = {
2168 { &hf_iap_ctl,
2169 { "Control Field", "iap.ctl",
2170 FT_UINT8, BASE_HEX, NULL, 0,
2171 NULL, HFILL }},
2172 { &hf_iap_ctl_lst,
2173 { "Last Frame", "iap.ctl.lst",
2174 FT_BOOLEAN, 8, TFS(&set_notset), IAP_LST,
2175 NULL, HFILL }},
2176 { &hf_iap_ctl_ack,
2177 { "Acknowledge", "iap.ctl.ack",
2178 FT_BOOLEAN, 8, TFS(&set_notset), IAP_ACK,
2179 NULL, HFILL }},
2180 { &hf_iap_ctl_opcode,
2181 { "Opcode", "iap.ctl.opcode",
2182 FT_UINT8, BASE_HEX, VALS(iap_opcode_vals), IAP_OP,
2183 NULL, HFILL }},
2184 { &hf_iap_class_name,
2185 { "Class Name", "iap.classname",
2186 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2187 NULL, HFILL }},
2188 { &hf_iap_attr_name,
2189 { "Attribute Name", "iap.attrname",
2190 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2191 NULL, HFILL }},
2192 { &hf_iap_return,
2193 { "Return", "iap.return",
2194 FT_UINT8, BASE_HEX, VALS(iap_return_vals), 0x0,
2195 NULL, HFILL }},
2196 { &hf_iap_list_len,
2197 { "List Length", "iap.listlen",
2198 FT_UINT16, BASE_DEC, NULL, 0x0,
2199 NULL, HFILL }},
2200 { &hf_iap_list_entry,
2201 { "List Entry", "iap.listentry",
2202 FT_NONE, BASE_NONE, NULL, 0x0,
2203 NULL, HFILL }},
2204 { &hf_iap_obj_id,
2205 { "Object Identifier", "iap.objectid",
2206 FT_UINT16, BASE_HEX, NULL, 0x0,
2207 NULL, HFILL }},
2208 { &hf_iap_attr_type,
2209 { "Type", "iap.attrtype",
2210 FT_UINT8, BASE_DEC, VALS(iap_attr_type_vals), 0x0,
2211 NULL, HFILL }},
2212 { &hf_iap_int,
2213 { "Value", "iap.int",
2214 FT_INT32, BASE_DEC, NULL, 0x0,
2215 NULL, HFILL }},
2216 { &hf_iap_seq_len,
2217 { "Sequence Length", "iap.seqlen",
2218 FT_UINT16, BASE_DEC, NULL, 0x0,
2219 NULL, HFILL }},
2220 { &hf_iap_oct_seq,
2221 { "Sequence", "iap.octseq",
2222 FT_BYTES, BASE_NONE, NULL, 0x0,
2223 NULL, HFILL }},
2224 { &hf_iap_char_set,
2225 { "Character Set", "iap.charset",
2226 FT_UINT8, BASE_HEX, NULL, 0x0,
2227 NULL, HFILL }},
2228 { &hf_iap_string,
2229 { "String", "iap.string",
2230 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2231 NULL, HFILL }},
2232 { &hf_iap_invaloctet,
2233 { "Malformed IAP result: \"", "iap.invaloctet",
2234 FT_NONE, BASE_NONE, NULL, 0,
2235 NULL, HFILL }},
2236 { &hf_iap_invallsap,
2237 { "Malformed IAP result: \"", "iap.invallsap",
2238 FT_NONE, BASE_NONE, NULL, 0,
2239 NULL, HFILL }}
2242 static hf_register_info hf_ttp[] = {
2243 { &hf_ttp_p,
2244 { "Parameter Bit", "ttp.p",
2245 FT_BOOLEAN, 8, TFS(&set_notset), TTP_PARAMETERS,
2246 NULL, HFILL }},
2247 { &hf_ttp_icredit,
2248 { "Initial Credit", "ttp.icredit",
2249 FT_UINT8, BASE_DEC, NULL, ~TTP_PARAMETERS,
2250 NULL, HFILL }},
2251 { &hf_ttp_m,
2252 { "More Bit", "ttp.m",
2253 FT_BOOLEAN, 8, TFS(&set_notset), TTP_MORE,
2254 NULL, HFILL }},
2255 { &hf_ttp_dcredit,
2256 { "Delta Credit", "ttp.dcredit",
2257 FT_UINT8, BASE_DEC, NULL, ~TTP_MORE,
2258 NULL, HFILL }}
2261 /* Setup protocol subtree arrays */
2262 static int* ett[] = {
2263 &ett_irlap,
2264 &ett_lap_a,
2265 &ett_lap_c,
2266 &ett_lap_i,
2267 &ett_xid_flags,
2268 &ett_log,
2269 &ett_irlmp,
2270 &ett_lmp_dst,
2271 &ett_lmp_src,
2272 &ett_iap,
2273 &ett_iap_ctl,
2274 &ett_ttp
2277 int* ett_p[MAX_PARAMETERS];
2278 int* ett_iap_e[MAX_IAP_ENTRIES];
2281 /* Register protocol names and descriptions */
2282 proto_irlap = proto_register_protocol("IrDA Link Access Protocol", "IrLAP", "irlap");
2283 proto_log = proto_register_protocol("Log Message", "Log", "log");
2284 proto_irlmp = proto_register_protocol("IrDA Link Management Protocol", "IrLMP", "irlmp");
2285 proto_iap = proto_register_protocol("Information Access Protocol", "IAP", "iap");
2286 proto_ttp = proto_register_protocol("Tiny Transport Protocol", "TTP", "ttp");
2288 /* Register the dissector */
2289 irda_handle = register_dissector("irda", dissect_irda, proto_irlap);
2291 /* Required function calls to register the header fields */
2292 proto_register_field_array(proto_irlap, hf_lap, array_length(hf_lap));
2293 proto_register_field_array(proto_log, hf_log, array_length(hf_log));
2294 proto_register_field_array(proto_irlmp, hf_lmp, array_length(hf_lmp));
2295 proto_register_field_array(proto_iap, hf_iap, array_length(hf_iap));
2296 proto_register_field_array(proto_ttp, hf_ttp, array_length(hf_ttp));
2298 /* Register subtrees */
2299 proto_register_subtree_array(ett, array_length(ett));
2300 for (i = 0; i < MAX_PARAMETERS; i++)
2302 ett_p[i] = &ett_param[i];
2304 proto_register_subtree_array(ett_p, MAX_PARAMETERS);
2305 for (i = 0; i < MAX_IAP_ENTRIES; i++)
2307 ett_iap_e[i] = &ett_iap_entry[i];
2309 proto_register_subtree_array(ett_iap_e, MAX_IAP_ENTRIES);
2311 irda_address_type = address_type_dissector_register("AT_IRDA", "IRDA Address", irda_addr_to_str, irda_addr_str_len, NULL, irda_col_filter_str, irda_addr_len, NULL, NULL);
2315 /* If this dissector uses sub-dissector registration add a registration routine.
2316 This format is required because a script is used to find these routines and
2317 create the code that calls these routines.
2320 void proto_reg_handoff_irda(void)
2322 dissector_add_uint("wtap_encap", WTAP_ENCAP_IRDA, irda_handle);
2323 dissector_add_uint("sll.ltype", LINUX_SLL_P_IRDA_LAP, irda_handle);
2327 * Editor modelines - https://www.wireshark.org/tools/modelines.html
2329 * Local variables:
2330 * c-basic-offset: 4
2331 * tab-width: 8
2332 * indent-tabs-mode: nil
2333 * End:
2335 * vi: set shiftwidth=4 tabstop=8 expandtab:
2336 * :indentSize=4:tabSize=8:noTabs=true: