xref: /openbsd-src/usr.sbin/tcpdump/print-ether.c (revision 33b4f39fbeffad07bc3206f173cff9f3c9901cd1)
1 /*	$OpenBSD: print-ether.c,v 1.19 2004/01/22 16:18:52 jason Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23 #ifndef lint
24 static const char rcsid[] =
25     "@(#) $Header: /home/cvs/src/usr.sbin/tcpdump/print-ether.c,v 1.19 2004/01/22 16:18:52 jason Exp $ (LBL)";
26 #endif
27 
28 #include <sys/param.h>
29 #include <sys/time.h>
30 #include <sys/socket.h>
31 
32 struct mbuf;
33 struct rtentry;
34 #include <net/if.h>
35 
36 #include <netinet/in.h>
37 #include <netinet/if_ether.h>
38 #include <netinet/in_systm.h>
39 #include <netinet/ip.h>
40 #include <netinet/ip_var.h>
41 #include <netinet/udp.h>
42 #include <netinet/udp_var.h>
43 #include <netinet/tcp.h>
44 
45 #include <stdio.h>
46 #include <pcap.h>
47 
48 #ifdef INET6
49 #include <netinet/ip6.h>
50 #endif
51 
52 #include "interface.h"
53 #include "addrtoname.h"
54 #include "ethertype.h"
55 #include "extract.h"
56 
57 const u_char *packetp;
58 const u_char *snapend;
59 
60 void ether_macctl(const u_char *, u_int);
61 
62 void
63 ether_print(register const u_char *bp, u_int length)
64 {
65 	register const struct ether_header *ep;
66 
67 	ep = (const struct ether_header *)bp;
68 	if (qflag)
69 		(void)printf("%s %s %d: ",
70 			     etheraddr_string(ESRC(ep)),
71 			     etheraddr_string(EDST(ep)),
72 			     length);
73 	else
74 		(void)printf("%s %s %s %d: ",
75 			     etheraddr_string(ESRC(ep)),
76 			     etheraddr_string(EDST(ep)),
77 			     etherproto_string(ep->ether_type),
78 			     length);
79 }
80 
81 u_short extracted_ethertype;
82 
83 /*
84  * This is the top level routine of the printer.  'p' is the points
85  * to the ether header of the packet, 'tvp' is the timestamp,
86  * 'length' is the length of the packet off the wire, and 'caplen'
87  * is the number of bytes actually captured.
88  */
89 void
90 ether_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
91 {
92 	u_int caplen = h->caplen;
93 	u_int length = h->len;
94 	struct ether_header *ep;
95 	u_short ether_type;
96 
97 	ts_print(&h->ts);
98 
99 	if (caplen < sizeof(struct ether_header)) {
100 		printf("[|ether]");
101 		goto out;
102 	}
103 
104 	if (eflag)
105 		ether_print(p, length);
106 
107 	/*
108 	 * Some printers want to get back at the ethernet addresses,
109 	 * and/or check that they're not walking off the end of the packet.
110 	 * Rather than pass them all the way down, we set these globals.
111 	 */
112 	packetp = p;
113 	snapend = p + caplen;
114 
115 	length -= sizeof(struct ether_header);
116 	caplen -= sizeof(struct ether_header);
117 	ep = (struct ether_header *)p;
118 	p += sizeof(struct ether_header);
119 
120 	ether_type = ntohs(ep->ether_type);
121 
122 	/*
123 	 * Is it (gag) an 802.3 encapsulation?
124 	 */
125 	extracted_ethertype = 0;
126 	if (ether_type <= ETHERMTU) {
127 		/* Try to print the LLC-layer header & higher layers */
128 		if (llc_print(p, length, caplen, ESRC(ep), EDST(ep)) == 0) {
129 			/* ether_type not known, print raw packet */
130 			if (!eflag)
131 				ether_print((u_char *)ep, length);
132 			if (extracted_ethertype) {
133 				printf("(LLC %s) ",
134 			       etherproto_string(htons(extracted_ethertype)));
135 			}
136 			if (!xflag && !qflag)
137 				default_print(p, caplen);
138 		}
139 	} else if (ether_encap_print(ether_type, p, length, caplen) == 0) {
140 		/* ether_type not known, print raw packet */
141 		if (!eflag)
142 			ether_print((u_char *)ep, length + sizeof(*ep));
143 		if (!xflag && !qflag)
144 			default_print(p, caplen);
145 	}
146 	if (xflag)
147 		default_print(p, caplen);
148  out:
149 	putchar('\n');
150 }
151 
152 /*
153  * Prints the packet encapsulated in an Ethernet data segment
154  * (or an equivalent encapsulation), given the Ethernet type code.
155  *
156  * Returns non-zero if it can do so, zero if the ethertype is unknown.
157  *
158  * Stuffs the ether type into a global for the benefit of lower layers
159  * that might want to know what it is.
160  */
161 
162 int
163 ether_encap_print(u_short ethertype, const u_char *p,
164     u_int length, u_int caplen)
165 {
166 recurse:
167 	extracted_ethertype = ethertype;
168 
169 	switch (ethertype) {
170 
171 	case ETHERTYPE_IP:
172 		ip_print(p, length);
173 		return (1);
174 
175 #ifdef INET6
176 	case ETHERTYPE_IPV6:
177 		ip6_print(p, length);
178 		return (1);
179 #endif /*INET6*/
180 
181 	case ETHERTYPE_ARP:
182 	case ETHERTYPE_REVARP:
183 		arp_print(p, length, caplen);
184 		return (1);
185 
186 	case ETHERTYPE_DN:
187 		decnet_print(p, length, caplen);
188 		return (1);
189 
190 	case ETHERTYPE_ATALK:
191 		if (vflag)
192 			fputs("et1 ", stdout);
193 		atalk_print_llap(p, length);
194 		return (1);
195 
196 	case ETHERTYPE_AARP:
197 		aarp_print(p, length);
198 		return (1);
199 
200 	case ETHERTYPE_8021Q:
201 		printf("802.1Q vid %d pri %d%s",
202 		       ntohs(*(unsigned short*)p)&0xFFF,
203 		       ntohs(*(unsigned short*)p)>>13,
204 		       (ntohs(*(unsigned short*)p)&0x1000) ? " cfi " : " ");
205 		ethertype = ntohs(*(unsigned short*)(p+2));
206 		p += 4;
207 		length -= 4;
208 		caplen -= 4;
209 		if (ethertype > ETHERMTU)
210 			goto recurse;
211 
212 		extracted_ethertype = 0;
213 
214 		if (llc_print(p, length, caplen, p-18, p-12) == 0) {
215 			/* ether_type not known, print raw packet */
216 			if (!eflag)
217 				ether_print(p-18, length+4);
218 			if (extracted_ethertype) {
219 				printf("(LLC %s) ",
220 				etherproto_string(htons(extracted_ethertype)));
221 			}
222 			if (!xflag && !qflag)
223 				default_print(p-18, caplen+4);
224 		}
225 		return (1);
226 
227 #ifdef PPP
228 	case ETHERTYPE_PPPOEDISC:
229 	case ETHERTYPE_PPPOE:
230 		pppoe_if_print(ethertype, p, length, caplen);
231 		return (1);
232 #endif
233 
234 	case ETHERTYPE_FLOWCONTROL:
235 		ether_macctl(p, length);
236 		return (1);
237 
238 	case ETHERTYPE_LAT:
239 	case ETHERTYPE_SCA:
240 	case ETHERTYPE_MOPRC:
241 	case ETHERTYPE_MOPDL:
242 		/* default_print for now */
243 	default:
244 		return (0);
245 	}
246 }
247 
248 void
249 ether_macctl(const u_char *p, u_int length)
250 {
251 	printf("MACCTL");
252 
253 	if (length < 2)
254 		goto trunc;
255 	if (EXTRACT_16BITS(p) == 0x0001) {
256 		u_int plen;
257 
258 		printf(" PAUSE");
259 
260 		length -= 2;
261 		p += 2;
262 		if (length < 2)
263 			goto trunc;
264 		plen = 512 * EXTRACT_16BITS(p);
265 		printf(" quanta %u", plen);
266 	} else {
267 		printf(" unknown-opcode(0x%04x)", EXTRACT_16BITS(p));
268 	}
269 	return;
270 
271 trunc:
272 	printf("[|MACCTL]");
273 }
274