3 * Routines for dissecting Apple's PKTAP header
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 2007 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/packet.h>
15 #include <epan/capture_dissectors.h>
16 #include <epan/expert.h>
17 #include <wsutil/pint.h>
19 #include "packet-eth.h"
21 static dissector_handle_t pcap_pktdata_handle
;
23 void proto_register_pktap(void);
24 void proto_reg_handoff_pktap(void);
27 * Apple's PKTAP header.
31 * Minimum header length.
33 * XXX - I'm assuming the header begins with a length field so that it
34 * can be transparently *extended*, not so that fields in the current
35 * header can be *omitted*.
37 #define MIN_PKTAP_HDR_LEN 108
42 #define PKT_REC_NONE 0 /* nothing follows the header */
43 #define PKT_REC_PACKET 1 /* a packet follows the header */
46 static int proto_pktap
;
48 static int hf_pktap_hdrlen
;
49 static int hf_pktap_rectype
;
50 static int hf_pktap_dlt
;
51 static int hf_pktap_ifname
;
52 static int hf_pktap_flags
;
53 static int hf_pktap_pfamily
;
54 static int hf_pktap_llhdrlen
;
55 static int hf_pktap_lltrlrlen
;
56 static int hf_pktap_pid
;
57 static int hf_pktap_cmdname
;
58 static int hf_pktap_svc_class
;
59 static int hf_pktap_iftype
;
60 static int hf_pktap_ifunit
;
61 static int hf_pktap_epid
;
62 static int hf_pktap_ecmdname
;
66 static expert_field ei_pktap_hdrlen_too_short
;
68 static dissector_handle_t pktap_handle
;
69 static capture_dissector_handle_t eth_cap_handle
;
72 * XXX - these are only little-endian because they've been created on
73 * little-endian machines; the code in bsd/net/pktap.c in XNU writes
74 * the structure out in host byte order.
76 * We haven't been treating it as host-endian in libpcap and libwiretap,
77 * i.e. we haven't been byte-swapping its members when reading it on
78 * a machine whose byte order differs from the byte order of the machine
79 * on which the file is being read.
81 * Furthermore, the header is extensible, so we don't necessarily know
82 * what fields to swap.
84 * Fortunately, the length of the PKTAP header is a 32-bit field and is
85 * *presumably* never going to be 65536 or greater, so if any of the upper
86 * 16 bits appear to be set, it means we're looking at it in the wrong
87 * byte order, and it's never going to be zero, so those bits *will* be
88 * set if it's >= 65536, so we can determine its byte order.
90 * We should do that here.
94 capture_pktap(const unsigned char *pd
, int offset _U_
, int len
, capture_packet_info_t
*cpinfo
, const union wtap_pseudo_header
*pseudo_header _U_
)
96 uint32_t hdrlen
, rectype
, dlt
;
98 hdrlen
= pletoh32(pd
);
99 if (hdrlen
< MIN_PKTAP_HDR_LEN
|| !BYTES_ARE_IN_FRAME(0, len
, hdrlen
))
102 rectype
= pletoh32(pd
+4);
103 if (rectype
!= PKT_REC_PACKET
)
106 dlt
= pletoh32(pd
+4);
108 /* XXX - We should probably combine this with capture_info.c:capture_info_packet() */
111 case 1: /* DLT_EN10MB */
112 return call_capture_dissector(eth_cap_handle
, pd
, hdrlen
, len
, cpinfo
, pseudo_header
);
120 dissect_pktap(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
122 proto_tree
*pktap_tree
= NULL
;
123 proto_item
*ti
= NULL
;
126 uint32_t pkt_len
, rectype
, dlt
;
128 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "PKTAP");
129 col_clear(pinfo
->cinfo
, COL_INFO
);
131 pkt_len
= tvb_get_letohl(tvb
, offset
);
132 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "PKTAP, %u byte header", pkt_len
);
134 /* Dissect the packet */
135 ti
= proto_tree_add_item(tree
, proto_pktap
, tvb
, offset
, pkt_len
, ENC_NA
);
136 pktap_tree
= proto_item_add_subtree(ti
, ett_pktap
);
138 proto_tree_add_item(pktap_tree
, hf_pktap_hdrlen
, tvb
, offset
, 4,
140 if (pkt_len
< MIN_PKTAP_HDR_LEN
) {
141 proto_tree_add_expert(tree
, pinfo
, &ei_pktap_hdrlen_too_short
,
143 return tvb_captured_length(tvb
);
147 proto_tree_add_item(pktap_tree
, hf_pktap_rectype
, tvb
, offset
, 4,
149 rectype
= tvb_get_letohl(tvb
, offset
);
151 proto_tree_add_item(pktap_tree
, hf_pktap_dlt
, tvb
, offset
, 4,
153 dlt
= tvb_get_letohl(tvb
, offset
);
155 proto_tree_add_item(pktap_tree
, hf_pktap_ifname
, tvb
, offset
, 24,
158 proto_tree_add_item(pktap_tree
, hf_pktap_flags
, tvb
, offset
, 4,
161 proto_tree_add_item(pktap_tree
, hf_pktap_pfamily
, tvb
, offset
, 4,
164 proto_tree_add_item(pktap_tree
, hf_pktap_llhdrlen
, tvb
, offset
, 4,
167 proto_tree_add_item(pktap_tree
, hf_pktap_lltrlrlen
, tvb
, offset
, 4,
170 proto_tree_add_item(pktap_tree
, hf_pktap_pid
, tvb
, offset
, 4,
173 proto_tree_add_item(pktap_tree
, hf_pktap_cmdname
, tvb
, offset
, 20,
176 proto_tree_add_item(pktap_tree
, hf_pktap_svc_class
, tvb
, offset
, 4,
179 proto_tree_add_item(pktap_tree
, hf_pktap_iftype
, tvb
, offset
, 2,
182 proto_tree_add_item(pktap_tree
, hf_pktap_ifunit
, tvb
, offset
, 2,
185 proto_tree_add_item(pktap_tree
, hf_pktap_epid
, tvb
, offset
, 4,
188 proto_tree_add_item(pktap_tree
, hf_pktap_ecmdname
, tvb
, offset
, 20,
192 if (rectype
== PKT_REC_PACKET
) {
193 next_tvb
= tvb_new_subset_remaining(tvb
, pkt_len
);
194 call_dissector_with_data(pcap_pktdata_handle
, next_tvb
,
197 return tvb_captured_length(tvb
);
201 proto_register_pktap(void)
203 static hf_register_info hf
[] = {
205 { "Header length", "pktap.hdrlen",
206 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
208 { "Record type", "pktap.rectype",
209 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
211 { "DLT", "pktap.dlt",
212 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
213 { &hf_pktap_ifname
, /* fixed length *and* null-terminated */
214 { "Interface name", "pktap.ifname",
215 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
217 { "Flags", "pktap.flags",
218 FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
220 { "Protocol family", "pktap.pfamily",
221 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
222 { &hf_pktap_llhdrlen
,
223 { "Link-layer header length", "pktap.llhdrlen",
224 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
225 { &hf_pktap_lltrlrlen
,
226 { "Link-layer trailer length", "pktap.lltrlrlen",
227 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
229 { "Process ID", "pktap.pid",
230 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
231 { &hf_pktap_cmdname
, /* fixed length *and* null-terminated */
232 { "Command name", "pktap.cmdname",
233 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
234 { &hf_pktap_svc_class
,
235 { "Service class", "pktap.svc_class",
236 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
238 { "Interface type", "pktap.iftype",
239 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
241 { "Interface unit", "pktap.ifunit",
242 FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
244 { "Effective process ID", "pktap.epid",
245 FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
246 { &hf_pktap_ecmdname
, /* fixed length *and* null-terminated */
247 { "Effective command name", "pktap.ecmdname",
248 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
251 static int *ett
[] = {
255 static ei_register_info ei
[] = {
256 { &ei_pktap_hdrlen_too_short
,
257 { "pktap.hdrlen_too_short", PI_MALFORMED
, PI_ERROR
,
258 "Header length is too short", EXPFILL
}},
261 expert_module_t
* expert_pktap
;
263 proto_pktap
= proto_register_protocol("PKTAP packet header", "PKTAP",
265 proto_register_field_array(proto_pktap
, hf
, array_length(hf
));
266 proto_register_subtree_array(ett
, array_length(ett
));
267 expert_pktap
= expert_register_protocol(proto_pktap
);
268 expert_register_field_array(expert_pktap
, ei
, array_length(ei
));
270 pktap_handle
= register_dissector("pktap", dissect_pktap
, proto_pktap
);
274 proto_reg_handoff_pktap(void)
276 capture_dissector_handle_t pktap_cap_handle
;
278 dissector_add_uint("wtap_encap", WTAP_ENCAP_PKTAP
, pktap_handle
);
280 pcap_pktdata_handle
= find_dissector_add_dependency("pcap_pktdata", proto_pktap
);
282 /* XXX - WTAP_ENCAP_USER2 to handle Mavericks' botch wherein it
283 uses DLT_USER2 for PKTAP; if you are using DLT_USER2 for your
284 own purposes, feel free to call your own capture_ routine for
286 pktap_cap_handle
= create_capture_dissector_handle(capture_pktap
, proto_pktap
);
287 capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_PKTAP
, pktap_cap_handle
);
288 capture_dissector_add_uint("wtap_encap", WTAP_ENCAP_USER2
, pktap_cap_handle
);
290 eth_cap_handle
= find_capture_dissector("eth");
294 * Editor modelines - https://www.wireshark.org/tools/modelines.html
299 * indent-tabs-mode: t
302 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
303 * :indentSize=8:tabSize=8:noTabs=false: