1/*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
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#include <sys/cdefs.h>
23#ifndef lint
24#if 0
25static const char rcsid[] _U_ =
26    "@(#) Header: /tcpdump/master/tcpdump/print-arp.c,v 1.66 2006-03-03 22:53:21 hannes Exp (LBL)";
27#else
28__RCSID("$NetBSD$");
29#endif
30#endif
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include <tcpdump-stdinc.h>
37
38#include <stdio.h>
39#include <string.h>
40
41#include "netdissect.h"
42#include "addrtoname.h"
43#include "ether.h"
44#include "ethertype.h"
45#include "extract.h"			/* must come after interface.h */
46
47/*
48 * Address Resolution Protocol.
49 *
50 * See RFC 826 for protocol description.  ARP packets are variable
51 * in size; the arphdr structure defines the fixed-length portion.
52 * Protocol type values are the same as those for 10 Mb/s Ethernet.
53 * It is followed by the variable-sized fields ar_sha, arp_spa,
54 * arp_tha and arp_tpa in that order, according to the lengths
55 * specified.  Field names used correspond to RFC 826.
56 */
57struct  arp_pkthdr {
58        u_short ar_hrd;         /* format of hardware address */
59#define ARPHRD_ETHER    1       /* ethernet hardware format */
60#define ARPHRD_IEEE802  6       /* token-ring hardware format */
61#define ARPHRD_ARCNET   7       /* arcnet hardware format */
62#define ARPHRD_FRELAY   15      /* frame relay hardware format */
63#define ARPHRD_ATM2225  19      /* ATM (RFC 2225) */
64#define ARPHRD_STRIP    23      /* Ricochet Starmode Radio hardware format */
65#define ARPHRD_IEEE1394 24      /* IEEE 1394 (FireWire) hardware format */
66        u_short ar_pro;         /* format of protocol address */
67        u_char  ar_hln;         /* length of hardware address */
68        u_char  ar_pln;         /* length of protocol address */
69        u_short ar_op;          /* one of: */
70#define ARPOP_REQUEST   1       /* request to resolve address */
71#define ARPOP_REPLY     2       /* response to previous request */
72#define ARPOP_REVREQUEST 3      /* request protocol address given hardware */
73#define ARPOP_REVREPLY  4       /* response giving protocol address */
74#define ARPOP_INVREQUEST 8      /* request to identify peer */
75#define ARPOP_INVREPLY  9       /* response identifying peer */
76#define ARPOP_NAK       10      /* NAK - only valif for ATM ARP */
77
78/*
79 * The remaining fields are variable in size,
80 * according to the sizes above.
81 */
82#ifdef COMMENT_ONLY
83	u_char	ar_sha[];	/* sender hardware address */
84	u_char	ar_spa[];	/* sender protocol address */
85	u_char	ar_tha[];	/* target hardware address */
86	u_char	ar_tpa[];	/* target protocol address */
87#endif
88#define ar_sha(ap)	(((const u_char *)((ap)+1))+0)
89#define ar_spa(ap)	(((const u_char *)((ap)+1))+  (ap)->ar_hln)
90#define ar_tha(ap)	(((const u_char *)((ap)+1))+  (ap)->ar_hln+(ap)->ar_pln)
91#define ar_tpa(ap)	(((const u_char *)((ap)+1))+2*(ap)->ar_hln+(ap)->ar_pln)
92};
93
94#define ARP_HDRLEN	8
95
96#define HRD(ap) EXTRACT_16BITS(&(ap)->ar_hrd)
97#define HRD_LEN(ap) ((ap)->ar_hln)
98#define PROTO_LEN(ap) ((ap)->ar_pln)
99#define OP(ap)  EXTRACT_16BITS(&(ap)->ar_op)
100#define PRO(ap) EXTRACT_16BITS(&(ap)->ar_pro)
101#define SHA(ap) (ar_sha(ap))
102#define SPA(ap) (ar_spa(ap))
103#define THA(ap) (ar_tha(ap))
104#define TPA(ap) (ar_tpa(ap))
105
106
107struct tok arpop_values[] = {
108    { ARPOP_REQUEST, "Request" },
109    { ARPOP_REPLY, "Reply" },
110    { ARPOP_REVREQUEST, "Reverse Request" },
111    { ARPOP_REVREPLY, "Reverse Reply" },
112    { ARPOP_INVREQUEST, "Inverse Request" },
113    { ARPOP_INVREPLY, "Inverse Reply" },
114    { ARPOP_NAK, "NACK Reply" },
115    { 0, NULL }
116};
117
118struct tok arphrd_values[] = {
119    { ARPHRD_ETHER, "Ethernet" },
120    { ARPHRD_IEEE802, "TokenRing" },
121    { ARPHRD_ARCNET, "ArcNet" },
122    { ARPHRD_FRELAY, "FrameRelay" },
123    { ARPHRD_STRIP, "Strip" },
124    { ARPHRD_IEEE1394, "IEEE 1394" },
125    { ARPHRD_ATM2225, "ATM" },
126    { 0, NULL }
127};
128
129/*
130 * ATM Address Resolution Protocol.
131 *
132 * See RFC 2225 for protocol description.  ATMARP packets are similar
133 * to ARP packets, except that there are no length fields for the
134 * protocol address - instead, there are type/length fields for
135 * the ATM number and subaddress - and the hardware addresses consist
136 * of an ATM number and an ATM subaddress.
137 */
138struct  atmarp_pkthdr {
139        u_short aar_hrd;        /* format of hardware address */
140        u_short aar_pro;        /* format of protocol address */
141        u_char  aar_shtl;       /* length of source ATM number */
142        u_char  aar_sstl;       /* length of source ATM subaddress */
143#define ATMARP_IS_E164  0x40    /* bit in type/length for E.164 format */
144#define ATMARP_LEN_MASK 0x3F    /* length of {sub}address in type/length */
145        u_short aar_op;         /* same as regular ARP */
146        u_char  aar_spln;       /* length of source protocol address */
147        u_char  aar_thtl;       /* length of target ATM number */
148        u_char  aar_tstl;       /* length of target ATM subaddress */
149        u_char  aar_tpln;       /* length of target protocol address */
150/*
151 * The remaining fields are variable in size,
152 * according to the sizes above.
153 */
154#ifdef COMMENT_ONLY
155	u_char	aar_sha[];	/* source ATM number */
156	u_char	aar_ssa[];	/* source ATM subaddress */
157	u_char	aar_spa[];	/* sender protocol address */
158	u_char	aar_tha[];	/* target ATM number */
159	u_char	aar_tsa[];	/* target ATM subaddress */
160	u_char	aar_tpa[];	/* target protocol address */
161#endif
162
163#define ATMHRD(ap)  EXTRACT_16BITS(&(ap)->aar_hrd)
164#define ATMSHRD_LEN(ap) ((ap)->aar_shtl & ATMARP_LEN_MASK)
165#define ATMSSLN(ap) ((ap)->aar_sstl & ATMARP_LEN_MASK)
166#define ATMSPROTO_LEN(ap) ((ap)->aar_spln)
167#define ATMOP(ap)   EXTRACT_16BITS(&(ap)->aar_op)
168#define ATMPRO(ap)  EXTRACT_16BITS(&(ap)->aar_pro)
169#define ATMTHRD_LEN(ap) ((ap)->aar_thtl & ATMARP_LEN_MASK)
170#define ATMTSLN(ap) ((ap)->aar_tstl & ATMARP_LEN_MASK)
171#define ATMTPROTO_LEN(ap) ((ap)->aar_tpln)
172#define aar_sha(ap)	((const u_char *)((ap)+1))
173#define aar_ssa(ap)	(aar_sha(ap) + ATMSHRD_LEN(ap))
174#define aar_spa(ap)	(aar_ssa(ap) + ATMSSLN(ap))
175#define aar_tha(ap)	(aar_spa(ap) + ATMSPROTO_LEN(ap))
176#define aar_tsa(ap)	(aar_tha(ap) + ATMTHRD_LEN(ap))
177#define aar_tpa(ap)	(aar_tsa(ap) + ATMTSLN(ap))
178};
179
180#define ATMSHA(ap) (aar_sha(ap))
181#define ATMSSA(ap) (aar_ssa(ap))
182#define ATMSPA(ap) (aar_spa(ap))
183#define ATMTHA(ap) (aar_tha(ap))
184#define ATMTSA(ap) (aar_tsa(ap))
185#define ATMTPA(ap) (aar_tpa(ap))
186
187static u_char ezero[6];
188
189static void
190atmarp_addr_print(netdissect_options *ndo,
191		  const u_char *ha, u_int ha_len, const u_char *srca,
192    u_int srca_len)
193{
194	if (ha_len == 0)
195		ND_PRINT((ndo, "<No address>"));
196	else {
197		ND_PRINT((ndo, "%s", linkaddr_string(ha, LINKADDR_ATM, ha_len)));
198		if (srca_len != 0)
199			ND_PRINT((ndo, ",%s",
200				  linkaddr_string(srca, LINKADDR_ATM, srca_len)));
201	}
202}
203
204static void
205atmarp_print(netdissect_options *ndo,
206	     const u_char *bp, u_int length, u_int caplen)
207{
208	const struct atmarp_pkthdr *ap;
209	u_short pro, hrd, op;
210
211	ap = (const struct atmarp_pkthdr *)bp;
212	ND_TCHECK(*ap);
213
214	hrd = ATMHRD(ap);
215	pro = ATMPRO(ap);
216	op = ATMOP(ap);
217
218	if (!ND_TTEST2(*aar_tpa(ap), ATMTPROTO_LEN(ap))) {
219		ND_PRINT((ndo, "[|ARP]"));
220		ND_DEFAULTPRINT((const u_char *)ap, length);
221		return;
222	}
223
224        if (!ndo->ndo_eflag) {
225            ND_PRINT((ndo, "ARP, "));
226        }
227
228	if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) ||
229	    ATMSPROTO_LEN(ap) != 4 ||
230            ATMTPROTO_LEN(ap) != 4 ||
231            ndo->ndo_vflag) {
232                ND_PRINT((ndo, "%s, %s (len %u/%u)",
233                          tok2str(arphrd_values, "Unknown Hardware (%u)", hrd),
234                          tok2str(ethertype_values, "Unknown Protocol (0x%04x)", pro),
235                          ATMSPROTO_LEN(ap),
236                          ATMTPROTO_LEN(ap)));
237
238                /* don't know know about the address formats */
239                if (!ndo->ndo_vflag) {
240                    goto out;
241                }
242	}
243
244        /* print operation */
245        printf("%s%s ",
246               ndo->ndo_vflag ? ", " : "",
247               tok2str(arpop_values, "Unknown (%u)", op));
248
249	switch (op) {
250
251	case ARPOP_REQUEST:
252		ND_PRINT((ndo, "who-has %s", ipaddr_string(ATMTPA(ap))));
253		if (ATMTHRD_LEN(ap) != 0) {
254			ND_PRINT((ndo, " ("));
255			atmarp_addr_print(ndo, ATMTHA(ap), ATMTHRD_LEN(ap),
256			    ATMTSA(ap), ATMTSLN(ap));
257			ND_PRINT((ndo, ")"));
258		}
259		ND_PRINT((ndo, "tell %s", ipaddr_string(ATMSPA(ap))));
260		break;
261
262	case ARPOP_REPLY:
263		ND_PRINT((ndo, "%s is-at ", ipaddr_string(ATMSPA(ap))));
264		atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap),
265                                  ATMSSLN(ap));
266		break;
267
268	case ARPOP_INVREQUEST:
269		ND_PRINT((ndo, "who-is "));
270		atmarp_addr_print(ndo, ATMTHA(ap), ATMTHRD_LEN(ap), ATMTSA(ap),
271		    ATMTSLN(ap));
272		ND_PRINT((ndo, " tell "));
273		atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap),
274		    ATMSSLN(ap));
275		break;
276
277	case ARPOP_INVREPLY:
278		atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap),
279		    ATMSSLN(ap));
280		ND_PRINT((ndo, "at %s", ipaddr_string(ATMSPA(ap))));
281		break;
282
283	case ARPOP_NAK:
284		ND_PRINT((ndo, "for %s", ipaddr_string(ATMSPA(ap))));
285		break;
286
287	default:
288		ND_DEFAULTPRINT((const u_char *)ap, caplen);
289		return;
290	}
291
292 out:
293        ND_PRINT((ndo, ", length %u", length));
294        return;
295
296trunc:
297	ND_PRINT((ndo, "[|ARP]"));
298}
299
300void
301arp_print(netdissect_options *ndo,
302	  const u_char *bp, u_int length, u_int caplen)
303{
304	const struct arp_pkthdr *ap;
305	u_short pro, hrd, op, linkaddr;
306
307	ap = (const struct arp_pkthdr *)bp;
308	ND_TCHECK(*ap);
309
310	hrd = HRD(ap);
311	pro = PRO(ap);
312	op = OP(ap);
313
314
315        /* if its ATM then call the ATM ARP printer
316           for Frame-relay ARP most of the fields
317           are similar to Ethernet so overload the Ethernet Printer
318           and set the linkaddr type for linkaddr_string() accordingly */
319
320        switch(hrd) {
321        case ARPHRD_ATM2225:
322            atmarp_print(ndo, bp, length, caplen);
323            return;
324        case ARPHRD_FRELAY:
325            linkaddr = LINKADDR_FRELAY;
326        default:
327            linkaddr = LINKADDR_ETHER;
328            break;
329	}
330
331	if (!ND_TTEST2(*ar_tpa(ap), PROTO_LEN(ap))) {
332		ND_PRINT((ndo, "[|ARP]"));
333		ND_DEFAULTPRINT((const u_char *)ap, length);
334		return;
335	}
336
337        if (!ndo->ndo_eflag) {
338            ND_PRINT((ndo, "ARP, "));
339        }
340
341        /* print hardware type/len and proto type/len */
342        if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) ||
343	    PROTO_LEN(ap) != 4 ||
344            HRD_LEN(ap) == 0 ||
345            ndo->ndo_vflag) {
346            ND_PRINT((ndo, "%s (len %u), %s (len %u)",
347                      tok2str(arphrd_values, "Unknown Hardware (%u)", hrd),
348                      HRD_LEN(ap),
349                      tok2str(ethertype_values, "Unknown Protocol (0x%04x)", pro),
350                      PROTO_LEN(ap)));
351
352            /* don't know know about the address formats */
353            if (!ndo->ndo_vflag) {
354                goto out;
355            }
356	}
357
358        /* print operation */
359        printf("%s%s ",
360               ndo->ndo_vflag ? ", " : "",
361               tok2str(arpop_values, "Unknown (%u)", op));
362
363	switch (op) {
364
365	case ARPOP_REQUEST:
366		ND_PRINT((ndo, "who-has %s", ipaddr_string(TPA(ap))));
367		if (memcmp((const char *)ezero, (const char *)THA(ap), HRD_LEN(ap)) != 0)
368			ND_PRINT((ndo, " (%s)",
369				  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap))));
370		ND_PRINT((ndo, " tell %s", ipaddr_string(SPA(ap))));
371		break;
372
373	case ARPOP_REPLY:
374		ND_PRINT((ndo, "%s is-at %s",
375                          ipaddr_string(SPA(ap)),
376                          linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap))));
377		break;
378
379	case ARPOP_REVREQUEST:
380		ND_PRINT((ndo, "who-is %s tell %s",
381			  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)),
382			  linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap))));
383		break;
384
385	case ARPOP_REVREPLY:
386		ND_PRINT((ndo, "%s at %s",
387			  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)),
388			  ipaddr_string(TPA(ap))));
389		break;
390
391	case ARPOP_INVREQUEST:
392		ND_PRINT((ndo, "who-is %s tell %s",
393			  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)),
394			  linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap))));
395		break;
396
397	case ARPOP_INVREPLY:
398		ND_PRINT((ndo,"%s at %s",
399			  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)),
400			  ipaddr_string(TPA(ap))));
401		break;
402
403	default:
404		ND_DEFAULTPRINT((const u_char *)ap, caplen);
405		return;
406	}
407
408 out:
409        ND_PRINT((ndo, ", length %u", length));
410
411	return;
412trunc:
413	ND_PRINT((ndo, "[|ARP]"));
414}
415
416/*
417 * Local Variables:
418 * c-style: bsd
419 * End:
420 */
421
422