117680Spst/* 239300Sfenner * 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. 2056896Sfenner * 2156896Sfenner * $FreeBSD$ 2217680Spst */ 2317680Spst 2417680Spst#ifndef lint 25127675Sbmsstatic const char rcsid[] _U_ = 26190207Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-arp.c,v 1.66 2006-03-03 22:53:21 hannes Exp $ (LBL)"; 2717680Spst#endif 2817680Spst 2956896Sfenner#ifdef HAVE_CONFIG_H 3056896Sfenner#include "config.h" 3156896Sfenner#endif 3256896Sfenner 33127675Sbms#include <tcpdump-stdinc.h> 3417680Spst 3517680Spst#include <stdio.h> 3617680Spst#include <string.h> 3717680Spst 38146778Ssam#include "netdissect.h" 3917680Spst#include "addrtoname.h" 4075118Sfenner#include "ether.h" 4117680Spst#include "ethertype.h" 4217680Spst#include "extract.h" /* must come after interface.h */ 4317680Spst 4475118Sfenner/* 4575118Sfenner * Address Resolution Protocol. 4675118Sfenner * 4775118Sfenner * See RFC 826 for protocol description. ARP packets are variable 4875118Sfenner * in size; the arphdr structure defines the fixed-length portion. 4975118Sfenner * Protocol type values are the same as those for 10 Mb/s Ethernet. 5075118Sfenner * It is followed by the variable-sized fields ar_sha, arp_spa, 5175118Sfenner * arp_tha and arp_tpa in that order, according to the lengths 5275118Sfenner * specified. Field names used correspond to RFC 826. 5375118Sfenner */ 54190207Srpaulostruct arp_pkthdr { 55190207Srpaulo u_short ar_hrd; /* format of hardware address */ 56190207Srpaulo#define ARPHRD_ETHER 1 /* ethernet hardware format */ 57190207Srpaulo#define ARPHRD_IEEE802 6 /* token-ring hardware format */ 58190207Srpaulo#define ARPHRD_ARCNET 7 /* arcnet hardware format */ 59190207Srpaulo#define ARPHRD_FRELAY 15 /* frame relay hardware format */ 60190207Srpaulo#define ARPHRD_ATM2225 19 /* ATM (RFC 2225) */ 61190207Srpaulo#define ARPHRD_STRIP 23 /* Ricochet Starmode Radio hardware format */ 62190207Srpaulo#define ARPHRD_IEEE1394 24 /* IEEE 1394 (FireWire) hardware format */ 63190207Srpaulo u_short ar_pro; /* format of protocol address */ 64190207Srpaulo u_char ar_hln; /* length of hardware address */ 65190207Srpaulo u_char ar_pln; /* length of protocol address */ 66190207Srpaulo u_short ar_op; /* one of: */ 67190207Srpaulo#define ARPOP_REQUEST 1 /* request to resolve address */ 68190207Srpaulo#define ARPOP_REPLY 2 /* response to previous request */ 69190207Srpaulo#define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ 70190207Srpaulo#define ARPOP_REVREPLY 4 /* response giving protocol address */ 71190207Srpaulo#define ARPOP_INVREQUEST 8 /* request to identify peer */ 72190207Srpaulo#define ARPOP_INVREPLY 9 /* response identifying peer */ 73190207Srpaulo#define ARPOP_NAK 10 /* NAK - only valif for ATM ARP */ 74190207Srpaulo 7575118Sfenner/* 7675118Sfenner * The remaining fields are variable in size, 7775118Sfenner * according to the sizes above. 7875118Sfenner */ 7975118Sfenner#ifdef COMMENT_ONLY 8075118Sfenner u_char ar_sha[]; /* sender hardware address */ 8175118Sfenner u_char ar_spa[]; /* sender protocol address */ 8275118Sfenner u_char ar_tha[]; /* target hardware address */ 8375118Sfenner u_char ar_tpa[]; /* target protocol address */ 8475118Sfenner#endif 85111729Sfenner#define ar_sha(ap) (((const u_char *)((ap)+1))+0) 86111729Sfenner#define ar_spa(ap) (((const u_char *)((ap)+1))+ (ap)->ar_hln) 87111729Sfenner#define ar_tha(ap) (((const u_char *)((ap)+1))+ (ap)->ar_hln+(ap)->ar_pln) 88111729Sfenner#define ar_tpa(ap) (((const u_char *)((ap)+1))+2*(ap)->ar_hln+(ap)->ar_pln) 8975118Sfenner}; 9075118Sfenner 9175118Sfenner#define ARP_HDRLEN 8 9275118Sfenner 93127675Sbms#define HRD(ap) EXTRACT_16BITS(&(ap)->ar_hrd) 94190207Srpaulo#define HRD_LEN(ap) ((ap)->ar_hln) 95190207Srpaulo#define PROTO_LEN(ap) ((ap)->ar_pln) 96127675Sbms#define OP(ap) EXTRACT_16BITS(&(ap)->ar_op) 97127675Sbms#define PRO(ap) EXTRACT_16BITS(&(ap)->ar_pro) 9898527Sfenner#define SHA(ap) (ar_sha(ap)) 9998527Sfenner#define SPA(ap) (ar_spa(ap)) 10098527Sfenner#define THA(ap) (ar_tha(ap)) 10198527Sfenner#define TPA(ap) (ar_tpa(ap)) 10275118Sfenner 103190207Srpaulo 104190207Srpaulostruct tok arpop_values[] = { 105190207Srpaulo { ARPOP_REQUEST, "Request" }, 106190207Srpaulo { ARPOP_REPLY, "Reply" }, 107190207Srpaulo { ARPOP_REVREQUEST, "Reverse Request" }, 108190207Srpaulo { ARPOP_REVREPLY, "Reverse Reply" }, 109190207Srpaulo { ARPOP_INVREQUEST, "Inverse Request" }, 110190207Srpaulo { ARPOP_INVREPLY, "Inverse Reply" }, 111190207Srpaulo { ARPOP_NAK, "NACK Reply" }, 112190207Srpaulo { 0, NULL } 113190207Srpaulo}; 114190207Srpaulo 115190207Srpaulostruct tok arphrd_values[] = { 116190207Srpaulo { ARPHRD_ETHER, "Ethernet" }, 117190207Srpaulo { ARPHRD_IEEE802, "TokenRing" }, 118190207Srpaulo { ARPHRD_ARCNET, "ArcNet" }, 119190207Srpaulo { ARPHRD_FRELAY, "FrameRelay" }, 120190207Srpaulo { ARPHRD_STRIP, "Strip" }, 121190207Srpaulo { ARPHRD_IEEE1394, "IEEE 1394" }, 122190207Srpaulo { ARPHRD_ATM2225, "ATM" }, 123190207Srpaulo { 0, NULL } 124190207Srpaulo}; 125190207Srpaulo 126127675Sbms/* 127127675Sbms * ATM Address Resolution Protocol. 128127675Sbms * 129127675Sbms * See RFC 2225 for protocol description. ATMARP packets are similar 130127675Sbms * to ARP packets, except that there are no length fields for the 131127675Sbms * protocol address - instead, there are type/length fields for 132127675Sbms * the ATM number and subaddress - and the hardware addresses consist 133127675Sbms * of an ATM number and an ATM subaddress. 134127675Sbms */ 135190207Srpaulostruct atmarp_pkthdr { 136190207Srpaulo u_short aar_hrd; /* format of hardware address */ 137190207Srpaulo u_short aar_pro; /* format of protocol address */ 138190207Srpaulo u_char aar_shtl; /* length of source ATM number */ 139190207Srpaulo u_char aar_sstl; /* length of source ATM subaddress */ 140190207Srpaulo#define ATMARP_IS_E164 0x40 /* bit in type/length for E.164 format */ 141190207Srpaulo#define ATMARP_LEN_MASK 0x3F /* length of {sub}address in type/length */ 142190207Srpaulo u_short aar_op; /* same as regular ARP */ 143190207Srpaulo u_char aar_spln; /* length of source protocol address */ 144190207Srpaulo u_char aar_thtl; /* length of target ATM number */ 145190207Srpaulo u_char aar_tstl; /* length of target ATM subaddress */ 146190207Srpaulo u_char aar_tpln; /* length of target protocol address */ 147127675Sbms/* 148127675Sbms * The remaining fields are variable in size, 149127675Sbms * according to the sizes above. 150127675Sbms */ 151127675Sbms#ifdef COMMENT_ONLY 152127675Sbms u_char aar_sha[]; /* source ATM number */ 153127675Sbms u_char aar_ssa[]; /* source ATM subaddress */ 154127675Sbms u_char aar_spa[]; /* sender protocol address */ 155127675Sbms u_char aar_tha[]; /* target ATM number */ 156127675Sbms u_char aar_tsa[]; /* target ATM subaddress */ 157127675Sbms u_char aar_tpa[]; /* target protocol address */ 158127675Sbms#endif 159127675Sbms 160127675Sbms#define ATMHRD(ap) EXTRACT_16BITS(&(ap)->aar_hrd) 161190207Srpaulo#define ATMSHRD_LEN(ap) ((ap)->aar_shtl & ATMARP_LEN_MASK) 162127675Sbms#define ATMSSLN(ap) ((ap)->aar_sstl & ATMARP_LEN_MASK) 163190207Srpaulo#define ATMSPROTO_LEN(ap) ((ap)->aar_spln) 164127675Sbms#define ATMOP(ap) EXTRACT_16BITS(&(ap)->aar_op) 165127675Sbms#define ATMPRO(ap) EXTRACT_16BITS(&(ap)->aar_pro) 166190207Srpaulo#define ATMTHRD_LEN(ap) ((ap)->aar_thtl & ATMARP_LEN_MASK) 167127675Sbms#define ATMTSLN(ap) ((ap)->aar_tstl & ATMARP_LEN_MASK) 168190207Srpaulo#define ATMTPROTO_LEN(ap) ((ap)->aar_tpln) 169127675Sbms#define aar_sha(ap) ((const u_char *)((ap)+1)) 170190207Srpaulo#define aar_ssa(ap) (aar_sha(ap) + ATMSHRD_LEN(ap)) 171127675Sbms#define aar_spa(ap) (aar_ssa(ap) + ATMSSLN(ap)) 172190207Srpaulo#define aar_tha(ap) (aar_spa(ap) + ATMSPROTO_LEN(ap)) 173190207Srpaulo#define aar_tsa(ap) (aar_tha(ap) + ATMTHRD_LEN(ap)) 174127675Sbms#define aar_tpa(ap) (aar_tsa(ap) + ATMTSLN(ap)) 175127675Sbms}; 176127675Sbms 177127675Sbms#define ATMSHA(ap) (aar_sha(ap)) 178127675Sbms#define ATMSSA(ap) (aar_ssa(ap)) 179127675Sbms#define ATMSPA(ap) (aar_spa(ap)) 180127675Sbms#define ATMTHA(ap) (aar_tha(ap)) 181127675Sbms#define ATMTSA(ap) (aar_tsa(ap)) 182127675Sbms#define ATMTPA(ap) (aar_tpa(ap)) 183127675Sbms 18417680Spststatic u_char ezero[6]; 18517680Spst 186127675Sbmsstatic void 187146778Ssamatmarp_addr_print(netdissect_options *ndo, 188146778Ssam const u_char *ha, u_int ha_len, const u_char *srca, 189127675Sbms u_int srca_len) 190127675Sbms{ 191127675Sbms if (ha_len == 0) 192146778Ssam ND_PRINT((ndo, "<No address>")); 193127675Sbms else { 194190207Srpaulo ND_PRINT((ndo, "%s", linkaddr_string(ha, LINKADDR_ATM, ha_len))); 195146778Ssam if (srca_len != 0) 196146778Ssam ND_PRINT((ndo, ",%s", 197190207Srpaulo linkaddr_string(srca, LINKADDR_ATM, srca_len))); 198127675Sbms } 199127675Sbms} 200127675Sbms 201127675Sbmsstatic void 202146778Ssamatmarp_print(netdissect_options *ndo, 203146778Ssam const u_char *bp, u_int length, u_int caplen) 204127675Sbms{ 205127675Sbms const struct atmarp_pkthdr *ap; 206127675Sbms u_short pro, hrd, op; 207127675Sbms 208127675Sbms ap = (const struct atmarp_pkthdr *)bp; 209146778Ssam ND_TCHECK(*ap); 210127675Sbms 211127675Sbms hrd = ATMHRD(ap); 212127675Sbms pro = ATMPRO(ap); 213127675Sbms op = ATMOP(ap); 214127675Sbms 215190207Srpaulo if (!ND_TTEST2(*aar_tpa(ap), ATMTPROTO_LEN(ap))) { 216190207Srpaulo ND_PRINT((ndo, "[|ARP]")); 217146778Ssam ND_DEFAULTPRINT((const u_char *)ap, length); 218127675Sbms return; 219127675Sbms } 220127675Sbms 221190207Srpaulo if (!ndo->ndo_eflag) { 222190207Srpaulo ND_PRINT((ndo, "ARP, ")); 223190207Srpaulo } 224190207Srpaulo 225127675Sbms if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) || 226190207Srpaulo ATMSPROTO_LEN(ap) != 4 || 227190207Srpaulo ATMTPROTO_LEN(ap) != 4 || 228190207Srpaulo ndo->ndo_vflag) { 229190207Srpaulo ND_PRINT((ndo, "%s, %s (len %u/%u)", 230190207Srpaulo tok2str(arphrd_values, "Unknown Hardware (%u)", hrd), 231190207Srpaulo tok2str(ethertype_values, "Unknown Protocol (0x%04x)", pro), 232190207Srpaulo ATMSPROTO_LEN(ap), 233190207Srpaulo ATMTPROTO_LEN(ap))); 234190207Srpaulo 235190207Srpaulo /* don't know know about the address formats */ 236190207Srpaulo if (!ndo->ndo_vflag) { 237190207Srpaulo goto out; 238190207Srpaulo } 239127675Sbms } 240190207Srpaulo 241190207Srpaulo /* print operation */ 242190207Srpaulo printf("%s%s ", 243190207Srpaulo ndo->ndo_vflag ? ", " : "", 244190207Srpaulo tok2str(arpop_values, "Unknown (%u)", op)); 245190207Srpaulo 246127675Sbms switch (op) { 247127675Sbms 248127675Sbms case ARPOP_REQUEST: 249190207Srpaulo ND_PRINT((ndo, "who-has %s", ipaddr_string(ATMTPA(ap)))); 250190207Srpaulo if (ATMTHRD_LEN(ap) != 0) { 251146778Ssam ND_PRINT((ndo, " (")); 252190207Srpaulo atmarp_addr_print(ndo, ATMTHA(ap), ATMTHRD_LEN(ap), 253127675Sbms ATMTSA(ap), ATMTSLN(ap)); 254146778Ssam ND_PRINT((ndo, ")")); 255127675Sbms } 256190207Srpaulo ND_PRINT((ndo, "tell %s", ipaddr_string(ATMSPA(ap)))); 257127675Sbms break; 258127675Sbms 259127675Sbms case ARPOP_REPLY: 260190207Srpaulo ND_PRINT((ndo, "%s is-at ", ipaddr_string(ATMSPA(ap)))); 261190207Srpaulo atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap), 262190207Srpaulo ATMSSLN(ap)); 263127675Sbms break; 264127675Sbms 265127675Sbms case ARPOP_INVREQUEST: 266190207Srpaulo ND_PRINT((ndo, "who-is ")); 267190207Srpaulo atmarp_addr_print(ndo, ATMTHA(ap), ATMTHRD_LEN(ap), ATMTSA(ap), 268127675Sbms ATMTSLN(ap)); 269146778Ssam ND_PRINT((ndo, " tell ")); 270190207Srpaulo atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap), 271127675Sbms ATMSSLN(ap)); 272127675Sbms break; 273127675Sbms 274127675Sbms case ARPOP_INVREPLY: 275190207Srpaulo atmarp_addr_print(ndo, ATMSHA(ap), ATMSHRD_LEN(ap), ATMSSA(ap), 276127675Sbms ATMSSLN(ap)); 277190207Srpaulo ND_PRINT((ndo, "at %s", ipaddr_string(ATMSPA(ap)))); 278127675Sbms break; 279127675Sbms 280190207Srpaulo case ARPOP_NAK: 281190207Srpaulo ND_PRINT((ndo, "for %s", ipaddr_string(ATMSPA(ap)))); 282127675Sbms break; 283127675Sbms 284127675Sbms default: 285146778Ssam ND_DEFAULTPRINT((const u_char *)ap, caplen); 286127675Sbms return; 287127675Sbms } 288190207Srpaulo 289190207Srpaulo out: 290190207Srpaulo ND_PRINT((ndo, ", length %u", length)); 291190207Srpaulo return; 292190207Srpaulo 293127675Sbmstrunc: 294190207Srpaulo ND_PRINT((ndo, "[|ARP]")); 295127675Sbms} 296127675Sbms 29717680Spstvoid 298146778Ssamarp_print(netdissect_options *ndo, 299146778Ssam const u_char *bp, u_int length, u_int caplen) 30017680Spst{ 301111729Sfenner const struct arp_pkthdr *ap; 302190207Srpaulo u_short pro, hrd, op, linkaddr; 30317680Spst 304111729Sfenner ap = (const struct arp_pkthdr *)bp; 305146778Ssam ND_TCHECK(*ap); 306190207Srpaulo 307127675Sbms hrd = HRD(ap); 308127675Sbms pro = PRO(ap); 309127675Sbms op = OP(ap); 310127675Sbms 311190207Srpaulo 312190207Srpaulo /* if its ATM then call the ATM ARP printer 313190207Srpaulo for Frame-relay ARP most of the fields 314190207Srpaulo are similar to Ethernet so overload the Ethernet Printer 315190207Srpaulo and set the linkaddr type for linkaddr_string() accordingly */ 316190207Srpaulo 317190207Srpaulo switch(hrd) { 318190207Srpaulo case ARPHRD_ATM2225: 319190207Srpaulo atmarp_print(ndo, bp, length, caplen); 320190207Srpaulo return; 321190207Srpaulo case ARPHRD_FRELAY: 322190207Srpaulo linkaddr = LINKADDR_FRELAY; 323235530Sdelphij break; 324190207Srpaulo default: 325190207Srpaulo linkaddr = LINKADDR_ETHER; 326190207Srpaulo break; 327190207Srpaulo } 328190207Srpaulo 329190207Srpaulo if (!ND_TTEST2(*ar_tpa(ap), PROTO_LEN(ap))) { 330190207Srpaulo ND_PRINT((ndo, "[|ARP]")); 331146778Ssam ND_DEFAULTPRINT((const u_char *)ap, length); 33217680Spst return; 33317680Spst } 33417680Spst 335190207Srpaulo if (!ndo->ndo_eflag) { 336190207Srpaulo ND_PRINT((ndo, "ARP, ")); 337190207Srpaulo } 338190207Srpaulo 339190207Srpaulo /* print hardware type/len and proto type/len */ 340190207Srpaulo if ((pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL) || 341190207Srpaulo PROTO_LEN(ap) != 4 || 342190207Srpaulo HRD_LEN(ap) == 0 || 343190207Srpaulo ndo->ndo_vflag) { 344190207Srpaulo ND_PRINT((ndo, "%s (len %u), %s (len %u)", 345190207Srpaulo tok2str(arphrd_values, "Unknown Hardware (%u)", hrd), 346190207Srpaulo HRD_LEN(ap), 347190207Srpaulo tok2str(ethertype_values, "Unknown Protocol (0x%04x)", pro), 348190207Srpaulo PROTO_LEN(ap))); 349190207Srpaulo 350190207Srpaulo /* don't know know about the address formats */ 351190207Srpaulo if (!ndo->ndo_vflag) { 352190207Srpaulo goto out; 353190207Srpaulo } 35417680Spst } 355190207Srpaulo 356190207Srpaulo /* print operation */ 357190207Srpaulo printf("%s%s ", 358190207Srpaulo ndo->ndo_vflag ? ", " : "", 359190207Srpaulo tok2str(arpop_values, "Unknown (%u)", op)); 360190207Srpaulo 36117680Spst switch (op) { 36217680Spst 36317680Spst case ARPOP_REQUEST: 364190207Srpaulo ND_PRINT((ndo, "who-has %s", ipaddr_string(TPA(ap)))); 365190207Srpaulo if (memcmp((const char *)ezero, (const char *)THA(ap), HRD_LEN(ap)) != 0) 366146778Ssam ND_PRINT((ndo, " (%s)", 367190207Srpaulo linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)))); 368146778Ssam ND_PRINT((ndo, " tell %s", ipaddr_string(SPA(ap)))); 36917680Spst break; 37017680Spst 37117680Spst case ARPOP_REPLY: 372190207Srpaulo ND_PRINT((ndo, "%s is-at %s", 373190207Srpaulo ipaddr_string(SPA(ap)), 374190207Srpaulo linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap)))); 37517680Spst break; 37617680Spst 37798527Sfenner case ARPOP_REVREQUEST: 378190207Srpaulo ND_PRINT((ndo, "who-is %s tell %s", 379190207Srpaulo linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), 380190207Srpaulo linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap)))); 38117680Spst break; 38217680Spst 38398527Sfenner case ARPOP_REVREPLY: 384190207Srpaulo ND_PRINT((ndo, "%s at %s", 385190207Srpaulo linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), 386146778Ssam ipaddr_string(TPA(ap)))); 38717680Spst break; 38817680Spst 389127675Sbms case ARPOP_INVREQUEST: 390190207Srpaulo ND_PRINT((ndo, "who-is %s tell %s", 391190207Srpaulo linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), 392190207Srpaulo linkaddr_string(SHA(ap), linkaddr, HRD_LEN(ap)))); 393127675Sbms break; 394127675Sbms 395127675Sbms case ARPOP_INVREPLY: 396190207Srpaulo ND_PRINT((ndo,"%s at %s", 397190207Srpaulo linkaddr_string(THA(ap), linkaddr, HRD_LEN(ap)), 398146778Ssam ipaddr_string(TPA(ap)))); 399127675Sbms break; 400127675Sbms 40117680Spst default: 402146778Ssam ND_DEFAULTPRINT((const u_char *)ap, caplen); 40317680Spst return; 40417680Spst } 405190207Srpaulo 406190207Srpaulo out: 407190207Srpaulo ND_PRINT((ndo, ", length %u", length)); 408190207Srpaulo 40998527Sfenner return; 41098527Sfennertrunc: 411190207Srpaulo ND_PRINT((ndo, "[|ARP]")); 41217680Spst} 413146778Ssam 414146778Ssam/* 415146778Ssam * Local Variables: 416146778Ssam * c-style: bsd 417146778Ssam * End: 418146778Ssam */ 419146778Ssam 420