print-arp.c revision 190207
117680Spst/*
217680Spst * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst *
2117680Spst * $FreeBSD: head/contrib/tcpdump/print-arp.c 190207 2009-03-21 18:30:25Z rpaulo $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
2526180Sfennerstatic const char rcsid[] _U_ =
2626180Sfenner    "@(#) $Header: /tcpdump/master/tcpdump/print-arp.c,v 1.66 2006-03-03 22:53:21 hannes Exp $ (LBL)";
2717680Spst#endif
2817680Spst
2917680Spst#ifdef HAVE_CONFIG_H
3017680Spst#include "config.h"
3117680Spst#endif
3217680Spst
3317680Spst#include <tcpdump-stdinc.h>
3417680Spst
3517680Spst#include <stdio.h>
3617680Spst#include <string.h>
3717680Spst
3817680Spst#include "netdissect.h"
3917680Spst#include "addrtoname.h"
4017680Spst#include "ether.h"
4117680Spst#include "ethertype.h"
4217680Spst#include "extract.h"			/* must come after interface.h */
4317680Spst
4417680Spst/*
4517680Spst * Address Resolution Protocol.
4617680Spst *
4717680Spst * See RFC 826 for protocol description.  ARP packets are variable
4817680Spst * in size; the arphdr structure defines the fixed-length portion.
4917680Spst * Protocol type values are the same as those for 10 Mb/s Ethernet.
5017680Spst * It is followed by the variable-sized fields ar_sha, arp_spa,
5117680Spst * arp_tha and arp_tpa in that order, according to the lengths
5217680Spst * specified.  Field names used correspond to RFC 826.
5317680Spst */
5417680Spststruct  arp_pkthdr {
5517680Spst        u_short ar_hrd;         /* format of hardware address */
5617680Spst#define ARPHRD_ETHER    1       /* ethernet hardware format */
5717680Spst#define ARPHRD_IEEE802  6       /* token-ring hardware format */
5817680Spst#define ARPHRD_ARCNET   7       /* arcnet hardware format */
5917680Spst#define ARPHRD_FRELAY   15      /* frame relay hardware format */
6017680Spst#define ARPHRD_ATM2225  19      /* ATM (RFC 2225) */
6117680Spst#define ARPHRD_STRIP    23      /* Ricochet Starmode Radio hardware format */
6217680Spst#define ARPHRD_IEEE1394 24      /* IEEE 1394 (FireWire) hardware format */
6317680Spst        u_short ar_pro;         /* format of protocol address */
6417680Spst        u_char  ar_hln;         /* length of hardware address */
6517680Spst        u_char  ar_pln;         /* length of protocol address */
6617680Spst        u_short ar_op;          /* one of: */
6717680Spst#define ARPOP_REQUEST   1       /* request to resolve address */
6817680Spst#define ARPOP_REPLY     2       /* response to previous request */
6917680Spst#define ARPOP_REVREQUEST 3      /* request protocol address given hardware */
7017680Spst#define ARPOP_REVREPLY  4       /* response giving protocol address */
7117680Spst#define ARPOP_INVREQUEST 8      /* request to identify peer */
7217680Spst#define ARPOP_INVREPLY  9       /* response identifying peer */
7317680Spst#define ARPOP_NAK       10      /* NAK - only valif for ATM ARP */
7417680Spst
7517680Spst/*
7617680Spst * The remaining fields are variable in size,
7717680Spst * according to the sizes above.
7817680Spst */
7917680Spst#ifdef COMMENT_ONLY
8017680Spst	u_char	ar_sha[];	/* sender hardware address */
8117680Spst	u_char	ar_spa[];	/* sender protocol address */
8217680Spst	u_char	ar_tha[];	/* target hardware address */
8317680Spst	u_char	ar_tpa[];	/* target protocol address */
8417680Spst#endif
8517680Spst#define ar_sha(ap)	(((const u_char *)((ap)+1))+0)
8617680Spst#define ar_spa(ap)	(((const u_char *)((ap)+1))+  (ap)->ar_hln)
8717680Spst#define ar_tha(ap)	(((const u_char *)((ap)+1))+  (ap)->ar_hln+(ap)->ar_pln)
8817680Spst#define ar_tpa(ap)	(((const u_char *)((ap)+1))+2*(ap)->ar_hln+(ap)->ar_pln)
8917680Spst};
9017680Spst
9117680Spst#define ARP_HDRLEN	8
9217680Spst
9317680Spst#define HRD(ap) EXTRACT_16BITS(&(ap)->ar_hrd)
9417680Spst#define HRD_LEN(ap) ((ap)->ar_hln)
9517680Spst#define PROTO_LEN(ap) ((ap)->ar_pln)
9617680Spst#define OP(ap)  EXTRACT_16BITS(&(ap)->ar_op)
9717680Spst#define PRO(ap) EXTRACT_16BITS(&(ap)->ar_pro)
9817680Spst#define SHA(ap) (ar_sha(ap))
9917680Spst#define SPA(ap) (ar_spa(ap))
10017680Spst#define THA(ap) (ar_tha(ap))
10117680Spst#define TPA(ap) (ar_tpa(ap))
10217680Spst
10317680Spst
10417680Spststruct tok arpop_values[] = {
10517680Spst    { ARPOP_REQUEST, "Request" },
10617680Spst    { ARPOP_REPLY, "Reply" },
10717680Spst    { ARPOP_REVREQUEST, "Reverse Request" },
10817680Spst    { ARPOP_REVREPLY, "Reverse Reply" },
10917680Spst    { ARPOP_INVREQUEST, "Inverse Request" },
11017680Spst    { ARPOP_INVREPLY, "Inverse Reply" },
11117680Spst    { ARPOP_NAK, "NACK Reply" },
11217680Spst    { 0, NULL }
11326180Sfenner};
11426180Sfenner
11526180Sfennerstruct tok arphrd_values[] = {
11626180Sfenner    { ARPHRD_ETHER, "Ethernet" },
11726180Sfenner    { ARPHRD_IEEE802, "TokenRing" },
11826180Sfenner    { ARPHRD_ARCNET, "ArcNet" },
11917680Spst    { ARPHRD_FRELAY, "FrameRelay" },
12026180Sfenner    { ARPHRD_STRIP, "Strip" },
12126180Sfenner    { ARPHRD_IEEE1394, "IEEE 1394" },
12226180Sfenner    { ARPHRD_ATM2225, "ATM" },
12326180Sfenner    { 0, NULL }
12426180Sfenner};
12526180Sfenner
12617680Spst/*
12717680Spst * ATM Address Resolution Protocol.
12817680Spst *
12917680Spst * See RFC 2225 for protocol description.  ATMARP packets are similar
13017680Spst * to ARP packets, except that there are no length fields for the
13117680Spst * protocol address - instead, there are type/length fields for
13217680Spst * the ATM number and subaddress - and the hardware addresses consist
13317680Spst * of an ATM number and an ATM subaddress.
13417680Spst */
13517680Spststruct  atmarp_pkthdr {
13617680Spst        u_short aar_hrd;        /* format of hardware address */
13717680Spst        u_short aar_pro;        /* format of protocol address */
13817680Spst        u_char  aar_shtl;       /* length of source ATM number */
13917680Spst        u_char  aar_sstl;       /* length of source ATM subaddress */
14017680Spst#define ATMARP_IS_E164  0x40    /* bit in type/length for E.164 format */
14117680Spst#define ATMARP_LEN_MASK 0x3F    /* length of {sub}address in type/length */
14217680Spst        u_short aar_op;         /* same as regular ARP */
14317680Spst        u_char  aar_spln;       /* length of source protocol address */
14417680Spst        u_char  aar_thtl;       /* length of target ATM number */
14517680Spst        u_char  aar_tstl;       /* length of target ATM subaddress */
14617680Spst        u_char  aar_tpln;       /* length of target protocol address */
14717680Spst/*
14817680Spst * The remaining fields are variable in size,
14917680Spst * according to the sizes above.
15017680Spst */
15117680Spst#ifdef COMMENT_ONLY
15217680Spst	u_char	aar_sha[];	/* source ATM number */
15317680Spst	u_char	aar_ssa[];	/* source ATM subaddress */
15417680Spst	u_char	aar_spa[];	/* sender protocol address */
15517680Spst	u_char	aar_tha[];	/* target ATM number */
15617680Spst	u_char	aar_tsa[];	/* target ATM subaddress */
15717680Spst	u_char	aar_tpa[];	/* target protocol address */
15817680Spst#endif
15917680Spst
16017680Spst#define ATMHRD(ap)  EXTRACT_16BITS(&(ap)->aar_hrd)
16117680Spst#define ATMSHRD_LEN(ap) ((ap)->aar_shtl & ATMARP_LEN_MASK)
16217680Spst#define ATMSSLN(ap) ((ap)->aar_sstl & ATMARP_LEN_MASK)
16317680Spst#define ATMSPROTO_LEN(ap) ((ap)->aar_spln)
16417680Spst#define ATMOP(ap)   EXTRACT_16BITS(&(ap)->aar_op)
16517680Spst#define ATMPRO(ap)  EXTRACT_16BITS(&(ap)->aar_pro)
16617680Spst#define ATMTHRD_LEN(ap) ((ap)->aar_thtl & ATMARP_LEN_MASK)
16717680Spst#define ATMTSLN(ap) ((ap)->aar_tstl & ATMARP_LEN_MASK)
16817680Spst#define ATMTPROTO_LEN(ap) ((ap)->aar_tpln)
16917680Spst#define aar_sha(ap)	((const u_char *)((ap)+1))
17017680Spst#define aar_ssa(ap)	(aar_sha(ap) + ATMSHRD_LEN(ap))
17117680Spst#define aar_spa(ap)	(aar_ssa(ap) + ATMSSLN(ap))
17217680Spst#define aar_tha(ap)	(aar_spa(ap) + ATMSPROTO_LEN(ap))
17317680Spst#define aar_tsa(ap)	(aar_tha(ap) + ATMTHRD_LEN(ap))
17417680Spst#define aar_tpa(ap)	(aar_tsa(ap) + ATMTSLN(ap))
17517680Spst};
17617680Spst
17717680Spst#define ATMSHA(ap) (aar_sha(ap))
17817680Spst#define ATMSSA(ap) (aar_ssa(ap))
17917680Spst#define ATMSPA(ap) (aar_spa(ap))
18017680Spst#define ATMTHA(ap) (aar_tha(ap))
18117680Spst#define ATMTSA(ap) (aar_tsa(ap))
18217680Spst#define ATMTPA(ap) (aar_tpa(ap))
18317680Spst
18417680Spststatic u_char ezero[6];
18517680Spst
18617680Spststatic void
18717680Spstatmarp_addr_print(netdissect_options *ndo,
18817680Spst		  const u_char *ha, u_int ha_len, const u_char *srca,
18917680Spst    u_int srca_len)
19017680Spst{
19117680Spst	if (ha_len == 0)
19217680Spst		ND_PRINT((ndo, "<No address>"));
19317680Spst	else {
19417680Spst		ND_PRINT((ndo, "%s", linkaddr_string(ha, LINKADDR_ATM, ha_len)));
19517680Spst		if (srca_len != 0)
19617680Spst			ND_PRINT((ndo, ",%s",
19717680Spst				  linkaddr_string(srca, LINKADDR_ATM, srca_len)));
19817680Spst	}
19917680Spst}
20017680Spst
20117680Spststatic void
20217680Spstatmarp_print(netdissect_options *ndo,
20317680Spst	     const u_char *bp, u_int length, u_int caplen)
20417680Spst{
20517680Spst	const struct atmarp_pkthdr *ap;
20617680Spst	u_short pro, hrd, op;
20717680Spst
20817680Spst	ap = (const struct atmarp_pkthdr *)bp;
20917680Spst	ND_TCHECK(*ap);
21017680Spst
21117680Spst	hrd = ATMHRD(ap);
21217680Spst	pro = ATMPRO(ap);
21317680Spst	op = ATMOP(ap);
21417680Spst
21517680Spst	if (!ND_TTEST2(*aar_tpa(ap), ATMTPROTO_LEN(ap))) {
21617680Spst		ND_PRINT((ndo, "[|ARP]"));
21717680Spst		ND_DEFAULTPRINT((const u_char *)ap, length);
21817680Spst		return;
21917680Spst	}
22017680Spst
22117680Spst        if (!ndo->ndo_eflag) {
22217680Spst            ND_PRINT((ndo, "ARP, "));
22317680Spst        }
22417680Spst
22517680Spst	if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) ||
22617680Spst	    ATMSPROTO_LEN(ap) != 4 ||
22717680Spst            ATMTPROTO_LEN(ap) != 4 ||
22817680Spst            ndo->ndo_vflag) {
22917680Spst                ND_PRINT((ndo, "%s, %s (len %u/%u)",
23017680Spst                          tok2str(arphrd_values, "Unknown Hardware (%u)", hrd),
23117680Spst                          tok2str(ethertype_values, "Unknown Protocol (0x%04x)", pro),
23217680Spst                          ATMSPROTO_LEN(ap),
23317680Spst                          ATMTPROTO_LEN(ap)));
23417680Spst
23517680Spst                /* don't know know about the address formats */
23617680Spst                if (!ndo->ndo_vflag) {
23717680Spst                    goto out;
23817680Spst                }
23917680Spst	}
24017680Spst
24117680Spst        /* print operation */
24217680Spst        printf("%s%s ",
24317680Spst               ndo->ndo_vflag ? ", " : "",
24417680Spst               tok2str(arpop_values, "Unknown (%u)", op));
24517680Spst
24617680Spst	switch (op) {
24717680Spst
24817680Spst	case ARPOP_REQUEST:
24917680Spst		ND_PRINT((ndo, "who-has %s", ipaddr_string(ATMTPA(ap))));
25017680Spst		if (ATMTHRD_LEN(ap) != 0) {
25117680Spst			ND_PRINT((ndo, " ("));
25217680Spst			atmarp_addr_print(ndo, ATMTHA(ap), ATMTHRD_LEN(ap),
25317680Spst			    ATMTSA(ap), ATMTSLN(ap));
25417680Spst			ND_PRINT((ndo, ")"));
25517680Spst		}
25617680Spst		ND_PRINT((ndo, "tell %s", ipaddr_string(ATMSPA(ap))));
25717680Spst		break;
25817680Spst
25917680Spst	case ARPOP_REPLY:
26017680Spst		ND_PRINT((ndo, "%s is-at ", ipaddr_string(ATMSPA(ap))));
26117680Spst		atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap),
26217680Spst                                  ATMSSLN(ap));
26317680Spst		break;
26417680Spst
26517680Spst	case ARPOP_INVREQUEST:
26617680Spst		ND_PRINT((ndo, "who-is "));
26717680Spst		atmarp_addr_print(ndo, ATMTHA(ap), ATMTHRD_LEN(ap), ATMTSA(ap),
26817680Spst		    ATMTSLN(ap));
26917680Spst		ND_PRINT((ndo, " tell "));
27017680Spst		atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap),
27117680Spst		    ATMSSLN(ap));
27217680Spst		break;
27317680Spst
27417680Spst	case ARPOP_INVREPLY:
27517680Spst		atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap),
27617680Spst		    ATMSSLN(ap));
27717680Spst		ND_PRINT((ndo, "at %s", ipaddr_string(ATMSPA(ap))));
27817680Spst		break;
27917680Spst
28017680Spst	case ARPOP_NAK:
28117680Spst		ND_PRINT((ndo, "for %s", ipaddr_string(ATMSPA(ap))));
28217680Spst		break;
28317680Spst
28426180Sfenner	default:
28517680Spst		ND_DEFAULTPRINT((const u_char *)ap, caplen);
28617680Spst		return;
28717680Spst	}
28817680Spst
28917680Spst out:
29017680Spst        ND_PRINT((ndo, ", length %u", length));
29117680Spst        return;
29217680Spst
29317680Spsttrunc:
29417680Spst	ND_PRINT((ndo, "[|ARP]"));
295}
296
297void
298arp_print(netdissect_options *ndo,
299	  const u_char *bp, u_int length, u_int caplen)
300{
301	const struct arp_pkthdr *ap;
302	u_short pro, hrd, op, linkaddr;
303
304	ap = (const struct arp_pkthdr *)bp;
305	ND_TCHECK(*ap);
306
307	hrd = HRD(ap);
308	pro = PRO(ap);
309	op = OP(ap);
310
311
312        /* if its ATM then call the ATM ARP printer
313           for Frame-relay ARP most of the fields
314           are similar to Ethernet so overload the Ethernet Printer
315           and set the linkaddr type for linkaddr_string() accordingly */
316
317        switch(hrd) {
318        case ARPHRD_ATM2225:
319            atmarp_print(ndo, bp, length, caplen);
320            return;
321        case ARPHRD_FRELAY:
322            linkaddr = LINKADDR_FRELAY;
323        default:
324            linkaddr = LINKADDR_ETHER;
325            break;
326	}
327
328	if (!ND_TTEST2(*ar_tpa(ap), PROTO_LEN(ap))) {
329		ND_PRINT((ndo, "[|ARP]"));
330		ND_DEFAULTPRINT((const u_char *)ap, length);
331		return;
332	}
333
334        if (!ndo->ndo_eflag) {
335            ND_PRINT((ndo, "ARP, "));
336        }
337
338        /* print hardware type/len and proto type/len */
339        if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) ||
340	    PROTO_LEN(ap) != 4 ||
341            HRD_LEN(ap) == 0 ||
342            ndo->ndo_vflag) {
343            ND_PRINT((ndo, "%s (len %u), %s (len %u)",
344                      tok2str(arphrd_values, "Unknown Hardware (%u)", hrd),
345                      HRD_LEN(ap),
346                      tok2str(ethertype_values, "Unknown Protocol (0x%04x)", pro),
347                      PROTO_LEN(ap)));
348
349            /* don't know know about the address formats */
350            if (!ndo->ndo_vflag) {
351                goto out;
352            }
353	}
354
355        /* print operation */
356        printf("%s%s ",
357               ndo->ndo_vflag ? ", " : "",
358               tok2str(arpop_values, "Unknown (%u)", op));
359
360	switch (op) {
361
362	case ARPOP_REQUEST:
363		ND_PRINT((ndo, "who-has %s", ipaddr_string(TPA(ap))));
364		if (memcmp((const char *)ezero, (const char *)THA(ap), HRD_LEN(ap)) != 0)
365			ND_PRINT((ndo, " (%s)",
366				  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap))));
367		ND_PRINT((ndo, " tell %s", ipaddr_string(SPA(ap))));
368		break;
369
370	case ARPOP_REPLY:
371		ND_PRINT((ndo, "%s is-at %s",
372                          ipaddr_string(SPA(ap)),
373                          linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap))));
374		break;
375
376	case ARPOP_REVREQUEST:
377		ND_PRINT((ndo, "who-is %s tell %s",
378			  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)),
379			  linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap))));
380		break;
381
382	case ARPOP_REVREPLY:
383		ND_PRINT((ndo, "%s at %s",
384			  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)),
385			  ipaddr_string(TPA(ap))));
386		break;
387
388	case ARPOP_INVREQUEST:
389		ND_PRINT((ndo, "who-is %s tell %s",
390			  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)),
391			  linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap))));
392		break;
393
394	case ARPOP_INVREPLY:
395		ND_PRINT((ndo,"%s at %s",
396			  linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)),
397			  ipaddr_string(TPA(ap))));
398		break;
399
400	default:
401		ND_DEFAULTPRINT((const u_char *)ap, caplen);
402		return;
403	}
404
405 out:
406        ND_PRINT((ndo, ", length %u", length));
407
408	return;
409trunc:
410	ND_PRINT((ndo, "[|ARP]"));
411}
412
413/*
414 * Local Variables:
415 * c-style: bsd
416 * End:
417 */
418
419