|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T a
Length: 9692 (0x25dc) Types: TextFile Names: »arp.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦3b20aab50⟧ »EurOpenD3/network/snmp/kip-snmp.91.tar.Z« └─⟦b503a39fe⟧ └─⟦this⟧ »kip/arp.c«
/* * (c) 1986, Stanford Univ. CSLI. * May be used but not sold without permission. * * (c) 1986, Kinetics, Inc. * May be used but not sold without permission. * * $Header: arp.c,v 4.1 88/11/01 19:47:44 sw0l Exp $ */ /* * Address resolution protocol. */ #include "gw.h" #include "fp/pbuf.h" #include "ab.h" #include "inet.h" #include "fp/cmdmacro.h" #include "glob.h" /* * See RFC 826 (see "arp.rfc") for protocol description. * Field names used correspond to RFC 826. */ #define ARPHLNMAX 6 /* largest arp_hln value needed */ #define ARPPLN 4 /* length of protocol address (IP) */ struct arp { u_short arp_hrd; /* format of hardware address */ u_short arp_pro; /* format of proto. address */ u_char arp_hln; /* length of hardware address */ u_char arp_pln; /* length of protocol address */ u_short arp_op; #define ARPOP_REQUEST 1 /* request to resolve address */ #define ARPOP_REPLY 2 /* response to previous request */ #define ARPOP_PROBE 3 /* Apple 'Address PROBE' opcode */ u_char arp_d[ARPHLNMAX*2+ARPPLN*2]; /* contains 4 packed fields: sender hardware/proto addresses, target hardware/proto addresses */ }; #define arp_sha(ea) (&(ea)->arp_d[0]) #define arp_spa(ea) (&(ea)->arp_d[hln]) #define arp_tha(ea) (&(ea)->arp_d[hln+ARPPLN]) #define arp_tpa(ea) (&(ea)->arp_d[hln+hln+ARPPLN]) #define sizeof_arp (sizeof(struct arp) - ARPHLNMAX*2 + hln + hln) /* * Internet to hardware address resolution table. */ struct arptab { iaddr_t at_iaddr; /* internet address */ u_char at_haddr[ARPHLNMAX]; /* hardware address */ u_char at_timer; /* minutes since last reference */ u_char at_flags; /* flags */ struct pbuf *at_hold; /* last packet until resolved/timeout */ }; /* at_flags field values */ #define ATF_INUSE 1 /* entry in use */ #define ATF_COM 2 /* completed entry (haddr valid) */ #define ARPTAB_BSIZ 3 /* bucket size */ #define ARPTAB_NB 8 /* number of buckets */ #define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB) struct arptab *arptnew(); struct arptab arptab[ARPTAB_SIZE]; #define ARPTAB_HASH(a) \ ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB) #define ARPTAB_LOOK(at,addr) { \ register n; \ at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \ for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \ if (at->at_iaddr == addr) \ break; \ if (n >= ARPTAB_BSIZ) \ at = 0; } int arpt_age; /* aging timer */ /* timer values */ #define ARPT_AGE (60*1) /* aging timer, 1 min. */ #define ARPT_KILLC 20 /* kill completed entry in 20 mins. */ #define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */ u_char broadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /* * Timeout routine. Age arptab entries once a minute. * Entered once per second. */ arptimer() { register struct arptab *at; register i; if (++arpt_age > ARPT_AGE) { arpt_age = 0; at = &arptab[0]; for (i = 0; i < ARPTAB_SIZE; i++, at++) { if (at->at_flags == 0) continue; if (++at->at_timer < ((at->at_flags&ATF_COM) ? ARPT_KILLC : ARPT_KILLI)) continue; /* timer has expired, clear entry */ arptfree(at); } } } /* * Broadcast an ARP packet, asking who has addr on interface ifp. */ arpwhohas(ifp, addr) register struct ifnet *ifp; iaddr_t *addr; { register struct pbuf *p; register struct arp *ea; register hln; if (ifp == &ifab) { nbpwhohasip(*addr); return; } hln = ifp->if_haddrlen; K_PGET(PT_ARP,p); /* get a buffer from the free list */ if (p == 0) return; p->p_len = sizeof_arp; ea = (struct arp *)p->p_off; bzero((caddr_t)ea, sizeof_arp); ea->arp_hrd = htons(ifp->if_haddrform); ea->arp_pro = htons(ifp->if_addrform); ea->arp_hln = hln; /* hardware address length */ ea->arp_pln = ARPPLN; /* protocol address length */ /* Check whether this is the Ethertalk interface, and * the address hasn't been set yet. If so we must still * be sending PROBE's */ if (ifp->if_dnode == 0) { /* This is probably the ethertalk interface and */ /* we must still be probing for an address */ ea->arp_op = htons(ARPOP_PROBE); } else ea->arp_op = htons(ARPOP_REQUEST); bcopy(ifp->if_haddr, arp_sha(ea), hln); bcopy((caddr_t)&ifp->if_addr, arp_spa(ea), ARPPLN); bcopy((caddr_t)addr, arp_tpa(ea), ARPPLN); (*ifp->if_output)(ifp, p, AF_ARP, broadcastaddr); } /* * Resolve an IP address into a hardware address. If success, * destha is filled in and 1 is returned. If there is no entry * in arptab, set one up and broadcast a request * for the IP address; return 0. Hold onto this pbuf and * resend it once the address is finally resolved. */ arpresolve(ifp, p, destip, destha) register struct ifnet *ifp; struct pbuf *p; register iaddr_t *destip; register u_char *destha; { register struct arptab *at; register hln = ifp->if_haddrlen; int lna = ntohl(*(long *)destip) & 0xFF; if (lna == 0xFF || lna == 0x0) { /* broadcast address */ bcopy(broadcastaddr, destha, hln); return (1); } /* * We used to do some (conservative) locking here at splimp, since * arpinput was called from input interrupt service. * * s = splimp(); */ ARPTAB_LOOK(at, *destip); if (at == 0) { /* not found */ at = arptnew(destip); at->at_hold = p; arpwhohas(ifp, destip); /* splx(s); */ return (0); } at->at_timer = 0; /* restart the timer */ if (at->at_flags & ATF_COM) { /* entry IS complete */ if (destha) bcopy(at->at_haddr, destha, hln); /* splx(s); */ return (1); } /* * There is an arptab entry, but no hardware address * response yet. Replace the held pbuf with this * latest one. */ if (at->at_hold) { /* put buffer back on the free list */ K_PFREE(at->at_hold); } if (p) at->at_hold = p; arpwhohas(ifp, destip); /* ask again */ /* splx(s); */ return (0); } /* * Called when packet containing ARP is received. * Algorithm is that given in RFC 826. * In addition, a sanity check is performed on the sender * protocol address, to catch impersonators. */ arpinput(p) struct pbuf *p; { #ifdef notdef register struct ifnet *ifp = p_if(p); #else register struct ifnet *ifp = source_if; #endif register struct arp *ea; register struct arptab *at = 0; /* same as "merge" flag */ register hln = ifp->if_haddrlen; struct pbuf *phold; iaddr_t isaddr,itaddr,myaddr; if (p->p_len < sizeof_arp) goto out; myaddr = ifp->if_addr; ea = (struct arp *) p->p_off; if (ntohs(ea->arp_pro) != ifp->if_addrform) goto out; bcopy(arp_spa(ea), (caddr_t)&isaddr, ARPPLN); bcopy(arp_tpa(ea), (caddr_t)&itaddr, ARPPLN); if (!bcmp(arp_sha(ea), ifp->if_haddr, hln)) goto out; /* it's from me, ignore it. */ /* Check for Ethertalk PROBE - Someone doing address aquisition */ if (ntohs(ea->arp_op) == ARPOP_PROBE) { if (itaddr == myaddr) goto reply; else goto out; /* ignore probes not meant for me */ } if (isaddr == myaddr) { int i; u_char *cp = arp_sha(ea); sendf("duplicate IP address %x!! sent from hardware address: "); for (i = 0 ; i < hln ; i++) sendf("%x ", *cp++); if (ntohs(ea->arp_op) == ARPOP_REQUEST) { itaddr = myaddr; goto reply; } goto out; } ARPTAB_LOOK(at, isaddr); if (at) { bcopy(arp_sha(ea), at->at_haddr, hln); at->at_flags |= ATF_COM; if (at->at_hold) { phold = at->at_hold; at->at_hold = 0; (*ifp->if_output)(ifp, phold, AF_IP, &isaddr); } } if (itaddr != myaddr && (ifp->if_matchus == 0 || (*ifp->if_matchus)(itaddr) == 0)) goto out; /* if I am not the target */ if (at == 0) { /* ensure we have a table entry */ at = arptnew(&isaddr); bcopy(arp_sha(ea), at->at_haddr, hln); at->at_flags |= ATF_COM; } if (ntohs(ea->arp_op) != ARPOP_REQUEST) goto out; reply: bcopy(arp_sha(ea), arp_tha(ea), hln); bcopy(arp_spa(ea), arp_tpa(ea), ARPPLN); bcopy(ifp->if_haddr, arp_sha(ea), hln); bcopy((caddr_t)&itaddr, arp_spa(ea), ARPPLN); ea->arp_op = htons(ARPOP_REPLY); (*ifp->if_output)(ifp, p, AF_ARP, arp_tha(ea)); return; out: /* put buffer back on the free list */ K_PFREE(p); return; } /* * Got an arp reply (via nbpinput). If it completes one of our arptab * entries, send off the held buffer. This subroutine is modeled after * the inner section of arpinput. */ arpgotreply(ifp, iaddr, haddr) register struct ifnet *ifp; iaddr_t iaddr; caddr_t haddr; { register struct arptab *at; struct pbuf *p; ARPTAB_LOOK(at, iaddr); if (at == 0) /* if no matching entry, nothing to do */ return; bcopy(haddr, at->at_haddr, 4); at->at_flags |= ATF_COM; if (at->at_hold) { p = at->at_hold; at->at_hold = 0; (*ifp->if_output)(ifp, p, AF_IP, &iaddr); } } /* * Delete an arp cache entry. Called from ipgassign when * new assignment made. */ arpdelete(iaddr) iaddr_t iaddr; { register struct arptab *at; ARPTAB_LOOK(at, iaddr); if (at) arptfree(at); } /* * Free an arptab entry. */ arptfree(at) register struct arptab *at; { short pri; K_SPLIMP(&pri); if (at->at_hold) { /* put buffer back on the free list */ K_PFREE(at->at_hold); } at->at_hold = 0; at->at_timer = at->at_flags = 0; at->at_iaddr = 0; K_SPLX(&pri); } /* * Enter a new address in arptab, pushing out the oldest entry * from the bucket if there is no room. */ struct arptab * arptnew(addr) iaddr_t *addr; { register n; int oldest = 0; register struct arptab *at, *ato; ato = at = &arptab[ARPTAB_HASH(*addr) * ARPTAB_BSIZ]; for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) { if (at->at_flags == 0) goto out; /* found an empty entry */ if (at->at_timer > oldest) { oldest = at->at_timer; ato = at; } } at = ato; arptfree(at); out: at->at_iaddr = *addr; at->at_flags = ATF_INUSE; return (at); }