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