X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/0880b18ef40ee52f08a23527900e6354275bcc33..d0461c724668ffddd1d106cccde57f7a41631355:/usr/src/sys/netinet/if_ether.c diff --git a/usr/src/sys/netinet/if_ether.c b/usr/src/sys/netinet/if_ether.c index 2453524abe..28dd53dcd3 100644 --- a/usr/src/sys/netinet/if_ether.c +++ b/usr/src/sys/netinet/if_ether.c @@ -1,17 +1,33 @@ /* - * Copyright (c) 1982, 1986 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. + * Copyright (c) 1982, 1986, 1988 Regents of the University of California. + * All rights reserved. * - * @(#)if_ether.c 7.1 (Berkeley) %G% + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)if_ether.c 7.10 (Berkeley) %G% */ /* * Ethernet address resolution protocol. + * TODO: + * run at splnet (add ARP protocol intr.) + * link entries onto hash chains, keep free list + * add "inuse/lock" bit (or ref. count) along with valid bit */ #include "param.h" #include "systm.h" +#include "malloc.h" #include "mbuf.h" #include "socket.h" #include "time.h" @@ -23,11 +39,17 @@ #include "../net/if.h" #include "in.h" #include "in_systm.h" +#include "in_var.h" #include "ip.h" #include "if_ether.h" +#ifdef GATEWAY +#define ARPTAB_BSIZ 16 /* bucket size */ +#define ARPTAB_NB 37 /* number of buckets */ +#else #define ARPTAB_BSIZ 9 /* bucket size */ #define ARPTAB_NB 19 /* number of buckets */ +#endif #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB) struct arptab arptab[ARPTAB_SIZE]; int arptab_size = ARPTAB_SIZE; /* for arp command */ @@ -56,7 +78,6 @@ int arptab_size = ARPTAB_SIZE; /* for arp command */ #define ARPT_KILLC 20 /* kill completed entry in 20 mins. */ #define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */ -u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; extern struct ifnet loif; /* @@ -92,10 +113,11 @@ arpwhohas(ac, addr) register struct ether_arp *ea; struct sockaddr sa; - if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL) + if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL) return; - m->m_len = sizeof *ea; - m->m_off = MMAXOFF - m->m_len; + m->m_len = sizeof(*ea); + m->m_pkthdr.len = sizeof(*ea); + MH_ALIGN(m, sizeof(*ea)); ea = mtod(m, struct ether_arp *); eh = (struct ether_header *)sa.sa_data; bzero((caddr_t)ea, sizeof (*ea)); @@ -113,9 +135,14 @@ arpwhohas(ac, addr) sizeof(ea->arp_spa)); bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa)); sa.sa_family = AF_UNSPEC; + sa.sa_len = sizeof(sa); (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); } +int useloopback = 1; /* use loopback interface for local traffic */ + +int useloopback = 1; /* use loopback interface for local traffic */ + /* * Resolve an IP address into an ethernet address. If success, * desten is filled in. If there is no entry in arptab, @@ -138,21 +165,33 @@ arpresolve(ac, m, destip, desten, usetrailers) int *usetrailers; { register struct arptab *at; - register struct ifnet *ifp; struct sockaddr_in sin; - int s, lna; + register struct in_ifaddr *ia; + u_long lna; + int s; *usetrailers = 0; - if (in_broadcast(*destip)) { /* broadcast address */ + if (m->m_flags & M_BCAST) { /* broadcast */ bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten, sizeof(etherbroadcastaddr)); return (1); } lna = in_lnaof(*destip); - ifp = &ac->ac_if; /* if for us, use software loopback driver if up */ - if (destip->s_addr == ac->ac_ipaddr.s_addr) { - if (loif.if_flags & IFF_UP) { + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if ((ia->ia_ifp == &ac->ac_if) && + (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) { + /* + * This test used to be + * if (loif.if_flags & IFF_UP) + * It allowed local traffic to be forced + * through the hardware by configuring the loopback down. + * However, it causes problems during network configuration + * for boards that can't receive packets they send. + * It is now necessary to clear "useloopback" + * to force traffic out to the hardware. + */ + if (useloopback) { sin.sin_family = AF_INET; sin.sin_addr = *destip; (void) looutput(&loif, m, (struct sockaddr *)&sin); @@ -169,7 +208,7 @@ arpresolve(ac, m, destip, desten, usetrailers) s = splimp(); ARPTAB_LOOK(at, destip->s_addr); if (at == 0) { /* not found */ - if (ifp->if_flags & IFF_NOARP) { + if (ac->ac_if.if_flags & IFF_NOARP) { bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3); desten[3] = (lna >> 16) & 0x7f; desten[4] = (lna >> 8) & 0xff; @@ -178,6 +217,8 @@ arpresolve(ac, m, destip, desten, usetrailers) return (1); } else { at = arptnew(destip); + if (at == 0) + panic("arpresolve: no free entry"); at->at_hold = m; arpwhohas(ac, destip); splx(s); @@ -220,7 +261,6 @@ arpinput(ac, m) if (ac->ac_if.if_flags & IFF_NOARP) goto out; - IF_ADJ(m); if (m->m_len < sizeof(struct arphdr)) goto out; ar = mtod(m, struct arphdr *); @@ -264,20 +304,31 @@ in_arpinput(ac, m) register struct ether_arp *ea; struct ether_header *eh; register struct arptab *at; /* same as "merge" flag */ + register struct in_ifaddr *ia; + struct in_ifaddr *maybe_ia = 0; struct mbuf *mcopy = 0; struct sockaddr_in sin; struct sockaddr sa; struct in_addr isaddr, itaddr, myaddr; - int proto, op; + int proto, op, s, completed = 0; - myaddr = ac->ac_ipaddr; ea = mtod(m, struct ether_arp *); proto = ntohs(ea->arp_pro); op = ntohs(ea->arp_op); - isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr; - itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr; + bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr)); + bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr)); + for (ia = in_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_ifp == &ac->ac_if) { + maybe_ia = ia; + if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) || + (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr)) + break; + } + if (maybe_ia == 0) + goto out; + myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr; if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr, - sizeof (ea->arp_sha))) + sizeof (ea->arp_sha))) goto out; /* it's from me, ignore it. */ if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr, sizeof (ea->arp_sha))) { @@ -287,18 +338,22 @@ in_arpinput(ac, m) goto out; } if (isaddr.s_addr == myaddr.s_addr) { - log(LOG_ERR, "%s: %s\n", - "duplicate IP address!! sent from ethernet address", - ether_sprintf(ea->arp_sha)); + log(LOG_ERR, + "duplicate IP address %x!! sent from ethernet address: %s\n", + ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha)); itaddr = myaddr; if (op == ARPOP_REQUEST) goto reply; goto out; } + s = splimp(); + s = splimp(); ARPTAB_LOOK(at, isaddr.s_addr); if (at) { bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, sizeof(ea->arp_sha)); + if ((at->at_flags & ATF_COM) == 0) + completed = 1; at->at_flags |= ATF_COM; if (at->at_hold) { sin.sin_family = AF_INET; @@ -310,11 +365,15 @@ in_arpinput(ac, m) } if (at == 0 && itaddr.s_addr == myaddr.s_addr) { /* ensure we have a table entry */ - at = arptnew(&isaddr); - bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, - sizeof(ea->arp_sha)); - at->at_flags |= ATF_COM; + if (at = arptnew(&isaddr)) { + bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr, + sizeof(ea->arp_sha)); + completed = 1; + at->at_flags |= ATF_COM; + } } + splx(s); + splx(s); reply: switch (proto) { @@ -331,10 +390,13 @@ reply: case ETHERTYPE_IP: /* - * Reply if this is an IP request, or if we want to send - * a trailer response. + * Reply if this is an IP request, + * or if we want to send a trailer response. + * Send the latter only to the IP response + * that completes the current ARP entry. */ - if (op != ARPOP_REQUEST && ac->ac_if.if_flags & IFF_NOTRAILERS) + if (op != ARPOP_REQUEST && + (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS)) goto out; } if (itaddr.s_addr == myaddr.s_addr) { @@ -375,6 +437,7 @@ reply: sizeof(eh->ether_dhost)); eh->ether_type = ETHERTYPE_ARP; sa.sa_family = AF_UNSPEC; + sa.sa_len = sizeof(sa); (*ac->ac_if.if_output)(&ac->ac_if, m, &sa); if (mcopy) { ea = mtod(mcopy, struct ether_arp *); @@ -409,6 +472,7 @@ arptfree(at) * This always succeeds since no bucket can be completely filled * with permanent entries (except from arpioctl when testing whether * another permanent entry will fit). + * MUST BE CALLED AT SPLIMP. */ struct arptab * arptnew(addr) @@ -429,7 +493,7 @@ arptnew(addr) goto out; /* found an empty entry */ if (at->at_flags & ATF_PERM) continue; - if (at->at_timer > oldest) { + if ((int) at->at_timer > oldest) { oldest = at->at_timer; ato = at; } @@ -453,10 +517,21 @@ arpioctl(cmd, data) register struct sockaddr_in *sin; int s; + sin = (struct sockaddr_in *)&ar->arp_ha; +#if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN + if (sin->sin_family == 0 && sin->sin_len < 16) + sin->sin_family = sin->sin_len; +#endif + sin->sin_len = sizeof(ar->arp_ha); + sin = (struct sockaddr_in *)&ar->arp_pa; +#if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN + if (sin->sin_family == 0 && sin->sin_len < 16) + sin->sin_family = sin->sin_len; +#endif + sin->sin_len = sizeof(ar->arp_pa); if (ar->arp_pa.sa_family != AF_INET || ar->arp_ha.sa_family != AF_UNSPEC) return (EAFNOSUPPORT); - sin = (struct sockaddr_in *)&ar->arp_pa; s = splimp(); ARPTAB_LOOK(at, sin->sin_addr.s_addr); if (at == NULL) { /* not found */ @@ -474,6 +549,10 @@ arpioctl(cmd, data) case SIOCSARP: /* set entry */ if (at == NULL) { at = arptnew(&sin->sin_addr); + if (at == NULL) { + splx(s); + return (EADDRNOTAVAIL); + } if (ar->arp_flags & ATF_PERM) { /* never make all entries in a bucket permanent */ register struct arptab *tat; @@ -491,7 +570,7 @@ arpioctl(cmd, data) bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr, sizeof(at->at_enaddr)); at->at_flags = ATF_COM | ATF_INUSE | - (ar->arp_flags & (ATF_PERM|ATF_PUBL)); + (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS)); at->at_timer = 0; break; @@ -500,32 +579,16 @@ arpioctl(cmd, data) break; case SIOCGARP: /* get entry */ + case OSIOCGARP: bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data, sizeof(at->at_enaddr)); +#ifdef COMPAT_43 + if (cmd == OSIOCGARP) + *(u_short *)&ar->arp_ha = ar->arp_ha.sa_family; +#endif ar->arp_flags = at->at_flags; break; } splx(s); return (0); } - -/* - * Convert Ethernet address to printable (loggable) representation. - */ -char * -ether_sprintf(ap) - register u_char *ap; -{ - register i; - static char etherbuf[18]; - register char *cp = etherbuf; - static char digits[] = "0123456789abcdef"; - - for (i = 0; i < 6; i++) { - *cp++ = digits[*ap >> 4]; - *cp++ = digits[*ap++ & 0xf]; - *cp++ = ':'; - } - *--cp = 0; - return (etherbuf); -}