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