1/*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22/* \summary: Apple's DLT_PKTAP printer */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <netdissect-stdinc.h>
29
30#include "netdissect.h"
31#include "extract.h"
32
33#ifdef DLT_PKTAP
34
35/*
36 * XXX - these are little-endian in the captures I've seen, but Apple
37 * no longer make any big-endian machines (Macs use x86, iOS machines
38 * use ARM and run it little-endian), so that might be by definition
39 * or they might be host-endian.
40 *
41 * If a big-endian PKTAP file ever shows up, and it comes from a
42 * big-endian machine, presumably these are host-endian, and we need
43 * to just fetch the fields directly in tcpdump but byte-swap them
44 * to host byte order in libpcap.
45 */
46typedef struct pktap_header {
47	uint32_t	pkt_len;	/* length of pktap header */
48	uint32_t	pkt_rectype;	/* type of record */
49	uint32_t	pkt_dlt;	/* DLT type of this packet */
50	char		pkt_ifname[24];	/* interface name */
51	uint32_t	pkt_flags;
52	uint32_t	pkt_pfamily;	/* "protocol family" */
53	uint32_t	pkt_llhdrlen;	/* link-layer header length? */
54	uint32_t	pkt_lltrlrlen;	/* link-layer trailer length? */
55	uint32_t	pkt_pid;	/* process ID */
56	char		pkt_cmdname[20]; /* command name */
57	uint32_t	pkt_svc_class;	/* "service class" */
58	uint16_t	pkt_iftype;	/* "interface type" */
59	uint16_t	pkt_ifunit;	/* unit number of interface? */
60	uint32_t	pkt_epid;	/* "effective process ID" */
61	char		pkt_ecmdname[20]; /* "effective command name" */
62} pktap_header_t;
63
64/*
65 * Record types.
66 */
67#define PKT_REC_NONE	0	/* nothing follows the header */
68#define PKT_REC_PACKET	1	/* a packet follows the header */
69
70static inline void
71pktap_header_print(netdissect_options *ndo, const u_char *bp, u_int length)
72{
73	const pktap_header_t *hdr;
74	uint32_t dlt, hdrlen;
75	const char *dltname;
76
77	hdr = (const pktap_header_t *)bp;
78
79	dlt = EXTRACT_LE_32BITS(&hdr->pkt_dlt);
80	hdrlen = EXTRACT_LE_32BITS(&hdr->pkt_len);
81	dltname = pcap_datalink_val_to_name(dlt);
82	if (!ndo->ndo_qflag) {
83		ND_PRINT((ndo,"DLT %s (%d) len %d",
84			  (dltname != NULL ? dltname : "UNKNOWN"), dlt, hdrlen));
85        } else {
86		ND_PRINT((ndo,"%s", (dltname != NULL ? dltname : "UNKNOWN")));
87        }
88
89	ND_PRINT((ndo, ", length %u: ", length));
90}
91
92/*
93 * This is the top level routine of the printer.  'p' points
94 * to the ether header of the packet, 'h->ts' is the timestamp,
95 * 'h->len' is the length of the packet off the wire, and 'h->caplen'
96 * is the number of bytes actually captured.
97 */
98u_int
99pktap_if_print(netdissect_options *ndo,
100               const struct pcap_pkthdr *h, const u_char *p)
101{
102	uint32_t dlt, hdrlen, rectype;
103	u_int caplen = h->caplen;
104	u_int length = h->len;
105	if_printer printer;
106	const pktap_header_t *hdr;
107	struct pcap_pkthdr nhdr;
108
109	if (caplen < sizeof(pktap_header_t) || length < sizeof(pktap_header_t)) {
110		ND_PRINT((ndo, "[|pktap]"));
111		return (0);
112	}
113	hdr = (const pktap_header_t *)p;
114	dlt = EXTRACT_LE_32BITS(&hdr->pkt_dlt);
115	hdrlen = EXTRACT_LE_32BITS(&hdr->pkt_len);
116	if (hdrlen < sizeof(pktap_header_t)) {
117		/*
118		 * Claimed header length < structure length.
119		 * XXX - does this just mean some fields aren't
120		 * being supplied, or is it truly an error (i.e.,
121		 * is the length supplied so that the header can
122		 * be expanded in the future)?
123		 */
124		ND_PRINT((ndo, "[|pktap]"));
125		return (0);
126	}
127	if (caplen < hdrlen || length < hdrlen) {
128		ND_PRINT((ndo, "[|pktap]"));
129		return (hdrlen);
130	}
131
132	if (ndo->ndo_eflag)
133		pktap_header_print(ndo, p, length);
134
135	length -= hdrlen;
136	caplen -= hdrlen;
137	p += hdrlen;
138
139	rectype = EXTRACT_LE_32BITS(&hdr->pkt_rectype);
140	switch (rectype) {
141
142	case PKT_REC_NONE:
143		ND_PRINT((ndo, "no data"));
144		break;
145
146	case PKT_REC_PACKET:
147		if ((printer = lookup_printer(dlt)) != NULL) {
148			nhdr = *h;
149			nhdr.caplen = caplen;
150			nhdr.len = length;
151			hdrlen += printer(ndo, &nhdr, p);
152		} else {
153			if (!ndo->ndo_eflag)
154				pktap_header_print(ndo, (const u_char *)hdr,
155						length + hdrlen);
156
157			if (!ndo->ndo_suppress_default_print)
158				ND_DEFAULTPRINT(p, caplen);
159		}
160		break;
161	}
162
163	return (hdrlen);
164}
165
166/*
167 * Local Variables:
168 * c-style: whitesmith
169 * c-basic-offset: 8
170 * End:
171 */
172
173#endif /* DLT_PKTAP */
174