if_arp.c revision 1.76 1 /* $NetBSD: if_arp.c,v 1.76 2001/07/04 02:29:58 itojun Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Public Access Networks Corporation ("Panix"). It was developed under
9 * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Copyright (c) 1982, 1986, 1988, 1993
42 * The Regents of the University of California. All rights reserved.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
71 *
72 * @(#)if_ether.c 8.2 (Berkeley) 9/26/94
73 */
74
75 /*
76 * Ethernet address resolution protocol.
77 * TODO:
78 * add "inuse/lock" bit (or ref. count) along with valid bit
79 */
80
81 #include "opt_ddb.h"
82 #include "opt_inet.h"
83
84 #ifdef INET
85
86 #include <sys/param.h>
87 #include <sys/systm.h>
88 #include <sys/callout.h>
89 #include <sys/malloc.h>
90 #include <sys/mbuf.h>
91 #include <sys/socket.h>
92 #include <sys/time.h>
93 #include <sys/kernel.h>
94 #include <sys/errno.h>
95 #include <sys/ioctl.h>
96 #include <sys/syslog.h>
97 #include <sys/proc.h>
98 #include <sys/protosw.h>
99 #include <sys/domain.h>
100
101 #include <net/ethertypes.h>
102 #include <net/if.h>
103 #include <net/if_dl.h>
104 #include <net/if_token.h>
105 #include <net/if_types.h>
106 #include <net/route.h>
107
108
109 #include <netinet/in.h>
110 #include <netinet/in_systm.h>
111 #include <netinet/in_var.h>
112 #include <netinet/ip.h>
113 #include <netinet/if_inarp.h>
114
115 #include "loop.h"
116 #include "arc.h"
117 #if NARC > 0
118 #include <net/if_arc.h>
119 #endif
120 #include "fddi.h"
121 #if NFDDI > 0
122 #include <net/if_fddi.h>
123 #endif
124 #include "token.h"
125 #include "token.h"
126
127 #define SIN(s) ((struct sockaddr_in *)s)
128 #define SDL(s) ((struct sockaddr_dl *)s)
129 #define SRP(s) ((struct sockaddr_inarp *)s)
130
131 /*
132 * ARP trailer negotiation. Trailer protocol is not IP specific,
133 * but ARP request/response use IP addresses.
134 */
135 #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
136
137 /* timer values */
138 int arpt_prune = (5*60*1); /* walk list every 5 minutes */
139 int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
140 int arpt_down = 20; /* once declared down, don't send for 20 secs */
141 #define rt_expire rt_rmx.rmx_expire
142
143 static void arprequest __P((struct ifnet *,
144 struct in_addr *, struct in_addr *, u_int8_t *));
145 static void arptfree __P((struct llinfo_arp *));
146 static void arptimer __P((void *));
147 static struct llinfo_arp *arplookup __P((struct mbuf *, struct in_addr *,
148 int, int));
149 static void in_arpinput __P((struct mbuf *));
150
151 #if NLOOP > 0
152 extern struct ifnet loif[NLOOP];
153 #endif
154 LIST_HEAD(, llinfo_arp) llinfo_arp;
155 struct ifqueue arpintrq = {0, 0, 0, 50};
156 int arp_inuse, arp_allocated, arp_intimer;
157 int arp_maxtries = 5;
158 int useloopback = 1; /* use loopback interface for local traffic */
159 int arpinit_done = 0;
160
161 struct arpstat arpstat;
162 struct callout arptimer_ch;
163
164
165 /* revarp state */
166 static struct in_addr myip, srv_ip;
167 static int myip_initialized = 0;
168 static int revarp_in_progress = 0;
169 static struct ifnet *myip_ifp = NULL;
170
171 #ifdef DDB
172 static void db_print_sa __P((struct sockaddr *));
173 static void db_print_ifa __P((struct ifaddr *));
174 static void db_print_llinfo __P((caddr_t));
175 static int db_show_radix_node __P((struct radix_node *, void *));
176 #endif
177
178 /*
179 * this should be elsewhere.
180 */
181
182 static char *
183 lla_snprintf __P((u_int8_t *, int));
184
185 static char *
186 lla_snprintf(adrp, len)
187 u_int8_t *adrp;
188 int len;
189 {
190 #define NUMBUFS 3
191 static char buf[NUMBUFS][16*3];
192 static int bnum = 0;
193 static const char hexdigits[] = {
194 '0','1','2','3','4','5','6','7',
195 '8','9','a','b','c','d','e','f'
196 };
197
198 int i;
199 char *p;
200
201 p = buf[bnum];
202
203 *p++ = hexdigits[(*adrp)>>4];
204 *p++ = hexdigits[(*adrp++)&0xf];
205
206 for (i=1; i<len && i<16; i++) {
207 *p++ = ':';
208 *p++ = hexdigits[(*adrp)>>4];
209 *p++ = hexdigits[(*adrp++)&0xf];
210 }
211
212 *p = 0;
213 p = buf[bnum];
214 bnum = (bnum + 1) % NUMBUFS;
215 return p;
216 }
217
218 struct protosw arpsw[] = {
219 { 0, 0, 0, 0,
220 0, 0, 0, 0,
221 0,
222 0, 0, 0, arp_drain,
223 }
224 };
225
226
227 struct domain arpdomain =
228 { PF_ARP, "arp", 0, 0, 0,
229 arpsw, &arpsw[sizeof(arpsw)/sizeof(arpsw[0])]
230 };
231
232 /*
233 * ARP table locking.
234 *
235 * to prevent lossage vs. the arp_drain routine (which may be called at
236 * any time, including in a device driver context), we do two things:
237 *
238 * 1) manipulation of la->la_hold is done at splnet() (for all of
239 * about two instructions).
240 *
241 * 2) manipulation of the arp table's linked list is done under the
242 * protection of the ARP_LOCK; if arp_drain() or arptimer is called
243 * while the arp table is locked, we punt and try again later.
244 */
245
246 int arp_locked;
247
248 static __inline int arp_lock_try __P((int));
249 static __inline void arp_unlock __P((void));
250
251 static __inline int
252 arp_lock_try(int recurse)
253 {
254 int s;
255
256 /*
257 * Use splvm() -- we're blocking things that would cause
258 * mbuf allocation.
259 */
260 s = splvm();
261 if (!recurse && arp_locked) {
262 splx(s);
263 return (0);
264 }
265 arp_locked++;
266 splx(s);
267 return (1);
268 }
269
270 static __inline void
271 arp_unlock()
272 {
273 int s;
274
275 s = splvm();
276 arp_locked--;
277 splx(s);
278 }
279
280 #ifdef DIAGNOSTIC
281 #define ARP_LOCK(recurse) \
282 do { \
283 if (arp_lock_try(recurse) == 0) { \
284 printf("%s:%d: arp already locked\n", __FILE__, __LINE__); \
285 panic("arp_lock"); \
286 } \
287 } while (0)
288 #define ARP_LOCK_CHECK() \
289 do { \
290 if (arp_locked == 0) { \
291 printf("%s:%d: arp lock not held\n", __FILE__, __LINE__); \
292 panic("arp lock check"); \
293 } \
294 } while (0)
295 #else
296 #define ARP_LOCK(x) (void) arp_lock_try(x)
297 #define ARP_LOCK_CHECK() /* nothing */
298 #endif
299
300 #define ARP_UNLOCK() arp_unlock()
301
302 /*
303 * ARP protocol drain routine. Called when memory is in short supply.
304 * Called at splvm();
305 */
306
307 void
308 arp_drain()
309 {
310 struct llinfo_arp *la, *nla;
311 int count = 0;
312 struct mbuf *mold;
313
314 if (arp_lock_try(0) == 0) {
315 printf("arp_drain: locked; punting\n");
316 return;
317 }
318
319 for (la = LIST_FIRST(&llinfo_arp); la != 0; la = nla) {
320 nla = LIST_NEXT(la, la_list);
321
322 mold = la->la_hold;
323 la->la_hold = 0;
324
325 if (mold) {
326 m_freem(mold);
327 count++;
328 }
329 }
330 ARP_UNLOCK();
331 arpstat.as_dfrdropped += count;
332 }
333
334
335 /*
336 * Timeout routine. Age arp_tab entries periodically.
337 */
338 /* ARGSUSED */
339 static void
340 arptimer(arg)
341 void *arg;
342 {
343 int s;
344 struct llinfo_arp *la, *nla;
345
346 s = splsoftnet();
347
348 if (arp_lock_try(0) == 0) {
349 /* get it later.. */
350 splx(s);
351 return;
352 }
353
354 callout_reset(&arptimer_ch, arpt_prune * hz, arptimer, NULL);
355 for (la = LIST_FIRST(&llinfo_arp); la != 0; la = nla) {
356 struct rtentry *rt = la->la_rt;
357
358 nla = LIST_NEXT(la, la_list);
359 if (rt->rt_expire && rt->rt_expire <= time.tv_sec)
360 arptfree(la); /* timer has expired; clear */
361 }
362
363 ARP_UNLOCK();
364
365 splx(s);
366 }
367
368 /*
369 * Parallel to llc_rtrequest.
370 */
371 void
372 arp_rtrequest(req, rt, info)
373 int req;
374 struct rtentry *rt;
375 struct rt_addrinfo *info;
376 {
377 struct sockaddr *gate = rt->rt_gateway;
378 struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
379 static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
380 size_t allocsize;
381 struct mbuf *mold;
382 int s;
383 struct in_ifaddr *ia;
384 struct ifaddr *ifa;
385
386 if (!arpinit_done) {
387 arpinit_done = 1;
388 /*
389 * We generate expiration times from time.tv_sec
390 * so avoid accidently creating permanent routes.
391 */
392 if (time.tv_sec == 0) {
393 time.tv_sec++;
394 }
395 callout_init(&arptimer_ch);
396 callout_reset(&arptimer_ch, hz, arptimer, NULL);
397 }
398 if (rt->rt_flags & RTF_GATEWAY)
399 return;
400
401 ARP_LOCK(1); /* we may already be locked here. */
402
403 switch (req) {
404
405 case RTM_ADD:
406 /*
407 * XXX: If this is a manually added route to interface
408 * such as older version of routed or gated might provide,
409 * restore cloning bit.
410 */
411 if ((rt->rt_flags & RTF_HOST) == 0 &&
412 SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
413 rt->rt_flags |= RTF_CLONING;
414 if (rt->rt_flags & RTF_CLONING) {
415 /*
416 * Case 1: This route should come from a route to iface.
417 */
418 rt_setgate(rt, rt_key(rt),
419 (struct sockaddr *)&null_sdl);
420 gate = rt->rt_gateway;
421 SDL(gate)->sdl_type = rt->rt_ifp->if_type;
422 SDL(gate)->sdl_index = rt->rt_ifp->if_index;
423 /*
424 * Give this route an expiration time, even though
425 * it's a "permanent" route, so that routes cloned
426 * from it do not need their expiration time set.
427 */
428 rt->rt_expire = time.tv_sec;
429 #if NFDDI > 0
430 if (rt->rt_ifp->if_type == IFT_FDDI
431 && (rt->rt_rmx.rmx_mtu > FDDIIPMTU
432 || (rt->rt_rmx.rmx_mtu == 0
433 && rt->rt_ifp->if_mtu > FDDIIPMTU))) {
434 rt->rt_rmx.rmx_mtu = FDDIIPMTU;
435 }
436 #endif
437 #if NARC > 0
438 if (rt->rt_ifp->if_type == IFT_ARCNET) {
439 int arcipifmtu;
440
441 if (rt->rt_ifp->if_flags & IFF_LINK0)
442 arcipifmtu = arc_ipmtu;
443 else
444 arcipifmtu = ARCMTU;
445
446 if (rt->rt_rmx.rmx_mtu > arcipifmtu ||
447 (rt->rt_rmx.rmx_mtu == 0 &&
448 rt->rt_ifp->if_mtu > arcipifmtu))
449
450 rt->rt_rmx.rmx_mtu = arcipifmtu;
451 }
452 #endif
453 break;
454 }
455 /* Announce a new entry if requested. */
456 if (rt->rt_flags & RTF_ANNOUNCE)
457 arprequest(rt->rt_ifp,
458 &SIN(rt_key(rt))->sin_addr,
459 &SIN(rt_key(rt))->sin_addr,
460 (u_char *)LLADDR(SDL(gate)));
461 /*FALLTHROUGH*/
462 case RTM_RESOLVE:
463 if (gate->sa_family != AF_LINK ||
464 gate->sa_len < sizeof(null_sdl)) {
465 log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n");
466 break;
467 }
468 SDL(gate)->sdl_type = rt->rt_ifp->if_type;
469 SDL(gate)->sdl_index = rt->rt_ifp->if_index;
470 if (la != 0)
471 break; /* This happens on a route change */
472 /*
473 * Case 2: This route may come from cloning, or a manual route
474 * add with a LL address.
475 */
476 switch (SDL(gate)->sdl_type) {
477 #if NTOKEN > 0
478 case IFT_ISO88025:
479 allocsize = sizeof(*la) + sizeof(struct token_rif);
480 break;
481 #endif /* NTOKEN > 0 */
482 default:
483 allocsize = sizeof(*la);
484 }
485 R_Malloc(la, struct llinfo_arp *, allocsize);
486 rt->rt_llinfo = (caddr_t)la;
487 if (la == 0) {
488 log(LOG_DEBUG, "arp_rtrequest: malloc failed\n");
489 break;
490 }
491 arp_inuse++, arp_allocated++;
492 Bzero(la, allocsize);
493 la->la_rt = rt;
494 rt->rt_flags |= RTF_LLINFO;
495 LIST_INSERT_HEAD(&llinfo_arp, la, la_list);
496
497 INADDR_TO_IA(SIN(rt_key(rt))->sin_addr, ia);
498 while (ia && ia->ia_ifp != rt->rt_ifp)
499 NEXT_IA_WITH_SAME_ADDR(ia);
500 if (ia) {
501 /*
502 * This test used to be
503 * if (loif.if_flags & IFF_UP)
504 * It allowed local traffic to be forced through
505 * the hardware by configuring the loopback down.
506 * However, it causes problems during network
507 * configuration for boards that can't receive
508 * packets they send. It is now necessary to clear
509 * "useloopback" and remove the route to force
510 * traffic out to the hardware.
511 *
512 * In 4.4BSD, the above "if" statement checked
513 * rt->rt_ifa against rt_key(rt). It was changed
514 * to the current form so that we can provide a
515 * better support for multiple IPv4 addresses on a
516 * interface.
517 */
518 rt->rt_expire = 0;
519 Bcopy(LLADDR(rt->rt_ifp->if_sadl),
520 LLADDR(SDL(gate)),
521 SDL(gate)->sdl_alen =
522 rt->rt_ifp->if_data.ifi_addrlen);
523 #if NLOOP > 0
524 if (useloopback)
525 rt->rt_ifp = &loif[0];
526 #endif
527 /*
528 * make sure to set rt->rt_ifa to the interface
529 * address we are using, otherwise we will have trouble
530 * with source address selection.
531 */
532 ifa = &ia->ia_ifa;
533 if (ifa != rt->rt_ifa) {
534 IFAFREE(rt->rt_ifa);
535 IFAREF(ifa);
536 rt->rt_ifa = ifa;
537 }
538 }
539 break;
540
541 case RTM_DELETE:
542 if (la == 0)
543 break;
544 arp_inuse--;
545 LIST_REMOVE(la, la_list);
546 rt->rt_llinfo = 0;
547 rt->rt_flags &= ~RTF_LLINFO;
548
549 s = splnet();
550 mold = la->la_hold;
551 la->la_hold = 0;
552 splx(s);
553
554 if (mold)
555 m_freem(mold);
556
557 Free((caddr_t)la);
558 }
559 ARP_UNLOCK();
560 }
561
562 /*
563 * Broadcast an ARP request. Caller specifies:
564 * - arp header source ip address
565 * - arp header target ip address
566 * - arp header source ethernet address
567 */
568 static void
569 arprequest(ifp, sip, tip, enaddr)
570 struct ifnet *ifp;
571 struct in_addr *sip, *tip;
572 u_int8_t *enaddr;
573 {
574 struct mbuf *m;
575 struct arphdr *ah;
576 struct sockaddr sa;
577
578 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
579 return;
580 m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
581 2*ifp->if_data.ifi_addrlen;
582 m->m_pkthdr.len = m->m_len;
583 MH_ALIGN(m, m->m_len);
584 ah = mtod(m, struct arphdr *);
585 bzero((caddr_t)ah, m->m_len);
586 ah->ar_pro = htons(ETHERTYPE_IP);
587 ah->ar_hln = ifp->if_data.ifi_addrlen; /* hardware address length */
588 ah->ar_pln = sizeof(struct in_addr); /* protocol address length */
589 ah->ar_op = htons(ARPOP_REQUEST);
590 bcopy((caddr_t)enaddr, (caddr_t)ar_sha(ah), ah->ar_hln);
591 bcopy((caddr_t)sip, (caddr_t)ar_spa(ah), ah->ar_pln);
592 bcopy((caddr_t)tip, (caddr_t)ar_tpa(ah), ah->ar_pln);
593 sa.sa_family = AF_ARP;
594 sa.sa_len = 2;
595 m->m_flags |= M_BCAST;
596 arpstat.as_sndtotal++;
597 arpstat.as_sndrequest++;
598 (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
599 }
600
601 /*
602 * Resolve an IP address into an ethernet address. If success,
603 * desten is filled in. If there is no entry in arptab,
604 * set one up and broadcast a request for the IP address.
605 * Hold onto this mbuf and resend it once the address
606 * is finally resolved. A return value of 1 indicates
607 * that desten has been filled in and the packet should be sent
608 * normally; a 0 return indicates that the packet has been
609 * taken over here, either now or for later transmission.
610 */
611 int
612 arpresolve(ifp, rt, m, dst, desten)
613 struct ifnet *ifp;
614 struct rtentry *rt;
615 struct mbuf *m;
616 struct sockaddr *dst;
617 u_char *desten;
618 {
619 struct llinfo_arp *la;
620 struct sockaddr_dl *sdl;
621 struct mbuf *mold;
622 int s;
623
624 if (rt)
625 la = (struct llinfo_arp *)rt->rt_llinfo;
626 else {
627 if ((la = arplookup(m, &SIN(dst)->sin_addr, 1, 0)) != NULL)
628 rt = la->la_rt;
629 }
630 if (la == 0 || rt == 0) {
631 arpstat.as_allocfail++;
632 log(LOG_DEBUG,
633 "arpresolve: can't allocate llinfo on %s for %s\n",
634 ifp->if_xname, in_fmtaddr(SIN(dst)->sin_addr));
635 m_freem(m);
636 return (0);
637 }
638 sdl = SDL(rt->rt_gateway);
639 /*
640 * Check the address family and length is valid, the address
641 * is resolved; otherwise, try to resolve.
642 */
643 if ((rt->rt_expire == 0 || rt->rt_expire > time.tv_sec) &&
644 sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
645 bcopy(LLADDR(sdl), desten,
646 min(sdl->sdl_alen, ifp->if_data.ifi_addrlen));
647 return 1;
648 }
649 /*
650 * There is an arptab entry, but no ethernet address
651 * response yet. Replace the held mbuf with this
652 * latest one.
653 */
654
655 arpstat.as_dfrtotal++;
656 s = splnet();
657 mold = la->la_hold;
658 la->la_hold = m;
659 splx(s);
660
661 if (mold) {
662 arpstat.as_dfrdropped++;
663 m_freem(mold);
664 }
665
666 /*
667 * Re-send the ARP request when appropriate.
668 */
669 #ifdef DIAGNOSTIC
670 if (rt->rt_expire == 0) {
671 /* This should never happen. (Should it? -gwr) */
672 printf("arpresolve: unresolved and rt_expire == 0\n");
673 /* Set expiration time to now (expired). */
674 rt->rt_expire = time.tv_sec;
675 }
676 #endif
677 if (rt->rt_expire) {
678 rt->rt_flags &= ~RTF_REJECT;
679 if (la->la_asked == 0 || rt->rt_expire != time.tv_sec) {
680 rt->rt_expire = time.tv_sec;
681 if (la->la_asked++ < arp_maxtries)
682 arprequest(ifp,
683 &SIN(rt->rt_ifa->ifa_addr)->sin_addr,
684 &SIN(dst)->sin_addr,
685 LLADDR(ifp->if_sadl));
686 else {
687 rt->rt_flags |= RTF_REJECT;
688 rt->rt_expire += arpt_down;
689 la->la_asked = 0;
690 }
691 }
692 }
693 return (0);
694 }
695
696 /*
697 * Common length and type checks are done here,
698 * then the protocol-specific routine is called.
699 */
700 void
701 arpintr()
702 {
703 struct mbuf *m;
704 struct arphdr *ar;
705 int s;
706
707 while (arpintrq.ifq_head) {
708 s = splnet();
709 IF_DEQUEUE(&arpintrq, m);
710 splx(s);
711 if (m == 0 || (m->m_flags & M_PKTHDR) == 0)
712 panic("arpintr");
713
714 arpstat.as_rcvtotal++;
715
716 if (m->m_len >= sizeof(struct arphdr) &&
717 (ar = mtod(m, struct arphdr *)) &&
718 /* XXX ntohs(ar->ar_hrd) == ARPHRD_ETHER && */
719 m->m_len >=
720 sizeof(struct arphdr) + 2 * (ar->ar_hln + ar->ar_pln))
721 switch (ntohs(ar->ar_pro)) {
722
723 case ETHERTYPE_IP:
724 case ETHERTYPE_IPTRAILERS:
725 in_arpinput(m);
726 continue;
727 default:
728 arpstat.as_rcvbadproto++;
729 }
730 else
731 arpstat.as_rcvbadlen++;
732 m_freem(m);
733 }
734 }
735
736 /*
737 * ARP for Internet protocols on 10 Mb/s Ethernet.
738 * Algorithm is that given in RFC 826.
739 * In addition, a sanity check is performed on the sender
740 * protocol address, to catch impersonators.
741 * We no longer handle negotiations for use of trailer protocol:
742 * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
743 * along with IP replies if we wanted trailers sent to us,
744 * and also sent them in response to IP replies.
745 * This allowed either end to announce the desire to receive
746 * trailer packets.
747 * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
748 * but formerly didn't normally send requests.
749 */
750 static void
751 in_arpinput(m)
752 struct mbuf *m;
753 {
754 struct arphdr *ah;
755 struct ifnet *ifp = m->m_pkthdr.rcvif;
756 struct llinfo_arp *la = 0;
757 struct rtentry *rt;
758 struct in_ifaddr *ia;
759 struct sockaddr_dl *sdl;
760 struct sockaddr sa;
761 struct in_addr isaddr, itaddr, myaddr;
762 int op;
763 struct mbuf *mold;
764 int s;
765
766 ah = mtod(m, struct arphdr *);
767 op = ntohs(ah->ar_op);
768 bcopy((caddr_t)ar_spa(ah), (caddr_t)&isaddr, sizeof (isaddr));
769 bcopy((caddr_t)ar_tpa(ah), (caddr_t)&itaddr, sizeof (itaddr));
770
771 if (m->m_flags & (M_BCAST|M_MCAST))
772 arpstat.as_rcvmcast++;
773
774 /*
775 * If the target IP address is zero, ignore the packet.
776 * This prevents the code below from tring to answer
777 * when we are using IP address zero (booting).
778 */
779 if (in_nullhost(itaddr)) {
780 arpstat.as_rcvzerotpa++;
781 goto out;
782 }
783
784 /*
785 * If the source IP address is zero, this is most likely a
786 * confused host trying to use IP address zero. (Windoze?)
787 * XXX: Should we bother trying to reply to these?
788 */
789 if (in_nullhost(isaddr)) {
790 arpstat.as_rcvzerospa++;
791 goto out;
792 }
793
794 /*
795 * Search for a matching interface address
796 * or any address on the interface to use
797 * as a dummy address in the rest of this function
798 */
799 INADDR_TO_IA(itaddr, ia);
800 while ((ia != NULL) && ia->ia_ifp != m->m_pkthdr.rcvif)
801 NEXT_IA_WITH_SAME_ADDR(ia);
802
803 if (ia == NULL) {
804 INADDR_TO_IA(isaddr, ia);
805 while ((ia != NULL) && ia->ia_ifp != m->m_pkthdr.rcvif)
806 NEXT_IA_WITH_SAME_ADDR(ia);
807
808 if (ia == NULL) {
809 IFP_TO_IA(ifp, ia);
810 if (ia == NULL) {
811 arpstat.as_rcvnoint++;
812 goto out;
813 }
814 }
815 }
816
817 myaddr = ia->ia_addr.sin_addr;
818
819 if (!bcmp((caddr_t)ar_sha(ah), LLADDR(ifp->if_sadl),
820 ifp->if_data.ifi_addrlen)) {
821 arpstat.as_rcvlocalsha++;
822 goto out; /* it's from me, ignore it. */
823 }
824
825 if (!bcmp((caddr_t)ar_sha(ah), (caddr_t)ifp->if_broadcastaddr,
826 ifp->if_data.ifi_addrlen)) {
827 arpstat.as_rcvbcastsha++;
828 log(LOG_ERR,
829 "%s: arp: link address is broadcast for IP address %s!\n",
830 ifp->if_xname, in_fmtaddr(isaddr));
831 goto out;
832 }
833
834 if (in_hosteq(isaddr, myaddr)) {
835 arpstat.as_rcvlocalspa++;
836 log(LOG_ERR,
837 "duplicate IP address %s sent from link address %s\n",
838 in_fmtaddr(isaddr), lla_snprintf(ar_sha(ah), ah->ar_hln));
839 itaddr = myaddr;
840 goto reply;
841 }
842 la = arplookup(m, &isaddr, in_hosteq(itaddr, myaddr), 0);
843 if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
844 if (sdl->sdl_alen &&
845 bcmp((caddr_t)ar_sha(ah), LLADDR(sdl), sdl->sdl_alen)) {
846 if (rt->rt_flags & RTF_STATIC) {
847 arpstat.as_rcvoverperm++;
848 log(LOG_INFO,
849 "%s tried to overwrite permanent arp info"
850 " for %s\n",
851 lla_snprintf(ar_sha(ah), ah->ar_hln),
852 in_fmtaddr(isaddr));
853 goto out;
854 } else if (rt->rt_ifp != ifp) {
855 arpstat.as_rcvoverint++;
856 log(LOG_INFO,
857 "%s on %s tried to overwrite "
858 "arp info for %s on %s\n",
859 lla_snprintf(ar_sha(ah), ah->ar_hln),
860 ifp->if_xname, in_fmtaddr(isaddr),
861 rt->rt_ifp->if_xname);
862 goto out;
863 } else {
864 arpstat.as_rcvover++;
865 log(LOG_INFO,
866 "arp info overwritten for %s by %s\n",
867 in_fmtaddr(isaddr),
868 lla_snprintf(ar_sha(ah), ah->ar_hln));
869 }
870 }
871 /*
872 * sanity check for the address length.
873 * XXX this does not work for protocols with variable address
874 * length. -is
875 */
876 if (sdl->sdl_alen &&
877 sdl->sdl_alen != ah->ar_hln) {
878 arpstat.as_rcvlenchg++;
879 log(LOG_WARNING,
880 "arp from %s: new addr len %d, was %d",
881 in_fmtaddr(isaddr), ah->ar_hln, sdl->sdl_alen);
882 }
883 if (ifp->if_data.ifi_addrlen != ah->ar_hln) {
884 arpstat.as_rcvbadlen++;
885 log(LOG_WARNING,
886 "arp from %s: addr len: new %d, i/f %d (ignored)",
887 in_fmtaddr(isaddr), ah->ar_hln,
888 ifp->if_data.ifi_addrlen);
889 goto reply;
890 }
891 #if NTOKEN > 0
892 /*
893 * XXX uses m_data and assumes the complete answer including
894 * XXX token-ring headers is in the same buf
895 */
896 if (ifp->if_type == IFT_ISO88025) {
897 struct token_header *trh;
898
899 trh = (struct token_header *)M_TRHSTART(m);
900 if (trh->token_shost[0] & TOKEN_RI_PRESENT) {
901 struct token_rif *rif;
902 size_t riflen;
903
904 rif = TOKEN_RIF(trh);
905 riflen = (ntohs(rif->tr_rcf) &
906 TOKEN_RCF_LEN_MASK) >> 8;
907
908 if (riflen > 2 &&
909 riflen < sizeof(struct token_rif) &&
910 (riflen & 1) == 0) {
911 rif->tr_rcf ^= htons(TOKEN_RCF_DIRECTION);
912 rif->tr_rcf &= htons(~TOKEN_RCF_BROADCAST_MASK);
913 bcopy(rif, TOKEN_RIF(la), riflen);
914 }
915 }
916 }
917 #endif /* NTOKEN > 0 */
918 bcopy((caddr_t)ar_sha(ah), LLADDR(sdl),
919 sdl->sdl_alen = ah->ar_hln);
920 if (rt->rt_expire)
921 rt->rt_expire = time.tv_sec + arpt_keep;
922 rt->rt_flags &= ~RTF_REJECT;
923 la->la_asked = 0;
924
925 s = splnet();
926 mold = la->la_hold;
927 la->la_hold = 0;
928 splx(s);
929
930 if (mold) {
931 arpstat.as_dfrsent++;
932 (*ifp->if_output)(ifp, mold, rt_key(rt), rt);
933 }
934 }
935 reply:
936 if (op != ARPOP_REQUEST) {
937 if (op == ARPOP_REPLY)
938 arpstat.as_rcvreply++;
939 out:
940 m_freem(m);
941 return;
942 }
943 arpstat.as_rcvrequest++;
944 if (in_hosteq(itaddr, myaddr)) {
945 /* I am the target */
946 bcopy((caddr_t)ar_sha(ah), (caddr_t)ar_tha(ah), ah->ar_hln);
947 bcopy(LLADDR(ifp->if_sadl), (caddr_t)ar_sha(ah), ah->ar_hln);
948 } else {
949 la = arplookup(m, &itaddr, 0, SIN_PROXY);
950 if (la == 0)
951 goto out;
952 rt = la->la_rt;
953 bcopy((caddr_t)ar_sha(ah), (caddr_t)ar_tha(ah), ah->ar_hln);
954 sdl = SDL(rt->rt_gateway);
955 bcopy(LLADDR(sdl), (caddr_t)ar_sha(ah), ah->ar_hln);
956 }
957
958 bcopy((caddr_t)ar_spa(ah), (caddr_t)ar_tpa(ah), ah->ar_pln);
959 bcopy((caddr_t)&itaddr, (caddr_t)ar_spa(ah), ah->ar_pln);
960 ah->ar_op = htons(ARPOP_REPLY);
961 ah->ar_pro = htons(ETHERTYPE_IP); /* let's be sure! */
962 m->m_flags &= ~(M_BCAST|M_MCAST); /* never reply by broadcast */
963 m->m_len = sizeof(*ah) + (2 * ah->ar_pln) + (2 * ah->ar_hln);
964 m->m_pkthdr.len = m->m_len;
965 sa.sa_family = AF_ARP;
966 sa.sa_len = 2;
967 arpstat.as_sndtotal++;
968 arpstat.as_sndreply++;
969 (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
970 return;
971 }
972
973 /*
974 * Free an arp entry.
975 */
976 static void
977 arptfree(la)
978 struct llinfo_arp *la;
979 {
980 struct rtentry *rt = la->la_rt;
981 struct sockaddr_dl *sdl;
982
983 ARP_LOCK_CHECK();
984
985 if (rt == 0)
986 panic("arptfree");
987 if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
988 sdl->sdl_family == AF_LINK) {
989 sdl->sdl_alen = 0;
990 la->la_asked = 0;
991 rt->rt_flags &= ~RTF_REJECT;
992 return;
993 }
994 rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
995 0, (struct rtentry **)0);
996 }
997
998 /*
999 * Lookup or enter a new address in arptab.
1000 */
1001 static struct llinfo_arp *
1002 arplookup(m, addr, create, proxy)
1003 struct mbuf *m;
1004 struct in_addr *addr;
1005 int create, proxy;
1006 {
1007 struct arphdr *ah;
1008 struct ifnet *ifp = m->m_pkthdr.rcvif;
1009 struct rtentry *rt;
1010 static struct sockaddr_inarp sin;
1011 const char *why = 0;
1012
1013 ah = mtod(m, struct arphdr *);
1014 sin.sin_len = sizeof(sin);
1015 sin.sin_family = AF_INET;
1016 sin.sin_addr = *addr;
1017 sin.sin_other = proxy ? SIN_PROXY : 0;
1018 rt = rtalloc1(sintosa(&sin), create);
1019 if (rt == 0)
1020 return (0);
1021 rt->rt_refcnt--;
1022
1023 if (rt->rt_flags & RTF_GATEWAY)
1024 why = "host is not on local network";
1025 else if ((rt->rt_flags & RTF_LLINFO) == 0) {
1026 arpstat.as_allocfail++;
1027 why = "could not allocate llinfo";
1028 } else if (rt->rt_gateway->sa_family != AF_LINK)
1029 why = "gateway route is not ours";
1030 else
1031 return ((struct llinfo_arp *)rt->rt_llinfo);
1032
1033 if (create)
1034 log(LOG_DEBUG, "arplookup: unable to enter address"
1035 " for %s@%s on %s (%s)\n",
1036 in_fmtaddr(*addr), lla_snprintf(ar_sha(ah), ah->ar_hln),
1037 ifp->if_xname, why);
1038 return (0);
1039 }
1040
1041 int
1042 arpioctl(cmd, data)
1043 u_long cmd;
1044 caddr_t data;
1045 {
1046
1047 return (EOPNOTSUPP);
1048 }
1049
1050 void
1051 arp_ifinit(ifp, ifa)
1052 struct ifnet *ifp;
1053 struct ifaddr *ifa;
1054 {
1055 struct in_addr *ip;
1056
1057 /*
1058 * Warn the user if another station has this IP address,
1059 * but only if the interface IP address is not zero.
1060 */
1061 ip = &IA_SIN(ifa)->sin_addr;
1062 if (!in_nullhost(*ip))
1063 arprequest(ifp, ip, ip, LLADDR(ifp->if_sadl));
1064
1065 ifa->ifa_rtrequest = arp_rtrequest;
1066 ifa->ifa_flags |= RTF_CLONING;
1067 }
1068
1069 /*
1070 * Called from 10 Mb/s Ethernet interrupt handlers
1071 * when ether packet type ETHERTYPE_REVARP
1072 * is received. Common length and type checks are done here,
1073 * then the protocol-specific routine is called.
1074 */
1075 void
1076 revarpinput(m)
1077 struct mbuf *m;
1078 {
1079 struct arphdr *ar;
1080
1081 if (m->m_len < sizeof(struct arphdr))
1082 goto out;
1083 ar = mtod(m, struct arphdr *);
1084 #if 0 /* XXX I don't think we need this... and it will prevent other LL */
1085 if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
1086 goto out;
1087 #endif
1088 if (m->m_len < sizeof(struct arphdr) + 2 * (ar->ar_hln + ar->ar_pln))
1089 goto out;
1090 switch (ntohs(ar->ar_pro)) {
1091
1092 case ETHERTYPE_IP:
1093 case ETHERTYPE_IPTRAILERS:
1094 in_revarpinput(m);
1095 return;
1096
1097 default:
1098 break;
1099 }
1100 out:
1101 m_freem(m);
1102 }
1103
1104 /*
1105 * RARP for Internet protocols on 10 Mb/s Ethernet.
1106 * Algorithm is that given in RFC 903.
1107 * We are only using for bootstrap purposes to get an ip address for one of
1108 * our interfaces. Thus we support no user-interface.
1109 *
1110 * Since the contents of the RARP reply are specific to the interface that
1111 * sent the request, this code must ensure that they are properly associated.
1112 *
1113 * Note: also supports ARP via RARP packets, per the RFC.
1114 */
1115 void
1116 in_revarpinput(m)
1117 struct mbuf *m;
1118 {
1119 struct ifnet *ifp;
1120 struct arphdr *ah;
1121 int op;
1122
1123 ah = mtod(m, struct arphdr *);
1124 op = ntohs(ah->ar_op);
1125 switch (op) {
1126 case ARPOP_REQUEST:
1127 case ARPOP_REPLY: /* per RFC */
1128 in_arpinput(m);
1129 return;
1130 case ARPOP_REVREPLY:
1131 break;
1132 case ARPOP_REVREQUEST: /* handled by rarpd(8) */
1133 default:
1134 goto out;
1135 }
1136 if (!revarp_in_progress)
1137 goto out;
1138 ifp = m->m_pkthdr.rcvif;
1139 if (ifp != myip_ifp) /* !same interface */
1140 goto out;
1141 if (myip_initialized)
1142 goto wake;
1143 if (bcmp(ar_tha(ah), LLADDR(ifp->if_sadl), ifp->if_sadl->sdl_alen))
1144 goto out;
1145 bcopy((caddr_t)ar_spa(ah), (caddr_t)&srv_ip, sizeof(srv_ip));
1146 bcopy((caddr_t)ar_tpa(ah), (caddr_t)&myip, sizeof(myip));
1147 myip_initialized = 1;
1148 wake: /* Do wakeup every time in case it was missed. */
1149 wakeup((caddr_t)&myip);
1150
1151 out:
1152 m_freem(m);
1153 }
1154
1155 /*
1156 * Send a RARP request for the ip address of the specified interface.
1157 * The request should be RFC 903-compliant.
1158 */
1159 void
1160 revarprequest(ifp)
1161 struct ifnet *ifp;
1162 {
1163 struct sockaddr sa;
1164 struct mbuf *m;
1165 struct arphdr *ah;
1166
1167 if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
1168 return;
1169 m->m_len = sizeof(*ah) + 2*sizeof(struct in_addr) +
1170 2*ifp->if_data.ifi_addrlen;
1171 m->m_pkthdr.len = m->m_len;
1172 MH_ALIGN(m, m->m_len);
1173 ah = mtod(m, struct arphdr *);
1174 bzero((caddr_t)ah, m->m_len);
1175 ah->ar_pro = htons(ETHERTYPE_IP);
1176 ah->ar_hln = ifp->if_data.ifi_addrlen; /* hardware address length */
1177 ah->ar_pln = sizeof(struct in_addr); /* protocol address length */
1178 ah->ar_op = htons(ARPOP_REVREQUEST);
1179
1180 bcopy(LLADDR(ifp->if_sadl), (caddr_t)ar_sha(ah), ah->ar_hln);
1181 bcopy(LLADDR(ifp->if_sadl), (caddr_t)ar_tha(ah), ah->ar_hln);
1182
1183 sa.sa_family = AF_ARP;
1184 sa.sa_len = 2;
1185 m->m_flags |= M_BCAST;
1186 (*ifp->if_output)(ifp, m, &sa, (struct rtentry *)0);
1187
1188 }
1189
1190 /*
1191 * RARP for the ip address of the specified interface, but also
1192 * save the ip address of the server that sent the answer.
1193 * Timeout if no response is received.
1194 */
1195 int
1196 revarpwhoarewe(ifp, serv_in, clnt_in)
1197 struct ifnet *ifp;
1198 struct in_addr *serv_in;
1199 struct in_addr *clnt_in;
1200 {
1201 int result, count = 20;
1202
1203 myip_initialized = 0;
1204 myip_ifp = ifp;
1205
1206 revarp_in_progress = 1;
1207 while (count--) {
1208 revarprequest(ifp);
1209 result = tsleep((caddr_t)&myip, PSOCK, "revarp", hz/2);
1210 if (result != EWOULDBLOCK)
1211 break;
1212 }
1213 revarp_in_progress = 0;
1214
1215 if (!myip_initialized)
1216 return ENETUNREACH;
1217
1218 bcopy((caddr_t)&srv_ip, serv_in, sizeof(*serv_in));
1219 bcopy((caddr_t)&myip, clnt_in, sizeof(*clnt_in));
1220 return 0;
1221 }
1222
1223
1224
1226 #ifdef DDB
1227
1228 #include <machine/db_machdep.h>
1229 #include <ddb/db_interface.h>
1230 #include <ddb/db_output.h>
1231 static void
1232 db_print_sa(sa)
1233 struct sockaddr *sa;
1234 {
1235 int len;
1236 u_char *p;
1237
1238 if (sa == 0) {
1239 db_printf("[NULL]");
1240 return;
1241 }
1242
1243 p = (u_char*)sa;
1244 len = sa->sa_len;
1245 db_printf("[");
1246 while (len > 0) {
1247 db_printf("%d", *p);
1248 p++; len--;
1249 if (len) db_printf(",");
1250 }
1251 db_printf("]\n");
1252 }
1253 static void
1254 db_print_ifa(ifa)
1255 struct ifaddr *ifa;
1256 {
1257 if (ifa == 0)
1258 return;
1259 db_printf(" ifa_addr=");
1260 db_print_sa(ifa->ifa_addr);
1261 db_printf(" ifa_dsta=");
1262 db_print_sa(ifa->ifa_dstaddr);
1263 db_printf(" ifa_mask=");
1264 db_print_sa(ifa->ifa_netmask);
1265 db_printf(" flags=0x%x,refcnt=%d,metric=%d\n",
1266 ifa->ifa_flags,
1267 ifa->ifa_refcnt,
1268 ifa->ifa_metric);
1269 }
1270 static void
1271 db_print_llinfo(li)
1272 caddr_t li;
1273 {
1274 struct llinfo_arp *la;
1275
1276 if (li == 0)
1277 return;
1278 la = (struct llinfo_arp *)li;
1279 db_printf(" la_rt=%p la_hold=%p, la_asked=0x%lx\n",
1280 la->la_rt, la->la_hold, la->la_asked);
1281 }
1282 /*
1283 * Function to pass to rn_walktree().
1284 * Return non-zero error to abort walk.
1285 */
1286 static int
1287 db_show_radix_node(rn, w)
1288 struct radix_node *rn;
1289 void *w;
1290 {
1291 struct rtentry *rt = (struct rtentry *)rn;
1292
1293 db_printf("rtentry=%p", rt);
1294
1295 db_printf(" flags=0x%x refcnt=%d use=%ld expire=%ld\n",
1296 rt->rt_flags, rt->rt_refcnt,
1297 rt->rt_use, rt->rt_expire);
1298
1299 db_printf(" key="); db_print_sa(rt_key(rt));
1300 db_printf(" mask="); db_print_sa(rt_mask(rt));
1301 db_printf(" gw="); db_print_sa(rt->rt_gateway);
1302
1303 db_printf(" ifp=%p ", rt->rt_ifp);
1304 if (rt->rt_ifp)
1305 db_printf("(%s)", rt->rt_ifp->if_xname);
1306 else
1307 db_printf("(NULL)");
1308
1309 db_printf(" ifa=%p\n", rt->rt_ifa);
1310 db_print_ifa(rt->rt_ifa);
1311
1312 db_printf(" genmask="); db_print_sa(rt->rt_genmask);
1313
1314 db_printf(" gwroute=%p llinfo=%p\n",
1315 rt->rt_gwroute, rt->rt_llinfo);
1316 db_print_llinfo(rt->rt_llinfo);
1317
1318 return (0);
1319 }
1320 /*
1321 * Function to print all the route trees.
1322 * Use this from ddb: "show arptab"
1323 */
1324 void
1325 db_show_arptab(addr, have_addr, count, modif)
1326 db_expr_t addr;
1327 int have_addr;
1328 db_expr_t count;
1329 char * modif;
1330 {
1331 struct radix_node_head *rnh;
1332 rnh = rt_tables[AF_INET];
1333 db_printf("Route tree for AF_INET\n");
1334 if (rnh == NULL) {
1335 db_printf(" (not initialized)\n");
1336 return;
1337 }
1338 rn_walktree(rnh, db_show_radix_node, NULL);
1339 return;
1340 }
1341 #endif
1342 #endif /* INET */
1343
1344