From e03842d0c71c4f8d6484e0522b5223145d1f6547 Mon Sep 17 00:00:00 2001 From: brezak Date: Sun, 8 May 1994 16:11:14 +0000 Subject: [PATCH] Standalone networking for network boot loaders. --- sys/lib/libsa/Makefile | 21 +- sys/lib/libsa/arp.c | 217 ++++++++++++ sys/lib/libsa/bootp.c | 347 +++++++++++++++++++ sys/lib/libsa/bootp.h | 107 ++++++ sys/lib/libsa/close.c | 13 +- sys/lib/libsa/ether.c | 102 ++++++ sys/lib/libsa/exec.c | 155 +++++++++ sys/lib/libsa/exit.c | 43 ++- sys/lib/libsa/globals.c | 28 ++ sys/lib/libsa/in_cksum.c | 82 +++++ sys/lib/libsa/ioctl.c | 4 +- sys/lib/libsa/iodesc.h | 54 +++ sys/lib/libsa/net.c | 393 +++++++++++++++++++++ sys/lib/libsa/net.h | 98 ++++++ sys/lib/libsa/netif.c | 329 ++++++++++++++++++ sys/lib/libsa/netif.h | 63 ++++ sys/lib/libsa/nfs.c | 720 +++++++++++++++++++++++++++++++++++++++ sys/lib/libsa/nfs.h | 43 +++ sys/lib/libsa/open.c | 56 ++- sys/lib/libsa/rarp.c | 137 ++++++++ sys/lib/libsa/rpc.c | 251 ++++++++++++++ sys/lib/libsa/rpc.h | 84 +++++ sys/lib/libsa/stand.h | 23 +- 23 files changed, 3330 insertions(+), 40 deletions(-) create mode 100644 sys/lib/libsa/arp.c create mode 100644 sys/lib/libsa/bootp.c create mode 100644 sys/lib/libsa/bootp.h create mode 100644 sys/lib/libsa/ether.c create mode 100644 sys/lib/libsa/exec.c create mode 100644 sys/lib/libsa/globals.c create mode 100644 sys/lib/libsa/in_cksum.c create mode 100644 sys/lib/libsa/iodesc.h create mode 100644 sys/lib/libsa/net.c create mode 100644 sys/lib/libsa/net.h create mode 100644 sys/lib/libsa/netif.c create mode 100644 sys/lib/libsa/netif.h create mode 100644 sys/lib/libsa/nfs.c create mode 100644 sys/lib/libsa/nfs.h create mode 100644 sys/lib/libsa/rarp.c create mode 100644 sys/lib/libsa/rpc.c create mode 100644 sys/lib/libsa/rpc.h diff --git a/sys/lib/libsa/Makefile b/sys/lib/libsa/Makefile index 82cb7871e339..2fc8b41579c2 100644 --- a/sys/lib/libsa/Makefile +++ b/sys/lib/libsa/Makefile @@ -1,15 +1,26 @@ -# $Id: Makefile,v 1.1 1994/01/26 02:03:32 brezak Exp $ +# $Id: Makefile,v 1.2 1994/05/08 16:11:14 brezak Exp $ LIB= sa -CFLAGS+=-DSTANDALONE -I${.CURDIR} +#DEBUGFLAGS= -DNFS_DEBUG -DRPC_DEBUG -DRARP_DEBUG -DDEBUG -DPARANOID -Wall +CFLAGS+=-DSTANDALONE $(DEBUGFLAGS) -I${.CURDIR} + +# stand routines +SRCS+= alloc.c bcopy.c exit.c exec.c getfile.c gets.c globals.c \ + printf.c strerror.c # io routines SRCS+= close.c dev.c disklabel.c ioctl.c lseek.c open.c read.c \ - stat.c ufs.c write.c + stat.c write.c -# other misc routines -SRCS+= alloc.c bcopy.c exit.c getfile.c gets.c printf.c strerror.c +# network routines +SRCS+= arp.c ether.c in_cksum.c net.c netif.c rpc.c + +# network info services: +SRCS+= bootp.c rarp.c + +# boot filesystems +SRCS+= ufs.c nfs.c NOPROFILE= NOPIC= diff --git a/sys/lib/libsa/arp.c b/sys/lib/libsa/arp.c new file mode 100644 index 000000000000..7dfd977a0fc1 --- /dev/null +++ b/sys/lib/libsa/arp.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from @(#) Header: arp.c,v 1.5 93/07/15 05:52:26 leres Exp (LBL) + * $Id: arp.c,v 1.1 1994/05/08 16:11:16 brezak Exp $ + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "stand.h" +#include "net.h" + +/* Cache stuff */ +#define ARP_NUM 8 /* need at most 3 arp entries */ + +static struct arp_list { + n_long addr; + u_char ea[6]; +} arp_list[ARP_NUM] = { + { INADDR_BROADCAST, BA } +}; +static int arp_num = 1; + +/* Local forwards */ +static int arpsend __P((struct iodesc *, void *, int)); +static int arprecv __P((struct iodesc *, void *, int)); + +/* Broadcast an ARP packet, asking who has addr on interface d */ +u_char * +arpwhohas(d, addr) + register struct iodesc *d; + n_long addr; +{ + register int i; + register struct ether_arp *ah; + register struct arp_list *al; + struct { + u_char header[ETHER_SIZE]; + struct ether_arp warp; + } wbuf; + union { + u_char buffer[RECV_SIZE]; + struct { + u_char header[ETHER_SIZE]; + struct ether_arp rarp; + } ru; + } rbuf; + +#ifdef ARP_DEBUG + if (debug) + printf("arpwhohas: called for %s\n", intoa(addr)); +#endif + /* Try for cached answer first */ + for (i = 0, al = arp_list; i < arp_num; ++i, ++al) + if (addr == al->addr) + return (al->ea); + + /* Don't overflow cache */ + if (arp_num > ARP_NUM - 1) + panic("arpwhohas: overflowed arp_list!"); + +#ifdef ARP_DEBUG + if (debug) + printf("arpwhohas: not cached\n"); +#endif + ah = &wbuf.warp; + bzero(ah, sizeof(*ah)); + + ah->arp_hrd = htons(ARPHRD_ETHER); + ah->arp_pro = htons(ETHERTYPE_IP); + ah->arp_hln = sizeof(ah->arp_sha); /* hardware address length */ + ah->arp_pln = sizeof(ah->arp_spa); /* protocol address length */ + ah->arp_op = htons(ARPOP_REQUEST); + MACPY(d->myea, ah->arp_sha); + bcopy(&d->myip, ah->arp_spa, sizeof(ah->arp_spa)); + bcopy(&addr, ah->arp_tpa, sizeof(ah->arp_tpa)); + + /* Store ip address in cache */ + al->addr = addr; + + (void)sendrecv(d, arpsend, ah, sizeof(*ah), arprecv, + ((u_char *)&rbuf.ru.rarp) - ETHER_SIZE, + ETHER_SIZE + sizeof(rbuf.ru.rarp)); + + /* Store ethernet address in cache */ + MACPY(rbuf.ru.rarp.arp_sha, al->ea); + ++arp_num; +#ifdef ARP_DEBUG + if (debug) + printf("arpwhohas: cacheing %s --> %s\n", intoa(addr), ether_sprintf(al->ea)); +#endif + + return (al->ea); +} + +static int +arpsend(d, pkt, len) + register struct iodesc *d; + register void *pkt; + register int len; +{ +#ifdef ARP_DEBUG + if (debug) + printf("arpsend: called\n"); +#endif + return (sendether(d, pkt, len, bcea, ETHERTYPE_ARP)); +} + +/* Returns 0 if this is the packet we're waiting for else -1 (and errno == 0) */ +static int +arprecv(d, pkt, len) + register struct iodesc *d; + register void *pkt; + register int len; +{ + register struct ether_header *eh; + register struct ether_arp *ah; + +#ifdef ARP_DEBUG + if (debug) + printf("arprecv: called\n"); +#endif + if (len < sizeof(*eh) + sizeof(*ah)) { + errno = 0; + return (-1); + } + + eh = (struct ether_header *)pkt; + + /* Must be to us */ + if (bcmp(d->myea, eh->ether_dhost, 6) != 0 && + bcmp(bcea, eh->ether_dhost, 6) != 0) { +#ifdef ARP_DEBUG + if (debug) + printf("arprecv: not ours %s\n", ether_sprintf(eh->ether_dhost)); +#endif + errno = 0; + return (-1); + } + + if (ntohs(eh->ether_type) != ETHERTYPE_ARP) { +#ifdef ARP_DEBUG + if (debug) + printf("arprecv: not arp %d\n", ntohs(eh->ether_type)); +#endif + errno = 0; + return (-1); + } + + ah = (struct ether_arp *)(eh + 1); + HTONS(ah->arp_hrd); + HTONS(ah->arp_pro); + HTONS(ah->arp_op); + if (ah->arp_hrd != ARPHRD_ETHER || ah->arp_pro != ETHERTYPE_IP || + ah->arp_hln != sizeof(ah->arp_sha) || + ah->arp_pln != sizeof(ah->arp_spa) || ah->arp_op != ARPOP_REPLY) { +#ifdef ARP_DEBUG + if (debug) + printf("arprecv: not valid reply\n"); +#endif + errno = 0; + return (-1); + } + if (bcmp(&arp_list[arp_num].addr, ah->arp_spa, sizeof(long)) != 0 || + bcmp(&d->myip, ah->arp_tpa, sizeof(d->myip)) != 0) { +#ifdef ARP_DEBUG + if (debug) + printf("arprecv: already cached??\n"); +#endif + errno = 0; + return (-1); + } + + return (0); +} diff --git a/sys/lib/libsa/bootp.c b/sys/lib/libsa/bootp.c new file mode 100644 index 000000000000..63ece3a3163b --- /dev/null +++ b/sys/lib/libsa/bootp.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp (LBL) + * $Id: bootp.c,v 1.1 1994/05/08 16:11:17 brezak Exp $ + */ + +#include +#include +#include + +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "bootp.h" + +static n_long nmask, smask; + +static time_t bot; + +static char vm_rfc1048[4] = VM_RFC1048; +static char vm_cmu[4] = VM_CMU; + +/* Local forwards */ +static int bootpsend __P((struct iodesc *, void *, int)); +static int bootprecv __P((struct iodesc*, void *, int)); +static void vend_cmu __P((u_char *)); +static void vend_rfc1048 __P((u_char *, u_int)); + +/* Fetch required bootp infomation */ +void +bootp(sock) + int sock; +{ + struct iodesc *d; + register struct bootp *bp; + register void *pkt; + struct { + u_char header[HEADER_SIZE]; + struct bootp wbootp; + } wbuf; + union { + u_char buffer[RECV_SIZE]; + struct { + u_char header[HEADER_SIZE]; + struct bootp xrbootp; + }xrbuf; +#define rbootp xrbuf.xrbootp + } rbuf; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootp: socket=%d\n", sock); +#endif + if (!bot) + bot = getsecs(); + + if (!(d = socktodesc(sock))) { + printf("bootp: bad socket. %d\n", sock); + return; + } +#ifdef BOOTP_DEBUG + if (debug) + printf("bootp: d=%x\n", (u_int)d); +#endif + bp = &wbuf.wbootp; + pkt = &rbuf.rbootp; + pkt -= HEADER_SIZE; + + bzero(bp, sizeof(*bp)); + + bp->bp_op = BOOTREQUEST; + bp->bp_htype = 1; /* 10Mb Ethernet (48 bits) */ + bp->bp_hlen = 6; + MACPY(d->myea, bp->bp_chaddr); + + d->xid = 0; + d->myip = myip; + d->myport = IPPORT_BOOTPC; + d->destip = INADDR_BROADCAST; + d->destport = IPPORT_BOOTPS; + + (void)sendrecv(d, + bootpsend, bp, sizeof(*bp), + bootprecv, pkt, RECV_SIZE); +} + +/* Transmit a bootp request */ +static int +bootpsend(d, pkt, len) + register struct iodesc *d; + register void *pkt; + register int len; +{ + register struct bootp *bp; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootpsend: d=%x called.\n", (u_int)d); +#endif + bp = pkt; + bzero(bp->bp_file, sizeof(bp->bp_file)); + bcopy(vm_rfc1048, bp->bp_vend, sizeof(long)); + bp->bp_xid = d->xid; + bp->bp_secs = (u_long)(getsecs() - bot); +#ifdef BOOTP_DEBUG + if (debug) + printf("bootpsend: calling sendudp\n"); +#endif + return (sendudp(d, pkt, len)); +} + +/* Returns 0 if this is the packet we're waiting for else -1 (and errno == 0) */ +static int +bootprecv(d, pkt, len) + register struct iodesc *d; + register void *pkt; + int len; +{ + register struct bootp *bp; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootprecv: called\n"); +#endif + bp = (struct bootp *)checkudp(d, pkt, &len); +#ifdef BOOTP_DEBUG + if (debug) + printf("bootprecv: checked. bp = 0x%x, len = %d\n", + (unsigned)bp, len); +#endif + if (bp == NULL || len < sizeof(*bp) || bp->bp_xid != d->xid) { +#ifdef BOOTP_DEBUG + if (debug) { + printf("bootprecv: not for us.\n"); + if (bp == NULL) + printf("bootprecv: bp null\n"); + else { + if (len < sizeof(*bp)) + printf("bootprecv: expected %d bytes, got %d\n", + sizeof(*bp), len); + if (bp->bp_xid != d->xid) + printf("bootprecv: expected xid 0x%x, got 0x%x\n", + d->xid, bp->bp_xid); + } + } +#endif + errno = 0; + return (-1); + } + + /* Bump xid so next request will be unique */ + ++d->xid; + +#ifdef BOOTP_DEBUG + if (debug) + printf("bootprecv: got one!\n"); +#endif + + /* Pick up our ip address (and natural netmask) */ + myip = d->myip = ntohl(bp->bp_yiaddr.s_addr); +#ifdef BOOTP_DEBUG + if (debug) + printf("our ip address is %s\n", intoa(d->myip)); +#endif + if (IN_CLASSA(d->myip)) + nmask = IN_CLASSA_NET; + else if (IN_CLASSB(d->myip)) + nmask = IN_CLASSB_NET; + else + nmask = IN_CLASSC_NET; +#ifdef BOOTP_DEBUG + if (debug) + printf("'native netmask' is %s\n", intoa(nmask)); +#endif + + /* Pick up root or swap server address and file spec */ + if (bp->bp_siaddr.s_addr != 0) { + rootip = ntohl(bp->bp_siaddr.s_addr); + } + if (bp->bp_file[0] != '\0') { + strncpy(bootfile, (char *)bp->bp_file, + sizeof(bootfile)); + bootfile[sizeof(bootfile) - 1] = '\0'; + } + + /* Suck out vendor info */ + if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0) + vend_cmu(bp->bp_vend); + else if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) + vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)); + else + printf("bootprecv: unknown vendor 0x%x\n", (int)bp->bp_vend); + + /* Check subnet mask against net mask; toss if bogus */ + if ((nmask & smask) != nmask) { +#ifdef BOOTP_DEBUG + if (debug) + printf("subnet mask (%s) bad\n", intoa(smask)); +#endif + smask = 0; + } + + /* Get subnet (or natural net) mask */ + mask = nmask; + if (smask) + mask = smask; +#ifdef BOOTP_DEBUG + if (debug) + printf("mask: %s\n", intoa(mask)); +#endif + + /* We need a gateway if root or swap is on a different net */ + if (!SAMENET(d->myip, rootip, mask)) { +#ifdef BOOTP_DEBUG + if (debug) + printf("need gateway for root ip\n"); +#endif + } + if (!SAMENET(d->myip, swapip, mask)) { +#ifdef BOOTP_DEBUG + if (debug) + printf("need gateway for swap ip\n"); +#endif + } + + /* Toss gateway if on a different net */ + if (!SAMENET(d->myip, gateip, mask)) { +#ifdef BOOTP_DEBUG + if (debug) + printf("gateway ip (%s) bad\n", intoa(gateip)); +#endif + gateip = 0; + } + return (0); +} + +static void +vend_cmu(cp) + u_char *cp; +{ + register struct cmu_vend *vp; + +#ifdef BOOTP_DEBUG + if (debug) + printf("vend_cmu bootp info.\n"); +#endif + vp = (struct cmu_vend *)cp; + + if (vp->v_smask.s_addr != 0) { + smask = ntohl(vp->v_smask.s_addr); + } + if (vp->v_dgate.s_addr != 0) { + gateip = ntohl(vp->v_dgate.s_addr); + } +} + +static void +vend_rfc1048(cp, len) + register u_char *cp; + u_int len; +{ + register u_char *ep; + register int size; + register u_char tag; + +#ifdef BOOTP_DEBUG + if (debug) + printf("vend_rfc1048 bootp info. len=%d\n", len); +#endif + ep = cp + len; + + /* Step over magic cookie */ + cp += sizeof(long); + + while (cp < ep) { + tag = *cp++; + size = *cp++; + if (tag == TAG_END) + break; + + if (tag == TAG_SUBNET_MASK) { + bcopy(cp, &smask, sizeof(smask)); + smask = ntohl(smask); + } + if (tag == TAG_GATEWAY) { + bcopy(cp, &gateip, sizeof(gateip)); + gateip = ntohl(gateip); + } + if (tag == TAG_SWAPSERVER) { + bcopy(cp, &swapip, sizeof(swapip)); + swapip = ntohl(swapip); + } + if (tag == TAG_DOMAIN_SERVER) { + bcopy(cp, &nameip, sizeof(nameip)); + nameip = ntohl(nameip); + } + if (tag == TAG_ROOTPATH) { + strncpy(rootpath, cp, sizeof(rootpath)); + rootpath[size] = '\0'; + } + if (tag == TAG_HOSTNAME) { + strncpy(hostname, cp, sizeof(hostname)); + hostname[size] = '\0'; + } + if (tag == TAG_DOMAINNAME) { + strncpy(domainname, cp, sizeof(domainname)); + domainname[size] = '\0'; + } + cp += size; + } +} diff --git a/sys/lib/libsa/bootp.h b/sys/lib/libsa/bootp.h new file mode 100644 index 000000000000..c1113ed0cb76 --- /dev/null +++ b/sys/lib/libsa/bootp.h @@ -0,0 +1,107 @@ +/* @(#) $Header: /cvsroot/src/sys/lib/libsa/bootp.h,v 1.1 1994/05/08 16:11:18 brezak Exp $ (LBL) */ +/* + * Bootstrap Protocol (BOOTP). RFC951 and RFC1048. + * + * This file specifies the "implementation-independent" BOOTP protocol + * information which is common to both client and server. + * + * Copyright 1988 by Carnegie Mellon. + * + * Permission to use, copy, modify, and distribute this program for any + * purpose and without fee is hereby granted, provided that this copyright + * and permission notice appear on all copies and supporting documentation, + * the name of Carnegie Mellon not be used in advertising or publicity + * pertaining to distribution of the program without specific prior + * permission, and notice be given in supporting documentation that copying + * and distribution is by permission of Carnegie Mellon and Stanford + * University. Carnegie Mellon makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + + +struct bootp { + unsigned char bp_op; /* packet opcode type */ + unsigned char bp_htype; /* hardware addr type */ + unsigned char bp_hlen; /* hardware addr length */ + unsigned char bp_hops; /* gateway hops */ + unsigned long bp_xid; /* transaction ID */ + unsigned short bp_secs; /* seconds since boot began */ + unsigned short bp_unused; + struct in_addr bp_ciaddr; /* client IP address */ + struct in_addr bp_yiaddr; /* 'your' IP address */ + struct in_addr bp_siaddr; /* server IP address */ + struct in_addr bp_giaddr; /* gateway IP address */ + unsigned char bp_chaddr[16]; /* client hardware address */ + unsigned char bp_sname[64]; /* server host name */ + unsigned char bp_file[128]; /* boot file name */ + unsigned char bp_vend[64]; /* vendor-specific area */ +}; + +/* + * UDP port numbers, server and client. + */ +#define IPPORT_BOOTPS 67 +#define IPPORT_BOOTPC 68 + +#define BOOTREPLY 2 +#define BOOTREQUEST 1 + + +/* + * Vendor magic cookie (v_magic) for CMU + */ +#define VM_CMU "CMU" + +/* + * Vendor magic cookie (v_magic) for RFC1048 + */ +#define VM_RFC1048 { 99, 130, 83, 99 } + + + +/* + * RFC1048 tag values used to specify what information is being supplied in + * the vendor field of the packet. + */ + +#define TAG_PAD ((unsigned char) 0) +#define TAG_SUBNET_MASK ((unsigned char) 1) +#define TAG_TIME_OFFSET ((unsigned char) 2) +#define TAG_GATEWAY ((unsigned char) 3) +#define TAG_TIME_SERVER ((unsigned char) 4) +#define TAG_NAME_SERVER ((unsigned char) 5) +#define TAG_DOMAIN_SERVER ((unsigned char) 6) +#define TAG_LOG_SERVER ((unsigned char) 7) +#define TAG_COOKIE_SERVER ((unsigned char) 8) +#define TAG_LPR_SERVER ((unsigned char) 9) +#define TAG_IMPRESS_SERVER ((unsigned char) 10) +#define TAG_RLP_SERVER ((unsigned char) 11) +#define TAG_HOSTNAME ((unsigned char) 12) +#define TAG_BOOTSIZE ((unsigned char) 13) +#define TAG_DUMPFILE ((unsigned char) 14) +#define TAG_DOMAINNAME ((unsigned char) 15) +#define TAG_SWAPSERVER ((unsigned char) 16) +#define TAG_ROOTPATH ((unsigned char) 17) +#define TAG_END ((unsigned char) 255) + + + +/* + * "vendor" data permitted for CMU bootp clients. + */ + +struct cmu_vend { + unsigned char v_magic[4]; /* magic number */ + unsigned long v_flags; /* flags/opcodes, etc. */ + struct in_addr v_smask; /* Subnet mask */ + struct in_addr v_dgate; /* Default gateway */ + struct in_addr v_dns1, v_dns2; /* Domain name servers */ + struct in_addr v_ins1, v_ins2; /* IEN-116 name servers */ + struct in_addr v_ts1, v_ts2; /* Time servers */ + unsigned char v_unused[25]; /* currently unused */ +}; + + +/* v_flags values */ +#define VF_SMASK 1 /* Subnet mask field contains valid data */ diff --git a/sys/lib/libsa/close.c b/sys/lib/libsa/close.c index dd1cc2f2bf5a..2b69a6393178 100644 --- a/sys/lib/libsa/close.c +++ b/sys/lib/libsa/close.c @@ -61,7 +61,7 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: close.c,v 1.1 1994/01/26 02:03:38 brezak Exp $ + * $Id: close.c,v 1.2 1994/05/08 16:11:19 brezak Exp $ */ #include "stand.h" @@ -70,7 +70,7 @@ close(fd) int fd; { register struct open_file *f = &files[fd]; - int err1, err2; + int err1 = 0, err2 = 0; if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { errno = EBADF; @@ -78,7 +78,8 @@ close(fd) } if (!(f->f_flags & F_RAW)) err1 = (f->f_ops->close)(f); - err2 = (f->f_dev->dv_close)(f); + if (!(f->f_flags & F_NODEV)) + err2 = (f->f_dev->dv_close)(f); f->f_flags = 0; if (err1) { errno = err1; @@ -96,7 +97,7 @@ closeall() { int i; - for (i = 0; i < SOPEN_MAX; i++) - if (files[i].f_flags != 0) - (void)close(i); + for (i = 0; i < SOPEN_MAX; i++) + if (files[i].f_flags != 0) + (void)close(i); } diff --git a/sys/lib/libsa/ether.c b/sys/lib/libsa/ether.c new file mode 100644 index 000000000000..ab1c6a2981b9 --- /dev/null +++ b/sys/lib/libsa/ether.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" + +const u_char bcea[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +/* Caller must leave room for ethernet header in front!! */ +int +sendether(d, buf, len, dea, etype) + struct iodesc *d; + void *buf; + int len; + u_char *dea; + int etype; +{ + register struct ether_header *eh; + +#ifdef ETHER_DEBUG + if (debug) + printf("sendether: called\n"); +#endif + eh = ((struct ether_header *)buf) - 1; + len += ETHER_SIZE; + + MACPY(d->myea, eh->ether_shost); /* by byte */ + MACPY(dea, eh->ether_dhost); /* by byte */ + eh->ether_type = htons(etype); + return (netif_put(d, eh, len) - ETHER_SIZE); +} + +/* + * Convert Ethernet address to printable (loggable) representation. + */ +static char digits[] = "0123456789abcdef"; +char * +ether_sprintf(ap) + register u_char *ap; +{ + register i; + static char etherbuf[18]; + register char *cp = etherbuf; + + for (i = 0; i < 6; i++) { + *cp++ = digits[*ap >> 4]; + *cp++ = digits[*ap++ & 0xf]; + *cp++ = ':'; + } + *--cp = 0; + return (etherbuf); +} diff --git a/sys/lib/libsa/exec.c b/sys/lib/libsa/exec.c new file mode 100644 index 000000000000..24dea43fb944 --- /dev/null +++ b/sys/lib/libsa/exec.c @@ -0,0 +1,155 @@ +/*- + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: exec.c,v 1.1 1994/05/08 16:11:21 brezak Exp $ + */ + +#include +#include +#include +#include +#include +#include + +#include "stand.h" + +static char *ssym, *esym; + +extern u_int opendev; + +int +exec(path, loadaddr, howto) + char *path; + char *loadaddr; + int howto; +{ + register int io; + struct exec x; + int i; + register char *addr; + + if (machdep_exec(path, loadaddr, howto) < 0) + return(0); + + io = open(path, 0); + if (io < 0) + return(io); + + i = read(io, (char *)&x, sizeof(x)); + if (i != sizeof(x) || + N_BADMAG(x)) { + printf("exec: %s: Bad format\n", path); + errno = ENOEXEC; + return(-1); + } + + /* Text */ + printf("%d", x.a_text); + addr = loadaddr; +#ifdef NO_LSEEK + if (N_GETMAGIC(x) == ZMAGIC && read(io, (char *)addr, 0x400) == -1) +#else + if (N_GETMAGIC(x) == ZMAGIC && lseek(io, 0x400, SEEK_SET) == -1) +#endif + goto shread; + if (read(io, (char *)addr, x.a_text) != x.a_text) + goto shread; + addr += x.a_text; + if (N_GETMAGIC(x) == ZMAGIC || N_GETMAGIC(x) == NMAGIC) + while ((int)addr & CLOFSET) + *addr++ = 0; + /* Data */ + printf("+%d", x.a_data); + if (read(io, addr, x.a_data) != x.a_data) + goto shread; + addr += x.a_data; + + /* Bss */ + printf("+%d", x.a_bss); + for (i = 0; i < x.a_bss; i++) + *addr++ = 0; + + /* Symbols */ + ssym = addr; + bcopy(&x.a_syms, addr, sizeof(x.a_syms)); + addr += sizeof(x.a_syms); + printf(" [%d+", x.a_syms); + if (read(io, addr, x.a_syms) != x.a_syms) + goto shread; + addr += x.a_syms; + + if (read(io, &i, sizeof(int)) != sizeof(int)) + goto shread; + + bcopy(&i, addr, sizeof(int)); + if (i) { + i -= sizeof(int); + addr += sizeof(int); + if (read(io, addr, i) != i) + goto shread; + addr += i; + } + + /* and that many bytes of (debug symbols?) */ + + printf("%d] ", i); + +#define round_to_size(x) \ + (((int)(x) + sizeof(int) - 1) & ~(sizeof(int) - 1)) + esym = (char *)round_to_size(addr - loadaddr); +#undef round_to_size + + /* and note the end address of all this */ + printf("total=0x%x ", (u_int)addr); + + x.a_entry += (int)loadaddr; + printf(" start 0x%x\n", x.a_entry); + +#ifdef EXEC_DEBUG + printf("ssym=0x%x esym=0x%x\n", ssym, esym); + printf("\n\nReturn to boot...\n"); + getchar(); +#endif + + machdep_start((char *)x.a_entry, howto, loadaddr, ssym, esym); + + /* exec failed */ + printf("exec: %s: Cannot exec\n", path); + errno = ENOEXEC; + return(-1); + +shread: + close(io); + printf("exec: %s: Short read\n", path); + errno = EIO; + return(-1); +} diff --git a/sys/lib/libsa/exit.c b/sys/lib/libsa/exit.c index cc6df7ab8bd2..56167941a1d0 100644 --- a/sys/lib/libsa/exit.c +++ b/sys/lib/libsa/exit.c @@ -16,7 +16,7 @@ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -25,26 +25,37 @@ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +#include #ifndef lint -static char rcsid[] = "$Id: exit.c,v 1.1 1994/01/26 02:03:43 brezak Exp $"; +static char rcsid[] = "$Id: exit.c,v 1.2 1994/05/08 16:11:22 brezak Exp $"; #endif /* not lint */ +void +#ifdef __STDC__ +panic(const char *fmt, ...) +#else +panic(fmt /*, va_alist */) + char *fmt; +#endif +{ + va_list ap; + + static int paniced; + + if (!paniced) { + paniced = 1; + closeall(); + } + + va_start(ap, fmt); + printf(fmt, ap); + printf("\n"); + va_end(ap); + _rtt(); +} + exit() { panic("exit"); } - -panic(str) - char *str; -{ - static int paniced; - - if (!paniced) { - paniced = 1; - closeall(); - } - - printf("%s\n",str); - _rtt(); -} diff --git a/sys/lib/libsa/globals.c b/sys/lib/libsa/globals.c new file mode 100644 index 000000000000..317305267a05 --- /dev/null +++ b/sys/lib/libsa/globals.c @@ -0,0 +1,28 @@ +/* + * globals.c: + * + * global variables should be separate, so nothing else + * must be included extraneously. + * + * $Id: globals.c,v 1.1 1994/05/08 16:11:23 brezak Exp $ + */ + +#include +#include +#include + +#include "stand.h" +#include "net.h" + +u_char bcea[6] = BA; /* broadcast ethernet address */ + +char rootpath[FNAME_SIZE] = "/"; /* root mount path */ +char bootfile[FNAME_SIZE]; /* bootp says to boot this */ +char hostname[FNAME_SIZE]; /* our hostname */ +char domainname[FNAME_SIZE]; /* our DNS domain */ +char ifname[IFNAME_SIZE]; /* name of interface (e.g. "le0") */ +n_long nameip; /* DNS server ip address */ +n_long rootip; /* root ip address */ +n_long swapip; /* swap ip address */ +n_long gateip; /* swap ip address */ +n_long mask = 0xffffff00; /* subnet or net mask */ diff --git a/sys/lib/libsa/in_cksum.c b/sys/lib/libsa/in_cksum.c new file mode 100644 index 000000000000..bb5d80c61ab9 --- /dev/null +++ b/sys/lib/libsa/in_cksum.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from @(#) Header: in_cksum.c,v 1.1 92/09/11 01:15:55 leres Exp (LBL) + * $Id: in_cksum.c,v 1.1 1994/05/08 16:11:24 brezak Exp $ + */ + +#include + +/* + * Checksum routine for Internet Protocol family headers. + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * In particular, it should not be this one. + */ +int +in_cksum(p, len) + register void *p; + register int len; +{ + register int sum = 0, oddbyte = 0, v = 0; + register u_char *cp = p; + + /* we assume < 2^16 bytes being summed */ + while (len > 0) { + if (oddbyte) { + sum += v + *cp++; + len--; + } + if (((int)cp & 1) == 0) { + while ((len -= 2) >= 0) { + sum += *(u_short *)cp; + cp += 2; + } + } else { + while ((len -= 2) >= 0) { + sum += *cp++ << 8; + sum += *cp++; + } + } + if ((oddbyte = len & 1) != 0) + v = *cp << 8; + } + if (oddbyte) + sum += v; + sum = (sum >> 16) + (sum & 0xffff); /* add in accumulated carries */ + sum += sum >> 16; /* add potential last carry */ + return (0xffff & ~sum); +} diff --git a/sys/lib/libsa/ioctl.c b/sys/lib/libsa/ioctl.c index bbffd41792db..16fede82a2c8 100644 --- a/sys/lib/libsa/ioctl.c +++ b/sys/lib/libsa/ioctl.c @@ -61,11 +61,12 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: ioctl.c,v 1.1 1994/01/26 02:03:48 brezak Exp $ + * $Id: ioctl.c,v 1.2 1994/05/08 16:11:25 brezak Exp $ */ #include "stand.h" +int ioctl(fd, cmd, arg) int fd; int cmd; @@ -83,5 +84,6 @@ ioctl(fd, cmd, arg) return (-1); return (0); } + errno = EIO; return (-1); } diff --git a/sys/lib/libsa/iodesc.h b/sys/lib/libsa/iodesc.h new file mode 100644 index 000000000000..0699c44695e2 --- /dev/null +++ b/sys/lib/libsa/iodesc.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1993 Adam Glass + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: iodesc.h,v 1.1 1994/05/08 16:11:26 brezak Exp $ + */ + +#ifndef __SYS_LIBNETBOOT_IODESC_H +#define __SYS_LIBNETBOOT_IODESC_H + +struct iodesc { + n_long destip; /* destination ip address */ + n_long myip; /* my ip address */ + u_short destport; /* destination port */ + u_short myport; /* destination port */ + u_long xid; /* transaction identification */ + u_char myea[6]; /* my ethernet address */ + struct netif *io_netif; +}; + +#endif /* __SYS_LIBNETBOOT_IODESC_H */ diff --git a/sys/lib/libsa/net.c b/sys/lib/libsa/net.c new file mode 100644 index 000000000000..23990921e69d --- /dev/null +++ b/sys/lib/libsa/net.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL) + */ + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" + +n_long myip; + +/* Caller must leave room for ethernet, ip and udp headers in front!! */ +int +sendudp(d, buf, len) + register struct iodesc *d; + register void *buf; + register int len; +{ + register int cc; + register struct ip *ip; + register struct udpiphdr *ui; + register struct udphdr *uh; + register u_char *ea; + struct ip tip; + +#ifdef NET_DEBUG + if (debug) { + printf("sendudp: d=%x called.\n", (u_int)d); + if (d) { + printf("saddr: %s:%d", + intoa(d->myip), d->myport); + printf(" daddr: %s:%d\n", + intoa(d->destip), d->destport); + } + } +#endif + uh = ((struct udphdr *)buf) - 1; + ip = ((struct ip *)uh) - 1; + len += sizeof(*ip) + sizeof(*uh); + + bzero(ip, sizeof(*ip) + sizeof(*uh)); + + ip->ip_v = IPVERSION; /* half-char */ + ip->ip_hl = sizeof(*ip) >> 2; /* half-char */ + ip->ip_len = htons(len); + ip->ip_p = IPPROTO_UDP; /* char */ + ip->ip_ttl = IP_TTL; /* char */ + ip->ip_src.s_addr = htonl(d->myip); + ip->ip_dst.s_addr = htonl(d->destip); + ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */ + + uh->uh_sport = htons(d->myport); + uh->uh_dport = htons(d->destport); + uh->uh_ulen = htons(len - sizeof(*ip)); + + /* Calculate checksum (must save and restore ip header) */ + tip = *ip; + ui = (struct udpiphdr *)ip; + ui->ui_next = 0; + ui->ui_prev = 0; + ui->ui_x1 = 0; + ui->ui_len = uh->uh_ulen; + uh->uh_sum = in_cksum(ui, len); + *ip = tip; + + if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 || + mask == 0 || SAMENET(ip->ip_src.s_addr, ip->ip_dst.s_addr, mask)) + ea = arpwhohas(d, ip->ip_dst.s_addr); + else + ea = arpwhohas(d, htonl(gateip)); + + cc = sendether(d, ip, len, ea, ETHERTYPE_IP); + if (cc < 0) + return (cc); + if (cc != len) + panic("sendudp: bad write (%d != %d)", cc, len); + return (cc - (sizeof(*ip) + sizeof(*uh))); +} + +/* Check that packet is a valid udp packet for us */ +void * +checkudp(d, pkt, lenp) + register struct iodesc *d; + register void *pkt; + register int *lenp; +{ + register int hlen, len; + register struct ether_header *eh; + register struct ip *ip; + register struct udphdr *uh; + register struct udpiphdr *ui; + struct ip tip; + +#ifdef NET_DEBUG + if (debug) + printf("checkudp: called\n"); +#endif + eh = pkt; + ip = (struct ip *)(eh + 1); + uh = (struct udphdr *)(ip + 1); + + /* Must be to us */ + if (bcmp(d->myea, eh->ether_dhost, 6) != 0 && /* by byte */ + bcmp(bcea, eh->ether_dhost, 6) != 0) { /* by byte */ +#ifdef NET_DEBUG + if (debug) + printf("checkudp: not ours. myea=%s bcea=%s\n", + ether_sprintf(d->myea), ether_sprintf(bcea)); +#endif + return (NULL); + } + + /* And ip */ + if (ntohs(eh->ether_type) != ETHERTYPE_IP) { +#ifdef NET_DEBUG + if (debug) + printf("checkudp: not IP. ether_type=%x\n", eh->ether_type); +#endif + return (NULL); + } + + /* Check ip header */ + if (ip->ip_v != IPVERSION || ip->ip_p != IPPROTO_UDP) { /* half char */ +#ifdef NET_DEBUG + if (debug) + printf("checkudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p); +#endif + return (NULL); + } + + hlen = ip->ip_hl << 2; + if (hlen < sizeof(*ip) || in_cksum(ip, hlen) != 0) { +#ifdef NET_DEBUG + if (debug) + printf("checkudp: short hdr or bad cksum.\n"); +#endif + return (NULL); + } + NTOHS(ip->ip_len); + if (*lenp - sizeof(*eh) < ip->ip_len) { +#ifdef NET_DEBUG + if (debug) + printf("checkudp: bad length %d < %d.\n", + *lenp - sizeof(*eh), ip->ip_len); +#endif + return (NULL); + } + if (d->myip && ntohl(ip->ip_dst.s_addr) != d->myip) { +#ifdef NET_DEBUG + if (debug) { + printf("checkudp: bad saddr %s != ", + intoa(d->myip)); + printf("%s\n", + intoa(ntohl(ip->ip_dst.s_addr))); + } +#endif + return (NULL); + } + + /* If there were ip options, make them go away */ + if (hlen != sizeof(*ip)) { + bcopy(((u_char *)ip) + hlen, uh, + *lenp - (sizeof(*eh) + hlen)); + ip->ip_len = sizeof(*ip); + *lenp -= hlen - sizeof(*ip); + } + if (ntohs(uh->uh_dport) != d->myport) { +#ifdef NET_DEBUG + if (debug) + printf("checkudp: bad dport %d != %d\n", + d->myport, ntohs(uh->uh_dport)); +#endif + return (NULL); + } + + if (uh->uh_sum) { + len = ntohs(uh->uh_ulen); + if (len > RECV_SIZE - (sizeof(*eh) + sizeof(*ip))) { + printf("checkudp: huge packet, udp len %d\n", len); + return (NULL); + } + + /* Check checksum (must save and restore ip header) */ + tip = *ip; + ui = (struct udpiphdr *)ip; + ui->ui_next = 0; + ui->ui_prev = 0; + ui->ui_x1 = 0; + ui->ui_len = uh->uh_ulen; + if (in_cksum(ui, len + sizeof(*ip)) != 0) { +#ifdef NET_DEBUG + if (debug) + printf("checkudp: bad cksum\n"); +#endif + *ip = tip; + return (NULL); + } + *ip = tip; + } + NTOHS(uh->uh_dport); + NTOHS(uh->uh_sport); + NTOHS(uh->uh_ulen); + if (uh->uh_ulen < sizeof(*uh)) { +#ifdef NET_DEBUG + if (debug) + printf("checkudp: bad udp len %d < %d\n", + uh->uh_ulen, sizeof(*uh)); +#endif + return (NULL); + } + *lenp -= sizeof(*eh) + sizeof(*ip) + sizeof(*uh); + return (uh + 1); +} + +/* + * Send a packet and wait for a reply, with exponential backoff. + * + * The send routine must return the actual number of bytes written. + * + * The receive routine can indicate success by returning the number of + * bytes read; it can return 0 to indicate EOF; it can return -1 with a + * non-zero errno to indicate failure; finally, it can return -1 with a + * zero errno to indicate it isn't done yet. + */ +int +sendrecv(d, sproc, sbuf, ssize, rproc, rbuf, rsize) + register struct iodesc *d; + register int (*sproc)(struct iodesc *, void *, int); + register void *sbuf; + register int ssize; + register int (*rproc)(struct iodesc *, void *, int); + register void *rbuf; + register int rsize; +{ + register int cc; + register time_t t, tmo, tlast, tleft; + +#ifdef NET_DEBUG + if (debug) + printf("sendrecv: called\n"); +#endif + tmo = MINTMO; + tlast = tleft = 0; + t = getsecs(); + for (;;) { + if (tleft <= 0) { + cc = (*sproc)(d, sbuf, ssize); + if (cc < ssize) + panic("sendrecv: short write! (%d < %d)", + cc, ssize); + + tleft = tmo; + tmo <<= 1; + if (tmo > MAXTMO) + tmo = MAXTMO; + tlast = t; + } + + cc = netif_get(d, rbuf, rsize, tleft); + if (cc >= 0) { + /* Got a packet, process it */ + cc = (*rproc)(d, rbuf, cc); + /* Return on data, EOF or real error */ + if (cc >= 0 || errno != 0) + return (cc); + } + /* Timed out or didn't get the packet we're waiting for */ + t = getsecs(); + tleft -= t - tlast; + tlast = t; + } +} + +/* Similar to inet_ntoa() */ +char * +intoa(addr) + n_long addr; +{ + register char *cp; + register u_int byte; + register int n; + static char buf[17]; /* strlen(".255.255.255.255") + 1 */ + + cp = &buf[sizeof buf]; + *--cp = '\0'; + + n = 4; + do { + byte = addr & 0xff; + *--cp = byte % 10 + '0'; + byte /= 10; + if (byte > 0) { + *--cp = byte % 10 + '0'; + byte /= 10; + if (byte > 0) + *--cp = byte + '0'; + } + *--cp = '.'; + addr >>= 8; + } while (--n > 0); + + return (cp+1); +} + +static char * +number(s, n) + char *s; + int *n; +{ + for (*n = 0; isdigit(*s); s++) + *n = (*n * 10) + *s - '0'; + return s; +} + +n_long +ip_convertaddr(p) + char *p; +{ +#define IP_ANYADDR 0 + n_long addr = 0, n; + + if (p == (char *)0 || *p == '\0') + return IP_ANYADDR; + p = number(p, &n); + addr |= (n << 24) & 0xff000000; + if (*p == '\0' || *p++ != '.') + return IP_ANYADDR; + p = number(p, &n); + addr |= (n << 16) & 0xff0000; + if (*p == '\0' || *p++ != '.') + return IP_ANYADDR; + p = number(p, &n); + addr |= (n << 8) & 0xff00; + if (*p == '\0' || *p++ != '.') + return IP_ANYADDR; + p = number(p, &n); + addr |= n & 0xff; + if (*p != '\0') + return IP_ANYADDR; + + return ntohl(addr); +} diff --git a/sys/lib/libsa/net.h b/sys/lib/libsa/net.h new file mode 100644 index 000000000000..c569a0055a5f --- /dev/null +++ b/sys/lib/libsa/net.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1993 Adam Glass + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: net.h,v 1.1 1994/05/08 16:11:28 brezak Exp $ + */ + +#include "iodesc.h" + +#define BA { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + +/* Returns true if n_long's on the same net */ +#define SAMENET(a1, a2, m) ((a1 & m) == (a2 & m)) + +#define MACPY(s, d) bcopy((char *)s, (char *)d, 6) + +#define MAXTMO 20 /* seconds */ +#define MINTMO 2 /* seconds */ + +#define FNAME_SIZE 128 +#define IFNAME_SIZE 16 +#define RECV_SIZE 1536 /* XXX delete this */ + +/* Size of struct ether_header + struct ip + struct udphdr */ +#define ETHER_SIZE 14 +#define HEADER_SIZE (ETHER_SIZE + 20 + 8) + +extern u_char bcea[6]; +extern char rootpath[FNAME_SIZE]; +extern char bootfile[FNAME_SIZE]; +extern char hostname[FNAME_SIZE]; +extern char domainname[FNAME_SIZE]; +extern char ifname[IFNAME_SIZE]; + +extern n_long myip; +extern n_long rootip; +extern n_long swapip; +extern n_long gateip; +extern n_long nameip; +extern n_long mask; + +extern int debug; /* defined in the machdep sources */ + +extern struct iodesc sockets[SOPEN_MAX]; + +/* ARP functions: */ + +u_char *arpwhohas __P((struct iodesc *, n_long)); + +int sendether __P((struct iodesc *, void *, int, u_char *, int)); +int sendudp __P((struct iodesc *, void *, int)); +int recvudp __P((struct iodesc *, void *, int, time_t)); +int sendrecv __P((struct iodesc *, int (*)(struct iodesc *, void *, int), + void *, int, int (*)(struct iodesc *, void *, int), void *, int)); +void *checkudp __P((struct iodesc *, void *, int *)); + +/* utilties: */ + +char *ether_sprintf __P((u_char *)); +int in_cksum __P((void *, int)); +char *intoa __P((n_long)); /* similar to inet_ntoa */ + +/* Machine-dependent functions: */ + +time_t getsecs __P((void)); diff --git a/sys/lib/libsa/netif.c b/sys/lib/libsa/netif.c new file mode 100644 index 000000000000..b4f2e27b1cf0 --- /dev/null +++ b/sys/lib/libsa/netif.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 1993 Adam Glass + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Glass. + * 4. The name of the Author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: netif.c,v 1.1 1994/05/08 16:11:29 brezak Exp $ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" + +struct iodesc sockets[SOPEN_MAX]; + +/* + * netif_init: + * + * initialize the generic network interface layer + */ + +void +netif_init() +{ + struct netif_driver *drv; + int d, i; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("netif_init: called\n"); +#endif + for (d = 0; d < n_netif_drivers; d++) { + drv = netif_drivers[d]; + for (i = 0; i < drv->netif_nifs; i++) + drv->netif_ifs[i].dif_used = 0; + } +} + +int +netif_match(nif, machdep_hint) + struct netif *nif; + void *machdep_hint; +{ + struct netif_driver *drv = nif->nif_driver; + +#if 0 + if (netif_debug) + printf("%s%d: netif_match (%d)\n", drv->netif_bname, + nif->nif_unit, nif->nif_sel); +#endif + return drv->netif_match(nif, machdep_hint); +} + +struct netif * +netif_select(machdep_hint) + void *machdep_hint; +{ + int d, u, unit_done, s; + struct netif_driver *drv; + struct netif cur_if; + static struct netif best_if; + int best_val; + int val; + + best_val = 0; + best_if.nif_driver = NULL; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("netif_select: %d interfaces\n", n_netif_drivers); +#endif + + for (d = 0; d < n_netif_drivers; d++) { + cur_if.nif_driver = netif_drivers[d]; + drv = cur_if.nif_driver; + + for (u = 0; u < drv->netif_nifs; u++) { + cur_if.nif_unit = u; + unit_done = 0; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("\t%s%d:", drv->netif_bname, + cur_if.nif_unit); +#endif + + for (s = 0; s < drv->netif_ifs[u].dif_nsel; s++) { + cur_if.nif_sel = s; + + if (drv->netif_ifs[u].dif_used & (1 << s)) { +#ifdef NETIF_DEBUG + if (netif_debug) + printf(" [%d used]", s); +#endif + continue; + } + + val = netif_match(&cur_if, machdep_hint); +#ifdef NETIF_DEBUG + if (netif_debug) + printf(" [%d -> %d]", s, val); +#endif + if (val > best_val) { + best_val = val; + best_if = cur_if; + } + } +#ifdef NETIF_DEBUG + if (netif_debug) + printf("\n"); +#endif + } + } + + if (best_if.nif_driver == NULL) + return NULL; + + best_if.nif_driver-> + netif_ifs[best_if.nif_unit].dif_used |= (1 << best_if.nif_sel); + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("netif_select: %s%d(%d) wins\n", + best_if.nif_driver->netif_bname, + best_if.nif_unit, best_if.nif_sel); +#endif + return &best_if; +} + +int +netif_probe(nif, machdep_hint) + struct netif *nif; + void *machdep_hint; +{ + struct netif_driver *drv = nif->nif_driver; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_probe\n", drv->netif_bname, nif->nif_unit); +#endif + return drv->netif_probe(nif, machdep_hint); +} + +void +netif_attach(nif, desc, machdep_hint) + struct netif *nif; + struct iodesc *desc; + void *machdep_hint; +{ + struct netif_driver *drv = nif->nif_driver; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_attach\n", drv->netif_bname, nif->nif_unit); +#endif + desc->io_netif = nif; +#ifdef PARANOID + if (drv->netif_init == NULL) + panic("%s%d: no netif_init support\n", drv->netif_bname, + nif->nif_unit); +#endif + drv->netif_init(desc, machdep_hint); + bzero(drv->netif_ifs[nif->nif_unit].dif_stats, + sizeof(struct netif_stats)); +} + +void +netif_detach(nif) + struct netif *nif; +{ + struct netif_driver *drv = nif->nif_driver; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_detach\n", drv->netif_bname, nif->nif_unit); +#endif +#ifdef PARANOID + if (drv->netif_end == NULL) + panic("%s%d: no netif_end support\n", drv->netif_bname, + nif->nif_unit); +#endif + drv->netif_end(nif); +} + +int +netif_get(desc, pkt, len, timo) + struct iodesc *desc; + void *pkt; + int len; + time_t timo; +{ + struct netif *nif = desc->io_netif; + struct netif_driver *drv = desc->io_netif->nif_driver; + int rv; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_get\n", drv->netif_bname, nif->nif_unit); +#endif +#ifdef PARANOID + if (drv->netif_get == NULL) + panic("%s%d: no netif_get support\n", drv->netif_bname, + nif->nif_unit); +#endif + rv = drv->netif_get(desc, pkt, len, timo); +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_get returning %d\n", drv->netif_bname, + nif->nif_unit, rv); +#endif + return rv; +} + +int +netif_put(desc, pkt, len) + struct iodesc *desc; + void *pkt; + int len; +{ + struct netif *nif = desc->io_netif; + struct netif_driver *drv = desc->io_netif->nif_driver; + int rv; + +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_put\n", drv->netif_bname, nif->nif_unit); +#endif +#ifdef PARANOID + if (drv->netif_put == NULL) + panic("%s%d: no netif_put support\n", drv->netif_bname, + nif->nif_unit); +#endif + rv = drv->netif_put(desc, pkt, len); +#ifdef NETIF_DEBUG + if (netif_debug) + printf("%s%d: netif_put returning %d\n", drv->netif_bname, + nif->nif_unit, rv); +#endif + return rv; +} + +struct iodesc * +socktodesc(sock) + int sock; +{ + if (sock >= SOPEN_MAX) { + return(NULL); + } + return (&sockets[sock]); +} + +int +netif_open(machdep_hint) + void *machdep_hint; +{ + int fd; + register struct iodesc *s; + struct netif *nif; + + /* find a free socket */ + for (fd = 0, s = sockets; fd < SOPEN_MAX; fd++, s++) + if (s->io_netif == (struct netif *)0) + goto fnd; + return (-1); + +fnd: + bzero(s, sizeof(*s)); + netif_init(); + nif = netif_select(machdep_hint); + if (!nif) + panic("netboot: no interfaces left untried"); + if (netif_probe(nif, machdep_hint)) { + printf("netboot: couldn't probe %s%d\n", + nif->nif_driver->netif_bname, nif->nif_unit); + errno = EINVAL; + return(-1); + } + netif_attach(nif, s, machdep_hint); + + return(fd); +} + +int +netif_close(sock) + int sock; +{ + if (sock >= SOPEN_MAX) { + errno = EBADF; + return(-1); + } + netif_detach(sockets[sock].io_netif); + sockets[sock].io_netif = (struct netif *)0; + + return(0); +} diff --git a/sys/lib/libsa/netif.h b/sys/lib/libsa/netif.h new file mode 100644 index 000000000000..2ae9698e9423 --- /dev/null +++ b/sys/lib/libsa/netif.h @@ -0,0 +1,63 @@ + +#ifndef __SYS_LIBNETBOOT_NETIF_H +#define __SYS_LIBNETBOOT_NETIF_H +#include "iodesc.h" + +#define NENTS(x) sizeof(x)/sizeof(x[0]) + +struct netif_driver { + char *netif_bname; + int (*netif_match) __P((struct netif *, void *)); + int (*netif_probe) __P((struct netif *, void *)); + void (*netif_init) __P((struct iodesc *, void *)); + int (*netif_get) __P((struct iodesc *, void *, int, time_t)); + int (*netif_put) __P((struct iodesc *, void *, int)); + void (*netif_end) __P((struct netif *)); + struct netif_dif *netif_ifs; + int netif_nifs; +}; + +struct netif_dif { + int dif_unit; + int dif_nsel; + struct netif_stats *dif_stats; + void *dif_private; + /* the following fields are used internally by the netif layer */ + u_long dif_used; +}; + +struct netif_stats { + int collisions; + int collision_error; + int missed; + int sent; + int received; + int deferred; + int overflow; +}; + +struct netif { + struct netif_driver *nif_driver; + int nif_unit; + int nif_sel; +}; + +extern struct netif_driver *netif_drivers[]; /* machdep */ +extern int n_netif_drivers; + +extern int netif_debug; + +void netif_init __P((void)); +struct netif *netif_select __P((void *)); +int netif_probe __P((struct netif *, void *)); +void netif_attach __P((struct netif *, struct iodesc *, void *)); +void netif_detach __P((struct netif *)); +int netif_get __P((struct iodesc *, void *, int, time_t)); +int netif_put __P((struct iodesc *, void *, int)); + +int netif_open __P((void *)); +int netif_close __P((int)); + +struct iodesc *socktodesc __P((int)); + +#endif /* __SYS_LIBNETBOOT_NETIF_H */ diff --git a/sys/lib/libsa/nfs.c b/sys/lib/libsa/nfs.c new file mode 100644 index 000000000000..b283627e181a --- /dev/null +++ b/sys/lib/libsa/nfs.c @@ -0,0 +1,720 @@ +/*- + * Copyright (c) 1993 John Brezak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $Id: nfs.c,v 1.1 1994/05/08 16:11:31 brezak Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#undef NFSX_FATTR + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "nfs.h" +#include "rpc.h" + +struct nfs_call_data { + u_char fh[NFS_FHSIZE]; + u_long off; + u_long len; + u_long xxx; /* XXX what's this for? */ +}; + +/* Data part of nfs rpc reply (also the largest thing we receive) */ +struct nfs_reply_data { + u_long errno; +#ifndef NFSX_FATTR + struct nfsv2_fattr fa; +#else + u_char fa[NFSX_FATTR(0)]; +#endif + u_long count; + u_char data[1200]; +}; +#define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data) + +/* max number of nfs reads pending */ +#define NFS_COUNT 10 + +static struct nfsstate { + u_long off; + u_long len; + int done; + void *addr; + u_long xid; +} nfsstate[NFS_COUNT]; + +static u_long nfscc; + +struct nfs_iodesc { + off_t off; + size_t size; + u_char *fh; + struct iodesc *iodesc; +}; + +/* Fetch (mount) file handle */ +static int +getmountfh(d, path, fhp) + register struct iodesc *d; + char *path; + u_char *fhp; +{ + register int len; + struct { + u_long len; + char path[FNAME_SIZE]; + } sdata; + struct { + u_long errno; + u_char fh[NFS_FHSIZE]; + } rdata; + int cc; + +#ifdef NFS_DEBUG + if (debug) + printf("getmountfh: called\n"); +#endif + bzero(&sdata, sizeof(sdata)); + len = strlen(path); + if (len > sizeof(sdata.path)) + len = sizeof(sdata.path); + bcopy(path, sdata.path, len); + sdata.len = htonl(len); + len = sizeof(sdata) - sizeof(sdata.path) + roundup(len, sizeof(long)); + + if ((cc = callrpc(d, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, + &sdata, len, &rdata, sizeof(rdata))) < 0) + return(-1); + if (cc < sizeof(rdata.errno)) + panic("getmountfh: callrpc small read"); + if (rdata.errno) { + errno = ntohl(rdata.errno); + return(-1); + } + bcopy(rdata.fh, fhp, sizeof(rdata.fh)); + return(0); +} + +/* Fetch file timestamp and size */ +static int +getnfsinfo(d, tp, sp, fp, mp, up, gp) + register struct nfs_iodesc *d; + register time_t *tp; + u_long *sp, *fp; + mode_t *mp; + uid_t *up; + gid_t *gp; +{ + register int rlen; + register u_long t; + struct { + u_long errno; + struct nfsv2_fattr fa; + } rdata; + int cc; + +#ifdef NFS_DEBUG + if (debug) + printf("getnfsinfo: called\n"); +#endif + rlen = sizeof(rdata); +#if 0 +#ifdef NFSX_FATTR +#if NFSX_FATTR(1) > NFSX_FATTR(0) + /* nqnfs makes this more painful than it needs to be */ + rlen -= NFSX_FATTR(1) - NFSX_FATTR(0); +#endif +#endif +#endif + if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_GETATTR, + d->fh, NFS_FHSIZE, &rdata, rlen)) < 0) + return(-1); + if (cc < sizeof(rdata.errno)) + panic("getnfsinfo: callrpc small read"); + if (rdata.errno) { + errno = ntohl(rdata.errno); + return(-1); + } + if (tp) { + *tp = ntohl(rdata.fa.fa_mtime.tv_sec); + t = ntohl(rdata.fa.fa_atime.tv_sec); + if (*tp < t) + *tp = t; + } + if (sp) + *sp = ntohl(rdata.fa.fa_size); + if (fp) + *fp = ntohl(rdata.fa.fa_type); + if (mp) + *mp = ntohl(rdata.fa.fa_mode); + if (up) + *up = ntohl(rdata.fa.fa_uid); + if (gp) + *gp = ntohl(rdata.fa.fa_gid); + return(0); +} + +/* Lookup a file. Optionally return timestamp and size */ +static int +lookupfh(d, name, fhp, tp, sp, fp) + struct nfs_iodesc *d; + char *name; + u_char *fhp; + time_t *tp; + u_long *sp, *fp; +{ + register int len, rlen; + struct { + u_char fh[NFS_FHSIZE]; + u_long len; + char name[FNAME_SIZE]; + } sdata; + struct { + u_long errno; + u_char fh[NFS_FHSIZE]; + struct nfsv2_fattr fa; + } rdata; + int cc; + +#ifdef NFS_DEBUG + if (debug) + printf("lookupfh: called\n"); +#endif + + bzero(&sdata, sizeof(sdata)); + bcopy(d->fh, sdata.fh, sizeof(sdata.fh)); + len = strlen(name); + if (len > sizeof(sdata.name)) + len = sizeof(sdata.name); + bcopy(name, sdata.name, len); + sdata.len = htonl(len); + len = sizeof(sdata) - sizeof(sdata.name) + roundup(len, sizeof(long)); + + rlen = sizeof(rdata); +#if 0 +#ifdef NFSX_FATTR +#if NFSX_FATTR(1) > NFSX_FATTR(0) + /* nqnfs makes this more painful than it needs to be */ + rlen -= NFSX_FATTR(1) - NFSX_FATTR(0); +#endif +#endif +#endif + if ((cc = callrpc(d->iodesc, NFS_PROG, NFS_VER2, NFSPROC_LOOKUP, + &sdata, len, &rdata, rlen)) < 0) + return (-1); + if (cc < sizeof(rdata.errno)) + panic("lookupfh: callrpc small read"); + if (rdata.errno) { + errno = ntohl(rdata.errno); + return(-1); + } + bcopy(rdata.fh, fhp, sizeof(rdata.fh)); + if (tp) + *tp = ntohl(rdata.fa.fa_ctime.tv_sec); + if (sp) + *sp = ntohl(rdata.fa.fa_size); + if (fp) + *fp = ntohl(rdata.fa.fa_type); + return (0); +} + +static int +sendreaddata(d, pkt, len) + register struct nfs_iodesc *d; + register void *pkt; + register int len; +{ + register int i; + register u_long cc; + register struct rpc_call *rpc; + register struct nfs_call_data *nfs; + register struct nfsstate *ns; + +#ifdef NFS_DEBUG + if (debug) + printf("sendreaddata: called\n"); +#endif + + if (len != sizeof(*rpc) + sizeof(*nfs)) + panic("sendreaddata: bad buffer (%d != %d)", + len, sizeof(*rpc) + sizeof(*nfs)); + rpc = pkt; + nfs = (struct nfs_call_data *)(rpc + 1); + for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) { + if (ns->done) + continue; + + rpc->rp_xid = ns->xid; + nfs->off = htonl(ns->off); + nfs->len = htonl(ns->len); + cc = sendudp(d->iodesc, rpc, len); + + if (cc != len) + panic("sendreaddata: short write (%d != %d)", cc, len); + } + /* XXX we may have actually sent a lot more bytes... */ + + return (len); +} + +/* Returns char count if done else -1 (and errno == 0) */ +static int +recvreaddata(d, pkt, len) + register struct nfs_iodesc *d; + register void *pkt; + int len; +{ + register int i; + register struct rpc_reply *rpc; + register struct nfs_reply_data *nfs; + register struct nfsstate *ns; + +#ifdef NFS_DEBUG + if (debug) + printf("recvreaddata: called\n"); +#endif + rpc = (struct rpc_reply *)checkudp(d->iodesc, pkt, &len); + if (rpc == NULL || len < sizeof(*rpc)) { + errno = 0; + return (-1); + } + len -= sizeof(*rpc); + + NTOHL(rpc->rp_direction); + NTOHL(rpc->rp_stat); + + if (rpc->rp_direction != REPLY || rpc->rp_stat != MSG_ACCEPTED) { + errno = 0; + return (-1); + } + + for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) + if (rpc->rp_xid == ns->xid) + break; + if (i >= NFS_COUNT) { + errno = 0; + return (-1); + } + + if (ns->done) { + errno = 0; + return (-1); + } +#ifdef NFS_DEBUG + if (debug) + printf("recvreaddata: ns=%x\n", (u_int)ns); +#endif + nfs = (struct nfs_reply_data *)(rpc + 1); + if (len < sizeof(nfs->errno)) + panic("recvreaddata: bad read %d", len); + if (nfs->errno) { + errno = ntohl(nfs->errno); + return (-1); + } + if (len < sizeof(*nfs) - sizeof(nfs->data)) + panic("recvreaddata: less than nfs sized %d", len); + len -= sizeof(*nfs) - sizeof(nfs->data); + + if (len < nfs->count) + panic("recvreaddata: short read (%d < %d)", len, nfs->count); + len = nfs->count; + if (len > ns->len) + panic("recvreaddata: huge read (%d > %d)", len, ns->len); + + +#ifdef NFS_DEBUG + if (debug) + printf("recvreaddata: read %d bytes.\n", len); +#endif + bcopy(nfs->data, ns->addr, len); + ns->done = 1; + nfscc += len; + + if (len < ns->len) { + /* If first packet assume no more data to read */ + if (i == 0) + return (0); + + /* Short read, assume we are at EOF */ + ++i; + ++ns; + while (i < NFS_COUNT) { + ns->done = 1; + ++i; + ++ns; + } + } + + for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) + if (!ns->done) { + errno = 0; + return (-1); + } + + /* Return data count (thus indicating success) */ + return (nfscc); +} + +/* Read data from a file */ +static int +readdata(d, off, addr, len) + register struct nfs_iodesc *d; + register u_long off; + register void *addr; + register u_long len; +{ + register int i, cc; + register struct rpc_call *rpc; + register struct nfsstate *ns; + struct { + u_char header[HEADER_SIZE]; + struct rpc_call rpc; + struct nfs_call_data nfs; + } sdata; + struct { + u_char header[HEADER_SIZE]; + struct rpc_call rpc; + struct nfs_reply_data nfs; + } rdata; + +#ifdef NFS_DEBUG + if (debug) + printf("readdata: addr=%x, off=%d len=%d\n", (u_int)addr, off, len); +#endif + if (len == 0) + return (0); + d->iodesc->destport = getport(d->iodesc, NFS_PROG, NFS_VER2); + + bzero(&sdata, sizeof(sdata)); + + for (i = 0, ns = nfsstate; i < NFS_COUNT; ++i, ++ns) { + if (len <= 0) { + ns->done = 1; + continue; + } + ns->done = 0; + + ns->xid = d->iodesc->xid; + ++d->iodesc->xid; + + ns->off = off; + ns->len = len; + if (ns->len > NFSREAD_SIZE) + ns->len = NFSREAD_SIZE; +#ifdef notdef +/* XXX to align or not align? It doesn't seem to speed things up... */ + if ((ns->off % NFSREAD_SIZE) != 0) + ns->len -= off % NFSREAD_SIZE; +#endif + + off += ns->len; + len -= ns->len; + + ns->addr = addr; + addr += NFSREAD_SIZE; + } + + rpc = &sdata.rpc; + rpc->rp_rpcvers = htonl(RPC_MSG_VERSION); + rpc->rp_prog = htonl(NFS_PROG); + rpc->rp_vers = htonl(NFS_VER2); + rpc->rp_proc = htonl(NFSPROC_READ); + bcopy(d->fh, sdata.nfs.fh, sizeof(sdata.nfs.fh)); + + nfscc = 0; + cc = sendrecv(d->iodesc, + sendreaddata, &sdata.rpc, + sizeof(struct rpc_call) + sizeof(struct nfs_call_data), + recvreaddata, + ((u_char *)&rdata.rpc) - HEADER_SIZE, HEADER_SIZE + + sizeof(struct rpc_call) + sizeof(struct nfs_reply_data)); + return (cc); +} + +static struct iodesc *mountfs; +static u_char mountfh[NFS_FHSIZE]; +static time_t mounttime; + +/* + * nfs_mount - mount this nfs filesystem to a host + */ +int +nfs_mount(sock, ip, path) + int sock; + n_long ip; + char *path; +{ + struct iodesc *desc; + struct nfs_iodesc *fp; + u_long ftype; + + if (!(desc = socktodesc(sock))) { + errno = EINVAL; + return(-1); + } + bcopy(&desc->myea[4], &desc->myport, 2); + desc->destip = ip; + getmountfh(desc, path, mountfh); + + fp = alloc(sizeof(struct nfs_iodesc)); + fp->iodesc = desc; + fp->fh = mountfh; + fp->off = 0; + if (getnfsinfo(fp, &mounttime, NULL, &ftype, NULL, NULL, NULL) < 0) { + free(fp, sizeof(struct nfs_iodesc)); + return(-1); + } + + if (ftype != NFDIR) { + free(fp, sizeof(struct nfs_iodesc)); + errno = EINVAL; + printf("nfs_mount: bad mount ftype %d", ftype); + return(-1); + } +#ifdef NFS_DEBUG + if (debug) + printf("nfs_mount: got fh for %s, mtime=%d, ftype=%d\n", + path, mounttime, ftype); +#endif + mountfs = desc; + free(fp, sizeof(struct nfs_iodesc)); + + return(0); +} + +/* + * Open a file. + */ +int +nfs_open(path, f) + char *path; + struct open_file *f; +{ + register struct nfs_iodesc *fp; + u_char *imagefh; + u_long size, ftype; + int rc = 0; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_open: %s\n", path); +#endif + if (!mountfs) { + errno = EIO; + printf("nfs_open: must mount first.\n"); + return(-1); + } + + /* allocate file system specific data structure */ + fp = alloc(sizeof(struct nfs_iodesc)); + fp->iodesc = mountfs; + fp->fh = mountfh; + fp->off = 0; + + f->f_fsdata = (void *)fp; + imagefh = alloc(NFS_FHSIZE); + bzero(imagefh, NFS_FHSIZE); + + /* lookup a file handle */ + rc = lookupfh(fp, path, imagefh, NULL, &size, &ftype); + if (rc < 0) { +#ifdef NFS_DEBUG + if (debug) + printf("nfs_open: %s lookupfh failed: %s\n", path, strerror(errno)); +#endif + f->f_fsdata = (void *)0; + free(fp, sizeof(struct nfs_iodesc)); + free(imagefh, NFS_FHSIZE); + return(rc); + } + fp->fh = imagefh; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_open: %s success, size=%d ftype=%d\n", + path, size, ftype); +#endif + fp->size = size; + + return(rc); +} + +int +nfs_close(f) + struct open_file *f; +{ + register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_close: called\n"); +#endif + f->f_fsdata = (void *)0; + if (fp == (struct nfs_iodesc *)0) + return (0); + + free(fp->fh, NFS_FHSIZE); + free(fp, sizeof(struct nfs_iodesc)); + + return (0); +} + +/* + * read a portion of a file + */ +int +nfs_read(f, addr, size, resid) + struct open_file *f; + char *addr; + u_int size; + u_int *resid; /* out */ +{ + register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + register int cc; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: size=%d off=%d\n", size, fp->off); +#endif + while (size > 0) { + cc = readdata(fp->iodesc, fp->off, (void *)addr, size); + if (cc <= 0) { + /* XXX maybe should retry on certain errors */ + if (cc < 0) { +#ifdef NFS_DEBUG + if (debug) + printf("nfs_read: read: %s", + strerror(errno)); +#endif + return (-1); + } + if (debug) + printf("nfs_read: hit EOF unexpectantly"); + goto ret; + } + fp->off += cc; + addr += cc; + size -= cc; + } +ret: + if (resid) + *resid = size; + + return (0); +} + +/* + * Not implemented. + */ +int +nfs_write(f, start, size, resid) + struct open_file *f; + char *start; + u_int size; + u_int *resid; /* out */ +{ + errno = EROFS; + + return (-1); +} + +off_t +nfs_seek(f, offset, where) + struct open_file *f; + off_t offset; + int where; +{ + register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + + switch (where) { + case SEEK_SET: + fp->off = offset; + break; + case SEEK_CUR: + fp->off += offset; + break; + case SEEK_END: + fp->off = fp->size - offset; + break; + default: + return (-1); + } + return (fp->off); +} + +int +nfs_stat(f, sb) + struct open_file *f; + struct stat *sb; +{ + register struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata; + mode_t mode = 0; + u_long ftype = 0; + +#ifdef NFS_DEBUG + if (debug) + printf("nfs_stat: called\n"); +#endif + if (getnfsinfo(fp, &mounttime, &sb->st_size, &ftype, &mode, &sb->st_uid, &sb->st_gid) < 0) + return(-1); + + /* create a mode */ + switch (ftype) { + case NFNON: + sb->st_mode = 0; + break; + case NFREG: + sb->st_mode = S_IFREG; + break; + case NFDIR: + sb->st_mode = S_IFDIR; + break; + case NFBLK: + sb->st_mode = S_IFBLK; + break; + case NFCHR: + sb->st_mode = S_IFCHR; + break; + case NFLNK: + sb->st_mode = S_IFLNK; + break; + } + sb->st_mode |= mode; + + return (0); +} diff --git a/sys/lib/libsa/nfs.h b/sys/lib/libsa/nfs.h new file mode 100644 index 000000000000..9e62bbe6d009 --- /dev/null +++ b/sys/lib/libsa/nfs.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: nfs.h,v 1.1 1994/05/08 16:11:32 brezak Exp $ + */ + +int nfs_open __P((char *path, struct open_file *f)); +int nfs_close __P((struct open_file *f)); +int nfs_read __P((struct open_file *f, char *buf, + u_int size, u_int *resid)); +int nfs_write __P((struct open_file *f, char *buf, + u_int size, u_int *resid)); +off_t nfs_seek __P((struct open_file *f, off_t offset, int where)); +int nfs_stat __P((struct open_file *f, struct stat *sb)); diff --git a/sys/lib/libsa/open.c b/sys/lib/libsa/open.c index b3b89ca71c8c..6e805aad2f01 100644 --- a/sys/lib/libsa/open.c +++ b/sys/lib/libsa/open.c @@ -61,23 +61,17 @@ * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * - * $Id: open.c,v 1.2 1994/03/01 20:57:56 pk Exp $ + * $Id: open.c,v 1.3 1994/05/08 16:11:33 brezak Exp $ */ #include "stand.h" -#include "ufs.h" +struct open_file files[SOPEN_MAX]; /* * File primitives proper */ -struct fs_ops file_system[] = { - { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat } -}; -#define NFSYS (sizeof(file_system) / sizeof(struct fs_ops)) - -struct open_file files[SOPEN_MAX]; - +int open(fname, mode) char *fname; int mode; @@ -101,7 +95,8 @@ fnd: f->f_dev = (struct devsw *)0; file = (char *)0; error = devopen(f, fname, &file); - if (error || f->f_dev == (struct devsw *)0) + if (error || + (((f->f_flags & F_NODEV) == 0) && f->f_dev == (struct devsw *)0)) goto err; /* see if we opened a raw device; otherwise, 'file' is the file name. */ @@ -111,7 +106,7 @@ fnd: } /* pass file name to the different filesystem open routines */ - for (i = 0; i < NFSYS; i++) { + for (i = 0; i < nfsys; i++) { /* convert mode (0,1,2) to FREAD, FWRITE. */ error = (file_system[i].open)(file, f); if (error == 0) { @@ -126,3 +121,42 @@ err: errno = error; return (-1); } + +/* + * Null filesystem + */ +int null_open (char *path, struct open_file *f) +{ + errno = EIO; + return -1; +} + +int null_close(struct open_file *f) +{ + return 0; +} + +int null_read (struct open_file *f, char *buf, u_int size, u_int *resid) +{ + errno = EIO; + return -1; +} + +int null_write (struct open_file *f, char *buf, u_int size, u_int *resid) +{ + errno = EIO; + return -1; +} + +off_t null_seek (struct open_file *f, off_t offset, int where) +{ + errno = EIO; + return -1; +} + +int null_stat (struct open_file *f, struct stat *sb) +{ + errno = EIO; + return -1; +} + diff --git a/sys/lib/libsa/rarp.c b/sys/lib/libsa/rarp.c new file mode 100644 index 000000000000..790f51ac289f --- /dev/null +++ b/sys/lib/libsa/rarp.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" + +static int rarpsend(struct iodesc *, void *, int); +static int rarprecv(struct iodesc *, void *, int); + +/* + * Ethernet (Reverse) Address Resolution Protocol (see RFC 903, and 826). + */ +n_long +rarp_getipaddress(sock) + int sock; +{ + struct iodesc *d; + register struct ether_arp *ap; + register void *pkt; + struct { + u_char header[HEADER_SIZE]; + struct ether_arp wrarp; + } wbuf; + union { + u_char buffer[RECV_SIZE]; + struct { + u_char header[HEADER_SIZE]; + struct ether_arp xrrarp; + }xrbuf; +#define rrarp xrbuf.xrrarp + } rbuf; + +#ifdef RARP_DEBUG + if (debug) + printf("rarp: socket=%d\n", sock); +#endif + if (!(d = socktodesc(sock))) { + printf("rarp: bad socket. %d\n", sock); + return(INADDR_ANY); + } +#ifdef RARP_DEBUG + if (debug) + printf("rarp: d=%x\n", (u_int)d); +#endif + ap = &wbuf.wrarp; + pkt = &rbuf.rrarp; + pkt -= HEADER_SIZE; + + bzero(ap, sizeof(*ap)); + + ap->arp_hrd = htons(ARPHRD_ETHER); + ap->arp_pro = htons(ETHERTYPE_IP); + ap->arp_hln = sizeof(ap->arp_sha); /* hardware address length */ + ap->arp_pln = sizeof(ap->arp_spa); /* protocol address length */ + ap->arp_op = htons(REVARP_REQUEST); + bcopy(d->myea, ap->arp_sha, 6); + bcopy(d->myea, ap->arp_tha, 6); + + if (sendrecv(d, + rarpsend, ap, sizeof(*ap), + rarprecv, pkt, RECV_SIZE) < 0) { + printf("No response for RARP request\n"); + return(INADDR_ANY); + } + + return(myip); +} + +/* + * Broadcast a RARP request (i.e. who knows who I am) + */ +static int +rarpsend(d, pkt, len) + register struct iodesc *d; + register void *pkt; + register int len; +{ +#ifdef RARP_DEBUG + if (debug) + printf("rarpsend: called\n"); +#endif + return (sendether(d, pkt, len, bcea, ETHERTYPE_REVARP)); +} + +/* + * Called when packet containing RARP is received + */ +static int +rarprecv(d, pkt, len) + register struct iodesc *d; + register void *pkt; + register int len; +{ + register struct ether_header *ep; + register struct ether_arp *ap; + +#ifdef RARP_DEBUG + if (debug) + printf("rarprecv: called\n"); +#endif + if (len < sizeof(struct ether_header) + sizeof(struct ether_arp)) { + errno = 0; + return (-1); + } + + ep = (struct ether_header *)pkt; + if (ntohs(ep->ether_type) != ETHERTYPE_REVARP) { + errno = 0; + return (-1); + } + + ap = (struct ether_arp *)(ep + 1); + if (ntohs(ap->arp_op) != REVARP_REPLY || + ntohs(ap->arp_pro) != ETHERTYPE_IP) { + errno = 0; + return (-1); + } + + if (bcmp(ap->arp_tha, d->myea, 6)) { + errno = 0; + return (-1); + } + + bcopy(ap->arp_tpa, (char *)&myip, sizeof(myip)); + bcopy(ap->arp_spa, (char *)&rootip, sizeof(rootip)); + + return(0); +} diff --git a/sys/lib/libsa/rpc.c b/sys/lib/libsa/rpc.c new file mode 100644 index 000000000000..b9731be58008 --- /dev/null +++ b/sys/lib/libsa/rpc.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) + * $Id: rpc.c,v 1.1 1994/05/08 16:11:35 brezak Exp $ + */ + +#include +#include + +#include +#include + +#include +#include +#undef NFSX_FATTR +#include + +#include "stand.h" +#include "net.h" +#include "netif.h" +#include "rpc.h" + +/* XXX Data part of nfs rpc reply (also the largest thing we receive) */ +struct nfs_reply_data { + u_long errno; +#ifndef NFSX_FATTR + struct nfsv2_fattr fa; +#else + u_char fa[NFSX_FATTR(0)]; +#endif + u_long count; + u_char data[1200]; +}; +#define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data) + +/* Cache stuff */ +#define PMAP_NUM 8 /* need at most 5 pmap entries */ + +static struct pmap_list { + u_long addr; /* address of server */ + u_long prog; + u_long vers; + u_short port; /* cached port for service */ +} pmap_list[PMAP_NUM] = { + { 0, PMAPPROG, PMAPVERS, PMAPPORT } +}; +static int pmap_num = 1; + +/* Local forwards */ +static int recvrpc __P((struct iodesc *, void *, int)); + +/* Make a rpc call; return length of answer */ +int +callrpc(d, prog, vers, proc, sdata, slen, rdata, rlen) + register struct iodesc *d; + register u_long prog, vers, proc; + register void *sdata; + register int slen; + register void *rdata; + register int rlen; +{ + register int cc; + register struct rpc_call *rpc; + struct { + u_char header[HEADER_SIZE]; + struct rpc_call wrpc; + u_char data[sizeof(struct nfs_reply_data)]; /* XXX */ + } wbuf; + struct { + u_char header[HEADER_SIZE]; + struct rpc_reply rrpc; + union { + u_long errno; + u_char data[sizeof(struct nfs_reply_data)]; + } ru; + } rbuf; + +#ifdef RPC_DEBUG + if (debug) + printf("callrpc: called\n"); +#endif + if (rlen > sizeof(rbuf.ru.data)) + panic("callrpc: huge read (%d > %d)", + rlen, sizeof(rbuf.ru.data)); + + d->destport = getport(d, prog, vers); + + rpc = &wbuf.wrpc; + + bzero(rpc, sizeof(*rpc)); + + rpc->rp_xid = d->xid; + rpc->rp_rpcvers = htonl(RPC_MSG_VERSION); + rpc->rp_prog = htonl(prog); + rpc->rp_vers = htonl(vers); + rpc->rp_proc = htonl(proc); + bcopy(sdata, wbuf.data, slen); + + cc = sendrecv(d, sendudp, rpc, sizeof(*rpc) + slen, recvrpc, + ((u_char *)&rbuf.rrpc) - HEADER_SIZE, sizeof(rbuf) - HEADER_SIZE); + + if (cc < rlen) { + /* Check for an error return */ + if (cc >= sizeof(rbuf.ru.errno) && rbuf.ru.errno != 0) { + errno = ntohl(rbuf.ru.errno); + return (-1); + } + panic("callrpc: missing data (%d < %d)", cc, rlen); + } + if (cc > sizeof(rbuf.ru.data)) + panic("callrpc: huge return (%d > %d)", + cc, sizeof(rbuf.ru.data)); + bcopy(rbuf.ru.data, rdata, cc); + return (cc); +} + +/* Returns true if packet is the one we're waiting for */ +static int +recvrpc(d, pkt, len) + register struct iodesc *d; + register void *pkt; + int len; +{ + register struct rpc_reply *rpc; + + errno = 0; +#ifdef RPC_DEBUG + if (debug) + printf("recvrpc: called\n"); +#endif + rpc = (struct rpc_reply *)checkudp(d, pkt, &len); + if (rpc == NULL || len < sizeof(*rpc)) { +#ifdef RPC_DEBUG + if (debug) + printf("recvrpc: bad response rpc=%x len=%d\n", + (u_int)rpc, len); +#endif + return (-1); + } + + NTOHL(rpc->rp_direction); + NTOHL(rpc->rp_stat); + + if (rpc->rp_xid != d->xid || rpc->rp_direction != REPLY || + rpc->rp_stat != MSG_ACCEPTED) { +#ifdef RPC_DEBUG + if (debug) { + if (rpc->rp_xid != d->xid) + printf("recvrpc: rp_xid %d != xid %d\n", + rpc->rp_xid, d->xid); + if (rpc->rp_direction != REPLY) + printf("recvrpc: %d != REPLY\n", rpc->rp_direction); + if (rpc->rp_stat != MSG_ACCEPTED) + printf("recvrpc: %d != MSG_ACCEPTED\n", rpc->rp_stat); + } +#endif + return (-1); + } + + /* Bump xid so next request will be unique */ + ++d->xid; + + /* Return data count (thus indicating success) */ + return (len - sizeof(*rpc)); +} + +/* Request a port number from the port mapper */ +u_short +getport(d, prog, vers) + register struct iodesc *d; + u_long prog; + u_long vers; +{ + register int i; + register struct pmap_list *pl; + u_long port; + struct { + u_long prog; /* call program */ + u_long vers; /* call version */ + u_long proto; /* call protocol */ + u_long port; /* call port (unused) */ + } sdata; + +#ifdef RPC_DEBUG + if (debug) + printf("getport: called\n"); +#endif + /* Try for cached answer first */ + for (i = 0, pl = pmap_list; i < pmap_num; ++i, ++pl) + if ((pl->addr == d->destip || pl->addr == 0) && + pl->prog == prog && pl->vers == vers) + return (pl->port); + + /* Don't overflow cache */ + if (pmap_num > PMAP_NUM - 1) + panic("getport: overflowed pmap_list!"); + + sdata.prog = htonl(prog); + sdata.vers = htonl(vers); + sdata.proto = htonl(IPPROTO_UDP); + sdata.port = 0; + + if (callrpc(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, + &sdata, sizeof(sdata), &port, sizeof(port)) < 0) { + printf("getport: %s", strerror(errno)); + return(-1); + } + + /* Cache answer */ + pl->addr = d->destip; + pl->prog = prog; + pl->vers = vers; + pl->port = port; + ++pmap_num; + + return ((u_short)port); +} diff --git a/sys/lib/libsa/rpc.h b/sys/lib/libsa/rpc.h new file mode 100644 index 000000000000..bdcad50a6f20 --- /dev/null +++ b/sys/lib/libsa/rpc.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1992 Regents of the University of California. + * All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: rpc.h,v 1.1 1994/05/08 16:11:36 brezak Exp $ + */ + +/* XXX defines we can't easily get from system includes */ +#define PMAPPORT 111 +#define PMAPPROG 100000 +#define PMAPVERS 2 +#define PMAPPROC_GETPORT 3 + +#define RPC_MSG_VERSION 2 +#define MSG_ACCEPTED 0 +#define CALL 0 +#define REPLY 1 + + +/* Null rpc auth info */ +struct auth_info { + int rp_atype; /* zero (really AUTH_NULL) */ + u_long rp_alen; /* zero (size of auth struct) */ +}; + +/* Generic rpc call header */ +struct rpc_call { + u_long rp_xid; /* request transaction id */ + int rp_direction; /* call direction */ + u_long rp_rpcvers; /* rpc version (2) */ + u_long rp_prog; /* program */ + u_long rp_vers; /* version */ + u_long rp_proc; /* procedure */ + struct auth_info rp_auth; /* AUTH_NULL */ + struct auth_info rp_verf; /* AUTH_NULL */ +}; + +/* Generic rpc reply header */ +struct rpc_reply { + u_long rp_xid; /* request transaction id */ + int rp_direction; /* call direction */ + int rp_stat; /* accept status */ + u_long rp_prog; /* program (unused) */ + u_long rp_vers; /* version (unused) */ + u_long rp_proc; /* procedure (unused) */ +}; + +/* RPC functions: */ +int callrpc __P((struct iodesc *d, u_long prog, u_long ver, u_long op, + void *sdata, int slen, void *rdata, int rlen)); +u_short getport __P((struct iodesc *d, u_long prog, u_long vers)); + diff --git a/sys/lib/libsa/stand.h b/sys/lib/libsa/stand.h index 84b406ebd655..0e31b1771323 100644 --- a/sys/lib/libsa/stand.h +++ b/sys/lib/libsa/stand.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)stand.h 8.1 (Berkeley) 6/11/93 - * $Id: stand.h,v 1.1 1994/01/26 02:03:58 brezak Exp $ + * $Id: stand.h,v 1.2 1994/05/08 16:11:37 brezak Exp $ */ #include @@ -92,11 +92,13 @@ struct open_file { #define SOPEN_MAX 4 extern struct open_file files[SOPEN_MAX]; +extern int nfsys; /* f_flags values */ #define F_READ 0x0001 /* file opened for reading */ #define F_WRITE 0x0002 /* file opened for writing */ #define F_RAW 0x0004 /* raw device open - no file system */ +#define F_NODEV 0x0008 /* network open - no device */ #define isupper(c) ((c) >= 'A' && (c) <= 'Z') #define tolower(c) ((c) - 'A' + 'a') @@ -108,5 +110,24 @@ void *alloc __P((unsigned size)); void free __P((void *ptr, unsigned size)); struct disklabel; char *getdisklabel __P((const char *buf, struct disklabel *lp)); + +int printf __P((char *, ...)); +void panic __P((char *, ...)); +int getchar __P((void)); +int exec __P((char *, char *, int)); + int nodev(), noioctl(); void nullsys(); + +int null_open __P((char *path, struct open_file *f)); +int null_close __P((struct open_file *f)); +int null_read __P((struct open_file *f, char *buf, + u_int size, u_int *resid)); +int null_write __P((struct open_file *f, char *buf, + u_int size, u_int *resid)); +off_t null_seek __P((struct open_file *f, off_t offset, int where)); +int null_stat __P((struct open_file *f, struct stat *sb)); + +/* Machine dependant functions */ +void machdep_start __P((char *, int, char *, char *, char *)); +int machdep_exec __P((char *, char *, int));