]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/tcpip/v2_0/src/sys/netinet/if_ether.c
Initial revision
[karo-tx-redboot.git] / packages / net / tcpip / v2_0 / src / sys / netinet / if_ether.c
1 //==========================================================================
2 //
3 //      sys/netinet/if_ether.c
4 //
5 //     
6 //
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 //
12 // Portions of this software may have been derived from OpenBSD or other sources,
13 // and are covered by the appropriate copyright disclaimers included herein.
14 //
15 // -------------------------------------------
16 //
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
20 //
21 // Author(s):    gthomas
22 // Contributors: gthomas
23 // Date:         2000-01-10
24 // Purpose:      
25 // Description:  
26 //              
27 //
28 //####DESCRIPTIONEND####
29 //
30 //==========================================================================
31
32
33 /*      $OpenBSD: if_ether.c,v 1.19 1999/11/10 18:48:47 chris Exp $     */
34 /*      $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $    */
35
36 /*
37  * Copyright (c) 1982, 1986, 1988, 1993
38  *      The Regents of the University of California.  All rights reserved.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. All advertising materials mentioning features or use of this software
49  *    must display the following acknowledgement:
50  *      This product includes software developed by the University of
51  *      California, Berkeley and its contributors.
52  * 4. Neither the name of the University nor the names of its contributors
53  *    may be used to endorse or promote products derived from this software
54  *    without specific prior written permission.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66  * SUCH DAMAGE.
67  *
68  *      @(#)if_ether.c  8.1 (Berkeley) 6/10/93
69  */
70
71 /*
72  * Ethernet address resolution protocol.
73  * TODO:
74  *      add "inuse/lock" bit (or ref. count) along with valid bit
75  */
76
77 #include <sys/param.h>
78 #ifndef __ECOS
79 #include <sys/systm.h>
80 #endif
81 #include <sys/malloc.h>
82 #include <sys/mbuf.h>
83 #include <sys/socket.h>
84 #include <sys/time.h>
85 #include <sys/kernel.h>
86 #include <sys/errno.h>
87 #include <sys/ioctl.h>
88 #ifndef __ECOS
89 #include <sys/syslog.h>
90 #include <sys/proc.h>
91 #endif
92
93 #ifdef INET
94
95 #include <net/if.h>
96 #include <net/if_dl.h>
97 #include <net/route.h>
98
99 #include <netinet/in.h>
100 #include <netinet/in_systm.h>
101 #include <netinet/in_var.h>
102 #include <netinet/ip.h>
103 #include <netinet/if_ether.h>
104
105 #define SIN(s) ((struct sockaddr_in *)s)
106 #define SDL(s) ((struct sockaddr_dl *)s)
107 #define SRP(s) ((struct sockaddr_inarp *)s)
108
109 /*
110  * ARP trailer negotiation.  Trailer protocol is not IP specific,
111  * but ARP request/response use IP addresses.
112  */
113 #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
114
115 /* timer values */
116 int     arpt_prune = (5*60*1);  /* walk list every 5 minutes */
117 int     arpt_keep = (20*60);    /* once resolved, good for 20 more minutes */
118 int     arpt_down = 20;         /* once declared down, don't send for 20 secs */
119 #define rt_expire rt_rmx.rmx_expire
120
121 static  void arprequest
122             __P((struct arpcom *, u_int32_t *, u_int32_t *, u_int8_t *));
123 static  void arptfree __P((struct llinfo_arp *));
124 static  void arptimer __P((void *));
125 static  struct llinfo_arp *arplookup __P((u_int32_t, int, int));
126 static  void in_arpinput __P((struct mbuf *));
127
128 extern  struct ifnet loif;
129 LIST_HEAD(, llinfo_arp) llinfo_arp;
130 struct  ifqueue arpintrq = {0, 0, 0, 50};
131 int     arp_inuse, arp_allocated, arp_intimer;
132 int     arp_maxtries = 5;
133 int     useloopback = 1;        /* use loopback interface for local traffic */
134 int     arpinit_done = 0;
135
136 /* revarp state */
137 static struct in_addr myip, srv_ip;
138 static int myip_initialized = 0;
139 static int revarp_in_progress = 0;
140 struct ifnet *myip_ifp = NULL;
141
142 static void arptimer __P((void *));
143 static void arprequest __P((struct arpcom *, u_int32_t *, u_int32_t *,
144                             u_int8_t *));
145 static void in_arpinput __P((struct mbuf *));
146 static void arptfree __P((struct llinfo_arp *));
147 static struct llinfo_arp *arplookup __P((u_int32_t, int, int ));
148 #ifdef DDB
149 #include <vm/vm.h>
150
151 static void db_print_sa __P((struct sockaddr *));
152 static void db_print_ifa __P((struct ifaddr *));
153 static void db_print_llinfo __P((caddr_t));
154 static int db_show_radix_node __P((struct radix_node *, void *));
155 #endif
156
157 /*
158  * Timeout routine.  Age arp_tab entries periodically.
159  */
160 /* ARGSUSED */
161 static void
162 arptimer(arg)
163         void *arg;
164 {
165         int s;
166         register struct llinfo_arp *la, *nla;
167
168         s = splsoftnet();
169         timeout(arptimer, NULL, arpt_prune * hz);
170         for (la = llinfo_arp.lh_first; la != 0; la = nla) {
171                 register struct rtentry *rt = la->la_rt;
172
173                 nla = la->la_list.le_next;
174                 if (rt->rt_expire && rt->rt_expire <= time.tv_sec)
175                         arptfree(la); /* timer has expired; clear */
176         }
177         splx(s);
178 }
179
180 /*
181  * Parallel to llc_rtrequest.
182  */
183 void
184 arp_rtrequest(req, rt, sa)
185         int req;
186         register struct rtentry *rt;
187         struct sockaddr *sa;
188 {
189         register struct sockaddr *gate = rt->rt_gateway;
190         register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
191         static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
192
193         if (!arpinit_done) {
194                 arpinit_done = 1;
195                 /*
196                  * We generate expiration times from time.tv_sec
197                  * so avoid accidently creating permanent routes.
198                  */
199                 if (time.tv_sec == 0) {
200                         time.tv_sec++;
201                 }
202                 timeout(arptimer, (caddr_t)0, hz);
203         }
204         if (rt->rt_flags & RTF_GATEWAY)
205                 return;
206         switch (req) {
207
208         case RTM_ADD:
209                 /*
210                  * XXX: If this is a manually added route to interface
211                  * such as older version of routed or gated might provide,
212                  * restore cloning bit.
213                  */
214                 if ((rt->rt_flags & RTF_HOST) == 0 &&
215                     SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
216                         rt->rt_flags |= RTF_CLONING;
217                 if (rt->rt_flags & RTF_CLONING) {
218                         /*
219                          * Case 1: This route should come from a route to iface.
220                          */
221                         rt_setgate(rt, rt_key(rt),
222                                         (struct sockaddr *)&null_sdl);
223                         gate = rt->rt_gateway;
224                         SDL(gate)->sdl_type = rt->rt_ifp->if_type;
225                         SDL(gate)->sdl_index = rt->rt_ifp->if_index;
226                         /*
227                          * Give this route an expiration time, even though
228                          * it's a "permanent" route, so that routes cloned
229                          * from it do not need their expiration time set.
230                          */
231                         rt->rt_expire = time.tv_sec;
232                         break;
233                 }
234                 /* Announce a new entry if requested. */
235                 if (rt->rt_flags & RTF_ANNOUNCE)
236                         arprequest((struct arpcom *)rt->rt_ifp,
237                             &SIN(rt_key(rt))->sin_addr.s_addr,
238                             &SIN(rt_key(rt))->sin_addr.s_addr,
239                             (u_char *)LLADDR(SDL(gate)));
240                 /*FALLTHROUGH*/
241         case RTM_RESOLVE:
242                 if (gate->sa_family != AF_LINK ||
243                     gate->sa_len < sizeof(null_sdl)) {
244 #ifdef __ECOS
245 #else
246                         log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
247 #endif
248                         break;
249                 }
250                 SDL(gate)->sdl_type = rt->rt_ifp->if_type;
251                 SDL(gate)->sdl_index = rt->rt_ifp->if_index;
252                 if (la != 0)
253                         break; /* This happens on a route change */
254                 /*
255                  * Case 2:  This route may come from cloning, or a manual route
256                  * add with a LL address.
257                  */
258                 R_Malloc(la, struct llinfo_arp *, sizeof(*la));
259                 rt->rt_llinfo = (caddr_t)la;
260                 if (la == 0) {
261 #ifdef __ECOS
262 #else
263                         log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");
264 #endif
265                         break;
266                 }
267                 arp_inuse++, arp_allocated++;
268                 Bzero(la, sizeof(*la));
269                 la->la_rt = rt;
270                 rt->rt_flags |= RTF_LLINFO;
271                 LIST_INSERT_HEAD(&llinfo_arp, la, la_list);
272                 if (SIN(rt_key(rt))->sin_addr.s_addr ==
273                     (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) {
274                         /*
275                          * This test used to be
276                          *      if (loif.if_flags & IFF_UP)
277                          * It allowed local traffic to be forced through
278                          * the hardware by configuring the loopback down.
279                          * However, it causes problems during network
280                          * configuration for boards that can't receive
281                          * packets they send.  It is now necessary to clear
282                          * "useloopback" and remove the route to force
283                          * traffic out to the hardware.
284                          */
285                         rt->rt_expire = 0;
286                         Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr,
287                             LLADDR(SDL(gate)),
288                             SDL(gate)->sdl_alen = ETHER_ADDR_LEN);
289                         if (useloopback)
290                                 rt->rt_ifp = &loif;
291                 }
292                 break;
293
294         case RTM_DELETE:
295                 if (la == 0)
296                         break;
297                 arp_inuse--;
298                 LIST_REMOVE(la, la_list);
299                 rt->rt_llinfo = 0;
300                 rt->rt_flags &= ~RTF_LLINFO;
301                 if (la->la_hold)
302                         m_freem(la->la_hold);
303                 Free((caddr_t)la);
304         }
305 }
306
307 /*
308  * Broadcast an ARP request. Caller specifies:
309  *      - arp header source ip address
310  *      - arp header target ip address
311  *      - arp header source ethernet address
312  */
313 static void
314 arprequest(ac, sip, tip, enaddr)
315         register struct arpcom *ac;
316         register u_int32_t *sip, *tip;
317         register u_int8_t *enaddr;
318 {
319         register struct mbuf *m;
320         register struct ether_header *eh;
321         register struct ether_arp *ea;
322         struct sockaddr sa;
323
324         if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
325                 return;
326         m->m_len = sizeof(*ea);
327         m->m_pkthdr.len = sizeof(*ea);
328         MH_ALIGN(m, sizeof(*ea));
329         ea = mtod(m, struct ether_arp *);
330         eh = (struct ether_header *)sa.sa_data;
331         bzero((caddr_t)ea, sizeof (*ea));
332         bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
333             sizeof(eh->ether_dhost));
334         eh->ether_type = htons(ETHERTYPE_ARP);  /* if_output will not swap */
335         ea->arp_hrd = htons(ARPHRD_ETHER);
336         ea->arp_pro = htons(ETHERTYPE_IP);
337         ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
338         ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
339         ea->arp_op = htons(ARPOP_REQUEST);
340         bcopy((caddr_t)enaddr, (caddr_t)eh->ether_shost,
341               sizeof(eh->ether_shost));
342         bcopy((caddr_t)enaddr, (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
343         bcopy((caddr_t)sip, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
344         bcopy((caddr_t)tip, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
345         sa.sa_family = AF_UNSPEC;
346         sa.sa_len = sizeof(sa);
347         (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
348 }
349
350 /*
351  * Resolve an IP address into an ethernet address.  If success,
352  * desten is filled in.  If there is no entry in arptab,
353  * set one up and broadcast a request for the IP address.
354  * Hold onto this mbuf and resend it once the address
355  * is finally resolved.  A return value of 1 indicates
356  * that desten has been filled in and the packet should be sent
357  * normally; a 0 return indicates that the packet has been
358  * taken over here, either now or for later transmission.
359  */
360 int
361 arpresolve(ac, rt, m, dst, desten)
362         register struct arpcom *ac;
363         register struct rtentry *rt;
364         struct mbuf *m;
365         register struct sockaddr *dst;
366         register u_char *desten;
367 {
368         register struct llinfo_arp *la;
369         struct sockaddr_dl *sdl;
370
371         if (m->m_flags & M_BCAST) {     /* broadcast */
372                 bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
373                     sizeof(etherbroadcastaddr));
374                 return (1);
375         }
376         if (m->m_flags & M_MCAST) {     /* multicast */
377                 ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
378                 return (1);
379         }
380         if (rt)
381                 la = (struct llinfo_arp *)rt->rt_llinfo;
382         else {
383                 if ((la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0)) != NULL)
384                         rt = la->la_rt;
385         }
386         if (la == 0 || rt == 0) {
387 #ifdef __ECOS
388 #else
389                 log(LOG_DEBUG, "arpresolve: can't allocate llinfo\n");
390 #endif
391                 m_freem(m);
392                 return (0);
393         }
394         sdl = SDL(rt->rt_gateway);
395         /*
396          * Check the address family and length is valid, the address
397          * is resolved; otherwise, try to resolve.
398          */
399         if ((rt->rt_expire == 0 || rt->rt_expire > time.tv_sec) &&
400             sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
401                 bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
402                 return 1;
403         }
404         if (((struct ifnet *)ac)->if_flags & IFF_NOARP)
405                 return 0;
406
407         /*
408          * There is an arptab entry, but no ethernet address
409          * response yet.  Replace the held mbuf with this
410          * latest one.
411          */
412         if (la->la_hold)
413                 m_freem(la->la_hold);
414         la->la_hold = m;
415         /*
416          * Re-send the ARP request when appropriate.
417          */
418 #ifdef  DIAGNOSTIC
419         if (rt->rt_expire == 0) {
420                 /* This should never happen. (Should it? -gwr) */
421                 printf("arpresolve: unresolved and rt_expire == 0\n");
422                 /* Set expiration time to now (expired). */
423                 rt->rt_expire = time.tv_sec;
424         }
425 #endif
426         if (rt->rt_expire) {
427                 rt->rt_flags &= ~RTF_REJECT;
428                 if (la->la_asked == 0 || rt->rt_expire != time.tv_sec) {
429                         rt->rt_expire = time.tv_sec;
430                         if (la->la_asked++ < arp_maxtries)
431                                 arprequest(ac,
432                                     &(SIN(rt->rt_ifa->ifa_addr)->sin_addr.s_addr),
433                                     &(SIN(dst)->sin_addr.s_addr),
434                                     ac->ac_enaddr);
435                         else {
436                                 rt->rt_flags |= RTF_REJECT;
437                                 rt->rt_expire += arpt_down;
438                                 la->la_asked = 0;
439                         }
440                 }
441         }
442         return (0);
443 }
444
445 /*
446  * Common length and type checks are done here,
447  * then the protocol-specific routine is called.
448  */
449 void
450 arpintr()
451 {
452         register struct mbuf *m;
453         register struct arphdr *ar;
454         int s;
455
456         while (arpintrq.ifq_head) {
457                 s = splimp();
458                 IF_DEQUEUE(&arpintrq, m);
459                 splx(s);
460                 if (m == 0 || (m->m_flags & M_PKTHDR) == 0)
461                         panic("arpintr");
462                 if (m->m_len >= sizeof(struct arphdr) &&
463                     (ar = mtod(m, struct arphdr *)) &&
464                     ntohs(ar->ar_hrd) == ARPHRD_ETHER &&
465                     m->m_len >=
466                       sizeof(struct arphdr) + 2 * (ar->ar_hln + ar->ar_pln))
467                         switch (ntohs(ar->ar_pro)) {
468
469                         case ETHERTYPE_IP:
470                         case ETHERTYPE_IPTRAILERS:
471                                 in_arpinput(m);
472                                 continue;
473                         }
474                 m_freem(m);
475         }
476 }
477
478 /*
479  * ARP for Internet protocols on Ethernet.
480  * Algorithm is that given in RFC 826.
481  * In addition, a sanity check is performed on the sender
482  * protocol address, to catch impersonators.
483  * We no longer handle negotiations for use of trailer protocol:
484  * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
485  * along with IP replies if we wanted trailers sent to us,
486  * and also sent them in response to IP replies.
487  * This allowed either end to announce the desire to receive
488  * trailer packets.
489  * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
490  * but formerly didn't normally send requests.
491  */
492 static void
493 in_arpinput(m)
494         struct mbuf *m;
495 {
496         register struct ether_arp *ea;
497         register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif;
498         struct ether_header *eh;
499         register struct llinfo_arp *la = 0;
500         register struct rtentry *rt;
501         struct in_ifaddr *ia, *maybe_ia = 0;
502         struct sockaddr_dl *sdl;
503         struct sockaddr sa;
504         struct in_addr isaddr, itaddr, myaddr;
505         int op;
506
507         ea = mtod(m, struct ether_arp *);
508         op = ntohs(ea->arp_op);
509         bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
510         bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
511         for (ia = in_ifaddr.tqh_first; ia != 0; ia = ia->ia_list.tqe_next)
512                 if (ia->ia_ifp == &ac->ac_if ||
513                     (ia->ia_ifp->if_bridge &&
514                     ia->ia_ifp->if_bridge == ac->ac_if.if_bridge)) {
515                         maybe_ia = ia;
516                         if (itaddr.s_addr == ia->ia_addr.sin_addr.s_addr ||
517                             isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)
518                                 break;
519                 }
520         if (maybe_ia == 0)
521                 goto out;
522         myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
523         if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
524             sizeof (ea->arp_sha)))
525                 goto out;       /* it's from me, ignore it. */
526         if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
527             sizeof (ea->arp_sha))) {
528 #ifdef __ECOS
529 #else
530                 log(LOG_ERR,
531                     "arp: ether address is broadcast for IP address %s!\n",
532                     inet_ntoa(isaddr));
533 #endif
534                 goto out;
535         }
536         if (isaddr.s_addr == myaddr.s_addr) {
537 #ifdef __ECOS
538 #else
539                 log(LOG_ERR,
540                    "duplicate IP address %s sent from ethernet address %s\n",
541                    inet_ntoa(isaddr), ether_sprintf(ea->arp_sha));
542 #endif
543                 itaddr = myaddr;
544                 goto reply;
545         }
546         la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
547         if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
548                 if (sdl->sdl_alen &&
549                     bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen)) {
550                         if (rt->rt_flags & RTF_PERMANENT_ARP) {
551 #ifdef __ECOS
552 #else
553                                 log(LOG_WARNING,
554                                    "arp: attempt to overwrite permanent "
555                                    "entry for %s by %s on %s\n", 
556                                    inet_ntoa(isaddr),
557                                    ether_sprintf(ea->arp_sha),
558                                    (&ac->ac_if)->if_xname);
559 #endif
560                                 goto out;
561                         } else if (rt->rt_ifp != &ac->ac_if) {
562 #ifdef __ECOS
563 #else
564                                 log(LOG_WARNING,
565                                    "arp: attempt to overwrite entry for %s "
566                                    "on %s by %s on %s\n",
567                                    inet_ntoa(isaddr), rt->rt_ifp->if_xname,
568                                    ether_sprintf(ea->arp_sha),
569                                    (&ac->ac_if)->if_xname);
570 #endif
571                                 goto out;
572                         } else {
573 #ifdef __ECOS
574 #else
575                                 log(LOG_INFO,
576                                    "arp info overwritten for %s by %s on %s\n",
577                                    inet_ntoa(isaddr), 
578                                    ether_sprintf(ea->arp_sha),
579                                    (&ac->ac_if)->if_xname);
580 #endif
581                                 rt->rt_expire = 1; /* no longer static */
582                         }
583                 }
584                 bcopy((caddr_t)ea->arp_sha, LLADDR(sdl),
585                     sdl->sdl_alen = sizeof(ea->arp_sha));
586                 if (rt->rt_expire)
587                         rt->rt_expire = time.tv_sec + arpt_keep;
588                 rt->rt_flags &= ~RTF_REJECT;
589                 la->la_asked = 0;
590                 if (la->la_hold) {
591                         (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold,
592                                 rt_key(rt), rt);
593                         la->la_hold = 0;
594                 }
595         }
596 reply:
597         if (op != ARPOP_REQUEST) {
598         out:
599                 m_freem(m);
600                 return;
601         }
602         if (itaddr.s_addr == myaddr.s_addr) {
603                 /* I am the target */
604                 bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
605                     sizeof(ea->arp_sha));
606                 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
607                     sizeof(ea->arp_sha));
608         } else {
609                 la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
610                 if (la == 0)
611                         goto out;
612                 rt = la->la_rt;
613                 bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
614                     sizeof(ea->arp_sha));
615                 sdl = SDL(rt->rt_gateway);
616                 bcopy(LLADDR(sdl), (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
617         }
618
619         bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, sizeof(ea->arp_spa));
620         bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
621         ea->arp_op = htons(ARPOP_REPLY);
622         ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
623         eh = (struct ether_header *)sa.sa_data;
624         bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
625             sizeof(eh->ether_dhost));
626         bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
627             sizeof(eh->ether_shost));
628         eh->ether_type = htons(ETHERTYPE_ARP);
629         sa.sa_family = AF_UNSPEC;
630         sa.sa_len = sizeof(sa);
631         (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
632         return;
633 }
634
635 /*
636  * Free an arp entry.
637  */
638 static void
639 arptfree(la)
640         register struct llinfo_arp *la;
641 {
642         register struct rtentry *rt = la->la_rt;
643         register struct sockaddr_dl *sdl;
644
645         if (rt == 0)
646                 panic("arptfree");
647         if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
648             sdl->sdl_family == AF_LINK) {
649                 sdl->sdl_alen = 0;
650                 la->la_asked = 0;
651                 rt->rt_flags &= ~RTF_REJECT;
652                 return;
653         }
654         rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
655             0, (struct rtentry **)0);
656 }
657
658 /*
659  * Lookup or enter a new address in arptab.
660  */
661 static struct llinfo_arp *
662 arplookup(addr, create, proxy)
663         u_int32_t addr;
664         int create, proxy;
665 {
666         register struct rtentry *rt;
667         static struct sockaddr_inarp sin;
668
669         sin.sin_len = sizeof(sin);
670         sin.sin_family = AF_INET;
671         sin.sin_addr.s_addr = addr;
672         sin.sin_other = proxy ? SIN_PROXY : 0;
673         rt = rtalloc1(sintosa(&sin), create);
674         if (rt == 0)
675                 return (0);
676         rt->rt_refcnt--;
677         if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||
678             rt->rt_gateway->sa_family != AF_LINK) {
679                 if (create)
680 #ifdef __ECOS
681 #else
682                         log(LOG_DEBUG,
683                             "arplookup: unable to enter address for %s\n",
684                             inet_ntoa(sin.sin_addr));
685 #endif
686                 return (0);
687         }
688         return ((struct llinfo_arp *)rt->rt_llinfo);
689 }
690
691 int
692 arpioctl(cmd, data)
693         u_long cmd;
694         caddr_t data;
695 {
696
697         return (EOPNOTSUPP);
698 }
699
700 void
701 arp_ifinit(ac, ifa)
702         struct arpcom *ac;
703         struct ifaddr *ifa;
704 {
705
706         /* Warn the user if another station has this IP address. */
707         arprequest(ac,
708             &(IA_SIN(ifa)->sin_addr.s_addr),
709             &(IA_SIN(ifa)->sin_addr.s_addr),
710             ac->ac_enaddr);
711         ifa->ifa_rtrequest = arp_rtrequest;
712         ifa->ifa_flags |= RTF_CLONING;
713 }
714
715 /*
716  * Called from Ethernet interrupt handlers
717  * when ether packet type ETHERTYPE_REVARP
718  * is received.  Common length and type checks are done here,
719  * then the protocol-specific routine is called.
720  */
721 void
722 revarpinput(m)
723         struct mbuf *m;
724 {
725         struct arphdr *ar;
726
727         if (m->m_len < sizeof(struct arphdr))
728                 goto out;
729         ar = mtod(m, struct arphdr *);
730         if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
731                 goto out;
732         if (m->m_len < sizeof(struct arphdr) + 2 * (ar->ar_hln + ar->ar_pln))
733                 goto out;
734         switch (ntohs(ar->ar_pro)) {
735
736         case ETHERTYPE_IP:
737         case ETHERTYPE_IPTRAILERS:
738                 in_revarpinput(m);
739                 return;
740
741         default:
742                 break;
743         }
744 out:
745         m_freem(m);
746 }
747
748 /*
749  * RARP for Internet protocols on Ethernet.
750  * Algorithm is that given in RFC 903.
751  * We are only using for bootstrap purposes to get an ip address for one of
752  * our interfaces.  Thus we support no user-interface.
753  *
754  * Since the contents of the RARP reply are specific to the interface that
755  * sent the request, this code must ensure that they are properly associated.
756  *
757  * Note: also supports ARP via RARP packets, per the RFC.
758  */
759 void
760 in_revarpinput(m)
761         struct mbuf *m;
762 {
763         struct ifnet *ifp;
764         struct ether_arp *ar;
765         int op;
766
767         ar = mtod(m, struct ether_arp *);
768         op = ntohs(ar->arp_op);
769         switch (op) {
770         case ARPOP_REQUEST:
771         case ARPOP_REPLY:       /* per RFC */
772                 in_arpinput(m);
773                 return;
774         case ARPOP_REVREPLY:
775                 break;
776         case ARPOP_REVREQUEST:  /* handled by rarpd(8) */
777         default:
778                 goto out;
779         }
780         if (!revarp_in_progress)
781                 goto out;
782         ifp = m->m_pkthdr.rcvif;
783         if (ifp != myip_ifp) /* !same interface */
784                 goto out;
785         if (myip_initialized)
786                 goto wake;
787         if (bcmp(ar->arp_tha, ((struct arpcom *)ifp)->ac_enaddr,
788             sizeof(ar->arp_tha)))
789                 goto out;
790         bcopy((caddr_t)ar->arp_spa, (caddr_t)&srv_ip, sizeof(srv_ip));
791         bcopy((caddr_t)ar->arp_tpa, (caddr_t)&myip, sizeof(myip));
792         myip_initialized = 1;
793 wake:   /* Do wakeup every time in case it was missed. */
794         wakeup((caddr_t)&myip);
795
796 out:
797         m_freem(m);
798 }
799
800 /*
801  * Send a RARP request for the ip address of the specified interface.
802  * The request should be RFC 903-compliant.
803  */
804 void
805 revarprequest(ifp)
806         struct ifnet *ifp;
807 {
808         struct sockaddr sa;
809         struct mbuf *m;
810         struct ether_header *eh;
811         struct ether_arp *ea;
812         struct arpcom *ac = (struct arpcom *)ifp;
813
814         if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
815                 return;
816         m->m_len = sizeof(*ea);
817         m->m_pkthdr.len = sizeof(*ea);
818         MH_ALIGN(m, sizeof(*ea));
819         ea = mtod(m, struct ether_arp *);
820         eh = (struct ether_header *)sa.sa_data;
821         bzero((caddr_t)ea, sizeof(*ea));
822         bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
823             sizeof(eh->ether_dhost));
824         eh->ether_type = htons(ETHERTYPE_REVARP);
825         ea->arp_hrd = htons(ARPHRD_ETHER);
826         ea->arp_pro = htons(ETHERTYPE_IP);
827         ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
828         ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
829         ea->arp_op = htons(ARPOP_REVREQUEST);
830         bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
831            sizeof(ea->arp_tha));
832         bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
833            sizeof(ea->arp_sha));
834         bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_tha,
835            sizeof(ea->arp_tha));
836         sa.sa_family = AF_UNSPEC;
837         sa.sa_len = sizeof(sa);
838         ifp->if_output(ifp, m, &sa, (struct rtentry *)0);
839 }
840
841 /*
842  * RARP for the ip address of the specified interface, but also
843  * save the ip address of the server that sent the answer.
844  * Timeout if no response is received.
845  */
846 int
847 revarpwhoarewe(ifp, serv_in, clnt_in)
848         struct ifnet *ifp;
849         struct in_addr *serv_in;
850         struct in_addr *clnt_in;
851 {
852         int result, count = 20;
853         
854         if (myip_initialized) 
855                 return EIO;
856
857         myip_ifp = ifp;
858         revarp_in_progress = 1;
859         while (count--) {
860                 revarprequest(ifp);
861                 result = tsleep((caddr_t)&myip, PSOCK, "revarp", hz/2);
862                 if (result != EWOULDBLOCK)
863                         break;
864         }
865         revarp_in_progress = 0;
866         if (!myip_initialized)
867                 return ENETUNREACH;
868         
869         bcopy((caddr_t)&srv_ip, serv_in, sizeof(*serv_in));
870         bcopy((caddr_t)&myip, clnt_in, sizeof(*clnt_in));
871         return 0;
872 }
873
874 /* For compatibility: only saves interface address. */
875 int
876 revarpwhoami(in, ifp)
877         struct in_addr *in;
878         struct ifnet *ifp;
879 {
880         struct in_addr server;
881         return (revarpwhoarewe(ifp, &server, in));
882 }
883 \f
884
885 #ifdef DDB
886
887 #include <machine/db_machdep.h>
888 #include <ddb/db_interface.h>
889 #include <ddb/db_output.h>
890
891 static void
892 db_print_sa(sa)
893         struct sockaddr *sa;
894 {
895         int len;
896         u_char *p;
897
898         if (sa == 0) {
899                 db_printf("[NULL]");
900                 return;
901         }
902
903         p = (u_char*)sa;
904         len = sa->sa_len;
905         db_printf("[");
906         while (len > 0) {
907                 db_printf("%d", *p);
908                 p++;
909                 len--;
910                 if (len)
911                         db_printf(",");
912         }
913         db_printf("]\n");
914 }
915
916 static void
917 db_print_ifa(ifa)
918         struct ifaddr *ifa;
919 {
920         if (ifa == 0)
921                 return;
922         db_printf("  ifa_addr=");
923         db_print_sa(ifa->ifa_addr);
924         db_printf("  ifa_dsta=");
925         db_print_sa(ifa->ifa_dstaddr);
926         db_printf("  ifa_mask=");
927         db_print_sa(ifa->ifa_netmask);
928         db_printf("  flags=0x%x, refcnt=%d, metric=%d\n",
929             ifa->ifa_flags, ifa->ifa_refcnt, ifa->ifa_metric);
930 }
931
932 static void
933 db_print_llinfo(li)
934         caddr_t li;
935 {
936         struct llinfo_arp *la;
937
938         if (li == 0)
939                 return;
940         la = (struct llinfo_arp *)li;
941         db_printf("  la_rt=%p la_hold=%p, la_asked=0x%lx\n",
942             la->la_rt, la->la_hold, la->la_asked);
943 }
944
945 /*
946  * Function to pass to rn_walktree().
947  * Return non-zero error to abort walk.
948  */
949 static int
950 db_show_radix_node(rn, w)
951         struct radix_node *rn;
952         void *w;
953 {
954         struct rtentry *rt = (struct rtentry *)rn;
955
956         db_printf("rtentry=%p", rt);
957
958         db_printf(" flags=0x%x refcnt=%d use=%ld expire=%ld\n",
959             rt->rt_flags, rt->rt_refcnt, rt->rt_use, rt->rt_expire);
960
961         db_printf(" key="); db_print_sa(rt_key(rt));
962         db_printf(" mask="); db_print_sa(rt_mask(rt));
963         db_printf(" gw="); db_print_sa(rt->rt_gateway);
964
965         db_printf(" ifp=%p ", rt->rt_ifp);
966         if (rt->rt_ifp)
967                 db_printf("(%s)", rt->rt_ifp->if_xname);
968         else
969                 db_printf("(NULL)");
970
971         db_printf(" ifa=%p\n", rt->rt_ifa);
972         db_print_ifa(rt->rt_ifa);
973
974         db_printf(" genmask="); db_print_sa(rt->rt_genmask);
975
976         db_printf(" gwroute=%p llinfo=%p\n", rt->rt_gwroute, rt->rt_llinfo);
977         db_print_llinfo(rt->rt_llinfo);
978         return (0);
979 }
980
981 /*
982  * Function to print all the route trees.
983  * Use this from ddb:  "call db_show_arptab"
984  */
985 int
986 db_show_arptab()
987 {
988         struct radix_node_head *rnh;
989         rnh = rt_tables[AF_INET];
990         db_printf("Route tree for AF_INET\n");
991         if (rnh == NULL) {
992                 db_printf(" (not initialized)\n");
993                 return (0);
994         }
995         rn_walktree(rnh, db_show_radix_node, NULL);
996         return (0);
997 }
998 #endif
999 #endif /* INET */