2 * Routines for Ethernet Passive Optical Network dissection
3 * Copyright 2014, Philip Rosenberg-Watt <p.rosenberg-watt[at]cablelabs.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 /* 2014-04 Philip Rosenberg-Watt <p.rosenberg-watt[at]cablelabs.com>
13 * + EPON preamble with CableLabs DPoE securty byte.
14 * See IEEE 802.3-2012 Section 5, Clause 65 and
15 * CableLabs DPoE SEC 1.0 specification.
20 #include <epan/packet.h>
21 #include <epan/expert.h>
24 #include <epan/addr_resolv.h>
25 #include <epan/crc8-tvb.h>
27 void proto_register_epon(void);
28 void proto_reg_handoff_epon(void);
30 static dissector_handle_t epon_handle
;
32 static int proto_epon
;
33 static int hf_epon_dpoe_security
;
34 static int hf_epon_dpoe_encrypted
;
35 static int hf_epon_dpoe_reserved
;
36 static int hf_epon_dpoe_encrypted_data
;
37 static int hf_epon_dpoe_keyid
;
38 static int hf_epon_mode
;
39 static int hf_epon_llid
;
40 static int hf_epon_checksum
;
41 static int hf_epon_checksum_status
;
43 static expert_field ei_epon_sld_bad
;
44 static expert_field ei_epon_dpoe_reserved_bad
;
45 static expert_field ei_epon_dpoe_bad
;
46 static expert_field ei_epon_dpoe_encrypted_data
;
47 static expert_field ei_epon_checksum_bad
;
49 static dissector_handle_t eth_maybefcs_handle
;
52 static int ett_epon_sec
;
53 static int ett_epon_checksum
;
55 static const true_false_string epon_mode_tfs
= {
56 "Broadcast/Multicast",
61 dissect_epon(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
64 proto_tree
*epon_tree
;
70 unsigned sent_checksum
;
72 unsigned dpoe_sec_byte
;
73 bool dpoe_encrypted
= false;
75 /* Start_of_Packet delimiter (/S/) can happen in byte 1, 2 or 3,
76 * making the captured preamble 8, 7 or 6 bytes in length. If the
77 * preamble starts with 0x55, then /S/ happened in byte 1, making the
78 * captured preamble 7 bytes in length.
80 if (tvb_get_ntohl(tvb
, 0) == 0x5555D555) {
82 } else if (tvb_get_ntoh24(tvb
, 0) == 0x55D555) {
84 } else if (tvb_get_ntohs(tvb
, 0) == 0xD555) {
87 item
= proto_tree_add_item(tree
, proto_epon
, tvb
, offset
, 0, ENC_NA
);
88 expert_add_info(pinfo
, item
, &ei_epon_sld_bad
);
93 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "EPON");
94 col_set_str(pinfo
->cinfo
, COL_INFO
, "EPON Preamble");
96 /* Create display subtree for the protocol */
97 ti
= proto_tree_add_item(tree
, proto_epon
, tvb
, 0+offset
, 6, ENC_NA
);
98 epon_tree
= proto_item_add_subtree(ti
, ett_epon
);
100 /* Decode byte 5 of the preamble according to CableLabs DPoE specification.
101 * If security is disabled, the DPoE byte will remain 0x55 and no decoding
104 dpoe_sec_byte
= tvb_get_uint8(tvb
, 2+offset
);
105 if (dpoe_sec_byte
!= 0x55) {
107 unsigned dpoe_reserved
;
109 item
= proto_tree_add_item(epon_tree
, hf_epon_dpoe_security
,
110 tvb
, 2+offset
, 1, ENC_BIG_ENDIAN
);
111 sec_tree
= proto_item_add_subtree(item
, ett_epon_sec
);
113 /* The DPoE security byte is split into three fields:
114 * bits 7-2 are reserved in 1G mode
115 * bit 1 is the encryption mode
116 * bit 0 is the key ID
118 dpoe_reserved
= dpoe_sec_byte
& 0xFC;
119 dpoe_encrypted
= dpoe_sec_byte
& 0x02;
120 dpoe_keyid
= dpoe_sec_byte
& 0x01;
122 /* Add encryption status text to sec_tree subtree
124 proto_item_append_text(item
, " (Encrypted: ");
125 if (dpoe_encrypted
) {
126 proto_item_append_text(item
, "True, Key ID: %x", dpoe_keyid
);
128 proto_item_append_text(item
, "False");
130 proto_item_append_text(item
, ")");
132 /* We don't need to see the reserved bits of the DPoE security byte unless
133 * there's something wrong with them.
135 if (dpoe_reserved
!= 0x54) {
136 proto_tree_add_item(sec_tree
, hf_epon_dpoe_reserved
, tvb
, 2+offset
, 1,
138 expert_add_info(pinfo
, sec_tree
, &ei_epon_dpoe_reserved_bad
);
141 /* Add encryption and key ID bits
142 * Error if encryption is disabled but key bit is not 1
144 proto_tree_add_item(sec_tree
, hf_epon_dpoe_encrypted
, tvb
, 2+offset
, 1,
146 proto_tree_add_item(sec_tree
, hf_epon_dpoe_keyid
, tvb
, 2+offset
, 1,
148 if (!dpoe_encrypted
&& (dpoe_keyid
== 0)) {
149 expert_add_info(pinfo
, sec_tree
, &ei_epon_dpoe_bad
);
156 proto_tree_add_item(epon_tree
, hf_epon_mode
, tvb
, 3+offset
, 2,
161 proto_tree_add_item(epon_tree
, hf_epon_llid
, tvb
, 3+offset
, 2,
164 /* Verify the CRC-8 checksum
166 sent_checksum
= tvb_get_uint8(tvb
, 5+offset
);
167 checksum
= get_crc8_ieee8023_epon(tvb
, 5, 0+offset
);
169 proto_tree_add_checksum(epon_tree
, tvb
, 5+offset
, hf_epon_checksum
, hf_epon_checksum_status
, &ei_epon_checksum_bad
, pinfo
, checksum
, ENC_NA
, PROTO_CHECKSUM_VERIFY
);
170 if (sent_checksum
!= checksum
) {
171 col_append_str(pinfo
->cinfo
, COL_INFO
, " [EPON PREAMBLE CHECKSUM INCORRECT]");
174 /* Do not bother parsing encrypted data, otherwise send the rest on to the
177 if (dpoe_encrypted
) {
178 item
= proto_tree_add_item(tree
, hf_epon_dpoe_encrypted_data
, tvb
,
179 6+offset
, -1, ENC_NA
);
180 expert_add_info(pinfo
, item
, &ei_epon_dpoe_encrypted_data
);
181 col_append_str(pinfo
->cinfo
, COL_INFO
, " [ENCRYPTED]");
183 next_tvb
= tvb_new_subset_remaining(tvb
, 6+offset
);
185 * XXX - is it guaranteed whether the capture will, or won't, have
188 call_dissector(eth_maybefcs_handle
, next_tvb
, pinfo
, tree
);
191 return tvb_captured_length(tvb
);
195 proto_register_epon(void)
197 expert_module_t
*expert_epon
;
199 static hf_register_info hf
[] = {
200 { &hf_epon_dpoe_security
,
201 { "DPoE security", "epon.dpoe.sec", FT_UINT8
, BASE_HEX
, NULL
, 0x0,
202 "DPoE security octet", HFILL
}
204 { &hf_epon_dpoe_reserved
,
205 { "Reserved", "epon.dpoe.reserved", FT_UINT8
, BASE_DEC
, NULL
, 0xFC,
206 "Reserved in 1G mode", HFILL
}
208 { &hf_epon_dpoe_encrypted
,
209 { "Encryption enabled", "epon.dpoe.encrypted", FT_BOOLEAN
, 8, NULL
, 0x02,
210 "Specifies if this is an encrypted frame", HFILL
}
212 { &hf_epon_dpoe_keyid
,
213 { "Key ID", "epon.dpoe.keyid", FT_UINT8
, BASE_HEX
, NULL
, 0x01,
214 "Identification number of the key used to encrypt this frame",
217 { &hf_epon_dpoe_encrypted_data
,
218 { "Encrypted data", "epon.dpoe.encrypted.data", FT_BYTES
, BASE_NONE
,
219 NULL
, 0x0, "DPoE encrypted data", HFILL
}
222 { "Mode", "epon.mode", FT_BOOLEAN
, 16, TFS(&epon_mode_tfs
), 0x8000,
223 "Broadcast/multicast if true, unicast if false", HFILL
}
226 { "LLID", "epon.llid", FT_UINT16
, BASE_DEC_HEX
, NULL
, 0x7FFF,
227 "Logical Link ID", HFILL
}
230 { "Frame check sequence", "epon.checksum", FT_UINT8
, BASE_HEX
, NULL
,
231 0x0, "EPON preamble checksum", HFILL
}
233 { &hf_epon_checksum_status
,
234 { "Frame check sequence Status", "epon.checksum.status", FT_UINT8
, BASE_NONE
, VALS(proto_checksum_vals
),
239 static int *ett
[] = {
245 /* Setup protocol expert items */
246 static ei_register_info ei
[] = {
247 { &ei_epon_checksum_bad
,
248 { "epon.checksum_bad.expert", PI_CHECKSUM
, PI_ERROR
,
249 "Bad checksum", EXPFILL
}
252 { "epon.sld_bad.expert", PI_MALFORMED
, PI_ERROR
,
253 "Unable to locate SLD or invalid byte sequence: preamble must start with 0xD555", EXPFILL
}
255 { &ei_epon_dpoe_reserved_bad
,
256 { "epon.dpoe.encrypted.expert", PI_MALFORMED
, PI_ERROR
,
257 "Bits 7-2 of DPoE security byte must be 010101 in 1G mode.", EXPFILL
}
260 { "epon.dpoe.expert", PI_MALFORMED
, PI_ERROR
,
261 "DPoE security byte must be 0x55 if encryption is disabled.", EXPFILL
}
263 { &ei_epon_dpoe_encrypted_data
,
264 { "epon.dpoe.encrypted.expert", PI_UNDECODED
, PI_NOTE
,
265 "Remaining data is encrypted and will not decode.", EXPFILL
}
269 proto_epon
= proto_register_protocol("IEEE 802.3 EPON Preamble",
272 proto_register_field_array(proto_epon
, hf
, array_length(hf
));
273 proto_register_subtree_array(ett
, array_length(ett
));
275 expert_epon
= expert_register_protocol(proto_epon
);
276 expert_register_field_array(expert_epon
, ei
, array_length(ei
));
278 epon_handle
= register_dissector("epon", dissect_epon
, proto_epon
);
282 proto_reg_handoff_epon(void)
284 dissector_add_uint("wtap_encap", WTAP_ENCAP_EPON
, epon_handle
);
286 eth_maybefcs_handle
= find_dissector_add_dependency("eth_maybefcs", proto_epon
);
290 * Editor modelines - https://www.wireshark.org/tools/modelines.html
295 * indent-tabs-mode: nil
298 * ex: set shiftwidth=2 tabstop=8 expandtab:
299 * :indentSize=2:tabSize=8:noTabs=true: