effd9b23bc9e6ca2ad3a902dc4615996f8092046
[obnox/wireshark/wip.git] / epan / dissectors / packet-homeplug.c
1 /* packet-homeplug.c
2  * Routines for homeplug dissection
3  *
4  * Copyright 2006, Sebastien Tandel <sebastien[AT]tandel.be>
5  *
6  * $Id: packet-sccp.c 20220 2006-12-26 22:27:46Z morriss $
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
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 <glib.h>
32
33 #include <epan/packet.h>
34 #include <epan/prefs.h>
35
36 #include <epan/etypes.h>
37
38 #include <epan/proto.h>
39 #include <epan/ptvcursor.h>
40
41
42
43 /* METYPE Values */
44 #define HOMEPLUG_MME_RCE      0x00
45 #define HOMEPLUG_MME_CER      0x01
46 #define HOMEPLUG_MME_RPS      0x07
47 #define HOMEPLUG_MME_PSR      0x08
48 #define HOMEPLUG_MME_NS       0x1A
49
50 /* Bit mask Operation */
51 #define HOMEPLUG_MCTRL_RSVD   0x80
52 #define HOMEPLUG_MCTRL_NE     0x7F
53
54 #define HOMEPLUG_MEHDR_MEV    0xE0
55 #define HOMEPLUG_MEHDR_METYPE 0x1F
56
57 #define HOMEPLUG_NS_AC        0x80
58 #define HOMEPLUG_NS_ICID      0x7F
59
60 #define HOMEPLUG_RCE_CEV      0xF0
61 #define HOMEPLUG_RCE_RSVD     0x0F
62
63 #define HOMEPLUG_CER_CERV     0xF0
64 #define HOMEPLUG_CER_RSVD     0x0FE0
65 #define HOMEPLUG_CER_RXTMI    0x1F
66 #define HOMEPLUG_CER_RATE     0x80
67 #define HOMEPLUG_CER_BP       0x40
68 #define HOMEPLUG_CER_VT11     0x0F
69 #define HOMEPLUG_CER_RSVD2    0x80
70 #define HOMEPLUG_CER_NBDAS    0x7F
71
72
73 /*  Length of Network Statistics Response defines whether it is the Basic or
74  *  the Extended Response
75  */
76 #define HOMEPLUG_NS_BASIC_LEN 187
77 #define HOMEPLUG_NS_EXT_LEN   199
78
79 /* forward reference */
80 void proto_reg_handoff_homeplug();
81
82 static int proto_homeplug = -1;
83
84 static int hf_homeplug_mctrl            = -1;
85   static int hf_homeplug_mctrl_reserved = -1;
86   static int hf_homeplug_mctrl_ne       = -1;
87 static int hf_homeplug_mehdr            = -1;
88   static int hf_homeplug_mehdr_mev      = -1;
89   static int hf_homeplug_mehdr_metype   = -1;
90 static int hf_homeplug_melen            = -1;
91 static int hf_homeplug_mme              = -1;
92   /* Request Channel Estimation */
93   static int hf_homeplug_rce            = -1;
94     static int hf_homeplug_rce_cev      = -1;
95     static int hf_homeplug_rce_rsvd     = -1;
96   /* Channel Estimation Response */
97   static int hf_homeplug_cer            = -1;
98     static int hf_homeplug_cer_cerv     = -1;
99     static int hf_homeplug_cer_rsvd1    = -1;
100     static int hf_homeplug_cer_rxtmi    = -1;
101     static int hf_homeplug_cer_vt       = -1;
102     static int hf_homeplug_cer_rate     = -1;
103     static int hf_homeplug_cer_bp       = -1;
104     static int hf_homeplug_cer_mod      = -1;
105     static int hf_homeplug_cer_vt11     = -1;
106     static int hf_homeplug_cer_rsvd2    = -1;
107     static int hf_homeplug_cer_nbdas    = -1;
108     static int hf_homeplug_cer_bda      = -1;
109   /* Request Parameters and Statistics */
110   static int hf_homeplug_rps            = -1;
111   /* Parameters and Statistics Response */
112   static int hf_homeplug_psr            = -1;
113     static int hf_homeplug_psr_txack    = -1;
114     static int hf_homeplug_psr_txnack   = -1;
115     static int hf_homeplug_psr_txfail   = -1;
116     static int hf_homeplug_psr_txcloss  = -1;
117     static int hf_homeplug_psr_txcoll   = -1;
118     static int hf_homeplug_psr_txca3lat = -1;
119     static int hf_homeplug_psr_txca2lat = -1;
120     static int hf_homeplug_psr_txca1lat = -1;
121     static int hf_homeplug_psr_txca0lat = -1;
122     static int hf_homeplug_psr_rxbp40   = -1;
123   /* Network Statistics */
124       /* Basic */
125   static int hf_homeplug_ns                     = -1;
126     static int hf_homeplug_ns_netw_ctrl_ac      = -1;
127     static int hf_homeplug_ns_netw_ctrl_icid    = -1;
128     static int hf_homeplug_ns_netw_ctrl_icid_rsvd= -1;
129     static int hf_homeplug_ns_bytes40_robo      = -1;
130     static int hf_homeplug_ns_fails_robo          = -1;
131     static int hf_homeplug_ns_drops_robo        = -1;
132     static int hf_homeplug_ns_netw_da           = -1;
133     static int hf_homeplug_ns_bytes40           = -1;
134     static int hf_homeplug_ns_fails             = -1;
135     static int hf_homeplug_ns_drops             = -1;
136     /* array of 15 elements */
137 /*    static int hf_homeplug_ns_bytes40_1       = -1;
138     static int hf_homeplug_ns_bytes40_1 */
139       /* Extended */
140     /* array of 6 elements */
141 /*    static int hf_homeplug_ns_tx_bfr_0_state  = -1;*/
142
143 static gint ett_homeplug                = -1;
144 static gint ett_homeplug_mctrl          = -1;
145 static gint ett_homeplug_mehdr          = -1;
146 /* for a later use */
147 /* static gint ett_homeplug_mme         = -1; */
148 static gint ett_homeplug_rce            = -1;
149 static gint ett_homeplug_cer            = -1;
150 static gint ett_homeplug_rps            = -1;
151 static gint ett_homeplug_psr            = -1;
152 static gint ett_homeplug_ns             = -1;
153 static gint ett_homeplug_tone           = -1;
154
155 static guint8 homeplug_ne = 0;
156 static guint8 homeplug_melen = 0;
157 static guint8 homeplug_metype = 0;
158
159 static guint32  homeplug_offset = 0;
160
161 /* IC_ID Values */
162 #define HOMEPLUG_NS_ICID5130A1          0x00
163 #define HOMEPLUG_NS_ICID51X1USB         0x01
164 #define HOMEPLUG_NS_ICID51X1PHY         0x02
165 #define HOMEPLUG_NS_ICID51X1HOST        0x03
166 #define HOMEPLUG_NS_ICID5130A2          0x04
167 #define HOMEPLUG_NS_ICID_RSVD1          0x05
168 #define HOMEPLUG_NS_ICID_RSVD2          0x06
169 #define HOMEPLUG_NS_ICID_RSVD3          0x07
170 /* ICID Bit Mask */
171 #define HOMEPLUG_NS_ICID_MASK           0x07
172 #define HOMEPLUG_NS_ICID_RSVD_MASK      0x78
173 /* string values in function of IC_ID values */
174 static const value_string homeplug_ns_icid_vals[] = {
175     { HOMEPLUG_NS_ICID5130A1,   "INT5130A1" },
176     { HOMEPLUG_NS_ICID51X1USB,  "INT51X1 (USB Option)" },
177     { HOMEPLUG_NS_ICID51X1PHY,  "INT51X1 (PHY Option)" },
178     { HOMEPLUG_NS_ICID51X1HOST, "INT51X1 (Host/DTE Option)" },
179     { HOMEPLUG_NS_ICID5130A2,   "INT5130A2" },
180     { HOMEPLUG_NS_ICID_RSVD1,   "Reserved"},
181     { HOMEPLUG_NS_ICID_RSVD2,   "Reserved"},
182     { HOMEPLUG_NS_ICID_RSVD3,   "Reserved"},
183     { 0,                        NULL }
184 };
185
186 /* Modulation Method Bit Mask */
187 #define HOMEPLUG_CER_MOD_MASK           0x30
188 /* Modulation Method Values */
189 #define HOMEPLUG_CER_MOD_ROBO           0x00
190 #define HOMEPLUG_CER_MOD_DBPSK          0x01
191 #define HOMEPLUG_CER_MOD_DQPSK          0x02
192 #define HOMEPLUG_CER_MOD_RSVD           0x03
193 /* string values in function of Modulation Method Values */
194 static const value_string homeplug_cer_mod_vals[] = {
195   { HOMEPLUG_CER_MOD_ROBO,  "ROBO Modulation"},
196   { HOMEPLUG_CER_MOD_DBPSK, "DBPSK Modulation"},
197   { HOMEPLUG_CER_MOD_DQPSK, "DQPSK Modulation"},
198   { HOMEPLUG_CER_MOD_RSVD,  "Reserved"},
199   { 0,                      NULL}
200 };
201
202 #define HOMEPLUG_MCTRL_LEN 1
203 #define HOMEPLUG_MEHDR_LEN 1
204 #define HOMEPLUG_MELEN_LEN 1
205
206
207 void
208 proto_register_homeplug(void)
209 {
210   static hf_register_info hf[] = {
211     /* MAC Control Field */
212     { &hf_homeplug_mctrl,
213       { "MAC Control Field", "homeplug.mctrl",
214       FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Control Field", HFILL }
215     },
216
217     { &hf_homeplug_mctrl_reserved,
218       { "Reserved", "homeplug.mctrl.rsvd",
219         FT_NONE, BASE_DEC, NULL, HOMEPLUG_MCTRL_RSVD, "Reserved", HFILL }
220     },
221
222     { &hf_homeplug_mctrl_ne,
223       { "Number of MAC Data Entries", "homeplug.mctrl.ne",
224         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_MCTRL_NE, "Number of MAC Data Entries", HFILL }
225     },
226
227     /* MAC Entry Header */
228     { &hf_homeplug_mehdr,
229       { "MAC Management Entry Header", "homeplug.mehdr",
230         FT_NONE, BASE_DEC, NULL, 0x0, "MAC Management Entry Header", HFILL }
231     },
232
233     { &hf_homeplug_mehdr_mev,
234       { "MAC Entry Version", "homeplug.mehdr.mev",
235         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_MEHDR_MEV, "MAC Entry Version", HFILL }
236     },
237
238     { &hf_homeplug_mehdr_metype,
239       { "MAC Entry Type", "homeplug.mehdr.metype",
240         FT_UINT8, BASE_HEX, NULL, HOMEPLUG_MEHDR_METYPE, "MAC Entry Type", HFILL }
241     },
242
243     /* MAC Entry Len */
244     { &hf_homeplug_melen,
245       { "MAC Management Entry Length", "homeplug.melen",
246         FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Management Entry Length", HFILL }
247     },
248
249     /* MAC Management Entry */
250     { &hf_homeplug_mme,
251       { "MAC Management Entry Data", "homeplug.mmentry",
252         FT_UINT8, BASE_DEC, NULL, 0x0, "MAC Management Entry Data", HFILL }
253     },
254
255     /* Request Channel Estimation */
256     { &hf_homeplug_rce,
257       { "Request Channel Estimation", "homeplug.rce",
258         FT_NONE, BASE_DEC, NULL, 0x0, "Request Channel Estimation", HFILL }
259     },
260
261     { &hf_homeplug_rce_cev,
262       { "Channel Estimation Version", "homeplug.rce.cev",
263         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_RCE_CEV, "Channel Estimation Version", HFILL }
264     },
265
266     { &hf_homeplug_rce_rsvd,
267       { "Reserved", "homeplug.rce.rsvd",
268         FT_NONE, BASE_DEC, NULL, HOMEPLUG_RCE_RSVD, "Reserved", HFILL }
269     },
270
271     /* Channel Estimation Response */
272     { &hf_homeplug_cer,
273       { "Channel Estimation Response", "homeplug.cer",
274         FT_NONE, BASE_DEC, NULL, 0x0, "Channel Estimation Response", HFILL }
275     },
276
277     { &hf_homeplug_cer_cerv,
278       { "Channel Estimation Response Version", "homeplug.cer.cerv",
279         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_CERV, "Channel Estimation Response Version", HFILL }
280     },
281
282     { &hf_homeplug_cer_rsvd1,
283       { "Reserved", "homeplug.cer.rsvd1",
284         FT_NONE, BASE_DEC, NULL, HOMEPLUG_CER_RSVD, "Reserved", HFILL }
285     },
286
287     { &hf_homeplug_cer_rxtmi,
288       { "Receive Tone Map Index", "homeplug.cer.rxtmi",
289         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RXTMI, "Receive Tone Map Index", HFILL }
290     },
291
292     /* TODO must append vt[79-0] */
293
294     { &hf_homeplug_cer_vt,
295       {"Valid Tone Flags", "homeplug.cer.vt",
296         FT_UINT8, BASE_HEX, NULL, 0x0, "Valid Tone Flags", HFILL }
297     },
298
299     { &hf_homeplug_cer_rate,
300       { "FEC Rate", "homeplug.cer.rate",
301         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RATE, "FEC Rate", HFILL }
302     },
303
304     { &hf_homeplug_cer_bp,
305       { "Bridge Proxy", "homeplug.cer.bp",
306         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_BP, "Bridge Proxy", HFILL }
307     },
308
309     { &hf_homeplug_cer_mod,
310       { "Modulation Method", "homeplug.cer.mod",
311         FT_UINT8, BASE_DEC, VALS(&homeplug_cer_mod_vals), HOMEPLUG_CER_MOD_MASK,
312         "Modulation Method", HFILL }
313     },
314
315     { &hf_homeplug_cer_vt11,
316       { "Valid Tone Flags [83-80]", "homeplug.cer.vt11",
317         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_VT11, "Valid Tone Flags [83-80]", HFILL }
318     },
319
320     { &hf_homeplug_cer_rsvd2,
321       { "Reserved", "homeplug.cer.rsvd2",
322         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_RSVD2, "Reserved", HFILL }
323     },
324
325     { &hf_homeplug_cer_nbdas,
326       { "Number Bridged Destination Addresses", "homeplug.cer.nbdas",
327         FT_UINT8, BASE_DEC, NULL, HOMEPLUG_CER_NBDAS, "Number Bridged Destination Addresses", HFILL }
328     },
329
330     { &hf_homeplug_cer_bda,
331       { "Bridged Destination Address", "homeplug.cer.bda",
332         FT_ETHER, BASE_HEX, NULL, 0x0, "Bridged Destination Address", HFILL }
333     },
334
335     /* Request Parameters and Statistics */
336     { &hf_homeplug_rps,
337       { "Request Parameters and Statistics", "homeplug.rps",
338         FT_NONE, BASE_DEC, NULL, 0x0, "Request Parameters and Statistics", HFILL }
339     },
340
341     /* Parameters and Statistics Response */
342     { &hf_homeplug_psr,
343       { "Parameters and Statistics Response", "homeplug.psr",
344         FT_NONE, BASE_DEC, NULL, 0x0, "Parameters and Statistics Response", HFILL }
345     },
346
347     { &hf_homeplug_psr_txack,
348       { "Transmit ACK Counter", "homeplug.psr.txack",
349         FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit ACK Counter", HFILL }
350     },
351
352     { &hf_homeplug_psr_txnack,
353       { "Transmit NACK Counter", "homeplug.psr.txnack",
354         FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit NACK Counter", HFILL }
355     },
356
357     { &hf_homeplug_psr_txfail,
358       { "Transmit FAIL Counter", "homeplug.psr.txfail",
359         FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit FAIL Counter", HFILL }
360     },
361
362     { &hf_homeplug_psr_txcloss,
363       { "Transmit Contention Loss Counter", "homeplug.psr.txcloss",
364         FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit Contention Loss Counter", HFILL }
365     },
366
367     { &hf_homeplug_psr_txcoll,
368       { "Transmit Collision Counter", "homeplug.psr.txcoll",
369         FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit Collision Counter", HFILL }
370     },
371
372     { &hf_homeplug_psr_txca3lat,
373       { "Transmit CA3 Latency Counter", "homeplug.psr.txca3lat",
374         FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA3 Latency Counter", HFILL }
375     },
376
377     { &hf_homeplug_psr_txca2lat,
378       { "Transmit CA2 Latency Counter", "homeplug.psr.txca2lat",
379         FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA2 Latency Counter", HFILL }
380     },
381     { &hf_homeplug_psr_txca1lat,
382       { "Transmit CA1 Latency Counter", "homeplug.psr.txca1lat",
383         FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA1 Latency Counter", HFILL }
384     },
385     { &hf_homeplug_psr_txca0lat,
386       { "Transmit CA0 Latency Counter", "homeplug.psr.txca0lat",
387         FT_UINT16, BASE_DEC, NULL, 0x0, "Transmit CA0 Latency Counter", HFILL }
388     },
389
390     { &hf_homeplug_psr_rxbp40,
391       { "Receive Cumulative Bytes per 40-symbol", "homeplug.psr.rxbp40",
392         FT_UINT32, BASE_DEC, NULL, 0x0, "Receive Cumulative Bytes per 40-symbol", HFILL }
393     },
394
395     /* Network Statistics Basic */
396     { &hf_homeplug_ns,
397       { "Network Statistics Basic", "homeplug.ns",
398         FT_NONE, BASE_DEC, NULL, 0x0, "Network Statistics Basic", HFILL }
399     },
400
401     { &hf_homeplug_ns_netw_ctrl_ac,
402       { "Action Control", "homeplug.ns.ac",
403       FT_BOOLEAN, BASE_DEC, NULL, HOMEPLUG_NS_AC, "Action Control", HFILL }
404     },
405
406     { &hf_homeplug_ns_netw_ctrl_icid,
407       { "IC_ID", "homeplug.ns.icid",
408       FT_UINT8, BASE_HEX, VALS(&homeplug_ns_icid_vals), HOMEPLUG_NS_ICID_MASK, "IC_ID", HFILL }
409     },
410
411     { &hf_homeplug_ns_netw_ctrl_icid_rsvd,
412       { "IC_ID Reserved", "homeplug.ns.icid",
413         FT_NONE, BASE_DEC, NULL, 0x0, "IC_ID Reserved", HFILL }
414     },
415
416     { &hf_homeplug_ns_bytes40_robo,
417       { "Bytes in 40 symbols in ROBO", "homeplug.ns.bytes40_robo",
418         FT_UINT16, BASE_DEC, NULL, 0x0, "Bytes in 40 symbols in ROBO", HFILL }
419     },
420
421     { &hf_homeplug_ns_fails_robo,
422       { "Fails Received in ROBO", "homeplug.ns.fails_robo",
423         FT_UINT16, BASE_DEC, NULL, 0x0, "Fails Received in ROBO", HFILL }
424     },
425
426     { &hf_homeplug_ns_drops_robo,
427       { "Frame Drops in ROBO", "homeplug.ns.drops_robo",
428         FT_UINT16, BASE_DEC, NULL, 0x0, "Frame Drops in ROBO", HFILL }
429     },
430
431     /* TODO NETW_DA1 ... */
432     { &hf_homeplug_ns_netw_da,
433       { "Address of Network DA", "homeplug.ns.netw_da",
434         FT_ETHER, BASE_HEX, NULL, 0x0, "Address of Network DA", HFILL }
435     },
436
437     { &hf_homeplug_ns_bytes40,
438       { "Bytes in 40 symbols", "homeplug.ns.bytes40",
439         FT_UINT16, BASE_DEC, NULL, 0x0, "Bytes in 40 symbols", HFILL }
440     },
441
442     { &hf_homeplug_ns_fails,
443       { "Fails Received", "homeplug.ns.fails",
444         FT_UINT16, BASE_DEC, NULL, 0x0, "Fails Received", HFILL }
445     },
446
447     { &hf_homeplug_ns_drops,
448       { "Frame Drops", "homeplug.ns.drops",
449         FT_UINT16, BASE_DEC, NULL, 0x0, "Frame Drops", HFILL }
450     }
451
452     /* TODO Network Statistics Extended */
453   };
454
455   /* Setup protocol subtree array */
456   static gint *ett[] = {
457     &ett_homeplug,
458     &ett_homeplug_mctrl,
459     &ett_homeplug_mehdr,
460     &ett_homeplug_rce,
461     &ett_homeplug_cer,
462     &ett_homeplug_rps,
463     &ett_homeplug_psr,
464     &ett_homeplug_ns,
465     &ett_homeplug_tone,
466   };
467
468   proto_homeplug = proto_register_protocol(
469                                           "HomePlug protocol",  /* Name */
470                                           "HomePlug",           /* Short Name */
471                                           "homeplug"            /* Abbrev */
472                                           );
473
474   proto_register_field_array(proto_homeplug, hf, array_length(hf));
475
476   proto_register_subtree_array(ett, array_length(ett));
477 }
478
479
480 /* Dissection of MCTRL */
481 static void dissect_homeplug_mctrl(ptvcursor_t * cursor)
482 {
483   proto_tree *initial_tree = NULL;
484   proto_tree *additional_tree = NULL;
485   proto_item *it = NULL;
486
487   if (!cursor || !ptvcursor_tree(cursor))
488     return;
489
490   initial_tree = ptvcursor_tree(cursor);
491
492   it = ptvcursor_add_no_advance(cursor, hf_homeplug_mctrl, 1, FALSE);
493   homeplug_ne = tvb_get_guint8(ptvcursor_tvbuff(cursor),
494                                ptvcursor_current_offset(cursor))
495                 & HOMEPLUG_MCTRL_NE;
496
497   additional_tree = proto_item_add_subtree(it, ett_homeplug_mctrl);
498   ptvcursor_set_tree(cursor, additional_tree);
499   ptvcursor_add_no_advance(cursor, hf_homeplug_mctrl_reserved, 1, FALSE);
500   ptvcursor_add(cursor, hf_homeplug_mctrl_ne, 1, FALSE);
501
502   ptvcursor_set_tree(cursor, initial_tree);
503 }
504
505 /* Dissection of MEHDR */
506 static void dissect_homeplug_mehdr(ptvcursor_t * cursor)
507 {
508   proto_tree *initial_tree = NULL;
509   proto_tree *additional_tree = NULL;
510   proto_item *it = NULL;
511
512   if (!cursor || !ptvcursor_tree(cursor))
513     return;
514
515   initial_tree = ptvcursor_tree(cursor);
516
517   it = ptvcursor_add_no_advance(cursor, hf_homeplug_mehdr, 0, FALSE);
518   homeplug_metype = tvb_get_guint8(ptvcursor_tvbuff(cursor),
519                                    ptvcursor_current_offset(cursor))
520                     & HOMEPLUG_MEHDR_METYPE;
521
522   additional_tree = proto_item_add_subtree(it, ett_homeplug_mehdr);
523   ptvcursor_set_tree(cursor, additional_tree);
524   ptvcursor_add_no_advance(cursor, hf_homeplug_mehdr_mev, 1, FALSE);
525   ptvcursor_add(cursor, hf_homeplug_mehdr_metype, 1, FALSE);
526
527   ptvcursor_set_tree(cursor, initial_tree);
528 }
529
530
531 /* dissection of MELEN */
532 static void dissect_homeplug_melen(ptvcursor_t *cursor)
533 {
534   if (!cursor || !ptvcursor_tree(cursor))
535     return;
536
537   homeplug_melen = tvb_get_guint8(ptvcursor_tvbuff(cursor),
538                                   ptvcursor_current_offset(cursor));
539   ptvcursor_add(cursor, hf_homeplug_melen, 1, FALSE);
540 }
541
542 /* Dissection of Request Channel Estimation MME */
543 static void dissect_homeplug_rce(ptvcursor_t *cursor)
544 {
545   proto_tree *initial_tree = NULL;
546   proto_tree *additional_tree = NULL;
547   proto_item *it = NULL;
548
549   if (!cursor || !ptvcursor_tree(cursor))
550     return;
551
552   initial_tree = ptvcursor_tree(cursor);
553
554   it = ptvcursor_add_no_advance(cursor, hf_homeplug_rce, homeplug_melen, FALSE);
555
556   additional_tree = proto_item_add_subtree(it , ett_homeplug_rce);
557   ptvcursor_set_tree(cursor, additional_tree);
558   ptvcursor_add_no_advance(cursor, hf_homeplug_rce_cev, 1, FALSE);
559   ptvcursor_add(cursor, hf_homeplug_rce_rsvd, 1, FALSE);
560
561   ptvcursor_set_tree(cursor, initial_tree);
562 }
563
564 /* Dissection of Channel Estimation Response MME */
565 static void dissect_homeplug_cer(ptvcursor_t *cursor)
566 {
567   proto_tree *initial_tree = NULL;
568   proto_tree *additional_tree = NULL;
569   proto_item *it = NULL;
570   guint8 iTone;
571   guint8 BP = 0;
572   guint8 iNBDA = 0;
573
574   if (!cursor || !ptvcursor_tree(cursor))
575     return;
576
577   initial_tree = ptvcursor_tree(cursor);
578
579   it = ptvcursor_add_no_advance(cursor, hf_homeplug_cer_cerv, homeplug_melen, FALSE);
580
581   additional_tree = proto_item_add_subtree(it, ett_homeplug_cer);
582   ptvcursor_set_tree(cursor, additional_tree);
583   ptvcursor_add_no_advance(cursor, hf_homeplug_cer_cerv, 1, FALSE);
584   ptvcursor_add(cursor, hf_homeplug_cer_rsvd1, 2, FALSE);
585   ptvcursor_add(cursor, hf_homeplug_cer_rxtmi, 1, FALSE);
586
587   for (iTone = 0; iTone < 10; iTone++) {
588     ptvcursor_add(cursor, hf_homeplug_cer_vt, 1, FALSE);
589   }
590
591   ptvcursor_add_no_advance(cursor, hf_homeplug_cer_rate, 1, FALSE);
592   ptvcursor_add_no_advance(cursor, hf_homeplug_cer_bp, 1, FALSE);
593   BP = tvb_get_guint8(ptvcursor_tvbuff(cursor),
594                       ptvcursor_current_offset(cursor)) & HOMEPLUG_CER_BP;
595   ptvcursor_add_no_advance(cursor, hf_homeplug_cer_mod, 1, FALSE);
596   ptvcursor_add(cursor, hf_homeplug_cer_vt11, 1, FALSE);
597   ptvcursor_add_no_advance(cursor, hf_homeplug_cer_rsvd2, 1, FALSE);
598
599   if (BP) {
600     iNBDA = tvb_get_guint8(ptvcursor_tvbuff(cursor),
601                            ptvcursor_current_offset(cursor))
602             & HOMEPLUG_CER_NBDAS;
603     ptvcursor_add(cursor, hf_homeplug_cer_nbdas, 1, FALSE);
604     /* TODO : Check on iNBDA! INT51X1 up to 16 dba. But up to 32 for INT51X1 (Host/DTE) */
605     for (;iNBDA > 0; iNBDA--) {
606       ptvcursor_add(cursor, hf_homeplug_cer_bda, 6, FALSE);
607     }
608   }
609
610   ptvcursor_set_tree(cursor, initial_tree);
611 }
612
613
614 /* Dissection of Request Parameters and Statistics MME */
615 static void dissect_homeplug_rps(ptvcursor_t *cursor)
616 {
617   if (!cursor || !ptvcursor_tree(cursor))
618     return;
619
620   ptvcursor_add(cursor, hf_homeplug_rps, 4, FALSE);
621 }
622
623 /* Dissection of Parameters and Statistics Response MME */
624 static void dissect_homeplug_psr(ptvcursor_t *cursor)
625 {
626   proto_tree *initial_tree = NULL;
627   proto_tree *additional_tree = NULL;
628   proto_item *it = NULL;
629
630   if (!cursor || !ptvcursor_tree(cursor))
631     return;
632
633   initial_tree = ptvcursor_tree(cursor);
634
635   it = ptvcursor_add_no_advance(cursor, hf_homeplug_psr, homeplug_melen, FALSE);
636
637   additional_tree = proto_item_add_subtree(it, ett_homeplug_psr);
638   ptvcursor_set_tree(cursor, additional_tree);
639   ptvcursor_add(cursor, hf_homeplug_psr_txack, 2, FALSE);
640   ptvcursor_add(cursor, hf_homeplug_psr_txnack, 2, FALSE);
641   ptvcursor_add(cursor, hf_homeplug_psr_txfail, 2, FALSE);
642   ptvcursor_add(cursor, hf_homeplug_psr_txcloss, 2, FALSE);
643   ptvcursor_add(cursor, hf_homeplug_psr_txcoll, 2, FALSE);
644   ptvcursor_add(cursor, hf_homeplug_psr_txca3lat, 2, FALSE);
645   ptvcursor_add(cursor, hf_homeplug_psr_txca2lat, 2, FALSE);
646   ptvcursor_add(cursor, hf_homeplug_psr_txca1lat, 2, FALSE);
647   ptvcursor_add(cursor, hf_homeplug_psr_txca0lat, 2, FALSE);
648   ptvcursor_add(cursor, hf_homeplug_psr_rxbp40, 4, FALSE);
649
650   ptvcursor_set_tree(cursor, initial_tree);
651 }
652
653 /* Dissection of the Network Statistic MME */
654 static void dissect_homeplug_ns(ptvcursor_t *cursor)
655 {
656   proto_item *it = NULL;
657   proto_tree *additional_tree = NULL, *tree_tone = NULL;
658   proto_tree *initial_tree = NULL;
659   guint8 homeplug_ns_icid_rsvd = 0;
660   guint8 iTone = 0;
661   guint16 ns_bytes40 = 0;
662   guint64 newt_da = 0;
663 #define NEWT_DA_INEXISTANT G_GINT64_CONSTANT(010000000000U)
664
665   if (!cursor || !ptvcursor_tree(cursor))
666     return;
667
668   initial_tree = ptvcursor_tree(cursor);
669
670   /* TODO : test length of the MME : differentiation of NS Basic and Extended */
671   it = ptvcursor_add_no_advance(cursor, hf_homeplug_ns, homeplug_melen, FALSE);
672
673   additional_tree = proto_item_add_subtree(it, ett_homeplug_ns);
674   ptvcursor_set_tree(cursor, additional_tree);
675   ptvcursor_add_no_advance(cursor, hf_homeplug_ns_netw_ctrl_ac, 1, FALSE);
676   homeplug_ns_icid_rsvd = tvb_get_guint8(ptvcursor_tvbuff(cursor),
677                                          ptvcursor_current_offset(cursor))
678                           & HOMEPLUG_NS_ICID_RSVD_MASK;
679
680   if (homeplug_ns_icid_rsvd)
681     ptvcursor_add(cursor, hf_homeplug_ns_netw_ctrl_icid_rsvd, 1, FALSE);
682   else
683     ptvcursor_add(cursor, hf_homeplug_ns_netw_ctrl_icid, 1, FALSE);
684
685   ptvcursor_add_no_advance(cursor, hf_homeplug_ns_bytes40_robo, 2, TRUE);
686   ns_bytes40 = tvb_get_letohs(ptvcursor_tvbuff(cursor),
687                               ptvcursor_current_offset(cursor));
688   it = proto_tree_add_text(additional_tree, ptvcursor_tvbuff(cursor),
689                            ptvcursor_current_offset(cursor), 2, "MHz :  %.3f",
690                            (float)(ns_bytes40)/42);
691   ptvcursor_advance(cursor, 2);
692
693   ptvcursor_add(cursor, hf_homeplug_ns_fails_robo, 2, TRUE);
694   ptvcursor_add(cursor, hf_homeplug_ns_drops_robo, 2, TRUE);
695
696   while (iTone < 15) {
697     newt_da = ((gint64)tvb_get_ntoh24(ptvcursor_tvbuff(cursor),
698                                       ptvcursor_current_offset(cursor))) << 24;
699     newt_da |= tvb_get_ntoh24(ptvcursor_tvbuff(cursor),
700                               ptvcursor_current_offset(cursor)+3);
701
702     if (newt_da != NEWT_DA_INEXISTANT) {
703       it = proto_tree_add_text(additional_tree, ptvcursor_tvbuff(cursor),
704                                ptvcursor_current_offset(cursor), 12,
705                                "Tone Map #%d", iTone+1);
706
707       tree_tone = proto_item_add_subtree(it, ett_homeplug_tone);
708       ptvcursor_set_tree(cursor, tree_tone);
709
710       ptvcursor_add(cursor, hf_homeplug_ns_netw_da, 6, FALSE);
711
712       ptvcursor_add_no_advance(cursor, hf_homeplug_ns_bytes40, 2, TRUE);
713       ns_bytes40 = tvb_get_letohs(ptvcursor_tvbuff(cursor),
714                                   ptvcursor_current_offset(cursor));
715       it = proto_tree_add_text(ptvcursor_tree(cursor), ptvcursor_tvbuff(cursor),
716                                ptvcursor_current_offset(cursor), 2,
717                                "MHz :  %.3f", (float)(ns_bytes40)/42);
718       ptvcursor_advance(cursor, 2);
719
720       ptvcursor_add(cursor, hf_homeplug_ns_fails, 2, TRUE);
721       ptvcursor_add(cursor, hf_homeplug_ns_drops, 2, TRUE);
722     } else
723       it = proto_tree_add_text(additional_tree, ptvcursor_tvbuff(cursor),
724                                ptvcursor_current_offset(cursor), 12,
725                                "Tone Map #%d does not exist", iTone+1);
726
727       iTone++;
728   }
729
730   ptvcursor_set_tree(cursor, initial_tree);
731 }
732
733 static void dissect_homeplug_mme(ptvcursor_t *cursor, packet_info *pinfo)
734 {
735   switch(homeplug_metype) {
736     case HOMEPLUG_MME_RCE:
737       if (check_col(pinfo->cinfo, COL_INFO)) {
738         col_clear(pinfo->cinfo, COL_INFO);
739         col_set_str(pinfo->cinfo, COL_INFO, "Request Channel Estimation");
740       }
741       dissect_homeplug_rce(cursor);
742       break;
743
744     case HOMEPLUG_MME_CER:
745       if (check_col(pinfo->cinfo, COL_INFO)) {
746         col_clear(pinfo->cinfo, COL_INFO);
747         col_set_str(pinfo->cinfo, COL_INFO, "Channel Estimation Response");
748       }
749       dissect_homeplug_cer(cursor);
750       break;
751
752     case HOMEPLUG_MME_RPS:
753       if (check_col(pinfo->cinfo, COL_INFO)) {
754         col_clear(pinfo->cinfo, COL_INFO);
755         col_set_str(pinfo->cinfo, COL_INFO, "Request Parameters and Statistics");
756       }
757       dissect_homeplug_rps(cursor);
758       break;
759
760     case HOMEPLUG_MME_PSR:
761       if (check_col(pinfo->cinfo, COL_INFO)) {
762         col_clear(pinfo->cinfo, COL_INFO);
763         col_set_str(pinfo->cinfo, COL_INFO, "Parameters and Statistics Response");
764       }
765       dissect_homeplug_psr(cursor);
766       break;
767
768     case HOMEPLUG_MME_NS:
769       if (check_col(pinfo->cinfo, COL_INFO)) {
770         col_clear(pinfo->cinfo, COL_INFO);
771         col_set_str(pinfo->cinfo, COL_INFO, "Network Statistics");
772       }
773       dissect_homeplug_ns(cursor);
774       break;
775   }
776 }
777
778 #define TVB_LEN_GREATEST  1
779 #define TVB_LEN_UNDEF     0
780 #define TVB_LEN_SHORTEST -1
781 static int check_tvb_length(ptvcursor_t *cursor, const gint length)
782 {
783   if (!cursor)
784     return TVB_LEN_UNDEF;
785
786   if (tvb_reported_length_remaining(ptvcursor_tvbuff(cursor),
787                                     ptvcursor_current_offset(cursor)) < length)
788     return TVB_LEN_SHORTEST;
789
790   return TVB_LEN_GREATEST;
791 }
792
793 static void
794 dissect_homeplug(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
795 {
796   proto_item *it = NULL;
797   proto_tree *homeplug_tree = NULL;
798   ptvcursor_t *cursor = NULL;
799
800   if (check_col(pinfo->cinfo, COL_PROTOCOL))
801     col_set_str(pinfo->cinfo, COL_PROTOCOL, "HomePlug");
802
803   /* Clear out stuff in the info column */
804   if (check_col(pinfo->cinfo, COL_INFO)) {
805     col_clear(pinfo->cinfo, COL_INFO);
806     col_set_str(pinfo->cinfo, COL_INFO, "MAC Management");
807   }
808
809   homeplug_offset = 0;
810
811   if (tree) {
812     it = proto_tree_add_item(tree, proto_homeplug, tvb, homeplug_offset, -1, FALSE);
813     homeplug_tree = proto_item_add_subtree(it, ett_homeplug);
814     cursor = ptvcursor_new(homeplug_tree, tvb, 0);
815   }
816
817   /*  We do not have enough data to read mctrl field stop the dissection */
818   if (check_tvb_length(cursor, HOMEPLUG_MCTRL_LEN) != TVB_LEN_SHORTEST) {
819
820     dissect_homeplug_mctrl(cursor);
821
822     /*  homeplug_ne indicates the number of MME entries. This field is fetched
823      *  from MCTRL.
824      */
825     for (; homeplug_ne > 0; homeplug_ne--) {
826
827       /* Check we have enough data in tvb to read MEHDR */
828       if (check_tvb_length(cursor, HOMEPLUG_MEHDR_LEN) == TVB_LEN_SHORTEST)
829         break;
830       dissect_homeplug_mehdr(cursor);
831
832       /* Check we have enough data in tvb to read MELEN */
833       if (check_tvb_length(cursor, HOMEPLUG_MELEN_LEN) == TVB_LEN_SHORTEST)
834         break;
835       dissect_homeplug_melen(cursor);
836
837       dissect_homeplug_mme(cursor, pinfo);
838     }
839   }
840
841   if (cursor)
842     ptvcursor_free(cursor);
843 }
844
845 static dissector_handle_t homeplug_handle;
846
847 void
848 proto_reg_handoff_homeplug(void)
849 {
850   static gboolean initialised = FALSE;
851
852   if (!initialised) {
853     homeplug_handle = create_dissector_handle(dissect_homeplug, proto_homeplug);
854     dissector_add("ethertype", ETHERTYPE_HOMEPLUG, homeplug_handle);
855     initialised = TRUE;
856   }
857 }