V1.49 ((inet 3 of 4) updated IP/TCP and XNS sources for 4.3BSD)
Keith Bostic
bostic at OKEEFFE.BERKELEY.EDU
Tue Apr 5 13:18:03 AEST 1988
Subject: (inet 3 of 4) updated IP/TCP and XNS sources for 4.3BSD
Index: sys 4.3BSD
Description:
This is number 4 of 11 total articles posted to the newsgroup
comp.bugs.4bsd.ucb-fixes. This archive is number 3 of the 4
articles that make up the inet posting.
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# netinet
# netinet/icmp_var.h
# netinet/if_ether.c
# netinet/if_ether.h
# netinet/in.c
# netinet/in.h
# netinet/in_cksum.c
# netinet/in_pcb.c
# netinet/in_pcb.h
# netinet/in_proto.c
# netinet/in_systm.h
# netinet/in_var.h
#
echo c - netinet
mkdir netinet > /dev/null 2>&1
echo x - netinet/icmp_var.h
sed 's/^X//' >netinet/icmp_var.h << 'END-of-netinet/icmp_var.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)icmp_var.h 7.3 (Berkeley) 12/7/87
X */
X
X/*
X * Variables related to this implementation
X * of the internet control message protocol.
X */
Xstruct icmpstat {
X/* statistics related to icmp packets generated */
X int icps_error; /* # of calls to icmp_error */
X int icps_oldshort; /* no error 'cuz old ip too short */
X int icps_oldicmp; /* no error 'cuz old was icmp */
X int icps_outhist[ICMP_MAXTYPE + 1];
X/* statistics related to input messages processed */
X int icps_badcode; /* icmp_code out of range */
X int icps_tooshort; /* packet < ICMP_MINLEN */
X int icps_checksum; /* bad checksum */
X int icps_badlen; /* calculated bound mismatch */
X int icps_reflect; /* number of responses */
X int icps_inhist[ICMP_MAXTYPE + 1];
X};
X
X#ifdef KERNEL
Xstruct icmpstat icmpstat;
X#endif
END-of-netinet/icmp_var.h
echo x - netinet/if_ether.c
sed 's/^X//' >netinet/if_ether.c << 'END-of-netinet/if_ether.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)if_ether.c 7.6 (Berkeley) 12/7/87
X */
X
X/*
X * Ethernet address resolution protocol.
X * TODO:
X * run at splnet (add ARP protocol intr.)
X * link entries onto hash chains, keep free list
X * add "inuse/lock" bit (or ref. count) along with valid bit
X */
X
X#include "param.h"
X#include "systm.h"
X#include "mbuf.h"
X#include "socket.h"
X#include "time.h"
X#include "kernel.h"
X#include "errno.h"
X#include "ioctl.h"
X#include "syslog.h"
X
X#include "../net/if.h"
X#include "in.h"
X#include "in_systm.h"
X#include "ip.h"
X#include "if_ether.h"
X
X#ifdef GATEWAY
X#define ARPTAB_BSIZ 16 /* bucket size */
X#define ARPTAB_NB 37 /* number of buckets */
X#else
X#define ARPTAB_BSIZ 9 /* bucket size */
X#define ARPTAB_NB 19 /* number of buckets */
X#endif
X#define ARPTAB_SIZE (ARPTAB_BSIZ * ARPTAB_NB)
Xstruct arptab arptab[ARPTAB_SIZE];
Xint arptab_size = ARPTAB_SIZE; /* for arp command */
X
X/*
X * ARP trailer negotiation. Trailer protocol is not IP specific,
X * but ARP request/response use IP addresses.
X */
X#define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
X
X#define ARPTAB_HASH(a) \
X ((u_long)(a) % ARPTAB_NB)
X
X#define ARPTAB_LOOK(at,addr) { \
X register n; \
X at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
X for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
X if (at->at_iaddr.s_addr == addr) \
X break; \
X if (n >= ARPTAB_BSIZ) \
X at = 0; \
X}
X
X/* timer values */
X#define ARPT_AGE (60*1) /* aging timer, 1 min. */
X#define ARPT_KILLC 20 /* kill completed entry in 20 mins. */
X#define ARPT_KILLI 3 /* kill incomplete entry in 3 minutes */
X
Xu_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
Xextern struct ifnet loif;
X
X/*
X * Timeout routine. Age arp_tab entries once a minute.
X */
Xarptimer()
X{
X register struct arptab *at;
X register i;
X
X timeout(arptimer, (caddr_t)0, ARPT_AGE * hz);
X at = &arptab[0];
X for (i = 0; i < ARPTAB_SIZE; i++, at++) {
X if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
X continue;
X if (++at->at_timer < ((at->at_flags&ATF_COM) ?
X ARPT_KILLC : ARPT_KILLI))
X continue;
X /* timer has expired, clear entry */
X arptfree(at);
X }
X}
X
X/*
X * Broadcast an ARP packet, asking who has addr on interface ac.
X */
Xarpwhohas(ac, addr)
X register struct arpcom *ac;
X struct in_addr *addr;
X{
X register struct mbuf *m;
X register struct ether_header *eh;
X register struct ether_arp *ea;
X struct sockaddr sa;
X
X if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL)
X return;
X m->m_len = sizeof *ea;
X m->m_off = MMAXOFF - m->m_len;
X ea = mtod(m, struct ether_arp *);
X eh = (struct ether_header *)sa.sa_data;
X bzero((caddr_t)ea, sizeof (*ea));
X bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
X sizeof(eh->ether_dhost));
X eh->ether_type = ETHERTYPE_ARP; /* if_output will swap */
X ea->arp_hrd = htons(ARPHRD_ETHER);
X ea->arp_pro = htons(ETHERTYPE_IP);
X ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
X ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
X ea->arp_op = htons(ARPOP_REQUEST);
X bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
X sizeof(ea->arp_sha));
X bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa,
X sizeof(ea->arp_spa));
X bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
X sa.sa_family = AF_UNSPEC;
X (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
X}
X
Xint useloopback = 1; /* use loopback interface for local traffic */
X
X/*
X * Resolve an IP address into an ethernet address. If success,
X * desten is filled in. If there is no entry in arptab,
X * set one up and broadcast a request for the IP address.
X * Hold onto this mbuf and resend it once the address
X * is finally resolved. A return value of 1 indicates
X * that desten has been filled in and the packet should be sent
X * normally; a 0 return indicates that the packet has been
X * taken over here, either now or for later transmission.
X *
X * We do some (conservative) locking here at splimp, since
X * arptab is also altered from input interrupt service (ecintr/ilintr
X * calls arpinput when ETHERTYPE_ARP packets come in).
X */
Xarpresolve(ac, m, destip, desten, usetrailers)
X register struct arpcom *ac;
X struct mbuf *m;
X register struct in_addr *destip;
X register u_char *desten;
X int *usetrailers;
X{
X register struct arptab *at;
X struct sockaddr_in sin;
X u_long lna;
X int s;
X
X *usetrailers = 0;
X if (in_broadcast(*destip)) { /* broadcast address */
X bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
X sizeof(etherbroadcastaddr));
X return (1);
X }
X lna = in_lnaof(*destip);
X /* if for us, use software loopback driver if up */
X if (destip->s_addr == ac->ac_ipaddr.s_addr) {
X /*
X * This test used to be
X * if (loif.if_flags & IFF_UP)
X * It allowed local traffic to be forced
X * through the hardware by configuring the loopback down.
X * However, it causes problems during network configuration
X * for boards that can't receive packets they send.
X * It is now necessary to clear "useloopback"
X * to force traffic out to the hardware.
X */
X if (useloopback) {
X sin.sin_family = AF_INET;
X sin.sin_addr = *destip;
X (void) looutput(&loif, m, (struct sockaddr *)&sin);
X /*
X * The packet has already been sent and freed.
X */
X return (0);
X } else {
X bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten,
X sizeof(ac->ac_enaddr));
X return (1);
X }
X }
X s = splimp();
X ARPTAB_LOOK(at, destip->s_addr);
X if (at == 0) { /* not found */
X if (ac->ac_if.if_flags & IFF_NOARP) {
X bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
X desten[3] = (lna >> 16) & 0x7f;
X desten[4] = (lna >> 8) & 0xff;
X desten[5] = lna & 0xff;
X splx(s);
X return (1);
X } else {
X at = arptnew(destip);
X if (at == 0)
X panic("arpresolve: no free entry");
X at->at_hold = m;
X arpwhohas(ac, destip);
X splx(s);
X return (0);
X }
X }
X at->at_timer = 0; /* restart the timer */
X if (at->at_flags & ATF_COM) { /* entry IS complete */
X bcopy((caddr_t)at->at_enaddr, (caddr_t)desten,
X sizeof(at->at_enaddr));
X if (at->at_flags & ATF_USETRAILERS)
X *usetrailers = 1;
X splx(s);
X return (1);
X }
X /*
X * There is an arptab entry, but no ethernet address
X * response yet. Replace the held mbuf with this
X * latest one.
X */
X if (at->at_hold)
X m_freem(at->at_hold);
X at->at_hold = m;
X arpwhohas(ac, destip); /* ask again */
X splx(s);
X return (0);
X}
X
X/*
X * Called from 10 Mb/s Ethernet interrupt handlers
X * when ether packet type ETHERTYPE_ARP
X * is received. Common length and type checks are done here,
X * then the protocol-specific routine is called.
X */
Xarpinput(ac, m)
X struct arpcom *ac;
X struct mbuf *m;
X{
X register struct arphdr *ar;
X
X if (ac->ac_if.if_flags & IFF_NOARP)
X goto out;
X IF_ADJ(m);
X if (m->m_len < sizeof(struct arphdr))
X goto out;
X ar = mtod(m, struct arphdr *);
X if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
X goto out;
X if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
X goto out;
X
X switch (ntohs(ar->ar_pro)) {
X
X case ETHERTYPE_IP:
X case ETHERTYPE_IPTRAILERS:
X in_arpinput(ac, m);
X return;
X
X default:
X break;
X }
Xout:
X m_freem(m);
X}
X
X/*
X * ARP for Internet protocols on 10 Mb/s Ethernet.
X * Algorithm is that given in RFC 826.
X * In addition, a sanity check is performed on the sender
X * protocol address, to catch impersonators.
X * We also handle negotiations for use of trailer protocol:
X * ARP replies for protocol type ETHERTYPE_TRAIL are sent
X * along with IP replies if we want trailers sent to us,
X * and also send them in response to IP replies.
X * This allows either end to announce the desire to receive
X * trailer packets.
X * We reply to requests for ETHERTYPE_TRAIL protocol as well,
X * but don't normally send requests.
X */
Xin_arpinput(ac, m)
X register struct arpcom *ac;
X struct mbuf *m;
X{
X register struct ether_arp *ea;
X struct ether_header *eh;
X register struct arptab *at; /* same as "merge" flag */
X struct mbuf *mcopy = 0;
X struct sockaddr_in sin;
X struct sockaddr sa;
X struct in_addr isaddr, itaddr, myaddr;
X int proto, op, s, completed = 0;
X
X myaddr = ac->ac_ipaddr;
X ea = mtod(m, struct ether_arp *);
X proto = ntohs(ea->arp_pro);
X op = ntohs(ea->arp_op);
X bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
X bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
X if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
X sizeof (ea->arp_sha)))
X goto out; /* it's from me, ignore it. */
X if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
X sizeof (ea->arp_sha))) {
X log(LOG_ERR,
X "arp: ether address is broadcast for IP address %x!\n",
X ntohl(isaddr.s_addr));
X goto out;
X }
X if (isaddr.s_addr == myaddr.s_addr) {
X log(LOG_ERR, "%s: %s\n",
X "duplicate IP address!! sent from ethernet address",
X ether_sprintf(ea->arp_sha));
X itaddr = myaddr;
X if (op == ARPOP_REQUEST)
X goto reply;
X goto out;
X }
X s = splimp();
X ARPTAB_LOOK(at, isaddr.s_addr);
X if (at) {
X bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
X sizeof(ea->arp_sha));
X if ((at->at_flags & ATF_COM) == 0)
X completed = 1;
X at->at_flags |= ATF_COM;
X if (at->at_hold) {
X sin.sin_family = AF_INET;
X sin.sin_addr = isaddr;
X (*ac->ac_if.if_output)(&ac->ac_if,
X at->at_hold, (struct sockaddr *)&sin);
X at->at_hold = 0;
X }
X }
X if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
X /* ensure we have a table entry */
X if (at = arptnew(&isaddr)) {
X bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
X sizeof(ea->arp_sha));
X completed = 1;
X at->at_flags |= ATF_COM;
X }
X }
X splx(s);
Xreply:
X switch (proto) {
X
X case ETHERTYPE_IPTRAILERS:
X /* partner says trailers are OK */
X if (at)
X at->at_flags |= ATF_USETRAILERS;
X /*
X * Reply to request iff we want trailers.
X */
X if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
X goto out;
X break;
X
X case ETHERTYPE_IP:
X /*
X * Reply if this is an IP request,
X * or if we want to send a trailer response.
X * Send the latter only to the IP response
X * that completes the current ARP entry.
X */
X if (op != ARPOP_REQUEST &&
X (completed == 0 || ac->ac_if.if_flags & IFF_NOTRAILERS))
X goto out;
X }
X if (itaddr.s_addr == myaddr.s_addr) {
X /* I am the target */
X bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
X sizeof(ea->arp_sha));
X bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
X sizeof(ea->arp_sha));
X } else {
X ARPTAB_LOOK(at, itaddr.s_addr);
X if (at == NULL || (at->at_flags & ATF_PUBL) == 0)
X goto out;
X bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
X sizeof(ea->arp_sha));
X bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
X sizeof(ea->arp_sha));
X }
X
X bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
X sizeof(ea->arp_spa));
X bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
X sizeof(ea->arp_spa));
X ea->arp_op = htons(ARPOP_REPLY);
X /*
X * If incoming packet was an IP reply,
X * we are sending a reply for type IPTRAILERS.
X * If we are sending a reply for type IP
X * and we want to receive trailers,
X * send a trailer reply as well.
X */
X if (op == ARPOP_REPLY)
X ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
X else if (proto == ETHERTYPE_IP &&
X (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0)
X mcopy = m_copy(m, 0, (int)M_COPYALL);
X eh = (struct ether_header *)sa.sa_data;
X bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
X sizeof(eh->ether_dhost));
X eh->ether_type = ETHERTYPE_ARP;
X sa.sa_family = AF_UNSPEC;
X (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
X if (mcopy) {
X ea = mtod(mcopy, struct ether_arp *);
X ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
X (*ac->ac_if.if_output)(&ac->ac_if, mcopy, &sa);
X }
X return;
Xout:
X m_freem(m);
X return;
X}
X
X/*
X * Free an arptab entry.
X */
Xarptfree(at)
X register struct arptab *at;
X{
X int s = splimp();
X
X if (at->at_hold)
X m_freem(at->at_hold);
X at->at_hold = 0;
X at->at_timer = at->at_flags = 0;
X at->at_iaddr.s_addr = 0;
X splx(s);
X}
X
X/*
X * Enter a new address in arptab, pushing out the oldest entry
X * from the bucket if there is no room.
X * This always succeeds since no bucket can be completely filled
X * with permanent entries (except from arpioctl when testing whether
X * another permanent entry will fit).
X * MUST BE CALLED AT SPLIMP.
X */
Xstruct arptab *
Xarptnew(addr)
X struct in_addr *addr;
X{
X register n;
X int oldest = -1;
X register struct arptab *at, *ato = NULL;
X static int first = 1;
X
X if (first) {
X first = 0;
X timeout(arptimer, (caddr_t)0, hz);
X }
X at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
X for (n = 0; n < ARPTAB_BSIZ; n++,at++) {
X if (at->at_flags == 0)
X goto out; /* found an empty entry */
X if (at->at_flags & ATF_PERM)
X continue;
X if ((int) at->at_timer > oldest) {
X oldest = at->at_timer;
X ato = at;
X }
X }
X if (ato == NULL)
X return (NULL);
X at = ato;
X arptfree(at);
Xout:
X at->at_iaddr = *addr;
X at->at_flags = ATF_INUSE;
X return (at);
X}
X
Xarpioctl(cmd, data)
X int cmd;
X caddr_t data;
X{
X register struct arpreq *ar = (struct arpreq *)data;
X register struct arptab *at;
X register struct sockaddr_in *sin;
X int s;
X
X if (ar->arp_pa.sa_family != AF_INET ||
X ar->arp_ha.sa_family != AF_UNSPEC)
X return (EAFNOSUPPORT);
X sin = (struct sockaddr_in *)&ar->arp_pa;
X s = splimp();
X ARPTAB_LOOK(at, sin->sin_addr.s_addr);
X if (at == NULL) { /* not found */
X if (cmd != SIOCSARP) {
X splx(s);
X return (ENXIO);
X }
X if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
X splx(s);
X return (ENETUNREACH);
X }
X }
X switch (cmd) {
X
X case SIOCSARP: /* set entry */
X if (at == NULL) {
X at = arptnew(&sin->sin_addr);
X if (at == NULL) {
X splx(s);
X return (EADDRNOTAVAIL);
X }
X if (ar->arp_flags & ATF_PERM) {
X /* never make all entries in a bucket permanent */
X register struct arptab *tat;
X
X /* try to re-allocate */
X tat = arptnew(&sin->sin_addr);
X if (tat == NULL) {
X arptfree(at);
X splx(s);
X return (EADDRNOTAVAIL);
X }
X arptfree(tat);
X }
X }
X bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
X sizeof(at->at_enaddr));
X at->at_flags = ATF_COM | ATF_INUSE |
X (ar->arp_flags & (ATF_PERM|ATF_PUBL|ATF_USETRAILERS));
X at->at_timer = 0;
X break;
X
X case SIOCDARP: /* delete entry */
X arptfree(at);
X break;
X
X case SIOCGARP: /* get entry */
X bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
X sizeof(at->at_enaddr));
X ar->arp_flags = at->at_flags;
X break;
X }
X splx(s);
X return (0);
X}
X
X/*
X * Convert Ethernet address to printable (loggable) representation.
X */
Xchar *
Xether_sprintf(ap)
X register u_char *ap;
X{
X register i;
X static char etherbuf[18];
X register char *cp = etherbuf;
X static char digits[] = "0123456789abcdef";
X
X for (i = 0; i < 6; i++) {
X *cp++ = digits[*ap >> 4];
X *cp++ = digits[*ap++ & 0xf];
X *cp++ = ':';
X }
X *--cp = 0;
X return (etherbuf);
X}
END-of-netinet/if_ether.c
echo x - netinet/if_ether.h
sed 's/^X//' >netinet/if_ether.h << 'END-of-netinet/if_ether.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)if_ether.h 7.2 (Berkeley) 12/7/87
X */
X
X/*
X * Structure of a 10Mb/s Ethernet header.
X */
Xstruct ether_header {
X u_char ether_dhost[6];
X u_char ether_shost[6];
X u_short ether_type;
X};
X
X#define ETHERTYPE_PUP 0x0200 /* PUP protocol */
X#define ETHERTYPE_IP 0x0800 /* IP protocol */
X#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */
X
X/*
X * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have
X * (type-ETHERTYPE_TRAIL)*512 bytes of data followed
X * by an ETHER type (as given above) and then the (variable-length) header.
X */
X#define ETHERTYPE_TRAIL 0x1000 /* Trailer packet */
X#define ETHERTYPE_NTRAILER 16
X
X#define ETHERMTU 1500
X#define ETHERMIN (60-14)
X
X/*
X * Ethernet Address Resolution Protocol.
X *
X * See RFC 826 for protocol description. Structure below is adapted
X * to resolving internet addresses. Field names used correspond to
X * RFC 826.
X */
Xstruct ether_arp {
X struct arphdr ea_hdr; /* fixed-size header */
X u_char arp_sha[6]; /* sender hardware address */
X u_char arp_spa[4]; /* sender protocol address */
X u_char arp_tha[6]; /* target hardware address */
X u_char arp_tpa[4]; /* target protocol address */
X};
X#define arp_hrd ea_hdr.ar_hrd
X#define arp_pro ea_hdr.ar_pro
X#define arp_hln ea_hdr.ar_hln
X#define arp_pln ea_hdr.ar_pln
X#define arp_op ea_hdr.ar_op
X
X
X/*
X * Structure shared between the ethernet driver modules and
X * the address resolution code. For example, each ec_softc or il_softc
X * begins with this structure.
X */
Xstruct arpcom {
X struct ifnet ac_if; /* network-visible interface */
X u_char ac_enaddr[6]; /* ethernet hardware address */
X struct in_addr ac_ipaddr; /* copy of ip address- XXX */
X};
X
X/*
X * Internet to ethernet address resolution table.
X */
Xstruct arptab {
X struct in_addr at_iaddr; /* internet address */
X u_char at_enaddr[6]; /* ethernet address */
X u_char at_timer; /* minutes since last reference */
X u_char at_flags; /* flags */
X struct mbuf *at_hold; /* last packet until resolved/timeout */
X};
X
X#ifdef KERNEL
Xu_char etherbroadcastaddr[6];
Xstruct arptab *arptnew();
Xchar *ether_sprintf();
X#endif
END-of-netinet/if_ether.h
echo x - netinet/in.c
sed 's/^X//' >netinet/in.c << 'END-of-netinet/in.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)in.c 7.7 (Berkeley) 4/3/88
X */
X
X#include "param.h"
X#include "ioctl.h"
X#include "mbuf.h"
X#include "protosw.h"
X#include "socket.h"
X#include "socketvar.h"
X#include "uio.h"
X#include "dir.h"
X#include "user.h"
X#include "in_systm.h"
X#include "../net/if.h"
X#include "../net/route.h"
X#include "../net/af.h"
X#include "in.h"
X#include "in_var.h"
X
X#ifdef INET
Xinet_hash(sin, hp)
X register struct sockaddr_in *sin;
X struct afhash *hp;
X{
X register u_long n;
X
X n = in_netof(sin->sin_addr);
X if (n)
X while ((n & 0xff) == 0)
X n >>= 8;
X hp->afh_nethash = n;
X hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
X}
X
Xinet_netmatch(sin1, sin2)
X struct sockaddr_in *sin1, *sin2;
X{
X
X return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr));
X}
X
X/*
X * Formulate an Internet address from network + host.
X */
Xstruct in_addr
Xin_makeaddr(net, host)
X u_long net, host;
X{
X register struct in_ifaddr *ia;
X register u_long mask;
X u_long addr;
X
X if (IN_CLASSA(net))
X mask = IN_CLASSA_HOST;
X else if (IN_CLASSB(net))
X mask = IN_CLASSB_HOST;
X else
X mask = IN_CLASSC_HOST;
X for (ia = in_ifaddr; ia; ia = ia->ia_next)
X if ((ia->ia_netmask & net) == ia->ia_net) {
X mask = ~ia->ia_subnetmask;
X break;
X }
X addr = htonl(net | (host & mask));
X return (*(struct in_addr *)&addr);
X}
X
X/*
X * Return the network number from an internet address.
X */
Xu_long
Xin_netof(in)
X struct in_addr in;
X{
X register u_long i = ntohl(in.s_addr);
X register u_long net;
X register struct in_ifaddr *ia;
X
X if (IN_CLASSA(i))
X net = i & IN_CLASSA_NET;
X else if (IN_CLASSB(i))
X net = i & IN_CLASSB_NET;
X else if (IN_CLASSC(i))
X net = i & IN_CLASSC_NET;
X else
X return (0);
X
X /*
X * Check whether network is a subnet;
X * if so, return subnet number.
X */
X for (ia = in_ifaddr; ia; ia = ia->ia_next)
X if (net == ia->ia_net)
X return (i & ia->ia_subnetmask);
X return (net);
X}
X
X/*
X * Return the host portion of an internet address.
X */
Xu_long
Xin_lnaof(in)
X struct in_addr in;
X{
X register u_long i = ntohl(in.s_addr);
X register u_long net, host;
X register struct in_ifaddr *ia;
X
X if (IN_CLASSA(i)) {
X net = i & IN_CLASSA_NET;
X host = i & IN_CLASSA_HOST;
X } else if (IN_CLASSB(i)) {
X net = i & IN_CLASSB_NET;
X host = i & IN_CLASSB_HOST;
X } else if (IN_CLASSC(i)) {
X net = i & IN_CLASSC_NET;
X host = i & IN_CLASSC_HOST;
X } else
X return (i);
X
X /*
X * Check whether network is a subnet;
X * if so, use the modified interpretation of `host'.
X */
X for (ia = in_ifaddr; ia; ia = ia->ia_next)
X if (net == ia->ia_net)
X return (host &~ ia->ia_subnetmask);
X return (host);
X}
X
X#ifndef SUBNETSARELOCAL
X#define SUBNETSARELOCAL 1
X#endif
Xint subnetsarelocal = SUBNETSARELOCAL;
X/*
X * Return 1 if an internet address is for a ``local'' host
X * (one to which we have a connection). If subnetsarelocal
X * is true, this includes other subnets of the local net.
X * Otherwise, it includes only the directly-connected (sub)nets.
X */
Xin_localaddr(in)
X struct in_addr in;
X{
X register u_long i = ntohl(in.s_addr);
X register struct in_ifaddr *ia;
X
X if (subnetsarelocal) {
X for (ia = in_ifaddr; ia; ia = ia->ia_next)
X if ((i & ia->ia_netmask) == ia->ia_net)
X return (1);
X } else {
X for (ia = in_ifaddr; ia; ia = ia->ia_next)
X if ((i & ia->ia_subnetmask) == ia->ia_subnet)
X return (1);
X }
X return (0);
X}
X
X/*
X * Determine whether an IP address is in a reserved set of addresses
X * that may not be forwarded, or whether datagrams to that destination
X * may be forwarded.
X */
Xin_canforward(in)
X struct in_addr in;
X{
X register u_long i = ntohl(in.s_addr);
X register u_long net;
X
X if (IN_EXPERIMENTAL(i))
X return (0);
X if (IN_CLASSA(i)) {
X net = i & IN_CLASSA_NET;
X if (net == 0 || net == IN_LOOPBACKNET)
X return (0);
X }
X return (1);
X}
X
Xint in_interfaces; /* number of external internet interfaces */
Xextern struct ifnet loif;
X
X/*
X * Generic internet control operations (ioctl's).
X * Ifp is 0 if not an interface-specific ioctl.
X */
X/* ARGSUSED */
Xin_control(so, cmd, data, ifp)
X struct socket *so;
X int cmd;
X caddr_t data;
X register struct ifnet *ifp;
X{
X register struct ifreq *ifr = (struct ifreq *)data;
X register struct in_ifaddr *ia = 0;
X struct ifaddr *ifa;
X struct mbuf *m;
X int error;
X
X /*
X * Find address for this interface, if it exists.
X */
X if (ifp)
X for (ia = in_ifaddr; ia; ia = ia->ia_next)
X if (ia->ia_ifp == ifp)
X break;
X
X switch (cmd) {
X
X case SIOCSIFADDR:
X case SIOCSIFNETMASK:
X case SIOCSIFDSTADDR:
X if (!suser())
X return (u.u_error);
X
X if (ifp == 0)
X panic("in_control");
X if (ia == (struct in_ifaddr *)0) {
X m = m_getclr(M_WAIT, MT_IFADDR);
X if (m == (struct mbuf *)NULL)
X return (ENOBUFS);
X if (ia = in_ifaddr) {
X for ( ; ia->ia_next; ia = ia->ia_next)
X ;
X ia->ia_next = mtod(m, struct in_ifaddr *);
X } else
X in_ifaddr = mtod(m, struct in_ifaddr *);
X ia = mtod(m, struct in_ifaddr *);
X if (ifa = ifp->if_addrlist) {
X for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
X ;
X ifa->ifa_next = (struct ifaddr *) ia;
X } else
X ifp->if_addrlist = (struct ifaddr *) ia;
X ia->ia_ifp = ifp;
X IA_SIN(ia)->sin_family = AF_INET;
X if (ifp != &loif)
X in_interfaces++;
X }
X break;
X
X case SIOCSIFBRDADDR:
X if (!suser())
X return (u.u_error);
X /* FALLTHROUGH */
X
X default:
X if (ia == (struct in_ifaddr *)0)
X return (EADDRNOTAVAIL);
X break;
X }
X
X switch (cmd) {
X
X case SIOCGIFADDR:
X ifr->ifr_addr = ia->ia_addr;
X break;
X
X case SIOCGIFBRDADDR:
X if ((ifp->if_flags & IFF_BROADCAST) == 0)
X return (EINVAL);
X ifr->ifr_dstaddr = ia->ia_broadaddr;
X break;
X
X case SIOCGIFDSTADDR:
X if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
X return (EINVAL);
X ifr->ifr_dstaddr = ia->ia_dstaddr;
X break;
X
X case SIOCGIFNETMASK:
X#define satosin(sa) ((struct sockaddr_in *)(sa))
X satosin(&ifr->ifr_addr)->sin_family = AF_INET;
X satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask);
X break;
X
X case SIOCSIFDSTADDR:
X {
X struct sockaddr oldaddr;
X
X if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
X return (EINVAL);
X oldaddr = ia->ia_dstaddr;
X ia->ia_dstaddr = ifr->ifr_dstaddr;
X if (ifp->if_ioctl &&
X (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
X ia->ia_dstaddr = oldaddr;
X return (error);
X }
X if (ia->ia_flags & IFA_ROUTE) {
X rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT,
X RTF_HOST);
X rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
X RTF_HOST|RTF_UP);
X }
X }
X break;
X
X case SIOCSIFBRDADDR:
X if ((ifp->if_flags & IFF_BROADCAST) == 0)
X return (EINVAL);
X ia->ia_broadaddr = ifr->ifr_broadaddr;
X break;
X
X case SIOCSIFADDR:
X return (in_ifinit(ifp, ia, &ifr->ifr_addr));
X
X case SIOCSIFNETMASK:
X ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
X break;
X
X default:
X if (ifp == 0 || ifp->if_ioctl == 0)
X return (EOPNOTSUPP);
X return ((*ifp->if_ioctl)(ifp, cmd, data));
X }
X return (0);
X}
X
X/*
X * Initialize an interface's internet address
X * and routing table entry.
X */
Xin_ifinit(ifp, ia, sin)
X register struct ifnet *ifp;
X register struct in_ifaddr *ia;
X struct sockaddr_in *sin;
X{
X register u_long i = ntohl(sin->sin_addr.s_addr);
X struct sockaddr oldaddr;
X struct sockaddr_in netaddr;
X int s = splimp(), error;
X
X oldaddr = ia->ia_addr;
X ia->ia_addr = *(struct sockaddr *)sin;
X
X /*
X * Give the interface a chance to initialize
X * if this is its first address,
X * and to validate the address if necessary.
X */
X if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
X splx(s);
X ia->ia_addr = oldaddr;
X return (error);
X }
X
X /*
X * Delete any previous route for an old address.
X */
X bzero((caddr_t)&netaddr, sizeof (netaddr));
X netaddr.sin_family = AF_INET;
X if (ia->ia_flags & IFA_ROUTE) {
X if (ifp->if_flags & IFF_LOOPBACK)
X rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST);
X else if (ifp->if_flags & IFF_POINTOPOINT)
X rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT,
X RTF_HOST);
X else {
X netaddr.sin_addr = in_makeaddr(ia->ia_subnet,
X INADDR_ANY);
X rtinit((struct sockaddr *)&netaddr, &oldaddr,
X (int)SIOCDELRT, 0);
X }
X ia->ia_flags &= ~IFA_ROUTE;
X }
X if (IN_CLASSA(i))
X ia->ia_netmask = IN_CLASSA_NET;
X else if (IN_CLASSB(i))
X ia->ia_netmask = IN_CLASSB_NET;
X else
X ia->ia_netmask = IN_CLASSC_NET;
X ia->ia_net = i & ia->ia_netmask;
X /*
X * The subnet mask includes at least the standard network part,
X * but may already have been set to a larger value.
X */
X ia->ia_subnetmask |= ia->ia_netmask;
X ia->ia_subnet = i & ia->ia_subnetmask;
X if (ifp->if_flags & IFF_BROADCAST) {
X ia->ia_broadaddr.sa_family = AF_INET;
X ((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
X in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
X ia->ia_netbroadcast.s_addr =
X htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
X }
X /*
X * Add route for the network.
X */
X if (ifp->if_flags & IFF_LOOPBACK)
X rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT,
X RTF_HOST|RTF_UP);
X else if (ifp->if_flags & IFF_POINTOPOINT)
X rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
X RTF_HOST|RTF_UP);
X else {
X netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
X rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
X (int)SIOCADDRT, RTF_UP);
X }
X ia->ia_flags |= IFA_ROUTE;
X splx(s);
X return (0);
X}
X
X/*
X * Return address info for specified internet network.
X */
Xstruct in_ifaddr *
Xin_iaonnetof(net)
X u_long net;
X{
X register struct in_ifaddr *ia;
X
X for (ia = in_ifaddr; ia; ia = ia->ia_next)
X if (ia->ia_subnet == net)
X return (ia);
X return ((struct in_ifaddr *)0);
X}
X
X/*
X * Return 1 if the address might be a local broadcast address.
X */
Xin_broadcast(in)
X struct in_addr in;
X{
X register struct in_ifaddr *ia;
X u_long t;
X
X /*
X * Look through the list of addresses for a match
X * with a broadcast address.
X */
X for (ia = in_ifaddr; ia; ia = ia->ia_next)
X if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
X if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr)
X return (1);
X /*
X * Check for old-style (host 0) broadcast.
X */
X if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
X return (1);
X }
X if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
X return (1);
X return (0);
X}
X#endif
END-of-netinet/in.c
echo x - netinet/in.h
sed 's/^X//' >netinet/in.h << 'END-of-netinet/in.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)in.h 7.5 (Berkeley) 2/22/88
X */
X
X/*
X * Constants and structures defined by the internet system,
X * Per RFC 790, September 1981.
X */
X
X/*
X * Protocols
X */
X#define IPPROTO_IP 0 /* dummy for IP */
X#define IPPROTO_ICMP 1 /* control message protocol */
X#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
X#define IPPROTO_TCP 6 /* tcp */
X#define IPPROTO_EGP 8 /* exterior gateway protocol */
X#define IPPROTO_PUP 12 /* pup */
X#define IPPROTO_UDP 17 /* user datagram protocol */
X#define IPPROTO_IDP 22 /* xns idp */
X
X#define IPPROTO_RAW 255 /* raw IP packet */
X#define IPPROTO_MAX 256
X
X
X/*
X * Ports < IPPORT_RESERVED are reserved for
X * privileged processes (e.g. root).
X * Ports > IPPORT_USERRESERVED are reserved
X * for servers, not necessarily privileged.
X */
X#define IPPORT_RESERVED 1024
X#define IPPORT_USERRESERVED 5000
X
X/*
X * Link numbers
X */
X#define IMPLINK_IP 155
X#define IMPLINK_LOWEXPER 156
X#define IMPLINK_HIGHEXPER 158
X
X/*
X * Internet address (a structure for historical reasons)
X */
Xstruct in_addr {
X u_long s_addr;
X};
X
X/*
X * Definitions of bits in internet address integers.
X * On subnets, the decomposition of addresses to host and net parts
X * is done according to subnet mask, not the masks here.
X */
X#define IN_CLASSA(i) (((long)(i) & 0x80000000) == 0)
X#define IN_CLASSA_NET 0xff000000
X#define IN_CLASSA_NSHIFT 24
X#define IN_CLASSA_HOST 0x00ffffff
X#define IN_CLASSA_MAX 128
X
X#define IN_CLASSB(i) (((long)(i) & 0xc0000000) == 0x80000000)
X#define IN_CLASSB_NET 0xffff0000
X#define IN_CLASSB_NSHIFT 16
X#define IN_CLASSB_HOST 0x0000ffff
X#define IN_CLASSB_MAX 65536
X
X#define IN_CLASSC(i) (((long)(i) & 0xe0000000) == 0xc0000000)
X#define IN_CLASSC_NET 0xffffff00
X#define IN_CLASSC_NSHIFT 8
X#define IN_CLASSC_HOST 0x000000ff
X
X#define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000)
X#define IN_MULTICAST(i) IN_CLASSD(i)
X
X#define IN_EXPERIMENTAL(i) (((long)(i) & 0xe0000000) == 0xe0000000)
X#define IN_BADCLASS(i) (((long)(i) & 0xf0000000) == 0xf0000000)
X
X#define INADDR_ANY (u_long)0x00000000
X#define INADDR_BROADCAST (u_long)0xffffffff /* must be masked */
X#ifndef KERNEL
X#define INADDR_NONE 0xffffffff /* -1 return */
X#endif
X
X#define IN_LOOPBACKNET 127 /* official! */
X
X/*
X * Socket address, internet style.
X */
Xstruct sockaddr_in {
X short sin_family;
X u_short sin_port;
X struct in_addr sin_addr;
X char sin_zero[8];
X};
X
X/*
X * Options for use with [gs]etsockopt at the IP level.
X */
X#define IP_OPTIONS 1 /* set/get IP per-packet options */
X
X#ifdef KERNEL
Xextern struct domain inetdomain;
Xextern struct protosw inetsw[];
Xstruct in_addr in_makeaddr();
Xu_long in_netof(), in_lnaof();
X#endif
END-of-netinet/in.h
echo x - netinet/in_cksum.c
sed 's/^X//' >netinet/in_cksum.c << 'END-of-netinet/in_cksum.c'
X/*
X * Copyright (c) 1988 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)in_cksum.c 7.1 (Berkeley) 3/29/88
X */
X
X#include "../h/types.h"
X#include "../h/mbuf.h"
X
X/*
X * Checksum routine for Internet Protocol family headers (Portable Version).
X *
X * This routine is very heavily used in the network
X * code and should be modified for each CPU to be as fast as possible.
X */
X
X#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
X#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
X
Xin_cksum_c(m, len)
X register struct mbuf *m;
X register int len;
X{
X register u_short *w;
X register int sum = 0;
X register int mlen = 0;
X int byte_swapped = 0;
X
X union {
X char c[2];
X u_short s;
X } s_util;
X union {
X u_short s[2];
X long l;
X } l_util;
X
X for (;m && len; m = m->m_next) {
X if (m->m_len == 0)
X continue;
X w = mtod(m, u_short *);
X if (mlen == -1) {
X /*
X * The first byte of this mbuf is the continuation
X * of a word spanning between this mbuf and the
X * last mbuf.
X *
X * s_util.c[0] is already saved when scanning previous
X * mbuf.
X */
X s_util.c[1] = *(char *)w;
X sum += s_util.s;
X w = (u_short *)((char *)w + 1);
X mlen = m->m_len - 1;
X len--;
X } else
X mlen = m->m_len;
X if (len < mlen)
X mlen = len;
X len -= mlen;
X /*
X * Force to even boundary.
X */
X if ((1 & (int) w) && (mlen > 0)) {
X REDUCE;
X sum <<= 8;
X s_util.c[0] = *(u_char *)w;
X w = (u_short *)((char *)w + 1);
X mlen--;
X byte_swapped = 1;
X }
X /*
X * Unroll the loop to make overhead from
X * branches &c small.
X */
X while ((mlen -= 32) >= 0) {
X sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
X sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7];
X sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11];
X sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15];
X w += 16;
X }
X mlen += 32;
X while ((mlen -= 8) >= 0) {
X sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3];
X w += 4;
X }
X mlen += 8;
X if (mlen == 0 && byte_swapped == 0)
X continue;
X REDUCE;
X while ((mlen -= 2) >= 0) {
X sum += *w++;
X }
X if (byte_swapped) {
X REDUCE;
X sum <<= 8;
X byte_swapped = 0;
X if (mlen == -1) {
X s_util.c[1] = *(char *)w;
X sum += s_util.s;
X mlen = 0;
X } else
X mlen = -1;
X } else if (mlen == -1)
X s_util.c[0] = *(char *)w;
X }
X if (len)
X printf("cksum: out of data\n");
X if (mlen == -1) {
X /* The last mbuf has odd # of bytes. Follow the
X standard (the odd byte may be shifted left by 8 bits
X or not as determined by endian-ness of the machine) */
X s_util.c[1] = 0;
X sum += s_util.s;
X }
X REDUCE;
X return (~sum & 0xffff);
X}
END-of-netinet/in_cksum.c
echo x - netinet/in_pcb.c
sed 's/^X//' >netinet/in_pcb.c << 'END-of-netinet/in_pcb.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)in_pcb.c 7.6 (Berkeley) 12/7/87
X */
X
X#include "param.h"
X#include "systm.h"
X#include "dir.h"
X#include "user.h"
X#include "mbuf.h"
X#include "socket.h"
X#include "socketvar.h"
X#include "ioctl.h"
X#include "in.h"
X#include "in_systm.h"
X#include "../net/if.h"
X#include "../net/route.h"
X#include "in_pcb.h"
X#include "in_var.h"
X#include "protosw.h"
X
Xstruct in_addr zeroin_addr;
X
Xin_pcballoc(so, head)
X struct socket *so;
X struct inpcb *head;
X{
X struct mbuf *m;
X register struct inpcb *inp;
X
X m = m_getclr(M_DONTWAIT, MT_PCB);
X if (m == NULL)
X return (ENOBUFS);
X inp = mtod(m, struct inpcb *);
X inp->inp_head = head;
X inp->inp_socket = so;
X insque(inp, head);
X so->so_pcb = (caddr_t)inp;
X return (0);
X}
X
Xin_pcbbind(inp, nam)
X register struct inpcb *inp;
X struct mbuf *nam;
X{
X register struct socket *so = inp->inp_socket;
X register struct inpcb *head = inp->inp_head;
X register struct sockaddr_in *sin;
X u_short lport = 0;
X
X if (in_ifaddr == 0)
X return (EADDRNOTAVAIL);
X if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
X return (EINVAL);
X if (nam == 0)
X goto noname;
X sin = mtod(nam, struct sockaddr_in *);
X if (nam->m_len != sizeof (*sin))
X return (EINVAL);
X if (sin->sin_addr.s_addr != INADDR_ANY) {
X int tport = sin->sin_port;
X
X sin->sin_port = 0; /* yech... */
X if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
X return (EADDRNOTAVAIL);
X sin->sin_port = tport;
X }
X lport = sin->sin_port;
X if (lport) {
X u_short aport = ntohs(lport);
X int wild = 0;
X
X /* GROSS */
X if (aport < IPPORT_RESERVED && u.u_uid != 0)
X return (EACCES);
X /* even GROSSER, but this is the Internet */
X if ((so->so_options & SO_REUSEADDR) == 0 &&
X ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
X (so->so_options & SO_ACCEPTCONN) == 0))
X wild = INPLOOKUP_WILDCARD;
X if (in_pcblookup(head,
X zeroin_addr, 0, sin->sin_addr, lport, wild))
X return (EADDRINUSE);
X }
X inp->inp_laddr = sin->sin_addr;
Xnoname:
X if (lport == 0)
X do {
X if (head->inp_lport++ < IPPORT_RESERVED ||
X head->inp_lport > IPPORT_USERRESERVED)
X head->inp_lport = IPPORT_RESERVED;
X lport = htons(head->inp_lport);
X } while (in_pcblookup(head,
X zeroin_addr, 0, inp->inp_laddr, lport, 0));
X inp->inp_lport = lport;
X return (0);
X}
X
X/*
X * Connect from a socket to a specified address.
X * Both address and port must be specified in argument sin.
X * If don't have a local address for this socket yet,
X * then pick one.
X */
Xin_pcbconnect(inp, nam)
X register struct inpcb *inp;
X struct mbuf *nam;
X{
X struct in_ifaddr *ia;
X struct sockaddr_in *ifaddr;
X register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
X
X if (nam->m_len != sizeof (*sin))
X return (EINVAL);
X if (sin->sin_family != AF_INET)
X return (EAFNOSUPPORT);
X if (sin->sin_port == 0)
X return (EADDRNOTAVAIL);
X if (in_ifaddr) {
X /*
X * If the destination address is INADDR_ANY,
X * use the primary local address.
X * If the supplied address is INADDR_BROADCAST,
X * and the primary interface supports broadcast,
X * choose the broadcast address for that interface.
X */
X#define satosin(sa) ((struct sockaddr_in *)(sa))
X if (sin->sin_addr.s_addr == INADDR_ANY)
X sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
X else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
X (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
X sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
X }
X if (inp->inp_laddr.s_addr == INADDR_ANY) {
X register struct route *ro;
X struct ifnet *ifp;
X
X ia = (struct in_ifaddr *)0;
X /*
X * If route is known or can be allocated now,
X * our src addr is taken from the i/f, else punt.
X */
X ro = &inp->inp_route;
X if (ro->ro_rt &&
X (satosin(&ro->ro_dst)->sin_addr.s_addr !=
X sin->sin_addr.s_addr ||
X inp->inp_socket->so_options & SO_DONTROUTE)) {
X RTFREE(ro->ro_rt);
X ro->ro_rt = (struct rtentry *)0;
X }
X if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
X (ro->ro_rt == (struct rtentry *)0 ||
X ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
X /* No route yet, so try to acquire one */
X ro->ro_dst.sa_family = AF_INET;
X ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
X sin->sin_addr;
X rtalloc(ro);
X }
X /*
X * If we found a route, use the address
X * corresponding to the outgoing interface
X * unless it is the loopback (in case a route
X * to our address on another net goes to loopback).
X */
X if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
X (ifp->if_flags & IFF_LOOPBACK) == 0)
X for (ia = in_ifaddr; ia; ia = ia->ia_next)
X if (ia->ia_ifp == ifp)
X break;
X if (ia == 0) {
X int fport = sin->sin_port;
X
X sin->sin_port = 0;
X ia = (struct in_ifaddr *)
X ifa_ifwithdstaddr((struct sockaddr *)sin);
X sin->sin_port = fport;
X if (ia == 0)
X ia = in_iaonnetof(in_netof(sin->sin_addr));
X if (ia == 0)
X ia = in_ifaddr;
X if (ia == 0)
X return (EADDRNOTAVAIL);
X }
X ifaddr = (struct sockaddr_in *)&ia->ia_addr;
X }
X if (in_pcblookup(inp->inp_head,
X sin->sin_addr,
X sin->sin_port,
X inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
X inp->inp_lport,
X 0))
X return (EADDRINUSE);
X if (inp->inp_laddr.s_addr == INADDR_ANY) {
X if (inp->inp_lport == 0)
X (void)in_pcbbind(inp, (struct mbuf *)0);
X inp->inp_laddr = ifaddr->sin_addr;
X }
X inp->inp_faddr = sin->sin_addr;
X inp->inp_fport = sin->sin_port;
X return (0);
X}
X
Xin_pcbdisconnect(inp)
X struct inpcb *inp;
X{
X
X inp->inp_faddr.s_addr = INADDR_ANY;
X inp->inp_fport = 0;
X if (inp->inp_socket->so_state & SS_NOFDREF)
X in_pcbdetach(inp);
X}
X
Xin_pcbdetach(inp)
X struct inpcb *inp;
X{
X struct socket *so = inp->inp_socket;
X
X so->so_pcb = 0;
X sofree(so);
X if (inp->inp_options)
X (void)m_free(inp->inp_options);
X if (inp->inp_route.ro_rt)
X rtfree(inp->inp_route.ro_rt);
X remque(inp);
X (void) m_free(dtom(inp));
X}
X
Xin_setsockaddr(inp, nam)
X register struct inpcb *inp;
X struct mbuf *nam;
X{
X register struct sockaddr_in *sin;
X
X nam->m_len = sizeof (*sin);
X sin = mtod(nam, struct sockaddr_in *);
X bzero((caddr_t)sin, sizeof (*sin));
X sin->sin_family = AF_INET;
X sin->sin_port = inp->inp_lport;
X sin->sin_addr = inp->inp_laddr;
X}
X
Xin_setpeeraddr(inp, nam)
X struct inpcb *inp;
X struct mbuf *nam;
X{
X register struct sockaddr_in *sin;
X
X nam->m_len = sizeof (*sin);
X sin = mtod(nam, struct sockaddr_in *);
X bzero((caddr_t)sin, sizeof (*sin));
X sin->sin_family = AF_INET;
X sin->sin_port = inp->inp_fport;
X sin->sin_addr = inp->inp_faddr;
X}
X
X/*
X * Pass some notification to all connections of a protocol
X * associated with address dst. Call the protocol specific
X * routine (if any) to handle each connection.
X */
Xin_pcbnotify(head, dst, errno, notify)
X struct inpcb *head;
X register struct in_addr *dst;
X int errno, (*notify)();
X{
X register struct inpcb *inp, *oinp;
X int s = splimp();
X
X for (inp = head->inp_next; inp != head;) {
X if (inp->inp_faddr.s_addr != dst->s_addr ||
X inp->inp_socket == 0) {
X inp = inp->inp_next;
X continue;
X }
X if (errno)
X inp->inp_socket->so_error = errno;
X oinp = inp;
X inp = inp->inp_next;
X if (notify)
X (*notify)(oinp);
X }
X splx(s);
X}
X
X/*
X * Check for alternatives when higher level complains
X * about service problems. For now, invalidate cached
X * routing information. If the route was created dynamically
X * (by a redirect), time to try a default gateway again.
X */
Xin_losing(inp)
X struct inpcb *inp;
X{
X register struct rtentry *rt;
X
X if ((rt = inp->inp_route.ro_rt)) {
X if (rt->rt_flags & RTF_DYNAMIC)
X (void) rtrequest((int)SIOCDELRT, rt);
X rtfree(rt);
X inp->inp_route.ro_rt = 0;
X /*
X * A new route can be allocated
X * the next time output is attempted.
X */
X }
X}
X
X/*
X * After a routing change, flush old routing
X * and allocate a (hopefully) better one.
X */
Xin_rtchange(inp)
X register struct inpcb *inp;
X{
X if (inp->inp_route.ro_rt) {
X rtfree(inp->inp_route.ro_rt);
X inp->inp_route.ro_rt = 0;
X /*
X * A new route can be allocated the next time
X * output is attempted.
X */
X }
X}
X
Xstruct inpcb *
Xin_pcblookup(head, faddr, fport, laddr, lport, flags)
X struct inpcb *head;
X struct in_addr faddr, laddr;
X u_short fport, lport;
X int flags;
X{
X register struct inpcb *inp, *match = 0;
X int matchwild = 3, wildcard;
X
X for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
X if (inp->inp_lport != lport)
X continue;
X wildcard = 0;
X if (inp->inp_laddr.s_addr != INADDR_ANY) {
X if (laddr.s_addr == INADDR_ANY)
X wildcard++;
X else if (inp->inp_laddr.s_addr != laddr.s_addr)
X continue;
X } else {
X if (laddr.s_addr != INADDR_ANY)
X wildcard++;
X }
X if (inp->inp_faddr.s_addr != INADDR_ANY) {
X if (faddr.s_addr == INADDR_ANY)
X wildcard++;
X else if (inp->inp_faddr.s_addr != faddr.s_addr ||
X inp->inp_fport != fport)
X continue;
X } else {
X if (faddr.s_addr != INADDR_ANY)
X wildcard++;
X }
X if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
X continue;
X if (wildcard < matchwild) {
X match = inp;
X matchwild = wildcard;
X if (matchwild == 0)
X break;
X }
X }
X return (match);
X}
END-of-netinet/in_pcb.c
echo x - netinet/in_pcb.h
sed 's/^X//' >netinet/in_pcb.h << 'END-of-netinet/in_pcb.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)in_pcb.h 7.2 (Berkeley) 12/7/87
X */
X
X/*
X * Common structure pcb for internet protocol implementation.
X * Here are stored pointers to local and foreign host table
X * entries, local and foreign socket numbers, and pointers
X * up (to a socket structure) and down (to a protocol-specific)
X * control block.
X */
Xstruct inpcb {
X struct inpcb *inp_next,*inp_prev;
X /* pointers to other pcb's */
X struct inpcb *inp_head; /* pointer back to chain of inpcb's
X for this protocol */
X struct in_addr inp_faddr; /* foreign host table entry */
X u_short inp_fport; /* foreign port */
X struct in_addr inp_laddr; /* local host table entry */
X u_short inp_lport; /* local port */
X struct socket *inp_socket; /* back pointer to socket */
X caddr_t inp_ppcb; /* pointer to per-protocol pcb */
X struct route inp_route; /* placeholder for routing entry */
X struct mbuf *inp_options; /* IP options */
X};
X
X#define INPLOOKUP_WILDCARD 1
X#define INPLOOKUP_SETLOCAL 2
X
X#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb)
X
X#ifdef KERNEL
Xstruct inpcb *in_pcblookup();
X#endif
END-of-netinet/in_pcb.h
echo x - netinet/in_proto.c
sed 's/^X//' >netinet/in_proto.c << 'END-of-netinet/in_proto.c'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)in_proto.c 7.2 (Berkeley) 12/7/87
X */
X
X#include "param.h"
X#include "socket.h"
X#include "protosw.h"
X#include "domain.h"
X#include "mbuf.h"
X
X#include "in.h"
X#include "in_systm.h"
X
X/*
X * TCP/IP protocol family: IP, ICMP, UDP, TCP.
X */
Xint ip_output(),ip_ctloutput();
Xint ip_init(),ip_slowtimo(),ip_drain();
Xint icmp_input();
Xint udp_input(),udp_ctlinput();
Xint udp_usrreq();
Xint udp_init();
Xint tcp_input(),tcp_ctlinput();
Xint tcp_usrreq(),tcp_ctloutput();
Xint tcp_init(),tcp_fasttimo(),tcp_slowtimo(),tcp_drain();
Xint rip_input(),rip_output(),rip_ctloutput();
Xextern int raw_usrreq();
X/*
X * IMP protocol family: raw interface.
X * Using the raw interface entry to get the timer routine
X * in is a kludge.
X */
X#include "imp.h"
X#if NIMP > 0
Xint rimp_output(), hostslowtimo();
X#endif
X
X#ifdef NSIP
Xint idpip_input(), nsip_ctlinput();
X#endif
X
Xextern struct domain inetdomain;
X
Xstruct protosw inetsw[] = {
X{ 0, &inetdomain, 0, 0,
X 0, ip_output, 0, 0,
X 0,
X ip_init, 0, ip_slowtimo, ip_drain,
X},
X{ SOCK_DGRAM, &inetdomain, IPPROTO_UDP, PR_ATOMIC|PR_ADDR,
X udp_input, 0, udp_ctlinput, ip_ctloutput,
X udp_usrreq,
X udp_init, 0, 0, 0,
X},
X{ SOCK_STREAM, &inetdomain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD,
X tcp_input, 0, tcp_ctlinput, tcp_ctloutput,
X tcp_usrreq,
X tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain,
X},
X{ SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR,
X rip_input, rip_output, 0, rip_ctloutput,
X raw_usrreq,
X 0, 0, 0, 0,
X},
X{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR,
X icmp_input, rip_output, 0, rip_ctloutput,
X raw_usrreq,
X 0, 0, 0, 0,
X},
X#ifdef NSIP
X{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR,
X idpip_input, rip_output, nsip_ctlinput, 0,
X raw_usrreq,
X 0, 0, 0, 0,
X},
X#endif
X /* raw wildcard */
X{ SOCK_RAW, &inetdomain, 0, PR_ATOMIC|PR_ADDR,
X rip_input, rip_output, 0, rip_ctloutput,
X raw_usrreq,
X 0, 0, 0, 0,
X},
X};
X
Xstruct domain inetdomain =
X { AF_INET, "internet", 0, 0, 0,
X inetsw, &inetsw[sizeof(inetsw)/sizeof(inetsw[0])] };
X
X#if NIMP > 0
Xextern struct domain impdomain;
X
Xstruct protosw impsw[] = {
X{ SOCK_RAW, &impdomain, 0, PR_ATOMIC|PR_ADDR,
X 0, rimp_output, 0, 0,
X raw_usrreq,
X 0, 0, hostslowtimo, 0,
X},
X};
X
Xstruct domain impdomain =
X { AF_IMPLINK, "imp", 0, 0, 0,
X impsw, &impsw[sizeof (impsw)/sizeof(impsw[0])] };
X#endif
X
X#include "hy.h"
X#if NHY > 0
X/*
X * HYPERchannel protocol family: raw interface.
X */
Xint rhy_output();
Xextern struct domain hydomain;
X
Xstruct protosw hysw[] = {
X{ SOCK_RAW, &hydomain, 0, PR_ATOMIC|PR_ADDR,
X 0, rhy_output, 0, 0,
X raw_usrreq,
X 0, 0, 0, 0,
X},
X};
X
Xstruct domain hydomain =
X { AF_HYLINK, "hy", 0, 0, 0, hysw, &hysw[sizeof (hysw)/sizeof(hysw[0])] };
X#endif
END-of-netinet/in_proto.c
echo x - netinet/in_systm.h
sed 's/^X//' >netinet/in_systm.h << 'END-of-netinet/in_systm.h'
X/*
X * Copyright (c) 1982, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)in_systm.h 7.2 (Berkeley) 12/7/87
X */
X
X/*
X * Miscellaneous internetwork
X * definitions for kernel.
X */
X
X/*
X * Network types.
X *
X * Internally the system keeps counters in the headers with the bytes
X * swapped so that VAX instructions will work on them. It reverses
X * the bytes before transmission at each protocol level. The n_ types
X * represent the types with the bytes in ``high-ender'' order.
X */
Xtypedef u_short n_short; /* short as received from the net */
Xtypedef u_long n_long; /* long as received from the net */
X
Xtypedef u_long n_time; /* ms since 00:00 GMT, byte rev */
X
X#ifdef KERNEL
Xn_time iptime();
X#endif
END-of-netinet/in_systm.h
echo x - netinet/in_var.h
sed 's/^X//' >netinet/in_var.h << 'END-of-netinet/in_var.h'
X/*
X * Copyright (c) 1985, 1986 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that this notice is preserved and that due credit is given
X * to the University of California at Berkeley. The name of the University
X * may not be used to endorse or promote products derived from this
X * software without specific prior written permission. This software
X * is provided ``as is'' without express or implied warranty.
X *
X * @(#)in_var.h 7.2 (Berkeley) 12/7/87
X */
X
X/*
X * Interface address, Internet version. One of these structures
X * is allocated for each interface with an Internet address.
X * The ifaddr structure contains the protocol-independent part
X * of the structure and is assumed to be first.
X */
Xstruct in_ifaddr {
X struct ifaddr ia_ifa; /* protocol-independent info */
X#define ia_addr ia_ifa.ifa_addr
X#define ia_broadaddr ia_ifa.ifa_broadaddr
X#define ia_dstaddr ia_ifa.ifa_dstaddr
X#define ia_ifp ia_ifa.ifa_ifp
X u_long ia_net; /* network number of interface */
X u_long ia_netmask; /* mask of net part */
X u_long ia_subnet; /* subnet number, including net */
X u_long ia_subnetmask; /* mask of net + subnet */
X struct in_addr ia_netbroadcast; /* broadcast addr for (logical) net */
X int ia_flags;
X struct in_ifaddr *ia_next; /* next in list of internet addresses */
X};
X/*
X * Given a pointer to an in_ifaddr (ifaddr),
X * return a pointer to the addr as a sockadd_in.
X */
X#define IA_SIN(ia) ((struct sockaddr_in *)(&((struct in_ifaddr *)ia)->ia_addr))
X/*
X * ia_flags
X */
X#define IFA_ROUTE 0x01 /* routing entry installed */
X
X#ifdef KERNEL
Xstruct in_ifaddr *in_ifaddr;
Xstruct in_ifaddr *in_iaonnetof();
Xstruct ifqueue ipintrq; /* ip packet input queue */
X#endif
END-of-netinet/in_var.h
exit
More information about the Comp.bugs.4bsd.ucb-fixes
mailing list