shannon@sun.uucp (Bill Shannon) (03/20/84)
----- cut here and extract with sh echo x - README sed 's/^X//' >README <<'!Funky!Stuff!' NEW ARP HANDLING FOR 4.2bsd (Release of 03/16/84) The code included here can be inserted into a VAX 4.2bsd system (with a little work) to greatly improve the flexibility and usability of the Ethernet Address Resolution Protocol. (See enclosed manual pages for more information.) There is no warranty of merchantability nor any warranty of fitness for a particular purpose nor any other warranty, either express or implied, as to the accuracy of the enclosed materials or as to their suitability for any particular purpose. Accordingly, Sun Microsystems Inc. assumes no responsibility for their use by the recipient. Further, Sun Microsystems Inc. assumes no obligation to furnish any assistance of any kind whatsoever, or to furnish any additional information or documentation. The included files are: README - this file arp.4p - improved ARP manual page arp.8c - manual page for new arp command ifconfig.8c - replacement manual page describing new options arp.c - code for new arp command if.c.diffs - changes to /sys/net/if.c if.h.diffs - changes to /sys/net/if.h if_ec.c.diffs - changes to /sys/vaxif/if_ec.c, as an example of changes necessary to ALL network drivers if_ether.c.diffs - changes to /sys/netinet/if_ether.c if_ether.h.diffs - changes to /sys/netinet/if_ether.h ifconfig.c.diffs - changes to /usr/src/etc/if_config.c ioctl.h.diffs - changes to /sys/h/ioctl.h (and /usr/include/ sys/ioctl.h if it isn't a link) ether_print - small routine to be added somewhere, it's in autoconf.c in the Sun system, but if_ether.c may be more appropriate in the VAX system Overview of changes You will have to change all of your network device drivers in order to put this code into your system. The changes should be straight-forward and are necessitated by the following changes to common code. 1. Ethernet addresses are now a structure instead of a 6 byte array. This allows them to be assigned directly instead of having to use bcopy. Hint - look for "edst" in the driver, all references to it will have to be changed. 2. The third address to the driver ioctl routines has changed. See the enclosed modifications of if_ec.c for an example. 3. Routine arpmyaddr() is gone. It always returned zero. Most drivers call it in the attach routine, just remove the line containing the call. The *.diffs files are diff -e scripts that can be applied to the standard files supplied with 4.2bsd. The diffs apply to the following versions of these files: /* if.c 6.2 83/09/27 */ /* if.h 6.2 83/08/28 */ /* if_ec.c 6.1 83/07/29 */ /* if_ether.c 6.2 83/08/28 */ /* if_ether.h 6.2 83/09/26 */ /* ioctl.h 6.1 83/07/29 */ static char sccsid[] = "@(#)ifconfig.c 4.5 (Berkeley) 11/2/83"; If you've modified any of these files locally you'll have to find the originals from your 4.2 distribution and apply the diffs to them, then merge in any local changes. Apply the diffs using a set of commands like this: chmod +w file ed - file <file.diffs You may want to save the originals before changing them. Good luck! Bill Shannon {ucbvax, decvax}!sun!shannon Sun Microsystems, Inc. !Funky!Stuff! echo x - arp.4p sed 's/^X//' >arp.4p <<'!Funky!Stuff!' X.\" @(#)arp.4p 1.8 84/02/02 SMI; from UCB 4.1 X.TH ARP 4P "11 January 1984" X.SH NAME arp \- Address Resolution Protocol X.SH SYNOPSIS X.B "pseudo-device ether" X.SH DESCRIPTION ARP is a protocol used to dynamically map between DARPA Internet and 10Mb/s Ethernet addresses. It is used by all the 10Mb/s Ethernet interface drivers. X.PP ARP caches Internet-Ethernet address mappings. When an interface requests a mapping for an address not in the cache, ARP queues the message which requires the mapping and broadcasts a message on the associated network requesting the address mapping. If a response is provided, the new mapping is cached and any pending messages are transmitted. ARP will queue at most one packet while waiting for a mapping request to be responded to; only the most recently ``transmitted'' packet is kept. X.PP To enable communications with systems which do not use ARP, ioctls are provided to enter and delete entries in the Internet-to-Ethernet tables. Usage: X.LP X.nf X.ft B #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> struct arpreq arpreq; ioctl(s, SIOCSARP, (caddr_t)&arpreq); ioctl(s, SIOCGARP, (caddr_t)&arpreq); ioctl(s, SIOCDARP, (caddr_t)&arpreq); X.fi X.ft R Each ioctl takes the same structure as an argument. SIOCSARP sets an ARP entry, SIOCGARP gets an ARP entry, and SIOCDARP deletes an ARP entry. These ioctls may be applied to any socket descriptor X.I s, but only by the super-user. The X.I arpreq structure contains: X.LP X.nf /* * ARP ioctl request */ struct arpreq { struct sockaddr arp_pa; /* protocol address */ struct sockaddr arp_ha; /* hardware address */ int arp_flags; /* flags */ }; /* arp_flags field values */ #define ATF_COM 2 /* completed entry (arp_ha valid) */ #define ATF_PERM 4 /* permanent entry */ #define ATF_PUBL 8 /* publish (respond for other host) */ X.fi X.LP The address family for the X.I arp_pa sockaddr must be AF_INET; for the X.I arp_ha sockaddr it must be AF_UNSPEC. The only flag bits which may be written are ATF_PERM and ATF_PUBL. ATF_PERM causes the entry to be permanent if the ioctl call succeeds. The peculiar nature of the ARP tables may cause the ioctl to fail if more than 4 (permanent) Internet host addresses hash to the same slot. ATF_PUBL specifies that the ARP code should respond to ARP requests for the indicated host coming from other machines. This allows a Sun to act as an "ARP server" which may be useful in convincing an ARP-only machine to talk to a non-ARP machine. X.PP ARP watches passively for hosts impersonating the local host (i.e. a host which responds to an ARP mapping request for the local host's address). X.SH DIAGNOSTICS X.B "duplicate IP address!! sent from ethernet address: %x:%x:%x:%x:%x:%x." ARP has discovered another host on the local network which responds to mapping requests for its own Internet address. X.SH SEE ALSO ec(4S), ie(4S), inet(4F), arp(8C), ifconfig(8C) X.br An Ethernet Address Resolution Protocol, RFC826, Dave Plummer, MIT (Sun 800-1059-01) X.SH BUGS ARP packets on the Ethernet use only 42 bytes of data, however, the smallest legal Ethernet packet is 60 bytes (not including CRC). Some systems may not enforce the minimum packet size, others will. !Funky!Stuff! echo x - arp.8c sed 's/^X//' >arp.8c <<'!Funky!Stuff!' X.\" @(#)arp.8c 1.1 84/01/12 SMI; X.TH ARP 8C "12 January 1984" X.SH NAME arp \- address resolution display and control X.SH SYNOPSIS X.B arp X.I hostname X.br X.B arp -a [ X.I vmunix ] [ X.I kmem ] X.br X.B arp -d X.I hostname X.br X.B arp -s X.I hostname ether_addr [ X.B temp ] [ X.B pub ] X.br X.B arp -f X.I filename X.SH DESCRIPTION The X.I arp program displays and modifies the Internet-to-Ethernet address translation tables used by the address resolution protocol ( X.IR arp (4p)). X.LP With no flags, the program displays the current ARP entry for X.I hostname. With the X.B -a flag, the program displays all of the current ARP entries by reading the table from the file X.I kmem (default /dev/kmem) based on the kernel file X.I vmunix (default /vmunix). X.LP With the X.B -d flag, a super-user may delete an entry for the host called X.I hostname. X.LP The X.B -s flag is given to create an ARP entry for the host called X.I hostname with the Ethernet address X.I ether_addr. The Ethernet address is given as six hex bytes separated by colons. The entry will be permanent unless the word X.B temp is given in the command. If the word X.B pub is given, the entry will be "published", e.g., this system will respond to ARP requests for X.I hostname even though the hostname is not its own. X.LP The X.B -f flag causes the file X.I filename to be read and multiple entries to be set in the ARP tables. Entries in the file should be of the form X.IP X.I hostname ether_addr [ X.B temp ] [ X.B pub ] X.LP with argument meanings as given above. X.SH "SEE ALSO" arp(4p), ifconfig(8c) !Funky!Stuff! echo x - arp.c sed 's/^X//' >arp.c <<'!Funky!Stuff!' #ifndef lint static char sccsid[] = "@(#)arp.c 1.1 83/11/29 SMI"; #endif /* * arp - display, set, and delete arp table entries */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/ioctl.h> #include <errno.h> #include <netdb.h> #include <nlist.h> #include <net/if.h> #include <netinet/if_ether.h> extern int errno; main(argc, argv) char **argv; { if (argc >= 2 && strcmp(argv[1], "-a") == 0) { char *kernel = "/vmunix", *mem = "/dev/kmem"; if (argc >= 3) kernel = argv[2]; if (argc >= 4) mem = argv[3]; dump(kernel, mem); exit(0); } if (argc == 2) { get(argv[1]); exit(0); } if (argc >= 4 && strcmp(argv[1], "-s") == 0) { set(argc-2, &argv[2]); exit(0); } if (argc == 3 && strcmp(argv[1], "-d") == 0) { delete(argv[2]); exit(0); } if (argc == 3 && strcmp(argv[1], "-f") == 0) { file(argv[2]); exit(0); } usage(); exit(1); } /* * Process a file to set standard arp entries */ file(name) char *name; { FILE *fp; int i; char line[100], arg[4][50], *args[4]; if ((fp = fopen(name, "r")) == NULL) { fprintf(stderr, "arp: cannot open %s\n", name); exit(1); } args[0] = &arg[0][0]; args[1] = &arg[1][0]; args[2] = &arg[2][0]; args[3] = &arg[3][0]; while(fgets(line, 100, fp) != NULL) { i = sscanf(line, "%s %s %s %s", arg[0], arg[1], arg[2], arg[3]); if (i < 2) { fprintf(stderr, "arp: bad line: %s\n", line); continue; } set(i, args); } fclose(fp); } /* * Set an individual arp entry */ set(argc, argv) char **argv; { struct arpreq ar; struct hostent *hp; struct sockaddr_in *sin; struct ether_addr *ea; int s; char *host = argv[0], *eaddr = argv[1]; argc -= 2; argv += 2; hp = gethostbyname(host); if (hp == NULL) { fprintf(stderr, "arp: %s: unknown host\n", host); return (1); } bzero((caddr_t)&ar, sizeof ar); ar.arp_pa.sa_family = AF_INET; sin = (struct sockaddr_in *)&ar.arp_pa; sin->sin_addr = *(struct in_addr *)hp->h_addr; ea = (struct ether_addr *)ar.arp_ha.sa_data; if (ether_aton(eaddr, ea)) return; ar.arp_flags = ATF_PERM; while(argc-- > 0) { if (strncmp(argv[0], "temp", 4) == 0) ar.arp_flags &= ~ATF_PERM; if (strncmp(argv[0], "pub", 3) == 0) ar.arp_flags |= ATF_PUBL; argv++; } s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("arp: socket"); exit(1); } if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) { perror(host); exit(1); } close(s); } /* * Display an individual arp entry */ get(host) char *host; { struct arpreq ar; struct hostent *hp; struct sockaddr_in *sin; struct ether_addr *ea; int s; hp = gethostbyname(host); if (hp == NULL) { fprintf(stderr, "arp: %s: unknown host\n", host); exit(1); } bzero((caddr_t)&ar, sizeof ar); ar.arp_pa.sa_family = AF_INET; sin = (struct sockaddr_in *)&ar.arp_pa; sin->sin_addr = *(struct in_addr *)hp->h_addr; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("arp: socket"); exit(1); } if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) { if (errno == ENXIO) printf("%s (%s) -- no entry\n", host, inet_ntoa(sin->sin_addr)); else perror("SIOCGARP"); exit(1); } close(s); ea = (struct ether_addr *)ar.arp_ha.sa_data; printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr)); if (ar.arp_flags & ATF_COM) ether_print(ea); else printf("(incomplete)"); if (!(ar.arp_flags & ATF_PERM)) printf(" temporary"); if (ar.arp_flags & ATF_PUBL) printf(" published"); printf("\n"); } /* * Delete an arp entry */ delete(host) char *host; { struct arpreq ar; struct hostent *hp; struct sockaddr_in *sin; int s; hp = gethostbyname(host); if (hp == NULL) { fprintf(stderr, "arp: %s: unknown host\n", host); exit(1); } bzero((caddr_t)&ar, sizeof ar); ar.arp_pa.sa_family = AF_INET; sin = (struct sockaddr_in *)&ar.arp_pa; sin->sin_addr = *(struct in_addr *)hp->h_addr; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("arp: socket"); exit(1); } if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) { if (errno == ENXIO) printf("%s (%s) -- no entry\n", host, inet_ntoa(sin->sin_addr)); else perror("SIOCDARP"); exit(1); } close(s); printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); } struct nlist nl[] = { #define X_ARPTAB 0 { "_arptab" }, #define X_ARPTAB_SIZE 1 { "_arptab_size" }, { "" }, }; /* * Dump the entire arp table */ dump(kernel, mem) char *kernel, *mem; { int mf, arptab_size, sz; struct arptab *at; struct hostent *hp; char *host; nlist(kernel, nl); if(nl[X_ARPTAB_SIZE].n_type == 0) { fprintf(stderr, "arp: %s: bad namelist\n", kernel); exit(1); } mf = open(mem, 0); if(mf < 0) { fprintf(fprintf, "arp: cannot open %s\n", mem); exit(1); } lseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, 0); read(mf, &arptab_size, sizeof arptab_size); if (arptab_size <=0 || arptab_size > 1000) { fprintf(stderr, "arp: %s: namelist wrong\n", kernel); exit(1); } sz = arptab_size * sizeof (struct arptab); at = (struct arptab *)malloc(sz); if (at == NULL) { fprintf(stderr, "arp: can't get memory for arptab\n"); exit(1); } lseek(mf, (long)nl[X_ARPTAB].n_value, 0); if (read(mf, (char *)at, sz) != sz) { perror("arp: error reading arptab"); exit(1); } close(mf); for (; arptab_size-- > 0; at++) { if (at->at_iaddr.s_addr == 0 || at->at_flags == 0) continue; hp = gethostbyaddr((caddr_t)&at->at_iaddr, sizeof at->at_iaddr, AF_INET); if (hp) host = hp->h_name; else host = "?"; printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr)); if (at->at_flags & ATF_COM) ether_print(&at->at_enaddr); else printf("(incomplete)"); if (!(at->at_flags & ATF_PERM)) printf(" temporary"); if (at->at_flags & ATF_PUBL) printf(" published"); printf("\n"); } } ether_print(ea) struct ether_addr *ea; { u_char *cp = &ea->ether_addr_octet[0]; printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); } ether_aton(a, n) char *a; struct ether_addr *n; { int i, o[6]; i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], &o[3], &o[4], &o[5]); if (i != 6) { fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a); return (1); } for (i=0; i<6; i++) n->ether_addr_octet[i] = o[i]; return (0); } usage() { printf("Usage: arp hostname\n"); printf(" arp -a [/vmunix] [/dev/kmem]\n"); printf(" arp -d hostname\n"); printf(" arp -s hostname ether_addr [temp] [pub]\n"); printf(" arp -f filename\n"); } !Funky!Stuff! echo x - ether_print sed 's/^X//' >ether_print <<'!Funky!Stuff!' ether_print(ea) struct ether_addr *ea; { u_char *cp = &ea->ether_addr_octet[0]; printf("%x:%x:%x:%x:%x:%x\n", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); } !Funky!Stuff! echo x - if.c.diffs sed 's/^X//' >if.c.diffs <<'!Funky!Stuff!' 260a } /* * Set a new interface address. * Called by ND address assignment as well as above * XXX Most of what the drivers do is device independent! */ if_setaddr(ifp, sa) register struct ifnet *ifp; struct sockaddr *sa; { if (ifp->if_ioctl == 0) return (EOPNOTSUPP); return ((*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)sa)); X. 258c return ((*ifp->if_ioctl)(ifp, cmd, ifr->ifr_data)); X. 254a case SIOCSIFADDR: return (if_setaddr(ifp, &ifr->ifr_addr)); X. 218a case SIOCSARP: case SIOCDARP: if (!suser()) return (u.u_error); /* fall through */ case SIOCGARP: return (arpioctl(cmd, data)); X. 194c unit = *cp - '0'; X. 192c if (*cp == '\0' || cp == name + IFNAMSIZ || cp == name) X. 1c /* @(#)if.c 1.5 83/12/07 SMI; from UCB 6.2 83/09/27 */ X. w !Funky!Stuff! echo x - if.h.diffs sed 's/^X//' >if.h.diffs <<'!Funky!Stuff!' 154a /* * ARP ioctl request */ struct arpreq { struct sockaddr arp_pa; /* protocol address */ struct sockaddr arp_ha; /* hardware address */ int arp_flags; /* flags */ }; /* arp_flags and at_flags field values */ #define ATF_INUSE 1 /* entry in use */ #define ATF_COM 2 /* completed entry (enaddr valid) */ #define ATF_PERM 4 /* permanent entry */ #define ATF_PUBL 8 /* publish entry (respond for other host) */ X. 1c /* @(#)if.h 1.6 84/01/11 SMI; from UCB 6.2 83/08/28 */ X. w !Funky!Stuff! echo x - if_ec.c.diffs sed 's/^X//' >if_ec.c.diffs <<'!Funky!Stuff!' 754c ecsetaddr(ifp, sin); X. 751a sa = (struct sockaddr *)data; if (sa->sa_family == AF_UNSPEC) { if (sa->sa_data[0] & 1) /* broad or multi-cast */ return (EINVAL); es->es_addr = *(struct ether_addr *)sa->sa_data; ecinit(ifp->if_unit); break; } sin = (struct sockaddr_in *)data; if (sin->sin_family != AF_INET) return (EINVAL); X. 746c struct ec_softc *es = &ec_softc[ifp->if_unit]; struct sockaddr *sa; struct sockaddr_in *sin; X. 584d 582c ec->ether_dhost = edst; ec->ether_shost = es->es_addr; X. 539c edst = ec->ether_dhost; X. 516c if (!arpresolve(&es->es_ac, m, &idst, &edst)) X. 503c struct ether_addr edst; X. 245d 183d 171c cp = (u_char *)&es->es_addr; X. 1c /* if_ec.c 6.1.1 84/03/16 */ X. w !Funky!Stuff! echo x - if_ether.c.diffs sed 's/^X//' >if_ether.c.diffs <<'!Funky!Stuff!' 390a } arpioctl(cmd, data) int cmd; caddr_t data; { register struct arpreq *ar = (struct arpreq *)data; register struct arptab *at; register struct sockaddr_in *sin; int s; 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 */ if (cmd != SIOCSARP) { splx(s); return (ENXIO); } if (if_ifwithnet(&ar->arp_pa) == NULL) { splx(s); return (ENETUNREACH); } at = arptnew(&sin->sin_addr); } switch (cmd) { case SIOCSARP: /* set entry */ at->at_enaddr = *(struct ether_addr *)ar->arp_ha.sa_data; at->at_flags = ATF_COM | ATF_INUSE | (ar->arp_flags & (ATF_PERM|ATF_PUBL)); at->at_timer = 0; if (ar->arp_flags & ATF_PERM) { /* never make all entries in a bucket permanent */ register struct arptab *tat; struct in_addr addr; /* defeat has and try to re-allocate */ addr = at->at_iaddr; at->at_iaddr.s_addr = 0; tat = arptnew(&addr); if (tat == NULL) { arptfree(at); splx(s); return (EADDRNOTAVAIL); } arptfree(tat); at->at_iaddr = addr; } break; case SIOCDARP: /* delete entry */ arptfree(at); break; case SIOCGARP: /* get entry */ *(struct ether_addr *)ar->arp_ha.sa_data = at->at_enaddr; ar->arp_flags = at->at_flags; break; } splx(s); return (0); X. 384a if (ato == NULL) return (NULL); X. 380c if (at->at_flags & ATF_PERM) continue; if (ato == NULL || at->at_timer > oldest) { X. 376c if (first) { first = 0; timeout(arptimer, (caddr_t)0, hz); } at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ]; ato = NULL; X. 374a static int first = 1; X. 366a * This always succeeds for dynamic entries since arpioctl * gaurantees that no bucket can be completely filled * with permanent entries. X. 348a * Called just before buffer passed to ipintr. If ip_src.s_net is 0, * then make the ether source address available by saving the mapping. */ arpipin(ec, m) register struct ether_header *ec; register struct mbuf *m; { register struct ip *ip; int hlen; extern int ipcksum; if (m->m_len < sizeof(struct ip)) return; ip = mtod(m, struct ip *); if (ip->ip_src.s_net != 0) return; arpseten(&ip->ip_src, &ec->ether_shost); } /* * Get an ethernet address, given the IP address. */ struct ether_addr * arpgeten(addr) register struct in_addr *addr; { register struct arptab *at; ARPTAB_LOOK(at, addr->s_addr); if (at == 0 || (at->at_flags & ATF_COM) == 0) return (0); return (&at->at_enaddr); } /* * Set an ether/IP mapping. Called externally to force a mapping. */ arpseten(iaddr, eaddr) struct in_addr *iaddr; struct ether_addr *eaddr; { register struct arptab *at; int s = splimp(); ARPTAB_LOOK(at, iaddr->s_addr); if (at == 0) at = arptnew(iaddr); at->at_timer = ARPT_KILLC - 3; /* so it expires faster than normal */ at->at_flags |= ATF_COM; if (at->at_hold) m_freem(at->at_hold); at->at_hold = 0; at->at_enaddr = *eaddr; splx(s); } #endif IPENADDR /* X. 347a #ifdef IPENADDR X. 337,338c eh->ether_dhost = arp_tha(ea); X. 327,334c arp_tha(ea) = arp_sha(ea); arp_tpa(ea) = arp_spa(ea); arp_sha(ea) = at->at_enaddr; arp_spa(ea) = itaddr; X. 325a ARPTAB_LOOK(at, itaddr.s_addr); if (at == NULL) { if (itaddr.s_addr != myaddr.s_addr) goto out; /* if I am not the target */ at = arptnew(&myaddr); at->at_enaddr = ac->ac_enaddr; at->at_flags |= ATF_COM; } if (itaddr.s_addr != myaddr.s_addr && (at->at_flags & ATF_PUBL) == 0) goto out; X. 320,321c at->at_enaddr = arp_sha(ea); X. 315,318c } else if (itaddr.s_addr == myaddr.s_addr) { /* ensure we have a table entry */ X. 303,305c if (at) { /* XXX ? - can overwrite ATF_PERM */ at->at_enaddr = arp_sha(ea); X. 295,297c ether_print(&arp_sha(ea)); itaddr = myaddr; X. 288,290c isaddr = arp_spa(ea); itaddr = arp_tpa(ea); if (!bcmp((caddr_t)&arp_sha(ea), (caddr_t)&ac->ac_enaddr, X. 283a if (ac->ac_if.if_flags & IFF_NOARP) goto out; X. 266c * is received. Algorithm is that given in RFC 826. X. 243,264d 225c *desten = at->at_enaddr; X. 217,221c if (ifp->if_flags & IFF_NOARP) { *desten = ac->ac_enaddr; desten->ether_addr_octet[3] = (lna >> 16) & 0x7f; desten->ether_addr_octet[4] = (lna >> 8) & 0xff; desten->ether_addr_octet[5] = lna & 0xff; splx(s); return (1); } else { at = arptnew(destip); at->at_hold = m; arpwhohas(ac, destip); splx(s); return (0); } X. 213a #endif IPENADDR X. 207,211c #ifdef IPENADDR if (destip->s_net == 0) { /* real IP address unknown */ struct ether_addr *arpgeten(), *ap; if ((ap = arpgeten(destip)) == NULL) return (0); *desten = *ap; X. 195,196c *desten = etherbroadcastaddr; X. 189a register int i; X. 186c register struct ether_addr *desten; X. 168c return ((*ac->ac_if.if_output)(&ac->ac_if, m, &sa)); X. 162,166c arp_sha(ea) = ac->ac_enaddr; arp_spa(ea) = ((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr; arp_tpa(ea) = *addr; X. 159,160c ea->arp_hln = sizeof arp_sha(ea); /* hardware address length */ ea->arp_pln = sizeof arp_spa(ea); /* protocol address length */ X. 154,155c eh->ether_dhost = etherbroadcastaddr; X. 148,149c return (1); m->m_len = sizeof *ea; X. 124c if (at->at_flags == 0 || (at->at_flags & ATF_PERM)) X. 105,119d 100a register struct arpcom *ac; X. 78,96d 62,75c #define IPENADDR 0 /* enable passing enaddr's thru IP layer */ X. 59c struct ether_addr etherbroadcastaddr = {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}; X. 51d 37a int arptab_size = ARPTAB_SIZE; /* for arp command */ X. 19,33d 16a #include "../netinet/in_systm.h" #include "../netinet/ip.h" X. 13a #include "../h/ioctl.h" X. 1c #ifndef lint static char sccsid[] = "@(#)if_ether.c 1.7 84/02/08 SMI"; #endif X. w !Funky!Stuff! echo x - if_ether.h.diffs sed 's/^X//' >if_ether.h.diffs <<'!Funky!Stuff!' 61,62c struct ether_addr etherbroadcastaddr; X. 59a /* * Internet to ethernet address resolution table. */ struct arptab { struct in_addr at_iaddr; /* internet address */ struct ether_addr at_enaddr; /* ethernet address */ struct mbuf *at_hold; /* last packet until resolved/timeout */ u_char at_timer; /* minutes since last reference */ u_char at_flags; /* flags */ }; X. 56c struct ether_addr ac_enaddr; /* ethernet hardware address */ X. 47a #define arp_sha(ea) (*(struct ether_addr *)(ea)->arp_xsha) #define arp_spa(ea) (*(struct in_addr *)(ea)->arp_xspa) #define arp_tha(ea) (*(struct ether_addr *)(ea)->arp_xtha) #define arp_tpa(ea) (*(struct in_addr *)(ea)->arp_xtpa) X. 43,46c u_char arp_xsha[6]; /* sender hardware address */ u_char arp_xspa[4]; /* sender protocol address */ u_char arp_xtha[6]; /* target hardware address */ u_char arp_xtpa[4]; /* target protocol address */ X. 7,8c struct ether_addr ether_dhost; struct ether_addr ether_shost; X. 3a * Ethernet address - 6 octets */ struct ether_addr { u_char ether_addr_octet[6]; }; /* X. 1c /* @(#)if_ether.h 1.4 84/01/11 SMI; from UCB 4.5 83/05/15 */ X. w !Funky!Stuff! echo x - ifconfig.8c sed 's/^X//' >ifconfig.8c <<'!Funky!Stuff!' X.\" @(#)ifconfig.8c 1.2 84/01/11 SMI; X.TH IFCONFIG 8C "12 January 1984" X.UC 4 X.SH NAME ifconfig \- configure network interface parameters X.SH SYOPNSIS X.B /etc/ifconfig interface [ X.I Ethernet_address ] [ X.I hostname ] [ X.I parameters ] X.SH DESCRIPTION X.I Ifconfig is used to assign an address to a network interface and/or to configure network interface parameters. X.I Ifconfig must be used at boot time to define the network address of each interface present on a machine; it may also be used at a later time to redefine an interface's address. Used without options, X.I ifconfig displays the current configuration for a network interface. Only the super-user may modify the configuration of a network interface. X.LP The X.B interface parameter is a string of the form ``name unit'', for example ``ie0''. X.SH OPTIONS X.LP \fIEthernet_address\fP is the hardware Ethernet address of a given machine. The address is a 6-byte hexadecimal value; each byte of the address is separated by a colon. A typical Ethernet adddress is `8:0:20:1:1:A3'. This address is contained in the ID PROM on the Sun-2 CPU Board, and is reported at boot time as one of the PROM monitor's sign-on messages. The \fIEthernet_address\fP option is normally not used \(em the hardware supplies the default; the option is used only when trying to talk to a device which does not support ARP (like a VAX on a 4.1c network). X.LP \fIhostname\fP may be either the hostname of a given machine (present in the hostname database, \fIhosts\fP\^(5)), or the complete Internet address consisting of your system's network number and the machine's unique host number. A typical Internet address might be ``192.9.200.44'', where ``192.9.200'' is the network number and ``44'' is the machine's hostnumber. To find a machine's Internet address, consult the local \fI/etc/hosts\fP file. X.PP The following \fIparameters\fP may be set with X.IR ifconfig : X.TP 15 X.B "\ \ \ up" Mark an interface ``up''. X.TP 15 X.B "\ \ \ down" Mark an interface ``down''. When an interface is marked ``down'', the system will not attempt to transmit messages through that interface. X.TP 15 X.B "\ \ \ trailers" Enable the use of a ``trailer'' link level encapsulation when sending (default). If a network interface supports X.IR trailers , the system will, when possible, encapsulate outgoing messages in a manner which minimizes the number of memory to memory copy operations performed by the receiver. X.TP 15 X.B "\ \ \ \-trailers" Disable the use of a ``trailer'' link level encapsulation. X.TP 15 X.B "\ \ \ arp Enable the use of the Address Resolution Protocol in mapping between network level addresses and link level addresses (default). This is currently implemented for mapping between DARPA Internet addreses and 10Mb/s Ethernet addresses. X.TP 15 X.B "\ \ \ \-arp" Disable the use of the Address Resolution Protocol. X.RE X.SH DIAGNOSTICS Messages indicating the specified interface does not exit, the requested address is unknown, the user is not privileged and tried to alter an interface's configuration. X.SH "SEE ALSO" rc(8), intro(4N), netstat(1) !Funky!Stuff! echo x - ifconfig.c.diffs sed 's/^X//' >ifconfig.c.diffs <<'!Funky!Stuff!' 187c n = sscanf(s, "%x:%x:%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], &o[3], &o[4], &o[5], &o[6], &o[7]); if (n > 0) { p = sa->sa_data; ip = &o[0]; while (n--) *p++ = *ip++; sa->sa_family = AF_UNSPEC; return; } fprintf(stderr, "ifconfig: %s: bad address\n", s); X. 163a bzero((caddr_t)sa, sizeof *sa); X. 162c int val, n, o[8], *ip; char *p; X. 159a struct sockaddr_in *sin = (struct sockaddr_in *)sa; X. 158c struct sockaddr *sa; X. 156c getaddr(s, sa) X. 128c printb("flags", ifr.ifr_flags, IFFBITS); putchar('\n'); X. 125a strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCGIFFLAGS)"); exit(1); } X. 110,111c ifr.ifr_flags |= value; X. 108c ifr.ifr_flags &= ~value; X. 105a strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCGIFFLAGS)"); exit(1); } X. 95c getaddr(addr, &ifr.ifr_addr); X. 65,70d 36,37d 20d 2c static char sccsid[] = "@(#)ifconfig.c 1.5 83/12/02 SMI"; /* from UCB 4.3 09/16/83 */ X. w !Funky!Stuff! echo x - ioctl.h.diffs sed 's/^X//' >ioctl.h.diffs <<'!Funky!Stuff!' 207a #define SIOCSARP _IOW(i, 30, struct arpreq) /* set arp entry */ #define SIOCGARP _IOWR(i, 31, struct arpreq) /* get arp entry */ #define SIOCDARP _IOW(i, 32, struct arpreq) /* delete arp entry */ X. 1c /* @(#)ioctl.h 1.4 83/11/29 SMI; from UCB 4.34 83/06/13 */ X. w !Funky!Stuff!