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