nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* packet-irda.c
2 * Routines for IrDA dissection
3 * By Shaun Jackman <sjackman@pathwayconnect.com>
4 * Copyright 2000 Shaun Jackman
5 *
6 * Extended by Jan Kiszka <jan.kiszka@web.de>
7 * Copyright 2003 Jan Kiszka
8 *
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 */
27  
28 #include "config.h"
29  
30 #include <string.h>
31  
32 #include <epan/packet.h>
33 #include <epan/address_types.h>
34 #include <epan/to_str.h>
35 #include <epan/conversation.h>
36 #include <epan/xdlc.h>
37 #include <wiretap/wtap.h>
38  
39 #include <epan/dissectors/packet-sll.h>
40 #include "irda-appl.h"
41  
42 /*
43 * This plugin dissects infrared data transmissions as defined by the IrDA
44 * specification (www.irda.org). See
45 *
46 * http://www.irda.org/standards/specifications.asp
47 *
48 * for various IrDA specifications.
49 *
50 * The plugin operates both offline with libpcap files and online on supported
51 * platforms. Live dissection is currently available for Linux-IrDA
52 * (irda.sourceforge.net) and for Windows if the Linux-IrDA port IrCOMM2k
53 * (www.ircomm2k.de) is installed.
54 */
55  
56 /*
57 * LAP
58 */
59  
60 /* Frame types and templates */
61 #define INVALID 0xff
62  
63 /*
64 * XXX - the IrDA spec gives XID as 0x2c; HDLC (and other HDLC-derived
65 * protocolc) use 0xAC.
66 */
67 #define IRDA_XID_CMD 0x2c /* Exchange Station Identification */
68  
69 #define CMD_FRAME 0x01
70 #define RSP_FRAME 0x00
71  
72 /* Discovery Flags */
73 #define S_MASK 0x03
74 #define CONFLICT 0x04
75  
76 /* Negotiation Parameters */
77 #define PI_BAUD_RATE 0x01
78 #define PI_MAX_TURN_TIME 0x82
79 #define PI_DATA_SIZE 0x83
80 #define PI_WINDOW_SIZE 0x84
81 #define PI_ADD_BOFS 0x85
82 #define PI_MIN_TURN_TIME 0x86
83 #define PI_LINK_DISC 0x08
84  
85  
86 /*
87 * LMP
88 */
89  
90 /* IrLMP frame opcodes */
91 #define CONNECT_CMD 0x01
92 #define CONNECT_CNF 0x81
93 #define DISCONNECT 0x02
94 #define ACCESSMODE_CMD 0x03
95 #define ACCESSMODE_CNF 0x83
96  
97 #define CONTROL_BIT 0x80
98 #define RESERVED_BIT 0x80
99  
100 /* LSAP-SEL's */
101 #define LSAP_MASK 0x7f
102 #define LSAP_IAS 0x00
103 #define LSAP_ANY 0xff
104 #define LSAP_MAX 0x6f /* 0x70-0x7f are reserved */
105 #define LSAP_CONNLESS 0x70 /* Connectionless LSAP, mostly used for Ultra */
106  
107  
108 /*
109 * IAP
110 */
111  
112 /* IrIAP Op-codes */
113 #define GET_INFO_BASE 0x01
114 #define GET_OBJECTS 0x02
115 #define GET_VALUE 0x03
116 #define GET_VALUE_BY_CLASS 0x04
117 #define GET_OBJECT_INFO 0x05
118 #define GET_ATTRIB_NAMES 0x06
119  
120 #define IAP_LST 0x80
121 #define IAP_ACK 0x40
122 #define IAP_OP 0x3F
123  
124 #define IAS_SUCCESS 0
125 #define IAS_CLASS_UNKNOWN 1
126 #define IAS_ATTRIB_UNKNOWN 2
127 #define IAS_ATTR_TOO_LONG 3
128 #define IAS_DISCONNECT 10
129 #define IAS_UNSUPPORTED 0xFF
130  
131  
132 /*
133 * TTP
134 */
135  
136 #define TTP_PARAMETERS 0x80
137 #define TTP_MORE 0x80
138  
139 void proto_reg_handoff_irda(void);
140 void proto_register_irda(void);
141  
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;
175  
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;
192  
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;
212  
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;
218  
219 static int proto_log = -1;
220 static int hf_log_msg = -1;
221 static int hf_log_missed = -1;
222  
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;
236  
237 #define MAX_PARAMETERS 32
238 static gint ett_param[MAX_PARAMETERS];
239  
240 static gint ett_iap_entry[MAX_IAP_ENTRIES];
241  
242 static int irda_address_type = -1;
243  
244 static const xdlc_cf_items irlap_cf_items = {
245 &hf_lap_c_nr,
246 &hf_lap_c_ns,
247 &hf_lap_c_p,
248 &hf_lap_c_f,
249 &hf_lap_c_s,
250 &hf_lap_c_u_cmd,
251 &hf_lap_c_u_rsp,
252 &hf_lap_c_i,
253 &hf_lap_c_s_u
254 };
255  
256 /* IAP conversation type */
257 typedef struct iap_conversation {
258 struct iap_conversation* pnext;
259 guint32 iap_query_frame;
260 ias_attr_dissector_t* pattr_dissector;
261 } iap_conversation_t;
262  
263 /* IrLMP conversation type */
264 typedef struct lmp_conversation {
265 struct lmp_conversation* pnext;
266 guint32 iap_result_frame;
267 gboolean ttp;
268 dissector_handle_t dissector;
269 } lmp_conversation_t;
270  
271 static const true_false_string lap_cr_vals = {
272 "Command",
273 "Response"
274 };
275  
276 static const true_false_string set_notset = {
277 "Set",
278 "Not set"
279 };
280  
281 static const value_string lap_c_ftype_vals[] = {
282 { XDLC_I, "Information frame" },
283 { XDLC_S, "Supervisory frame" },
284 { XDLC_U, "Unnumbered frame" },
285 { 0, NULL }
286 };
287  
288 static const value_string lap_c_u_cmd_abbr_vals[] = {
289 { XDLC_SNRM, "SNRM" },
290 { XDLC_DISC, "DISC" },
291 { XDLC_UI, "UI" },
292 { IRDA_XID_CMD, "XID" },
293 { XDLC_TEST, "TEST" },
294 { 0, NULL }
295 };
296  
297 static const value_string lap_c_u_rsp_abbr_vals[] = {
298 { XDLC_SNRM, "RNRM" },
299 { XDLC_UA, "UA" },
300 { XDLC_FRMR, "FRMR" },
301 { XDLC_DM, "DM" },
302 { XDLC_RD, "RD" },
303 { XDLC_UI, "UI" },
304 { XDLC_XID, "XID" },
305 { XDLC_TEST, "TEST" },
306 { 0, NULL }
307 };
308  
309 static const value_string lap_c_u_cmd_vals[] = {
310 { XDLC_SNRM>>2, "Set Normal Response Mode" },
311 { XDLC_DISC>>2, "Disconnect" },
312 { XDLC_UI>>2, "Unnumbered Information" },
313 { IRDA_XID_CMD>>2, "Exchange Station Identification" },
314 { XDLC_TEST>>2, "Test" },
315 { 0, NULL }
316 };
317  
318 static const value_string lap_c_u_rsp_vals[] = {
319 { XDLC_SNRM>>2, "Request Normal Response Mode" },
320 { XDLC_UA>>2, "Unnumbered Acknowledge" },
321 { XDLC_FRMR>>2, "Frame Reject" },
322 { XDLC_DM>>2, "Disconnect Mode" },
323 { XDLC_RD>>2, "Request Disconnect" },
324 { XDLC_UI>>2, "Unnumbered Information" },
325 { XDLC_XID>>2, "Exchange Station Identification" },
326 { XDLC_TEST>>2, "Test" },
327 { 0, NULL }
328 };
329  
330 static const value_string lap_c_s_vals[] = {
331 { XDLC_RR>>2, "Receiver ready" },
332 { XDLC_RNR>>2, "Receiver not ready" },
333 { XDLC_REJ>>2, "Reject" },
334 { XDLC_SREJ>>2, "Selective reject" },
335 { 0, NULL }
336 };
337  
338 static const value_string xid_slot_numbers[] = {
339 /* Number of XID slots */
340 { 0, "1" },
341 { 1, "6" },
342 { 2, "8" },
343 { 3, "16" },
344 { 0, NULL }
345 };
346  
347 static const value_string lmp_opcode_vals[] = {
348 /* IrLMP frame opcodes */
349 { CONNECT_CMD, "Connect Command" },
350 { CONNECT_CNF, "Connect Confirm" },
351 { DISCONNECT, "Disconnect" },
352 { ACCESSMODE_CMD, "Access Mode Command" },
353 { ACCESSMODE_CNF, "Access Mode Confirm" },
354 { 0, NULL }
355 };
356  
357 static const value_string lmp_reason_vals[] = {
358 /* IrLMP disconnect reasons */
359 { 0x01, "User Request" },
360 { 0x02, "Unexpected IrLAP Disconnect" },
361 { 0x03, "Failed to establish IrLAP connection" },
362 { 0x04, "IrLAP Reset" },
363 { 0x05, "Link Management Initiated Disconnect" },
364 { 0x06, "Data delivered on disconnected LSAP-Connection"},
365 { 0x07, "Non Responsive LM-MUX Client" },
366 { 0x08, "No available LM-MUX Client" },
367 { 0x09, "Connection Half Open" },
368 { 0x0A, "Illegal Source Address" },
369 { 0xFF, "Unspecified Disconnect Reason" },
370 { 0, NULL }
371 };
372  
373 static const value_string lmp_mode_vals[] = {
374 /* IrLMP modes */
375 { 0x00, "Multiplexed" },
376 { 0x01, "Exclusive" },
377 { 0, NULL }
378 };
379  
380 static const value_string lmp_status_vals[] = {
381 /* IrLMP status */
382 { 0x00, "Success" },
383 { 0x01, "Failure" },
384 { 0xFF, "Unsupported" },
385 { 0, NULL }
386 };
387  
388 static const value_string iap_opcode_vals[] = {
389 /* IrIAP Op-codes */
390 { GET_INFO_BASE, "GetInfoBase" },
391 { GET_OBJECTS, "GetObjects" },
392 { GET_VALUE, "GetValue" },
393 { GET_VALUE_BY_CLASS, "GetValueByClass" },
394 { GET_OBJECT_INFO, "GetObjectInfo" },
395 { GET_ATTRIB_NAMES, "GetAttributeNames" },
396 { 0, NULL }
397 };
398  
399 static const value_string iap_return_vals[] = {
400 /* IrIAP Return-codes */
401 { IAS_SUCCESS, "Success" },
402 { IAS_CLASS_UNKNOWN, "Class/Object Unknown" },
403 { IAS_ATTRIB_UNKNOWN, "Attribute Unknown" },
404 { IAS_ATTR_TOO_LONG, "Attribute List Too Long" },
405 { IAS_DISCONNECT, "Disconnect (Linux-IrDA only)" },
406 { IAS_UNSUPPORTED, "Unsupported Optional Operation" },
407 { 0, NULL }
408 };
409  
410 static const value_string iap_attr_type_vals[] = {
411 /* LM-IAS Attribute types */
412 { IAS_MISSING, "Missing" },
413 { IAS_INTEGER, "Integer" },
414 { IAS_OCT_SEQ, "Octet Sequence" },
415 { IAS_STRING, "String" },
416 { 0, NULL }
417 };
418  
419 static ias_attr_dissector_t device_attr_dissector[] = {
420 /* Device attribute dissectors */
421 /* { "IrLMPSupport", xxx }, not implemented yet... */
422 { NULL, NULL }
423 };
424  
425 /* IAS class dissectors */
426 static ias_class_dissector_t class_dissector[] = { CLASS_DISSECTORS };
427  
428  
429 /*
430 * Dissect parameter tuple
431 */
432 guint dissect_param_tuple(tvbuff_t* tvb, proto_tree* tree, guint offset)
433 {
434 guint8 len = tvb_get_guint8(tvb, offset + 1);
435  
436 if (tree)
437 proto_tree_add_item(tree, hf_param_pi, tvb, offset, 1, ENC_BIG_ENDIAN);
438 offset++;
439  
440 if (tree)
441 proto_tree_add_item(tree, hf_param_pl, tvb, offset, 1, ENC_BIG_ENDIAN);
442 offset++;
443  
444 if (len > 0)
445 {
446 if (tree)
447 proto_tree_add_item(tree, hf_param_pv, tvb, offset, len, ENC_NA);
448 offset += len;
449 }
450  
451 return offset;
452 }
453  
454  
455 /*
456 * Dissect TTP
457 */
458 static guint dissect_ttp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, gboolean data)
459 {
460 guint offset = 0;
461 guint8 head;
462 char buf[128];
463  
464 if (tvb_reported_length(tvb) == 0)
465 return 0;
466  
467 /* Make entries in Protocol column on summary display */
468 col_set_str(pinfo->cinfo, COL_PROTOCOL, "TTP");
469  
470 head = tvb_get_guint8(tvb, offset);
471  
472 g_snprintf(buf, 128, ", Credit=%d", head & ~TTP_PARAMETERS);
473 col_append_str(pinfo->cinfo, COL_INFO, buf);
474  
475 if (root)
476 {
477 /* create display subtree for the protocol */
478 proto_item* ti = proto_tree_add_item(root, proto_ttp, tvb, 0, -1, ENC_NA);
479 proto_tree* tree = proto_item_add_subtree(ti, ett_ttp);
480  
481 if (data)
482 {
483 proto_tree_add_item(tree, hf_ttp_m, tvb, offset, 1, ENC_BIG_ENDIAN);
484 proto_tree_add_item(tree, hf_ttp_dcredit, tvb, offset, 1, ENC_BIG_ENDIAN);
485 offset++;
486 }
487 else
488 {
489 proto_tree_add_item(tree, hf_ttp_p, tvb, offset, 1, ENC_BIG_ENDIAN);
490 proto_tree_add_item(tree, hf_ttp_icredit, tvb, offset, 1, ENC_BIG_ENDIAN);
491 offset++;
492 }
493 proto_item_set_len(tree, offset);
494 }
495 else
496 offset++;
497  
498 return offset;
499 }
500  
501  
502 /*
503 * Dissect IAP request
504 */
505 static void dissect_iap_request(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, guint8 circuit_id)
506 {
507 guint offset = 0;
508 guint8 op;
509 guint8 clen = 0;
510 guint8 alen = 0;
511 guint8 src;
512 address srcaddr;
513 address destaddr;
514 conversation_t* conv;
515 iap_conversation_t* iap_conv;
516 char buf[128];
517  
518 if (tvb_reported_length(tvb) == 0)
519 return;
520  
521 /* Make entries in Protocol column on summary display */
522 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAP");
523  
524 op = tvb_get_guint8(tvb, offset) & IAP_OP;
525  
526 switch (op)
527 {
528 case GET_VALUE_BY_CLASS:
529 clen = MIN(tvb_get_guint8(tvb, offset + 1), 60);
530 alen = MIN(tvb_get_guint8(tvb, offset + 1 + 1 + clen), 60);
531  
532 /* create conversation entry */
533 src = circuit_id ^ CMD_FRAME;
534 set_address(&srcaddr, irda_address_type, 1, &src);
535  
536 set_address(&destaddr, irda_address_type, 1, &circuit_id);
537  
538 conv = find_conversation(pinfo->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
539 if (conv)
540 {
541 iap_conv = (iap_conversation_t*)conversation_get_proto_data(conv, proto_iap);
542 while (1)
543 {
544 if (iap_conv->iap_query_frame == pinfo->num)
545 {
546 iap_conv = NULL;
547 break;
548 }
549 if (iap_conv->pnext == NULL)
550 {
551 iap_conv->pnext = wmem_new(wmem_file_scope(), iap_conversation_t);
552 iap_conv = iap_conv->pnext;
553 break;
554 }
555 iap_conv = iap_conv->pnext;
556 }
557 }
558 else
559 {
560 conv = conversation_new(pinfo->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
561 iap_conv = wmem_new(wmem_file_scope(), iap_conversation_t);
562 conversation_add_proto_data(conv, proto_iap, (void*)iap_conv);
563 }
564  
565 /* Dissect IAP query if it is new */
566 if (iap_conv)
567 {
568 int i, j;
569 char class_name[256];
570 char attr_name[256];
571  
572  
573 iap_conv->pnext = NULL;
574 iap_conv->iap_query_frame = pinfo->num;
575 iap_conv->pattr_dissector = NULL;
576  
577 tvb_memcpy(tvb, class_name, offset + 1 + 1, clen);
578 class_name[clen] = 0;
579 tvb_memcpy(tvb, attr_name, offset + 1 + 1 + clen + 1, alen);
580 attr_name[alen] = 0;
581  
582 /* Find the attribute dissector */
583 for (i = 0; class_dissector[i].class_name != NULL; i++)
584 if (strcmp(class_name, class_dissector[i].class_name) == 0)
585 {
586 for (j = 0; class_dissector[i].pattr_dissector[j].attr_name != NULL; j++)
587 if (strcmp(attr_name, class_dissector[i].pattr_dissector[j].attr_name) == 0)
588 {
589 iap_conv->pattr_dissector = &class_dissector[i].pattr_dissector[j];
590 break;
591 }
592 break;
593 }
594 }
595  
596 col_set_str(pinfo->cinfo, COL_INFO, "GetValueByClass: \"");
597  
598 tvb_memcpy(tvb, buf, offset + 1 + 1, clen);
599 memcpy(&buf[clen], "\" \"", 3);
600 tvb_memcpy(tvb, buf + clen + 3, offset + 1 + 1 + clen + 1, alen);
601 buf[clen + 3 + alen] = '\"';
602 buf[clen + 3 + alen + 1] = 0;
603 col_append_str(pinfo->cinfo, COL_INFO, buf);
604 }
605  
606 if (root)
607 {
608 /* create display subtree for the protocol */
609 proto_item* ti = proto_tree_add_item(root, proto_iap, tvb, 0, -1, ENC_NA);
610 proto_tree* tree = proto_item_add_subtree(ti, ett_iap);
611  
612 proto_tree* ctl_tree;
613  
614  
615 ti = proto_tree_add_item(tree, hf_iap_ctl, tvb, offset, 1, ENC_BIG_ENDIAN);
616 ctl_tree = proto_item_add_subtree(ti, ett_iap_ctl);
617 proto_tree_add_item(ctl_tree, hf_iap_ctl_lst, tvb, offset, 1, ENC_BIG_ENDIAN);
618 proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, ENC_BIG_ENDIAN);
619 proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
620 offset++;
621  
622 switch (op)
623 {
624 case GET_VALUE_BY_CLASS:
625 proto_tree_add_item(tree, hf_iap_class_name, tvb, offset, 1, ENC_ASCII|ENC_BIG_ENDIAN);
626 offset += 1 + clen;
627  
628 proto_tree_add_item(tree, hf_iap_attr_name, tvb, offset, 1, ENC_ASCII|ENC_BIG_ENDIAN);
629 offset += 1 + alen;
630 break;
631 }
632 }
633 else
634 {
635 offset++;
636 switch (op)
637 {
638 case GET_VALUE_BY_CLASS:
639 offset += 1 + clen + 1 + alen;
640 break;
641 }
642 }
643  
644 /* If any bytes remain, send it to the generic data dissector */
645 tvb = tvb_new_subset_remaining(tvb, offset);
646 call_data_dissector(tvb, pinfo, root);
647 }
648  
649  
650 /*
651 * Dissect IAP result
652 */
653 static void dissect_iap_result(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, guint8 circuit_id)
654 {
655 guint offset = 0;
656 guint len = tvb_reported_length(tvb);
657 guint n = 0;
658 guint list_len;
659 guint8 op;
660 guint8 retcode;
661 guint8 type;
662 guint16 attr_len;
663 char buf[300];
664 guint8 src;
665 address srcaddr;
666 address destaddr;
667 conversation_t* conv;
668 iap_conversation_t* cur_iap_conv;
669 iap_conversation_t* iap_conv = NULL;
670 guint32 num;
671  
672  
673 if (len == 0)
674 return;
675  
676 /* Make entries in Protocol column on summary display */
677 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IAP");
678  
679 op = tvb_get_guint8(tvb, offset) & IAP_OP;
680 retcode = tvb_get_guint8(tvb, offset + 1);
681  
682 src = circuit_id ^ CMD_FRAME;
683 set_address(&srcaddr, irda_address_type, 1, &src);
684  
685 set_address(&destaddr, irda_address_type, 1, &circuit_id);
686  
687 /* Find result value dissector */
688 conv = find_conversation(pinfo->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
689 if (conv)
690 {
691 num = pinfo->num;
692  
693 iap_conv = (iap_conversation_t*)conversation_get_proto_data(conv, proto_iap);
694 while (iap_conv && (iap_conv->iap_query_frame >= num))
695 iap_conv = iap_conv->pnext;
696  
697 if (iap_conv)
698 {
699 cur_iap_conv = iap_conv->pnext;
700 while (cur_iap_conv)
701 {
702 if ((cur_iap_conv->iap_query_frame < num) &&
703 (cur_iap_conv->iap_query_frame > iap_conv->iap_query_frame))
704 {
705 iap_conv = cur_iap_conv;
706 }
707  
708 cur_iap_conv = cur_iap_conv->pnext;
709 }
710 }
711 }
712  
713 col_set_str(pinfo->cinfo, COL_INFO, "Result: ");
714 col_append_str(pinfo->cinfo, COL_INFO, val_to_str(retcode, iap_return_vals, "0x%02X"));
715  
716 switch (op)
717 {
718 case GET_VALUE_BY_CLASS:
719 if (retcode == 0)
720 {
721 switch (tvb_get_guint8(tvb, offset + 6))
722 {
723 case IAS_MISSING:
724 col_append_str(pinfo->cinfo, COL_INFO, ", Missing");
725 break;
726  
727 case IAS_INTEGER:
728 col_append_fstr(pinfo->cinfo, COL_INFO, ", Integer: %d", tvb_get_ntohl(tvb, offset + 7));
729 break;
730  
731 case IAS_OCT_SEQ:
732 g_snprintf(buf, 300, ", %d Octets", tvb_get_ntohs(tvb, offset + 7));
733 break;
734  
735 case IAS_STRING:
736 n = tvb_get_guint8(tvb, offset + 8);
737 col_append_fstr(pinfo->cinfo, COL_INFO, ", \"%s\"", tvb_get_string_enc(wmem_packet_scope(), tvb, offset + 9, n, ENC_ASCII));
738 break;
739 default:
740 break;
741 }
742 if (tvb_get_ntohs(tvb, offset + 2) > 1)
743 col_append_str(pinfo->cinfo, COL_INFO, ", ...");
744 }
745 break;
746 }
747  
748 if (root)
749 {
750 /* create display subtree for the protocol */
751 proto_item* ti = proto_tree_add_item(root, proto_iap, tvb, 0, -1, ENC_NA);
752 proto_tree* tree = proto_item_add_subtree(ti, ett_iap);
753  
754 proto_tree* ctl_tree;
755 proto_tree* entry_tree;
756  
757  
758 ti = proto_tree_add_item(tree, hf_iap_ctl, tvb, offset, 1, ENC_BIG_ENDIAN);
759 ctl_tree = proto_item_add_subtree(ti, ett_iap_ctl);
760 proto_tree_add_item(ctl_tree, hf_iap_ctl_lst, tvb, offset, 1, ENC_BIG_ENDIAN);
761 proto_tree_add_item(ctl_tree, hf_iap_ctl_ack, tvb, offset, 1, ENC_BIG_ENDIAN);
762 proto_tree_add_item(ctl_tree, hf_iap_ctl_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
763 offset++;
764  
765 proto_tree_add_item(tree, hf_iap_return, tvb, offset, 1, ENC_BIG_ENDIAN);
766 offset++;
767  
768 switch (op)
769 {
770 case GET_VALUE_BY_CLASS:
771 if (retcode == 0)
772 {
773 list_len = tvb_get_ntohs(tvb, offset);
774  
775 proto_tree_add_item(tree, hf_iap_list_len, tvb, offset, 2, ENC_BIG_ENDIAN);
776 offset += 2;
777  
778 while ((offset < len) && (n < list_len))
779 {
780 type = tvb_get_guint8(tvb, offset + 2);
781 switch (type)
782 {
783 case IAS_INTEGER:
784 attr_len = 4;
785 break;
786  
787 case IAS_OCT_SEQ:
788 attr_len = tvb_get_ntohs(tvb, offset + 2 + 1) + 2;
789 break;
790  
791 case IAS_STRING:
792 attr_len = tvb_get_guint8(tvb, offset + 2 + 1 + 1) + 2;
793 break;
794  
795 default:
796 attr_len = 0;
797 }
798  
799 ti = proto_tree_add_item(tree, hf_iap_list_entry, tvb, offset, 2 + 1 + attr_len, ENC_NA);
800 proto_item_append_text(ti, "%d", n + 1);
801 entry_tree = proto_item_add_subtree(ti, ett_iap_entry[n]);
802  
803 proto_tree_add_item(entry_tree, hf_iap_obj_id, tvb, offset, 2, ENC_BIG_ENDIAN);
804 offset += 2;
805  
806 proto_tree_add_item(entry_tree, hf_iap_attr_type, tvb, offset, 1, ENC_BIG_ENDIAN);
807 offset++;
808  
809 switch (type)
810 {
811 case IAS_INTEGER:
812 if (!iap_conv || !iap_conv->pattr_dissector ||
813 !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
814 n, type, circuit_id))
815 proto_tree_add_item(entry_tree, hf_iap_int, tvb, offset, 4, ENC_BIG_ENDIAN);
816 break;
817  
818 case IAS_OCT_SEQ:
819 proto_tree_add_item(entry_tree, hf_iap_seq_len, tvb, offset, 2, ENC_BIG_ENDIAN);
820 if (!iap_conv || !iap_conv->pattr_dissector ||
821 !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
822 n, type, circuit_id))
823 proto_tree_add_item(entry_tree, hf_iap_oct_seq, tvb, offset + 2,
824 attr_len - 2, ENC_NA);
825 break;
826  
827 case IAS_STRING:
828 proto_tree_add_item(entry_tree, hf_iap_char_set, tvb, offset, 1, ENC_BIG_ENDIAN);
829 if (!iap_conv || !iap_conv->pattr_dissector ||
830 !iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, entry_tree,
831 n, type, circuit_id))
832 proto_tree_add_item(entry_tree, hf_iap_string, tvb, offset + 1, 1, ENC_ASCII|ENC_BIG_ENDIAN);
833 break;
834 }
835 offset += attr_len;
836  
837 n++;
838 }
839 }
840 break;
841 }
842 }
843 else
844 {
845 offset += 2;
846 switch (op)
847 {
848 case GET_VALUE_BY_CLASS:
849 if (retcode == 0)
850 {
851 offset += 2;
852  
853 while (offset < len)
854 {
855 offset += 2;
856 type = tvb_get_guint8(tvb, offset);
857 offset++;
858  
859 switch (type)
860 {
861 case IAS_INTEGER:
862 attr_len = 4;
863 if (iap_conv && iap_conv->pattr_dissector)
864 iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
865 n, type, circuit_id);
866 break;
867  
868 case IAS_OCT_SEQ:
869 attr_len = tvb_get_ntohs(tvb, offset) + 2;
870 if (iap_conv && iap_conv->pattr_dissector)
871 iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
872 n, type, circuit_id);
873 break;
874  
875 case IAS_STRING:
876 attr_len = tvb_get_guint8(tvb, offset + 1) + 2;
877 if (iap_conv && iap_conv->pattr_dissector)
878 iap_conv->pattr_dissector->value_dissector(tvb, offset, pinfo, 0,
879 n, type, circuit_id);
880 break;
881  
882 default:
883 attr_len = 0;
884 }
885 offset += attr_len;
886  
887 n++;
888 }
889 }
890 break;
891 }
892 }
893  
894 /* If any bytes remain, send it to the generic data dissector */
895 tvb = tvb_new_subset_remaining(tvb, offset);
896 call_data_dissector(tvb, pinfo, root);
897 }
898  
899  
900 /*
901 * Check if IAP result is octet sequence
902 */
903 gboolean check_iap_octet_result(tvbuff_t* tvb, proto_tree* tree, guint offset,
904 const char* attr_name, guint8 attr_type)
905 {
906 if (attr_type != IAS_OCT_SEQ)
907 {
908 if (tree)
909 {
910 proto_item* ti = proto_tree_add_item(tree, hf_iap_invaloctet, tvb, offset, 0, ENC_NA);
911 proto_item_append_text(ti, "%s", attr_name);
912 proto_item_append_text(ti, "\" attribute must be octet sequence!");
913 }
914  
915 return FALSE;
916 }
917 else
918 return TRUE;
919 }
920  
921  
922 /*
923 * Check if IAP result is correct LsapSel
924 */
925 guint8 check_iap_lsap_result(tvbuff_t* tvb, proto_tree* tree, guint offset,
926 const char* attr_name, guint8 attr_type)
927 {
928 guint32 lsap;
929  
930  
931 if ((attr_type != IAS_INTEGER) || ((lsap = tvb_get_ntohl(tvb, offset)) < 0x01) ||
932 (lsap > 0x6F))
933 {
934 if (tree)
935 {
936 proto_item* ti = proto_tree_add_item(tree, hf_iap_invallsap, tvb, offset, 0, ENC_NA);
937 proto_item_append_text(ti, "%s", attr_name);
938 proto_item_append_text(ti, "\" attribute must be integer value between 0x01 and 0x6F!");
939 }
940  
941 return 0;
942 }
943 else
944 return lsap;
945 }
946  
947  
948 /*
949 * Dissect IrDA application protocol
950 */
951 static void dissect_appl_proto(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, pdu_type_t pdu_type, guint8 circuit_id)
952 {
953 guint offset = 0;
954 guint8 src;
955 address srcaddr;
956 address destaddr;
957 conversation_t* conv;
958 lmp_conversation_t* cur_lmp_conv;
959 lmp_conversation_t* lmp_conv = NULL;
960 guint32 num;
961  
962  
963 src = circuit_id ^ CMD_FRAME;
964 set_address(&srcaddr, irda_address_type, 1, &src);
965  
966 set_address(&destaddr, irda_address_type, 1, &circuit_id);
967  
968 /* Find result value dissector */
969 conv = find_conversation(pinfo->num, &srcaddr, &destaddr, PT_NONE, pinfo->srcport, pinfo->destport, 0);
970 if (conv)
971 {
972 num = pinfo->num;
973  
974 lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
975 while (lmp_conv && (lmp_conv->iap_result_frame >= num))
976 lmp_conv = lmp_conv->pnext;
977  
978 if (lmp_conv)
979 {
980 cur_lmp_conv = lmp_conv->pnext;
981 while (cur_lmp_conv)
982 {
983 if ((cur_lmp_conv->iap_result_frame < num) &&
984 (cur_lmp_conv->iap_result_frame > lmp_conv->iap_result_frame))
985 {
986 lmp_conv = cur_lmp_conv;
987 }
988  
989 cur_lmp_conv = cur_lmp_conv->pnext;
990 }
991 }
992 }
993  
994 if (lmp_conv)
995 {
996 /*g_message("%x:%d->%x:%d = %p\n", src, pinfo->srcport, circuit_id, pinfo->destport, lmp_conv); */
997 /*g_message("->%d: %d %d %p\n", pinfo->num, lmp_conv->iap_result_frame, lmp_conv->ttp, lmp_conv->proto_dissector); */
998 if ((lmp_conv->ttp) && (pdu_type != DISCONNECT_PDU))
999 {
1000 offset += dissect_ttp(tvb, pinfo, root, (pdu_type == DATA_PDU));
1001  
1002 tvb = tvb_new_subset_remaining(tvb, offset);
1003 }
1004  
1005 call_dissector_with_data(lmp_conv->dissector, tvb, pinfo, root, GUINT_TO_POINTER(pdu_type));
1006 }
1007 else
1008 call_data_dissector(tvb, pinfo, root);
1009 }
1010  
1011  
1012 /*
1013 * Dissect LMP
1014 */
1015 static void dissect_irlmp(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, guint8 circuit_id)
1016 {
1017 guint offset = 0;
1018 guint8 dlsap;
1019 guint8 slsap;
1020 guint8 cbit;
1021 guint8 opcode = 0;
1022  
1023  
1024 /* Make entries in Protocol column on summary display */
1025 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLMP");
1026  
1027 dlsap = tvb_get_guint8(tvb, offset);
1028 cbit = dlsap & CONTROL_BIT;
1029 dlsap &= ~CONTROL_BIT;
1030  
1031 slsap = tvb_get_guint8(tvb, offset+1) & ~CONTROL_BIT;
1032  
1033 /* save Lsaps in pinfo */
1034 pinfo->srcport = slsap;
1035 pinfo->destport = dlsap;
1036  
1037 if (cbit != 0)
1038 {
1039 opcode = tvb_get_guint8(tvb, offset+2);
1040  
1041 col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, ", slsap, dlsap);
1042 col_append_str(pinfo->cinfo, COL_INFO, val_to_str(opcode, lmp_opcode_vals, "0x%02X"));
1043 if ((opcode == ACCESSMODE_CMD) || (opcode == ACCESSMODE_CNF))
1044 {
1045 col_append_str(pinfo->cinfo, COL_INFO, " (");
1046 col_append_str(pinfo->cinfo, COL_INFO,
1047 val_to_str(tvb_get_guint8(tvb, offset+4), lmp_mode_vals, "0x%02X"));
1048 col_append_str(pinfo->cinfo, COL_INFO, ")");
1049 }
1050 }
1051 else
1052 col_add_fstr(pinfo->cinfo, COL_INFO, "%d > %d, Len=%d", slsap, dlsap,
1053 tvb_reported_length(tvb) - 2);
1054  
1055 if (root)
1056 {
1057 /* create display subtree for the protocol */
1058 proto_item* ti = proto_tree_add_item(root, proto_irlmp, tvb, 0, -1, ENC_NA);
1059 proto_tree* tree = proto_item_add_subtree(ti, ett_irlmp);
1060  
1061 proto_tree* dst_tree;
1062 proto_tree* src_tree;
1063  
1064  
1065 ti = proto_tree_add_item(tree, hf_lmp_dst, tvb, offset, 1, ENC_BIG_ENDIAN);
1066 dst_tree = proto_item_add_subtree(ti, ett_lmp_dst);
1067 proto_tree_add_item(dst_tree, hf_lmp_dst_control, tvb, offset, 1, ENC_BIG_ENDIAN);
1068 proto_tree_add_item(dst_tree, hf_lmp_dst_lsap, tvb, offset, 1, ENC_BIG_ENDIAN);
1069 offset++;
1070  
1071 ti = proto_tree_add_item(tree, hf_lmp_src, tvb, offset, 1, ENC_BIG_ENDIAN);
1072 src_tree = proto_item_add_subtree(ti, ett_lmp_src);
1073 proto_tree_add_item(src_tree, hf_lmp_src_r, tvb, offset, 1, ENC_BIG_ENDIAN);
1074 proto_tree_add_item(src_tree, hf_lmp_src_lsap, tvb, offset, 1, ENC_BIG_ENDIAN);
1075 offset++;
1076  
1077 if (cbit != 0)
1078 {
1079 proto_tree_add_item(tree, hf_lmp_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
1080 offset++;
1081  
1082 switch (opcode)
1083 {
1084 case CONNECT_CMD:
1085 case CONNECT_CNF:
1086 if (offset < tvb_reported_length(tvb))
1087 {
1088 proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, ENC_BIG_ENDIAN);
1089 offset++;
1090 }
1091 break;
1092  
1093 case DISCONNECT:
1094 proto_tree_add_item(tree, hf_lmp_reason, tvb, offset, 1, ENC_BIG_ENDIAN);
1095 offset++;
1096 break;
1097  
1098 case ACCESSMODE_CMD:
1099 proto_tree_add_item(tree, hf_lmp_rsvd, tvb, offset, 1, ENC_BIG_ENDIAN);
1100 offset++;
1101  
1102 proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
1103 offset++;
1104 break;
1105  
1106 case ACCESSMODE_CNF:
1107 proto_tree_add_item( tree, hf_lmp_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1108 offset++;
1109  
1110 proto_tree_add_item(tree, hf_lmp_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
1111 offset++;
1112 break;
1113 }
1114 }
1115  
1116 tvb = tvb_new_subset_remaining(tvb, offset);
1117 proto_item_set_len(tree, offset);
1118 }
1119 else
1120 {
1121 offset += 2;
1122 if (cbit != 0)
1123 {
1124 offset += 1;
1125  
1126 switch (opcode)
1127 {
1128 case CONNECT_CMD:
1129 case CONNECT_CNF:
1130 if (offset < tvb_reported_length(tvb))
1131 offset++;
1132 break;
1133  
1134 case DISCONNECT:
1135 offset++;
1136 break;
1137  
1138 case ACCESSMODE_CMD:
1139 case ACCESSMODE_CNF:
1140 offset += 2;
1141 break;
1142 }
1143 }
1144  
1145 tvb = tvb_new_subset_remaining(tvb, offset);
1146 }
1147  
1148 if (cbit == 0)
1149 {
1150 if (dlsap == LSAP_IAS)
1151 dissect_iap_request(tvb, pinfo, root, circuit_id);
1152 else if (slsap == LSAP_IAS)
1153 dissect_iap_result(tvb, pinfo, root, circuit_id);
1154 else
1155 dissect_appl_proto(tvb, pinfo, root, DATA_PDU, circuit_id);
1156 }
1157 else
1158 {
1159 if ((dlsap == LSAP_IAS) || (slsap == LSAP_IAS))
1160 call_data_dissector(tvb, pinfo, root);
1161 else
1162 switch (opcode)
1163 {
1164 case CONNECT_CMD:
1165 case CONNECT_CNF:
1166 dissect_appl_proto(tvb, pinfo, root, CONNECT_PDU, circuit_id);
1167 break;
1168  
1169 case DISCONNECT:
1170 dissect_appl_proto(tvb, pinfo, root, DISCONNECT_PDU, circuit_id);
1171 break;
1172  
1173 default:
1174 call_data_dissector(tvb, pinfo, root);
1175 }
1176 }
1177 }
1178  
1179  
1180 /*
1181 * Add LMP conversation
1182 */
1183 void add_lmp_conversation(packet_info* pinfo, guint8 dlsap, gboolean ttp, dissector_handle_t dissector, guint8 circuit_id)
1184 {
1185 guint8 dest;
1186 address srcaddr;
1187 address destaddr;
1188 conversation_t* conv;
1189 lmp_conversation_t* lmp_conv = NULL;
1190  
1191  
1192 /*g_message("%d: add_lmp_conversation(%p, %d, %d, %p) = ", pinfo->num, pinfo, dlsap, ttp, proto_dissector); */
1193 set_address(&srcaddr, irda_address_type, 1, &circuit_id);
1194 dest = circuit_id ^ CMD_FRAME;
1195 set_address(&destaddr, irda_address_type, 1, &dest);
1196  
1197 conv = find_conversation(pinfo->num, &destaddr, &srcaddr, PT_NONE, dlsap, 0, NO_PORT_B);
1198 if (conv)
1199 {
1200 lmp_conv = (lmp_conversation_t*)conversation_get_proto_data(conv, proto_irlmp);
1201 while (1)
1202 {
1203 /* Does entry already exist? */
1204 if (lmp_conv->iap_result_frame == pinfo->num)
1205 return;
1206  
1207 if (lmp_conv->pnext == NULL)
1208 {
1209 lmp_conv->pnext = wmem_new(wmem_file_scope(), lmp_conversation_t);
1210 lmp_conv = lmp_conv->pnext;
1211 break;
1212 }
1213 lmp_conv = lmp_conv->pnext;
1214 }
1215 }
1216 else
1217 {
1218 conv = conversation_new(pinfo->num, &destaddr, &srcaddr, PT_NONE, dlsap, 0, NO_PORT_B);
1219 lmp_conv = wmem_new(wmem_file_scope(), lmp_conversation_t);
1220 conversation_add_proto_data(conv, proto_irlmp, (void*)lmp_conv);
1221 }
1222  
1223 lmp_conv->pnext = NULL;
1224 lmp_conv->iap_result_frame = pinfo->num;
1225 lmp_conv->ttp = ttp;
1226 lmp_conv->dissector = dissector;
1227  
1228 /*g_message("%p\n", lmp_conv); */
1229 }
1230  
1231  
1232 /*
1233 * Dissect Negotiation Parameters
1234 */
1235 static guint dissect_negotiation(tvbuff_t* tvb, proto_tree* tree, guint offset)
1236 {
1237 guint n = 0;
1238 proto_item* ti;
1239 proto_tree* p_tree;
1240 char buf[256];
1241 guint8 pv;
1242  
1243 while (tvb_reported_length_remaining(tvb, offset) > 0)
1244 {
1245 guint8 p_len = tvb_get_guint8(tvb, offset + 1);
1246  
1247 if (tree)
1248 {
1249 ti = proto_tree_add_item(tree, hf_negotiation_param, tvb, offset, p_len + 2, ENC_NA);
1250 p_tree = proto_item_add_subtree(ti, ett_param[n]);
1251  
1252 pv = tvb_get_guint8(tvb, offset+2);
1253 buf[0] = 0;
1254  
1255 switch (tvb_get_guint8(tvb, offset))
1256 {
1257 case PI_BAUD_RATE:
1258 proto_item_append_text(ti, ": Baud Rate (");
1259  
1260 if (pv & 0x01)
1261 g_strlcat(buf, ", 2400", 256);
1262 if (pv & 0x02)
1263 g_strlcat(buf, ", 9600", 256);
1264 if (pv & 0x04)
1265 g_strlcat(buf, ", 19200", 256);
1266 if (pv & 0x08)
1267 g_strlcat(buf, ", 38400", 256);
1268 if (pv & 0x10)
1269 g_strlcat(buf, ", 57600", 256);
1270 if (pv & 0x20)
1271 g_strlcat(buf, ", 115200", 256);
1272 if (pv & 0x40)
1273 g_strlcat(buf, ", 576000", 256);
1274 if (pv & 0x80)
1275 g_strlcat(buf, ", 1152000", 256);
1276 if ((p_len > 1) && (tvb_get_guint8(tvb, offset+3) & 0x01))
1277 g_strlcat(buf, ", 4000000", 256);
1278  
1279 g_strlcat(buf, " bps)", 256);
1280  
1281 proto_item_append_text(ti, "%s", buf+2);
1282  
1283 break;
1284  
1285 case PI_MAX_TURN_TIME:
1286 proto_item_append_text(ti, ": Maximum Turn Time (");
1287  
1288 if (pv & 0x01)
1289 g_strlcat(buf, ", 500", 256);
1290 if (pv & 0x02)
1291 g_strlcat(buf, ", 250", 256);
1292 if (pv & 0x04)
1293 g_strlcat(buf, ", 100", 256);
1294 if (pv & 0x08)
1295 g_strlcat(buf, ", 50", 256);
1296  
1297 g_strlcat(buf, " ms)", 256);
1298  
1299 proto_item_append_text(ti, "%s", buf+2);
1300  
1301 break;
1302  
1303 case PI_DATA_SIZE:
1304 proto_item_append_text(ti, ": Data Size (");
1305  
1306 if (pv & 0x01)
1307 g_strlcat(buf, ", 64", 256);
1308 if (pv & 0x02)
1309 g_strlcat(buf, ", 128", 256);
1310 if (pv & 0x04)
1311 g_strlcat(buf, ", 256", 256);
1312 if (pv & 0x08)
1313 g_strlcat(buf, ", 512", 256);
1314 if (pv & 0x10)
1315 g_strlcat(buf, ", 1024", 256);
1316 if (pv & 0x20)
1317 g_strlcat(buf, ", 2048", 256);
1318  
1319 g_strlcat(buf, " bytes)", 256);
1320  
1321 proto_item_append_text(ti, "%s", buf+2);
1322  
1323 break;
1324  
1325 case PI_WINDOW_SIZE:
1326 proto_item_append_text(ti, ": Window Size (");
1327  
1328 if (pv & 0x01)
1329 g_strlcat(buf, ", 1", 256);
1330 if (pv & 0x02)
1331 g_strlcat(buf, ", 2", 256);
1332 if (pv & 0x04)
1333 g_strlcat(buf, ", 3", 256);
1334 if (pv & 0x08)
1335 g_strlcat(buf, ", 4", 256);
1336 if (pv & 0x10)
1337 g_strlcat(buf, ", 5", 256);
1338 if (pv & 0x20)
1339 g_strlcat(buf, ", 6", 256);
1340 if (pv & 0x40)
1341 g_strlcat(buf, ", 7", 256);
1342  
1343 g_strlcat(buf, " frame window)", 256);
1344  
1345 proto_item_append_text(ti, "%s", buf+2);
1346  
1347 break;
1348  
1349 case PI_ADD_BOFS:
1350 proto_item_append_text(ti, ": Additional BOFs (");
1351  
1352 if (pv & 0x01)
1353 g_strlcat(buf, ", 48", 256);
1354 if (pv & 0x02)
1355 g_strlcat(buf, ", 24", 256);
1356 if (pv & 0x04)
1357 g_strlcat(buf, ", 12", 256);
1358 if (pv & 0x08)
1359 g_strlcat(buf, ", 5", 256);
1360 if (pv & 0x10)
1361 g_strlcat(buf, ", 3", 256);
1362 if (pv & 0x20)
1363 g_strlcat(buf, ", 2", 256);
1364 if (pv & 0x40)
1365 g_strlcat(buf, ", 1", 256);
1366 if (pv & 0x80)
1367 g_strlcat(buf, ", 0", 256);
1368  
1369 g_strlcat(buf, " additional BOFs at 115200)", 256);
1370  
1371 proto_item_append_text(ti, "%s", buf+2);
1372  
1373 break;
1374  
1375 case PI_MIN_TURN_TIME:
1376 proto_item_append_text(ti, ": Minimum Turn Time (");
1377  
1378 if (pv & 0x01)
1379 g_strlcat(buf, ", 10", 256);
1380 if (pv & 0x02)
1381 g_strlcat(buf, ", 5", 256);
1382 if (pv & 0x04)
1383 g_strlcat(buf, ", 1", 256);
1384 if (pv & 0x08)
1385 g_strlcat(buf, ", 0.5", 256);
1386 if (pv & 0x10)
1387 g_strlcat(buf, ", 0.1", 256);
1388 if (pv & 0x20)
1389 g_strlcat(buf, ", 0.05", 256);
1390 if (pv & 0x40)
1391 g_strlcat(buf, ", 0.01", 256);
1392 if (pv & 0x80)
1393 g_strlcat(buf, ", 0", 256);
1394  
1395 g_strlcat(buf, " ms)", 256);
1396  
1397 proto_item_append_text(ti, "%s", buf+2);
1398  
1399 break;
1400  
1401 case PI_LINK_DISC:
1402 proto_item_append_text(ti, ": Link Disconnect/Threshold Time (");
1403  
1404 if (pv & 0x01)
1405 g_strlcat(buf, ", 3/0", 256);
1406 if (pv & 0x02)
1407 g_strlcat(buf, ", 8/3", 256);
1408 if (pv & 0x04)
1409 g_strlcat(buf, ", 12/3", 256);
1410 if (pv & 0x08)
1411 g_strlcat(buf, ", 16/3", 256);
1412 if (pv & 0x10)
1413 g_strlcat(buf, ", 20/3", 256);
1414 if (pv & 0x20)
1415 g_strlcat(buf, ", 25/3", 256);
1416 if (pv & 0x40)
1417 g_strlcat(buf, ", 30/3", 256);
1418 if (pv & 0x80)
1419 g_strlcat(buf, ", 40/3", 256);
1420  
1421 g_strlcat(buf, " s)", 256);
1422  
1423 proto_item_append_text(ti, "%s", buf+2);
1424  
1425 break;
1426  
1427 default:
1428 proto_item_append_text(ti, ": unknown");
1429 }
1430 } else
1431 p_tree = NULL;
1432  
1433 offset = dissect_param_tuple(tvb, p_tree, offset);
1434 n++;
1435 }
1436  
1437 return offset;
1438 }
1439  
1440  
1441 /*
1442 * Dissect XID packet
1443 */
1444 static void dissect_xid(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, proto_tree* lap_tree, gboolean is_command)
1445 {
1446 int offset = 0;
1447 proto_item* ti = NULL;
1448 proto_tree* i_tree = NULL;
1449 proto_tree* flags_tree;
1450 guint32 saddr, daddr;
1451 guint8 s;
1452 proto_tree* lmp_tree = NULL;
1453  
1454 if (lap_tree)
1455 {
1456 ti = proto_tree_add_item(lap_tree, hf_lap_i, tvb, offset, -1, ENC_NA);
1457 i_tree = proto_item_add_subtree(ti, ett_lap_i);
1458  
1459 proto_tree_add_item(i_tree, hf_xid_ident, tvb, offset, 1, ENC_BIG_ENDIAN);
1460 }
1461 offset++;
1462  
1463 saddr = tvb_get_letohl(tvb, offset);
1464 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1465 if (lap_tree)
1466 proto_tree_add_uint(i_tree, hf_xid_saddr, tvb, offset, 4, saddr);
1467 offset += 4;
1468  
1469 daddr = tvb_get_letohl(tvb, offset);
1470 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1471 if (lap_tree)
1472 proto_tree_add_uint(i_tree, hf_xid_daddr, tvb, offset, 4, daddr);
1473 offset += 4;
1474  
1475 if (lap_tree)
1476 {
1477 ti = proto_tree_add_item(i_tree, hf_xid_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
1478 flags_tree = proto_item_add_subtree(ti, ett_xid_flags);
1479 proto_tree_add_item(flags_tree, hf_xid_s, tvb, offset, 1, ENC_BIG_ENDIAN);
1480 proto_tree_add_item(flags_tree, hf_xid_conflict, tvb, offset, 1, ENC_BIG_ENDIAN);
1481 }
1482 offset++;
1483  
1484 if (is_command)
1485 {
1486 s = tvb_get_guint8(tvb, offset);
1487 if (s == 0xFF)
1488 col_append_str(pinfo->cinfo, COL_INFO, ", s=final");
1489 else
1490 col_append_fstr(pinfo->cinfo, COL_INFO, ", s=%u", s);
1491 if (lap_tree)
1492 {
1493 ti = proto_tree_add_uint(i_tree, hf_xid_slotnr, tvb, offset, 1, s);
1494 if (s == 0xFF)
1495 proto_item_append_text(ti, " (final)");
1496 }
1497 }
1498 offset++;
1499  
1500 if (lap_tree)
1501 proto_tree_add_item(i_tree, hf_xid_version, tvb, offset, 1, ENC_BIG_ENDIAN);
1502 offset++;
1503  
1504 if (lap_tree)
1505 {
1506 proto_item_set_end(lap_tree, tvb, offset);
1507 proto_item_set_end(i_tree, tvb, offset);
1508 }
1509  
1510 if (tvb_reported_length_remaining(tvb, offset) > 0)
1511 {
1512 guint hints_len;
1513 guint8 hint1 = 0;
1514 guint8 hint2 = 0;
1515 char buf[23];
1516  
1517 if (root)
1518 {
1519 ti = proto_tree_add_item(root, proto_irlmp, tvb, offset, -1, ENC_NA);
1520 lmp_tree = proto_item_add_subtree(ti, ett_irlmp);
1521 }
1522  
1523 for (hints_len = 0;;)
1524 {
1525 guint8 hint = tvb_get_guint8(tvb, offset + hints_len++);
1526  
1527 if (hints_len == 1)
1528 hint1 = hint;
1529 else if (hints_len == 2)
1530 hint2 = hint;
1531  
1532 if ((hint & 0x80) == 0)
1533 break;
1534 }
1535  
1536 if (root)
1537 {
1538 ti = proto_tree_add_item(lmp_tree, hf_lmp_xid_hints, tvb, offset, hints_len, ENC_NA);
1539 if ((hint1 | hint2) != 0)
1540 {
1541 char service_hints[256];
1542  
1543 service_hints[0] = 0;
1544  
1545 if (hint1 & 0x01)
1546 g_strlcat(service_hints, ", PnP Compatible", 256);
1547 if (hint1 & 0x02)
1548 g_strlcat(service_hints, ", PDA/Palmtop", 256);
1549 if (hint1 & 0x04)
1550 g_strlcat(service_hints, ", Computer", 256);
1551 if (hint1 & 0x08)
1552 g_strlcat(service_hints, ", Printer", 256);
1553 if (hint1 & 0x10)
1554 g_strlcat(service_hints, ", Modem", 256);
1555 if (hint1 & 0x20)
1556 g_strlcat(service_hints, ", Fax", 256);
1557 if (hint1 & 0x40)
1558 g_strlcat(service_hints, ", LAN Access", 256);
1559 if (hint2 & 0x01)
1560 g_strlcat(service_hints, ", Telephony", 256);
1561 if (hint2 & 0x02)
1562 g_strlcat(service_hints, ", File Server", 256);
1563 if (hint2 & 0x04)
1564 g_strlcat(service_hints, ", IrCOMM", 256);
1565 if (hint2 & 0x20)
1566 g_strlcat(service_hints, ", OBEX", 256);
1567  
1568 g_strlcat(service_hints, ")", 256);
1569 service_hints[0] = ' ';
1570 service_hints[1] = '(';
1571  
1572 proto_item_append_text(ti, "%s", service_hints);
1573 }
1574 }
1575 offset += hints_len;
1576  
1577 if (tvb_reported_length_remaining(tvb, offset) > 0)
1578 {
1579 guint8 cset;
1580 gint name_len;
1581  
1582 cset = tvb_get_guint8(tvb, offset);
1583 if (root)
1584 proto_tree_add_uint(lmp_tree, hf_lmp_xid_charset, tvb, offset, 1, cset);
1585 offset++;
1586 name_len = tvb_reported_length_remaining(tvb, offset);
1587 if (name_len > 0)
1588 {
1589 if (cset == 0x00)
1590 {
1591  
1592 if (name_len > 22)
1593 name_len = 22;
1594 tvb_memcpy(tvb, buf, offset, name_len);
1595 buf[name_len] = 0;
1596 col_append_str(pinfo->cinfo, COL_INFO, ", \"");
1597 col_append_str(pinfo->cinfo, COL_INFO, buf);
1598 col_append_str(pinfo->cinfo, COL_INFO, "\"");
1599 if (root)
1600 proto_tree_add_item(lmp_tree, hf_lmp_xid_name, tvb, offset,
1601 -1, ENC_ASCII|ENC_NA);
1602 }
1603 else
1604 {
1605 if (root)
1606 proto_tree_add_item(lmp_tree, hf_lmp_xid_name_no_ascii, tvb, offset,
1607 -1, ENC_NA);
1608 }
1609 }
1610 }
1611 }
1612 }
1613  
1614  
1615 /*
1616 * Dissect Log Messages
1617 */
1618 static void dissect_log(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1619 {
1620 /* Make entries in Protocol column on summary display */
1621 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Log");
1622  
1623 /* missed messages? */
1624 if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1625 {
1626 col_set_str(pinfo->cinfo, COL_INFO, "WARNING: Missed one or more messages while capturing!");
1627 }
1628 else
1629 {
1630 guint length;
1631 char buf[256];
1632  
1633  
1634 length = tvb_captured_length(tvb);
1635 if (length > sizeof(buf)-1)
1636 length = sizeof(buf)-1;
1637 tvb_memcpy(tvb, buf, 0, length);
1638 buf[length] = 0;
1639 if (length > 0 && buf[length-1] == '\n')
1640 buf[length-1] = 0;
1641 else if (length > 1 && buf[length-2] == '\n')
1642 buf[length-2] = 0;
1643  
1644 col_add_str(pinfo->cinfo, COL_INFO, buf);
1645 }
1646  
1647 if (root)
1648 {
1649 proto_item* ti = proto_tree_add_item(root, proto_log, tvb, 0, -1, ENC_NA);
1650 proto_tree* tree = proto_item_add_subtree(ti, ett_log);
1651  
1652 if (pinfo->pseudo_header->irda.pkttype == IRDA_MISSED_MSG)
1653 proto_tree_add_item(tree, hf_log_missed, tvb, 0, 0, ENC_NA);
1654 else
1655 proto_tree_add_item(tree, hf_log_msg, tvb, 0, -1, ENC_ASCII|ENC_NA);
1656 }
1657 }
1658  
1659  
1660 /*
1661 * Dissect IrLAP
1662 */
1663 static void dissect_irlap(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root)
1664 {
1665 int offset = 0;
1666 guint8 circuit_id, c;
1667 gboolean is_response;
1668 char addr[9];
1669 proto_item* ti = NULL;
1670 proto_tree* tree = NULL;
1671 proto_tree* i_tree = NULL;
1672 guint32 saddr, daddr;
1673 guint8 ca;
1674  
1675 /* Make entries in Protocol column on summary display */
1676 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrLAP");
1677  
1678 /* Clear Info column */
1679 col_clear(pinfo->cinfo, COL_INFO);
1680  
1681 /* set direction column */
1682 switch (pinfo->pseudo_header->irda.pkttype)
1683 {
1684 case IRDA_OUTGOING:
1685 col_set_str(pinfo->cinfo, COL_IF_DIR, "Out");
1686 break;
1687  
1688 case IRDA_INCOMING:
1689 col_set_str(pinfo->cinfo, COL_IF_DIR, "In");
1690 break;
1691 }
1692  
1693 /* decode values used for demuxing */
1694 circuit_id = tvb_get_guint8(tvb, 0);
1695  
1696 /* initially set address columns to connection address */
1697 g_snprintf(addr, sizeof(addr)-1, "0x%02X", circuit_id >> 1);
1698 col_add_str(pinfo->cinfo, COL_DEF_SRC, addr);
1699 col_add_str(pinfo->cinfo, COL_DEF_DST, addr);
1700  
1701 if (root)
1702 {
1703 proto_tree* a_tree;
1704 proto_item* addr_item;
1705  
1706 /* create display subtree for the protocol */
1707 ti = proto_tree_add_item(root, proto_irlap, tvb, 0, -1, ENC_NA);
1708 tree = proto_item_add_subtree(ti, ett_irlap);
1709  
1710 /* create subtree for the address field */
1711 ti = proto_tree_add_item(tree, hf_lap_a, tvb, offset, 1, ENC_BIG_ENDIAN);
1712 a_tree = proto_item_add_subtree(ti, ett_lap_a);
1713 proto_tree_add_item(a_tree, hf_lap_a_cr, tvb, offset, 1, ENC_BIG_ENDIAN);
1714 addr_item = proto_tree_add_item(a_tree, hf_lap_a_address, tvb, offset, 1, ENC_BIG_ENDIAN);
1715 switch (circuit_id & ~CMD_FRAME)
1716 {
1717 case 0:
1718 proto_item_append_text(addr_item, " (NULL Address)");
1719 break;
1720 case 0xFE:
1721 proto_item_append_text(addr_item, " (Broadcast)");
1722 break;
1723 }
1724 }
1725 is_response = ((circuit_id & CMD_FRAME) == 0);
1726 offset++;
1727  
1728 /* process the control field */
1729 c = dissect_xdlc_control(tvb, 1, pinfo, tree, hf_lap_c,
1730 ett_lap_c, &irlap_cf_items, NULL, lap_c_u_cmd_abbr_vals,
1731 lap_c_u_rsp_abbr_vals, is_response, FALSE, FALSE);
1732 offset++;
1733  
1734 if ((c & XDLC_I_MASK) == XDLC_I) {
1735 /* I frame */
1736 proto_item_set_len(tree, offset);
1737 tvb = tvb_new_subset_remaining(tvb, offset);
1738 dissect_irlmp(tvb, pinfo, root, circuit_id);
1739 return;
1740 }
1741  
1742 if ((c & 0x03) == XDLC_U) {
1743 /* U frame */
1744 switch (c & XDLC_U_MODIFIER_MASK)
1745 {
1746 case XDLC_SNRM:
1747 if (root)
1748 {
1749 ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, ENC_NA);
1750 i_tree = proto_item_add_subtree(ti, ett_lap_i);
1751 }
1752  
1753 saddr = tvb_get_letohl(tvb, offset);
1754 if (!is_response)
1755 {
1756 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1757 }
1758 if (root)
1759 proto_tree_add_uint(i_tree, hf_snrm_saddr, tvb, offset, 4, saddr);
1760 offset += 4;
1761  
1762 daddr = tvb_get_letohl(tvb, offset);
1763 if (!is_response)
1764 {
1765 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1766 }
1767 if (root)
1768 proto_tree_add_uint(i_tree, hf_snrm_daddr, tvb, offset, 4, daddr);
1769 offset += 4;
1770  
1771 ca = tvb_get_guint8(tvb, offset);
1772 if (!is_response)
1773 {
1774 col_append_fstr(pinfo->cinfo, COL_INFO, ", ca=0x%02X",
1775 ca >> 1);
1776 }
1777 if (root)
1778 proto_tree_add_uint(i_tree, hf_snrm_ca, tvb, offset, 1, ca >> 1);
1779 offset++;
1780  
1781 offset = dissect_negotiation(tvb, i_tree, offset);
1782 if (root)
1783 proto_item_set_end(ti, tvb, offset);
1784 break;
1785  
1786 case IRDA_XID_CMD:
1787 tvb = tvb_new_subset_remaining(tvb, offset);
1788 dissect_xid(tvb, pinfo, root, tree, TRUE);
1789 return;
1790  
1791 case XDLC_UA:
1792 if (tvb_reported_length_remaining(tvb, offset) > 0)
1793 {
1794 if (root)
1795 {
1796 ti = proto_tree_add_item(tree, hf_lap_i, tvb, offset, -1, ENC_NA);
1797 i_tree = proto_item_add_subtree(ti, ett_lap_i);
1798 }
1799  
1800 saddr = tvb_get_letohl(tvb, offset);
1801 col_add_fstr(pinfo->cinfo, COL_DEF_SRC, "0x%08X", saddr);
1802 if (root)
1803 proto_tree_add_uint(i_tree, hf_ua_saddr, tvb, offset, 4, saddr);
1804 offset += 4;
1805  
1806 daddr = tvb_get_letohl(tvb, offset);
1807 col_add_fstr(pinfo->cinfo, COL_DEF_DST, "0x%08X", daddr);
1808 if (root)
1809 proto_tree_add_uint(i_tree, hf_ua_daddr, tvb, offset, 4, daddr);
1810 offset += 4;
1811  
1812 offset = dissect_negotiation(tvb, i_tree, offset);
1813 if (root)
1814 proto_item_set_end(ti, tvb, offset);
1815 }
1816 break;
1817  
1818 case XDLC_XID:
1819 tvb = tvb_new_subset_remaining(tvb, offset);
1820 dissect_xid(tvb, pinfo, root, tree, FALSE);
1821 return;
1822 }
1823 }
1824  
1825 /* If any bytes remain, send it to the generic data dissector */
1826 if (tvb_reported_length_remaining(tvb, offset) > 0)
1827 {
1828 tvb = tvb_new_subset_remaining(tvb, offset);
1829 call_data_dissector(tvb, pinfo, root);
1830 }
1831 }
1832  
1833  
1834 /*
1835 * Dissect IrDA protocol
1836 */
1837 static int dissect_irda(tvbuff_t* tvb, packet_info* pinfo, proto_tree* root, void* data _U_)
1838 {
1839 /* check if log message */
1840 if ((pinfo->pseudo_header->irda.pkttype & IRDA_CLASS_MASK) == IRDA_CLASS_LOG)
1841 {
1842 dissect_log(tvb, pinfo, root);
1843 return tvb_captured_length(tvb);
1844 }
1845  
1846  
1847 dissect_irlap(tvb, pinfo, root);
1848 return tvb_captured_length(tvb);
1849 }
1850  
1851 static int irda_addr_to_str(const address* addr, gchar *buf, int buf_len _U_)
1852 {
1853 const guint8 *addrdata = (const guint8 *)addr->data;
1854 gchar *start_buf = buf;
1855  
1856 buf = uint_to_str_back(buf, *addrdata);
1857 *buf = '\0';
1858 return (int)(buf-start_buf+1);
1859 }
1860  
1861 static int irda_addr_str_len(const address* addr _U_)
1862 {
1863 return 11; /* Leaves required space (10 bytes) for uint_to_str_back() */
1864 }
1865  
1866 static const char* irda_col_filter_str(const address* addr _U_, gboolean is_src _U_)
1867 {
1868 return "irlap.a";
1869 }
1870  
1871 static int irda_addr_len(void)
1872 {
1873 return 1;
1874 }
1875  
1876 /*
1877 * Register the protocol with Wireshark
1878 * This format is required because a script is used to build the C function
1879 * that calls all the protocol registrations.
1880 */
1881 void proto_register_irda(void)
1882 {
1883 guint i;
1884  
1885 /* Setup list of header fields */
1886 static hf_register_info hf_lap[] = {
1887 { &hf_lap_a,
1888 { "Address Field", "irlap.a",
1889 FT_UINT8, BASE_HEX, NULL, 0,
1890 NULL, HFILL }},
1891 { &hf_lap_a_cr,
1892 { "C/R", "irlap.a.cr",
1893 FT_BOOLEAN, 8, TFS(&lap_cr_vals), CMD_FRAME,
1894 NULL, HFILL }},
1895 { &hf_lap_a_address,
1896 { "Address", "irlap.a.address",
1897 FT_UINT8, BASE_HEX, NULL, ~CMD_FRAME,
1898 NULL, HFILL }},
1899 { &hf_lap_c,
1900 { "Control Field", "irlap.c",
1901 FT_UINT8, BASE_HEX, NULL, 0,
1902 NULL, HFILL }},
1903 { &hf_lap_c_nr,
1904 { "N(R)", "irlap.c.n_r",
1905 FT_UINT8, BASE_DEC, NULL, XDLC_N_R_MASK,
1906 NULL, HFILL }},
1907 { &hf_lap_c_ns,
1908 { "N(S)", "irlap.c.n_s",
1909 FT_UINT8, BASE_DEC, NULL, XDLC_N_S_MASK,
1910 NULL, HFILL }},
1911 { &hf_lap_c_p,
1912 { "Poll", "irlap.c.p",
1913 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1914 NULL, HFILL }},
1915 { &hf_lap_c_f,
1916 { "Final", "irlap.c.f",
1917 FT_BOOLEAN, 8, TFS(&set_notset), XDLC_P_F,
1918 NULL, HFILL }},
1919 { &hf_lap_c_s,
1920 { "Supervisory frame type", "irlap.c.s_ftype",
1921 FT_UINT8, BASE_HEX, VALS(lap_c_s_vals), XDLC_S_FTYPE_MASK,
1922 NULL, HFILL }},
1923 { &hf_lap_c_u_cmd,
1924 { "Command", "irlap.c.u_modifier_cmd",
1925 FT_UINT8, BASE_HEX, VALS(lap_c_u_cmd_vals), XDLC_U_MODIFIER_MASK,
1926 NULL, HFILL }},
1927 { &hf_lap_c_u_rsp,
1928 { "Response", "irlap.c.u_modifier_resp",
1929 FT_UINT8, BASE_HEX, VALS(lap_c_u_rsp_vals), XDLC_U_MODIFIER_MASK,
1930 NULL, HFILL }},
1931 { &hf_lap_c_i,
1932 { "Frame Type", "irlap.c.ftype",
1933 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_I_MASK,
1934 NULL, HFILL }},
1935 { &hf_lap_c_s_u,
1936 { "Frame Type", "irlap.c.ftype",
1937 FT_UINT8, BASE_HEX, VALS(lap_c_ftype_vals), XDLC_S_U_MASK,
1938 NULL, HFILL }},
1939 { &hf_lap_i,
1940 { "Information Field", "irlap.i",
1941 FT_NONE, BASE_NONE, NULL, 0,
1942 NULL, HFILL }},
1943 { &hf_snrm_saddr,
1944 { "Source Device Address", "irlap.snrm.saddr",
1945 FT_UINT32, BASE_HEX, NULL, 0,
1946 NULL, HFILL }},
1947 { &hf_snrm_daddr,
1948 { "Destination Device Address", "irlap.snrm.daddr",
1949 FT_UINT32, BASE_HEX, NULL, 0,
1950 NULL, HFILL }},
1951 { &hf_snrm_ca,
1952 { "Connection Address", "irlap.snrm.ca",
1953 FT_UINT8, BASE_HEX, NULL, 0,
1954 NULL, HFILL }},
1955 { &hf_negotiation_param,
1956 { "Negotiation Parameter", "irlap.negotiation",
1957 FT_NONE, BASE_NONE, NULL, 0,
1958 NULL, HFILL }},
1959 { &hf_param_pi,
1960 { "Parameter Identifier", "irlap.pi",
1961 FT_UINT8, BASE_HEX, NULL, 0,
1962 NULL, HFILL }},
1963 { &hf_param_pl,
1964 { "Parameter Length", "irlap.pl",
1965 FT_UINT8, BASE_HEX, NULL, 0,
1966 NULL, HFILL }},
1967 { &hf_param_pv,
1968 { "Parameter Value", "irlap.pv",
1969 FT_BYTES, BASE_NONE, NULL, 0,
1970 NULL, HFILL }},
1971 { &hf_ua_saddr,
1972 { "Source Device Address", "irlap.ua.saddr",
1973 FT_UINT32, BASE_HEX, NULL, 0,
1974 NULL, HFILL }},
1975 { &hf_ua_daddr,
1976 { "Destination Device Address", "irlap.ua.daddr",
1977 FT_UINT32, BASE_HEX, NULL, 0,
1978 NULL, HFILL }},
1979 { &hf_xid_ident,
1980 { "Format Identifier", "irlap.xid.fi",
1981 FT_UINT8, BASE_HEX, NULL, 0,
1982 NULL, HFILL }},
1983 { &hf_xid_saddr,
1984 { "Source Device Address", "irlap.xid.saddr",
1985 FT_UINT32, BASE_HEX, NULL, 0,
1986 NULL, HFILL }},
1987 { &hf_xid_daddr,
1988 { "Destination Device Address", "irlap.xid.daddr",
1989 FT_UINT32, BASE_HEX, NULL, 0,
1990 NULL, HFILL }},
1991 { &hf_xid_flags,
1992 { "Discovery Flags", "irlap.xid.flags",
1993 FT_UINT8, BASE_HEX, NULL, 0,
1994 NULL, HFILL }},
1995 { &hf_xid_s,
1996 { "Number of Slots", "irlap.xid.s",
1997 FT_UINT8, BASE_DEC, VALS(xid_slot_numbers), S_MASK,
1998 NULL, HFILL }},
1999 { &hf_xid_conflict,
2000 { "Conflict", "irlap.xid.conflict",
2001 FT_BOOLEAN, 8, TFS(&set_notset), CONFLICT,
2002 NULL, HFILL }},
2003 { &hf_xid_slotnr,
2004 { "Slot Number", "irlap.xid.slotnr",
2005 FT_UINT8, BASE_DEC, NULL, 0,
2006 NULL, HFILL }},
2007 { &hf_xid_version,
2008 { "Version Number", "irlap.xid.version",
2009 FT_UINT8, BASE_HEX, NULL, 0,
2010 NULL, HFILL }}
2011 };
2012  
2013 static hf_register_info hf_log[] = {
2014 { &hf_log_msg,
2015 { "Message", "log.msg",
2016 FT_STRING, BASE_NONE, NULL, 0,
2017 NULL, HFILL }},
2018 { &hf_log_missed,
2019 { "WARNING: Missed one or more messages while capturing!", "log.missed",
2020 FT_NONE, BASE_NONE, NULL, 0,
2021 NULL, HFILL }}
2022 };
2023  
2024 static hf_register_info hf_lmp[] = {
2025 { &hf_lmp_xid_hints,
2026 { "Service Hints", "irlmp.xid.hints",
2027 FT_BYTES, BASE_NONE, NULL, 0,
2028 NULL, HFILL }},
2029 { &hf_lmp_xid_charset,
2030 { "Character Set", "irlmp.xid.charset",
2031 FT_UINT8, BASE_HEX, NULL, 0,
2032 NULL, HFILL }},
2033 { &hf_lmp_xid_name,
2034 { "Device Nickname", "irlmp.xid.name",
2035 FT_STRING, BASE_NONE, NULL, 0,
2036 NULL, HFILL }},
2037 { &hf_lmp_xid_name_no_ascii,
2038 { "Device Nickname (unsupported character set)", "irlmp.xid.name.no_ascii",
2039 FT_BYTES, BASE_NONE, NULL, 0,
2040 NULL, HFILL }},
2041 { &hf_lmp_dst,
2042 { "Destination", "irlmp.dst",
2043 FT_UINT8, BASE_HEX, NULL, 0,
2044 NULL, HFILL }},
2045 { &hf_lmp_dst_control,
2046 { "Control Bit", "irlmp.dst.c",
2047 FT_BOOLEAN, 8, TFS(&set_notset), CONTROL_BIT,
2048 NULL, HFILL }},
2049 { &hf_lmp_dst_lsap,
2050 { "Destination LSAP", "irlmp.dst.lsap",
2051 FT_UINT8, BASE_DEC, NULL, ~CONTROL_BIT,
2052 NULL, HFILL }},
2053 { &hf_lmp_src,
2054 { "Source", "irlmp.src",
2055 FT_UINT8, BASE_HEX, NULL, 0,
2056 NULL, HFILL }},
2057 { &hf_lmp_src_r,
2058 { "reserved", "irlmp.src.r",
2059 FT_UINT8, BASE_DEC, NULL, RESERVED_BIT,
2060 NULL, HFILL }},
2061 { &hf_lmp_src_lsap,
2062 { "Source LSAP", "irlmp.src.lsap",
2063 FT_UINT8, BASE_DEC, NULL, ~RESERVED_BIT,
2064 NULL, HFILL }},
2065 { &hf_lmp_opcode,
2066 { "Opcode", "irlmp.opcode",
2067 FT_UINT8, BASE_HEX, VALS(lmp_opcode_vals), 0x0,
2068 NULL, HFILL }},
2069 { &hf_lmp_rsvd,
2070 { "Reserved", "irlmp.rsvd",
2071 FT_UINT8, BASE_HEX, NULL, 0x0,
2072 NULL, HFILL }},
2073 { &hf_lmp_reason,
2074 { "Reason", "irlmp.reason",
2075 FT_UINT8, BASE_HEX, VALS(lmp_reason_vals), 0x0,
2076 NULL, HFILL }},
2077 { &hf_lmp_mode,
2078 { "Mode", "irlmp.mode",
2079 FT_UINT8, BASE_HEX, VALS(lmp_mode_vals), 0x0,
2080 NULL, HFILL }},
2081 { &hf_lmp_status,
2082 { "Status", "irlmp.status",
2083 FT_UINT8, BASE_HEX, VALS(lmp_status_vals), 0x0,
2084 NULL, HFILL }}
2085 };
2086  
2087 static hf_register_info hf_iap[] = {
2088 { &hf_iap_ctl,
2089 { "Control Field", "iap.ctl",
2090 FT_UINT8, BASE_HEX, NULL, 0,
2091 NULL, HFILL }},
2092 { &hf_iap_ctl_lst,
2093 { "Last Frame", "iap.ctl.lst",
2094 FT_BOOLEAN, 8, TFS(&set_notset), IAP_LST,
2095 NULL, HFILL }},
2096 { &hf_iap_ctl_ack,
2097 { "Acknowledge", "iap.ctl.ack",
2098 FT_BOOLEAN, 8, TFS(&set_notset), IAP_ACK,
2099 NULL, HFILL }},
2100 { &hf_iap_ctl_opcode,
2101 { "Opcode", "iap.ctl.opcode",
2102 FT_UINT8, BASE_HEX, VALS(iap_opcode_vals), IAP_OP,
2103 NULL, HFILL }},
2104 { &hf_iap_class_name,
2105 { "Class Name", "iap.classname",
2106 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2107 NULL, HFILL }},
2108 { &hf_iap_attr_name,
2109 { "Attribute Name", "iap.attrname",
2110 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2111 NULL, HFILL }},
2112 { &hf_iap_return,
2113 { "Return", "iap.return",
2114 FT_UINT8, BASE_HEX, VALS(iap_return_vals), 0x0,
2115 NULL, HFILL }},
2116 { &hf_iap_list_len,
2117 { "List Length", "iap.listlen",
2118 FT_UINT16, BASE_DEC, NULL, 0x0,
2119 NULL, HFILL }},
2120 { &hf_iap_list_entry,
2121 { "List Entry", "iap.listentry",
2122 FT_NONE, BASE_NONE, NULL, 0x0,
2123 NULL, HFILL }},
2124 { &hf_iap_obj_id,
2125 { "Object Identifier", "iap.objectid",
2126 FT_UINT16, BASE_HEX, NULL, 0x0,
2127 NULL, HFILL }},
2128 { &hf_iap_attr_type,
2129 { "Type", "iap.attrtype",
2130 FT_UINT8, BASE_DEC, VALS(iap_attr_type_vals), 0x0,
2131 NULL, HFILL }},
2132 { &hf_iap_int,
2133 { "Value", "iap.int",
2134 FT_INT32, BASE_DEC, NULL, 0x0,
2135 NULL, HFILL }},
2136 { &hf_iap_seq_len,
2137 { "Sequence Length", "iap.seqlen",
2138 FT_UINT16, BASE_DEC, NULL, 0x0,
2139 NULL, HFILL }},
2140 { &hf_iap_oct_seq,
2141 { "Sequence", "iap.octseq",
2142 FT_BYTES, BASE_NONE, NULL, 0x0,
2143 NULL, HFILL }},
2144 { &hf_iap_char_set,
2145 { "Character Set", "iap.charset",
2146 FT_UINT8, BASE_HEX, NULL, 0x0,
2147 NULL, HFILL }},
2148 { &hf_iap_string,
2149 { "String", "iap.string",
2150 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
2151 NULL, HFILL }},
2152 { &hf_iap_invaloctet,
2153 { "Malformed IAP result: \"", "iap.invaloctet",
2154 FT_NONE, BASE_NONE, NULL, 0,
2155 NULL, HFILL }},
2156 { &hf_iap_invallsap,
2157 { "Malformed IAP result: \"", "iap.invallsap",
2158 FT_NONE, BASE_NONE, NULL, 0,
2159 NULL, HFILL }}
2160 };
2161  
2162 static hf_register_info hf_ttp[] = {
2163 { &hf_ttp_p,
2164 { "Parameter Bit", "ttp.p",
2165 FT_BOOLEAN, 8, TFS(&set_notset), TTP_PARAMETERS,
2166 NULL, HFILL }},
2167 { &hf_ttp_icredit,
2168 { "Initial Credit", "ttp.icredit",
2169 FT_UINT8, BASE_DEC, NULL, ~TTP_PARAMETERS,
2170 NULL, HFILL }},
2171 { &hf_ttp_m,
2172 { "More Bit", "ttp.m",
2173 FT_BOOLEAN, 8, TFS(&set_notset), TTP_MORE,
2174 NULL, HFILL }},
2175 { &hf_ttp_dcredit,
2176 { "Delta Credit", "ttp.dcredit",
2177 FT_UINT8, BASE_DEC, NULL, ~TTP_MORE,
2178 NULL, HFILL }}
2179 };
2180  
2181 /* Setup protocol subtree arrays */
2182 static gint* ett[] = {
2183 &ett_irlap,
2184 &ett_lap_a,
2185 &ett_lap_c,
2186 &ett_lap_i,
2187 &ett_xid_flags,
2188 &ett_log,
2189 &ett_irlmp,
2190 &ett_lmp_dst,
2191 &ett_lmp_src,
2192 &ett_iap,
2193 &ett_iap_ctl,
2194 &ett_ttp
2195 };
2196  
2197 gint* ett_p[MAX_PARAMETERS];
2198 gint* ett_iap_e[MAX_IAP_ENTRIES];
2199  
2200  
2201 /* Register protocol names and descriptions */
2202 proto_irlap = proto_register_protocol("IrDA Link Access Protocol", "IrLAP", "irlap");
2203 proto_log = proto_register_protocol("Log Message", "Log", "log");
2204 proto_irlmp = proto_register_protocol("IrDA Link Management Protocol", "IrLMP", "irlmp");
2205 proto_iap = proto_register_protocol("Information Access Protocol", "IAP", "iap");
2206 proto_ttp = proto_register_protocol("Tiny Transport Protocol", "TTP", "ttp");
2207  
2208 /* Register the dissector */
2209 register_dissector("irda", dissect_irda, proto_irlap);
2210  
2211 /* Required function calls to register the header fields */
2212 proto_register_field_array(proto_irlap, hf_lap, array_length(hf_lap));
2213 proto_register_field_array(proto_log, hf_log, array_length(hf_log));
2214 proto_register_field_array(proto_irlmp, hf_lmp, array_length(hf_lmp));
2215 proto_register_field_array(proto_iap, hf_iap, array_length(hf_iap));
2216 proto_register_field_array(proto_ttp, hf_ttp, array_length(hf_ttp));
2217  
2218 /* Register subtrees */
2219 proto_register_subtree_array(ett, array_length(ett));
2220 for (i = 0; i < MAX_PARAMETERS; i++)
2221 {
2222 ett_param[i] = -1;
2223 ett_p[i] = &ett_param[i];
2224 }
2225 proto_register_subtree_array(ett_p, MAX_PARAMETERS);
2226 for (i = 0; i < MAX_IAP_ENTRIES; i++)
2227 {
2228 ett_iap_entry[i] = -1;
2229 ett_iap_e[i] = &ett_iap_entry[i];
2230 }
2231 proto_register_subtree_array(ett_iap_e, MAX_IAP_ENTRIES);
2232  
2233 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);
2234 }
2235  
2236  
2237 /* If this dissector uses sub-dissector registration add a registration routine.
2238 This format is required because a script is used to find these routines and
2239 create the code that calls these routines.
2240 */
2241  
2242 void proto_reg_handoff_irda(void)
2243 {
2244 dissector_handle_t irda_handle;
2245  
2246 irda_handle = find_dissector("irda");
2247 dissector_add_uint("wtap_encap", WTAP_ENCAP_IRDA, irda_handle);
2248 dissector_add_uint("sll.ltype", LINUX_SLL_P_IRDA_LAP, irda_handle);
2249 }
2250  
2251 /*
2252 * Editor modelines - http://www.wireshark.org/tools/modelines.html
2253 *
2254 * Local variables:
2255 * c-basic-offset: 4
2256 * tab-width: 8
2257 * indent-tabs-mode: nil
2258 * End:
2259 *
2260 * vi: set shiftwidth=4 tabstop=8 expandtab:
2261 * :indentSize=4:tabSize=8:noTabs=true:
2262 */