1 /* packet-ircomm.c
2  * Routines for IrCOMM dissection
3  * Copyright 2003 Jan Kiszka <jan.kiszka@web.de>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 #include "config.h"
13 
14 #include <epan/packet.h>
15 
16 /*
17  * See
18  *
19  *    http://www.irdajp.info/specifications.php
20  *
21  * or
22  *
23  *    https://web.archive.org/web/20040405053146/http://www.irda.org/standards/specifications.asp
24  *
25  * for various IrDA specifications.
26  */
27 
28 #include "irda-appl.h"
29 
30 
31 /* Parameters common to all service types */
32 #define IRCOMM_SERVICE_TYPE     0x00
33 #define IRCOMM_PORT_TYPE        0x01 /* Only used in LM-IAS */
34 #define IRCOMM_PORT_NAME        0x02 /* Only used in LM-IAS */
35 
36 /* Parameters for both 3 wire and 9 wire */
37 #define IRCOMM_DATA_RATE        0x10
38 #define IRCOMM_DATA_FORMAT      0x11
39 #define IRCOMM_FLOW_CONTROL     0x12
40 #define IRCOMM_XON_XOFF         0x13
41 #define IRCOMM_ENQ_ACK          0x14
42 #define IRCOMM_LINE_STATUS      0x15
43 #define IRCOMM_BREAK            0x16
44 
45 /* Parameters for 9 wire */
46 #define IRCOMM_DTE              0x20
47 #define IRCOMM_DCE              0x21
48 #define IRCOMM_POLL             0x22
49 
50 /* Service type (details) */
51 #define IRCOMM_3_WIRE_RAW       0x01
52 #define IRCOMM_3_WIRE           0x02
53 #define IRCOMM_9_WIRE           0x04
54 #define IRCOMM_CENTRONICS       0x08
55 
56 /* Port type (details) */
57 #define IRCOMM_SERIAL           0x01
58 #define IRCOMM_PARALLEL         0x02
59 
60 /* Data format (details) */
61 #define IRCOMM_WSIZE_5          0x00
62 #define IRCOMM_WSIZE_6          0x01
63 #define IRCOMM_WSIZE_7          0x02
64 #define IRCOMM_WSIZE_8          0x03
65 
66 #define IRCOMM_1_STOP_BIT       0x00
67 #define IRCOMM_2_STOP_BIT       0x04 /* 1.5 if char len 5 */
68 
69 #define IRCOMM_PARITY_DISABLE   0x00
70 #define IRCOMM_PARITY_ENABLE    0x08
71 
72 #define IRCOMM_PARITY_ODD       0x00
73 #define IRCOMM_PARITY_EVEN      0x10
74 #define IRCOMM_PARITY_MARK      0x20
75 #define IRCOMM_PARITY_SPACE     0x30
76 
77 /* Flow control */
78 #define IRCOMM_XON_XOFF_IN      0x01
79 #define IRCOMM_XON_XOFF_OUT     0x02
80 #define IRCOMM_RTS_CTS_IN       0x04
81 #define IRCOMM_RTS_CTS_OUT      0x08
82 #define IRCOMM_DSR_DTR_IN       0x10
83 #define IRCOMM_DSR_DTR_OUT      0x20
84 #define IRCOMM_ENQ_ACK_IN       0x40
85 #define IRCOMM_ENQ_ACK_OUT      0x80
86 
87 /* Line status */
88 #define IRCOMM_OVERRUN_ERROR    0x02
89 #define IRCOMM_PARITY_ERROR     0x04
90 #define IRCOMM_FRAMING_ERROR    0x08
91 
92 /* DTE (Data terminal equipment) line settings */
93 #define IRCOMM_DELTA_DTR        0x01
94 #define IRCOMM_DELTA_RTS        0x02
95 #define IRCOMM_DTR              0x04
96 #define IRCOMM_RTS              0x08
97 
98 /* DCE (Data communications equipment) line settings */
99 #define IRCOMM_DELTA_CTS        0x01  /* Clear to send has changed */
100 #define IRCOMM_DELTA_DSR        0x02  /* Data set ready has changed */
101 #define IRCOMM_DELTA_RI         0x04  /* Ring indicator has changed */
102 #define IRCOMM_DELTA_CD         0x08  /* Carrier detect has changed */
103 #define IRCOMM_CTS              0x10  /* Clear to send is high */
104 #define IRCOMM_DSR              0x20  /* Data set ready is high */
105 #define IRCOMM_RI               0x40  /* Ring indicator is high */
106 #define IRCOMM_CD               0x80  /* Carrier detect is high */
107 #define IRCOMM_DCE_DELTA_ANY    0x0f
108 
109 void proto_reg_handoff_ircomm(void);
110 
111 /* Initialize the subtree pointers */
112 static gint ett_ircomm = -1;
113 static gint ett_ircomm_ctrl = -1;
114 
115 #define MAX_PARAMETERS          32
116 static gint ett_param[MAX_IAP_ENTRIES * MAX_PARAMETERS];
117 
118 static dissector_handle_t ircomm_raw_handle;
119 static dissector_handle_t ircomm_cooked_handle;
120 
121 static int proto_ircomm = -1;
122 static int hf_ircomm_param = -1;
123 /* static int hf_param_pi = -1; */
124 /* static int hf_param_pl = -1; */
125 /* static int hf_param_pv = -1; */
126 static int hf_control = -1;
127 static int hf_control_len = -1;
128 
129 static gboolean dissect_ircomm_parameters(tvbuff_t* tvb, guint offset, packet_info* pinfo,
130                                           proto_tree* tree, guint list_index, guint8 attr_type, guint8 circuit_id);
131 static gboolean dissect_ircomm_ttp_lsap(tvbuff_t* tvb, guint offset, packet_info* pinfo,
132                                         proto_tree* tree, guint list_index, guint8 attr_type, guint8 circuit_id);
133 static gboolean dissect_ircomm_lmp_lsap(tvbuff_t* tvb, guint offset, packet_info* pinfo,
134                                         proto_tree* tree, guint list_index, guint8 attr_type, guint8 circuit_id);
135 
136 ias_attr_dissector_t ircomm_attr_dissector[] = {
137 /* IrDA:IrCOMM attribute dissectors */
138     { "Parameters",             dissect_ircomm_parameters },
139     { "IrDA:TinyTP:LsapSel",    dissect_ircomm_ttp_lsap },
140     { NULL,                     NULL }
141 };
142 
143 ias_attr_dissector_t irlpt_attr_dissector[] = {
144 /* IrLPT attribute dissectors */
145     { "IrDA:IrLMP:LsapSel", dissect_ircomm_lmp_lsap },
146     { "IrDA:IrLMP:LSAPSel", dissect_ircomm_lmp_lsap },  /* according to IrCOMM V1.0, p25 */
147     { NULL, NULL }
148 };
149 
150 
151 /*
152  * Dissect the cooked IrCOMM protocol
153  */
dissect_cooked_ircomm(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)154 static int dissect_cooked_ircomm(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
155 {
156     proto_item *ti;
157     proto_tree *ircomm_tree, *ctrl_tree;
158     guint offset = 0;
159     guint clen;
160     gint len = tvb_reported_length(tvb);
161 
162     if (len == 0)
163         return len;
164 
165     /* Make entries in Protocol column on summary display */
166     col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrCOMM");
167 
168     clen = tvb_get_guint8(tvb, offset);
169     len -= 1 + clen;
170 
171     if (len > 0)
172         col_add_fstr(pinfo->cinfo, COL_INFO, "Clen=%d, UserData: %d byte%s", clen, len, (len > 1)? "s": "");
173     else
174         col_add_fstr(pinfo->cinfo, COL_INFO, "Clen=%d", clen);
175 
176     /* create display subtree for the protocol */
177     ti          = proto_tree_add_item(tree, proto_ircomm, tvb, 0, -1, ENC_NA);
178     ircomm_tree = proto_item_add_subtree(ti, ett_ircomm);
179 
180     ti        = proto_tree_add_item(ircomm_tree, hf_control, tvb, 0, clen + 1, ENC_NA);
181     ctrl_tree = proto_item_add_subtree(ti, ett_ircomm_ctrl);
182     proto_tree_add_item(ctrl_tree, hf_control_len, tvb, offset, 1, ENC_BIG_ENDIAN);
183     offset++;
184 
185     call_data_dissector(tvb_new_subset_length(tvb, offset, clen), pinfo, ctrl_tree);
186     offset += clen;
187 
188     call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, ircomm_tree);
189 
190     return len;
191 }
192 
193 
194 /*
195  * Dissect the raw IrCOMM/IrLPT protocol
196  */
dissect_raw_ircomm(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)197 static int dissect_raw_ircomm(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, void* data _U_)
198 {
199     guint len = tvb_reported_length(tvb);
200     proto_item* ti;
201     proto_tree* ircomm_tree;
202 
203     if (len == 0)
204         return 0;
205 
206     /* Make entries in Protocol column on summary display */
207     col_set_str(pinfo->cinfo, COL_PROTOCOL, "IrCOMM");
208 
209     col_add_fstr(pinfo->cinfo, COL_INFO, "User Data: %d byte%s", len, (len > 1)? "s": "");
210 
211     /* create display subtree for the protocol */
212     ti   = proto_tree_add_item(tree, proto_ircomm, tvb, 0, -1, ENC_NA);
213     ircomm_tree = proto_item_add_subtree(ti, ett_ircomm);
214 
215     call_data_dissector(tvb, pinfo, ircomm_tree);
216 
217     return len;
218 }
219 
220 
221 /*
222  * Dissect IrCOMM IAS "Parameters" attribute
223  */
dissect_ircomm_parameters(tvbuff_t * tvb,guint offset,packet_info * pinfo _U_,proto_tree * tree,guint list_index,guint8 attr_type,guint8 circuit_id _U_)224 static gboolean dissect_ircomm_parameters(tvbuff_t* tvb, guint offset, packet_info* pinfo _U_,
225                                           proto_tree* tree, guint list_index, guint8 attr_type, guint8 circuit_id _U_)
226 {
227     guint    len;
228     guint    n = 0;
229     proto_item* ti;
230     proto_tree* p_tree;
231     char        buf[256];
232     guint8      pv;
233 
234 
235     if (!check_iap_octet_result(tvb, tree, offset, "Parameters", attr_type))
236         return TRUE;
237 
238     if (tree)
239     {
240         len = tvb_get_ntohs(tvb, offset) + offset + 2;
241         offset += 2;
242 
243         while (offset < len)
244         {
245             guint8  p_len = tvb_get_guint8(tvb, offset + 1);
246 
247 
248             ti = proto_tree_add_item(tree, hf_ircomm_param, tvb, offset, p_len + 2, ENC_NA);
249             p_tree = proto_item_add_subtree(ti, ett_param[list_index * MAX_PARAMETERS + n]);
250 
251             buf[0] = 0;
252 
253             switch (tvb_get_guint8(tvb, offset))
254             {
255                 case IRCOMM_SERVICE_TYPE:
256                     proto_item_append_text(ti, ": Service Type (");
257 
258                     pv = tvb_get_guint8(tvb, offset+2);
259                     if (pv & IRCOMM_3_WIRE_RAW)
260                         (void) g_strlcat(buf, ", 3-Wire raw", 256);
261                     if (pv & IRCOMM_3_WIRE)
262                         (void) g_strlcat(buf, ", 3-Wire", 256);
263                     if (pv & IRCOMM_9_WIRE)
264                         (void) g_strlcat(buf, ", 9-Wire", 256);
265                     if (pv & IRCOMM_CENTRONICS)
266                         (void) g_strlcat(buf, ", Centronics", 256);
267 
268                     (void) g_strlcat(buf, ")", 256);
269 
270                     if (strlen(buf) > 2)
271                         proto_item_append_text(ti, "%s", buf+2);
272                     else
273                         proto_item_append_text(ti, "unknown)");
274 
275                     break;
276 
277                 case IRCOMM_PORT_TYPE:
278                     proto_item_append_text(ti, ": Port Type (");
279 
280                     pv = tvb_get_guint8(tvb, offset+2);
281                     if (pv & IRCOMM_SERIAL)
282                         (void) g_strlcat(buf, ", serial", 256);
283                     if (pv & IRCOMM_PARALLEL)
284                         (void) g_strlcat(buf, ", parallel", 256);
285 
286                     (void) g_strlcat(buf, ")", 256);
287 
288                     if (strlen(buf) > 2)
289                         proto_item_append_text(ti, "%s", buf+2);
290                     else
291                         proto_item_append_text(ti, "unknown)");
292 
293                     break;
294 
295                 case IRCOMM_PORT_NAME:
296                     /* XXX - the IrCOMM V1.0 spec says this "Normally
297                        human readable text, but not required". */
298                     proto_item_append_text(ti, ": Port Name (\"%s\")",
299                         tvb_format_text(pinfo->pool, tvb, offset+2, p_len));
300 
301                     break;
302 
303                 default:
304                     proto_item_append_text(ti, ": unknown");
305             }
306 
307             offset = dissect_param_tuple(tvb, p_tree, offset);
308             n++;
309         }
310 
311     }
312 
313     return TRUE;
314 }
315 
316 
317 /*
318  * Dissect IrCOMM IAS "IrDA:TinyTP:LsapSel" attribute
319  */
dissect_ircomm_ttp_lsap(tvbuff_t * tvb,guint offset,packet_info * pinfo,proto_tree * tree,guint list_index _U_,guint8 attr_type,guint8 circuit_id)320 static gboolean dissect_ircomm_ttp_lsap(tvbuff_t* tvb, guint offset, packet_info* pinfo,
321                                         proto_tree* tree, guint list_index _U_, guint8 attr_type, guint8 circuit_id)
322 {
323     guint8 dlsap;
324 
325 
326     if ((dlsap = check_iap_lsap_result(tvb, tree, offset, "IrDA:TinyTP:LsapSel", attr_type)) == 0)
327         return FALSE;
328 
329     add_lmp_conversation(pinfo, dlsap, TRUE, ircomm_cooked_handle, circuit_id);
330 
331     return FALSE;
332 }
333 
334 
335 /*
336  * Dissect IrCOMM/IrLPT IAS "IrDA:IrLMP:LsapSel" attribute
337  */
dissect_ircomm_lmp_lsap(tvbuff_t * tvb,guint offset,packet_info * pinfo,proto_tree * tree,guint list_index _U_,guint8 attr_type,guint8 circuit_id)338 static gboolean dissect_ircomm_lmp_lsap(tvbuff_t* tvb, guint offset, packet_info* pinfo,
339                                         proto_tree* tree, guint list_index _U_, guint8 attr_type, guint8 circuit_id)
340 {
341     guint8 dlsap;
342 
343 
344     if ((dlsap = check_iap_lsap_result(tvb, tree, offset, "IrDA:IrLMP:LsapSel", attr_type)) == 0)
345         return FALSE;
346 
347     add_lmp_conversation(pinfo, dlsap, FALSE, ircomm_raw_handle, circuit_id);
348 
349     return FALSE;
350 }
351 
352 
353 /*
354  * Register the IrCOMM protocol
355  */
proto_register_ircomm(void)356 void proto_register_ircomm(void)
357 {
358     guint i;
359 
360     /* Setup list of header fields */
361     static hf_register_info hf_ircomm[] = {
362         { &hf_ircomm_param,
363             { "IrCOMM Parameter", "ircomm.parameter",
364                 FT_NONE, BASE_NONE, NULL, 0,
365                 NULL, HFILL }},
366 #if 0
367         { &hf_param_pi,
368             { "Parameter Identifier", "ircomm.pi",
369                 FT_UINT8, BASE_HEX, NULL, 0,
370                 NULL, HFILL }},
371         { &hf_param_pl,
372             { "Parameter Length", "ircomm.pl",
373                 FT_UINT8, BASE_HEX, NULL, 0,
374                 NULL, HFILL }},
375         { &hf_param_pv,
376             { "Parameter Value", "ircomm.pv",
377                 FT_BYTES, BASE_NONE, NULL, 0,
378                 NULL, HFILL }},
379 #endif
380         { &hf_control,
381             { "Control Channel", "ircomm.control",
382                 FT_NONE, BASE_NONE, NULL, 0,
383                 NULL, HFILL }},
384         { &hf_control_len,
385             { "Clen", "ircomm.control.len",
386                 FT_UINT8, BASE_DEC, NULL, 0,
387                 NULL, HFILL }}
388     };
389 
390     /* Setup protocol subtree arrays */
391     static gint* ett[] = {
392         &ett_ircomm,
393         &ett_ircomm_ctrl
394     };
395 
396     gint* ett_p[MAX_IAP_ENTRIES * MAX_PARAMETERS];
397 
398 
399     /* Register protocol names and descriptions */
400     proto_ircomm = proto_register_protocol("IrCOMM Protocol", "IrCOMM", "ircomm");
401     ircomm_raw_handle = register_dissector("ircomm_raw", dissect_raw_ircomm, proto_ircomm);
402     ircomm_cooked_handle = register_dissector("ircomm_cooked", dissect_cooked_ircomm, proto_ircomm);
403 
404     /* Required function calls to register the header fields */
405     proto_register_field_array(proto_ircomm, hf_ircomm, array_length(hf_ircomm));
406 
407     /* Register subtrees */
408     proto_register_subtree_array(ett, array_length(ett));
409     for (i = 0; i < MAX_IAP_ENTRIES * MAX_PARAMETERS; i++)
410     {
411         ett_param[i] = -1;
412         ett_p[i]     = &ett_param[i];
413     }
414     proto_register_subtree_array(ett_p, MAX_IAP_ENTRIES * MAX_PARAMETERS);
415 }
416 
417 /*
418  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
419  *
420  * Local variables:
421  * c-basic-offset: 4
422  * tab-width: 8
423  * indent-tabs-mode: nil
424  * End:
425  *
426  * vi: set shiftwidth=4 tabstop=8 expandtab:
427  * :indentSize=4:tabSize=8:noTabs=true:
428  */
429