xref: /openbsd/usr.sbin/tcpdump/print-ether.c (revision db3296cf)
1 /*	$OpenBSD: print-ether.c,v 1.18 2002/02/19 19:39:40 millert 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.18 2002/02/19 19:39:40 millert 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 
56 const u_char *packetp;
57 const u_char *snapend;
58 
59 void
60 ether_print(register const u_char *bp, u_int length)
61 {
62 	register const struct ether_header *ep;
63 
64 	ep = (const struct ether_header *)bp;
65 	if (qflag)
66 		(void)printf("%s %s %d: ",
67 			     etheraddr_string(ESRC(ep)),
68 			     etheraddr_string(EDST(ep)),
69 			     length);
70 	else
71 		(void)printf("%s %s %s %d: ",
72 			     etheraddr_string(ESRC(ep)),
73 			     etheraddr_string(EDST(ep)),
74 			     etherproto_string(ep->ether_type),
75 			     length);
76 }
77 
78 u_short extracted_ethertype;
79 
80 /*
81  * This is the top level routine of the printer.  'p' is the points
82  * to the ether header of the packet, 'tvp' is the timestamp,
83  * 'length' is the length of the packet off the wire, and 'caplen'
84  * is the number of bytes actually captured.
85  */
86 void
87 ether_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
88 {
89 	u_int caplen = h->caplen;
90 	u_int length = h->len;
91 	struct ether_header *ep;
92 	u_short ether_type;
93 
94 	ts_print(&h->ts);
95 
96 	if (caplen < sizeof(struct ether_header)) {
97 		printf("[|ether]");
98 		goto out;
99 	}
100 
101 	if (eflag)
102 		ether_print(p, length);
103 
104 	/*
105 	 * Some printers want to get back at the ethernet addresses,
106 	 * and/or check that they're not walking off the end of the packet.
107 	 * Rather than pass them all the way down, we set these globals.
108 	 */
109 	packetp = p;
110 	snapend = p + caplen;
111 
112 	length -= sizeof(struct ether_header);
113 	caplen -= sizeof(struct ether_header);
114 	ep = (struct ether_header *)p;
115 	p += sizeof(struct ether_header);
116 
117 	ether_type = ntohs(ep->ether_type);
118 
119 	/*
120 	 * Is it (gag) an 802.3 encapsulation?
121 	 */
122 	extracted_ethertype = 0;
123 	if (ether_type <= ETHERMTU) {
124 		/* Try to print the LLC-layer header & higher layers */
125 		if (llc_print(p, length, caplen, ESRC(ep), EDST(ep)) == 0) {
126 			/* ether_type not known, print raw packet */
127 			if (!eflag)
128 				ether_print((u_char *)ep, length);
129 			if (extracted_ethertype) {
130 				printf("(LLC %s) ",
131 			       etherproto_string(htons(extracted_ethertype)));
132 			}
133 			if (!xflag && !qflag)
134 				default_print(p, caplen);
135 		}
136 	} else if (ether_encap_print(ether_type, p, length, caplen) == 0) {
137 		/* ether_type not known, print raw packet */
138 		if (!eflag)
139 			ether_print((u_char *)ep, length + sizeof(*ep));
140 		if (!xflag && !qflag)
141 			default_print(p, caplen);
142 	}
143 	if (xflag)
144 		default_print(p, caplen);
145  out:
146 	putchar('\n');
147 }
148 
149 /*
150  * Prints the packet encapsulated in an Ethernet data segment
151  * (or an equivalent encapsulation), given the Ethernet type code.
152  *
153  * Returns non-zero if it can do so, zero if the ethertype is unknown.
154  *
155  * Stuffs the ether type into a global for the benefit of lower layers
156  * that might want to know what it is.
157  */
158 
159 int
160 ether_encap_print(u_short ethertype, const u_char *p,
161     u_int length, u_int caplen)
162 {
163 recurse:
164 	extracted_ethertype = ethertype;
165 
166 	switch (ethertype) {
167 
168 	case ETHERTYPE_IP:
169 		ip_print(p, length);
170 		return (1);
171 
172 #ifdef INET6
173 	case ETHERTYPE_IPV6:
174 		ip6_print(p, length);
175 		return (1);
176 #endif /*INET6*/
177 
178 	case ETHERTYPE_ARP:
179 	case ETHERTYPE_REVARP:
180 		arp_print(p, length, caplen);
181 		return (1);
182 
183 	case ETHERTYPE_DN:
184 		decnet_print(p, length, caplen);
185 		return (1);
186 
187 	case ETHERTYPE_ATALK:
188 		if (vflag)
189 			fputs("et1 ", stdout);
190 		atalk_print_llap(p, length);
191 		return (1);
192 
193 	case ETHERTYPE_AARP:
194 		aarp_print(p, length);
195 		return (1);
196 
197 	case ETHERTYPE_8021Q:
198 		printf("802.1Q vid %d pri %d%s",
199 		       ntohs(*(unsigned short*)p)&0xFFF,
200 		       ntohs(*(unsigned short*)p)>>13,
201 		       (ntohs(*(unsigned short*)p)&0x1000) ? " cfi " : " ");
202 		ethertype = ntohs(*(unsigned short*)(p+2));
203 		p += 4;
204 		length -= 4;
205 		caplen -= 4;
206 		if (ethertype > ETHERMTU)
207 			goto recurse;
208 
209 		extracted_ethertype = 0;
210 
211 		if (llc_print(p, length, caplen, p-18, p-12) == 0) {
212 			/* ether_type not known, print raw packet */
213 			if (!eflag)
214 				ether_print(p-18, length+4);
215 			if (extracted_ethertype) {
216 				printf("(LLC %s) ",
217 				etherproto_string(htons(extracted_ethertype)));
218 			}
219 			if (!xflag && !qflag)
220 				default_print(p-18, caplen+4);
221 		}
222 		return (1);
223 
224 #ifdef PPP
225 	case ETHERTYPE_PPPOEDISC:
226 	case ETHERTYPE_PPPOE:
227 		pppoe_if_print(ethertype, p, length, caplen);
228 		return (1);
229 #endif
230 
231 	case ETHERTYPE_LAT:
232 	case ETHERTYPE_SCA:
233 	case ETHERTYPE_MOPRC:
234 	case ETHERTYPE_MOPDL:
235 		/* default_print for now */
236 	default:
237 		return (0);
238 	}
239 }
240