68cbb04819
Smack the netboot program around so that it will allow the user to specify mount options. [So that you can boot from a privileged port] Change the default boot image name in netboot to /kernel, then strip the leading slash when actually going out to get the NFS file handle. Added support for 3Com 3c503 cards. Also added another command to the (trans) that allows you to switch the 3Com's on-board transceiver on and off. (ether.c, ether.h, bootmenu.c) Modified the Makefile to support new compile-time options for 3c503 cards: -DINCLUDE_3COM Include support for 3c503 -D_3COM_BASE=0x300 Define 3c503 base i/o address (if not specified, 0x300 is the default) -D_3COM_USE_AUI Disable the 3c503's transceiver by default (without this flag the transceiver is on by default)
618 lines
18 KiB
C
618 lines
18 KiB
C
/**************************************************************************
|
|
NETBOOT - BOOTP/TFTP Bootstrap Program
|
|
|
|
Author: Martin Renters
|
|
Date: Dec/93
|
|
|
|
**************************************************************************/
|
|
|
|
#include "netboot.h"
|
|
|
|
int jmp_bootmenu[10];
|
|
|
|
struct exec head;
|
|
char *loadpoint;
|
|
char *kernel;
|
|
char kernel_buf[128];
|
|
#ifdef INCLUDE_3COM
|
|
#ifdef _3COM_USE_AUI
|
|
short aui = 1;
|
|
#else
|
|
short aui = 0;
|
|
#endif
|
|
#endif
|
|
void (*kernelentry)();
|
|
struct nfs_diskless nfsdiskless;
|
|
int hostnamelen;
|
|
char config_buffer[512]; /* Max TFTP packet */
|
|
struct bootinfo_t bootinfo;
|
|
unsigned long netmask;
|
|
|
|
extern char packet[];
|
|
extern int packetlen, rpc_id;
|
|
char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
|
|
|
/**************************************************************************
|
|
MAIN - Kick off routine
|
|
**************************************************************************/
|
|
main()
|
|
{
|
|
int c;
|
|
char *p;
|
|
extern char edata[], end[];
|
|
for (p=edata; p<end; p++) *p = 0; /* Zero BSS */
|
|
#ifdef ASK_BOOT
|
|
while (1) {
|
|
printf("\n\rBoot from Network (Y/N) ? ");
|
|
c = getchar();
|
|
if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
|
|
if (c == '\r') break;
|
|
putchar(c);
|
|
if (c == 'N')
|
|
exit(0);
|
|
if (c == 'Y')
|
|
break;
|
|
printf(" - bad response\n\r");
|
|
}
|
|
#endif
|
|
gateA20();
|
|
printf("\r\nBOOTP/TFTP/NFS bootstrap loader ESC for menu\n\r");
|
|
printf("\r\nSearching for adapter...");
|
|
if (!eth_probe()) {
|
|
printf("No adapter found.\r\n");
|
|
exit(0);
|
|
}
|
|
kernel = DEFAULT_BOOTFILE;
|
|
while (1) {
|
|
if (setjmp(jmp_bootmenu))
|
|
bootmenu();
|
|
else
|
|
load();
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
LOAD - Try to get booted
|
|
**************************************************************************/
|
|
load()
|
|
{
|
|
char *p,*q;
|
|
char cfg[64];
|
|
int root_nfs_port;
|
|
int root_mount_port;
|
|
int swap_nfs_port;
|
|
int swap_mount_port;
|
|
char kernel_handle[32];
|
|
char cmd_line[80];
|
|
int err, offset, read_size;
|
|
long addr, broadcast;
|
|
|
|
/* Initialize this early on */
|
|
|
|
nfsdiskless.root_args.rsize = 8192;
|
|
nfsdiskless.root_args.wsize = 8192;
|
|
nfsdiskless.swap_args.rsize = 8192;
|
|
nfsdiskless.swap_args.wsize = 8192;
|
|
nfsdiskless.root_args.sotype = SOCK_DGRAM;
|
|
nfsdiskless.root_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE);
|
|
nfsdiskless.swap_args.sotype = SOCK_DGRAM;
|
|
nfsdiskless.swap_args.flags = (NFSMNT_WSIZE | NFSMNT_RSIZE);
|
|
|
|
|
|
/* Find a server to get BOOTP reply from */
|
|
if (!arptable[ARP_CLIENT].ipaddr || !arptable[ARP_SERVER].ipaddr) {
|
|
printf("\r\nSearching for server...\r\n");
|
|
if (!bootp()) {
|
|
printf("No Server found.\r\n");
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
}
|
|
printf("My IP %I, Server IP %I, GW IP %I\r\n",
|
|
arptable[ARP_CLIENT].ipaddr,
|
|
arptable[ARP_SERVER].ipaddr,
|
|
arptable[ARP_GATEWAY].ipaddr);
|
|
|
|
/* Now use TFTP to load configuration file */
|
|
sprintf(cfg,"cfg.%I",arptable[ARP_CLIENT].ipaddr);
|
|
printf("Loading %s...\r\n",cfg);
|
|
if (!tftp(cfg)) {
|
|
sprintf(cfg,"/tftpboot/cfg.%I",arptable[ARP_CLIENT].ipaddr);
|
|
printf("Loading %s...\r\n",cfg);
|
|
if (!tftp(cfg)) {
|
|
printf("Unable to load config file.\r\n");
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
}
|
|
/* Execute commands in config file */
|
|
p = config_buffer;
|
|
while(*p) {
|
|
q = cmd_line;
|
|
while ((*p != '\n') && (*p)) *(q++) = *(p++);
|
|
*q = 0;
|
|
printf("%s\r\n",cmd_line);
|
|
execute(cmd_line);
|
|
if (*p) p++;
|
|
}
|
|
|
|
/* Check to make sure we've got a rootfs */
|
|
if (!arptable[ARP_ROOTSERVER].ipaddr) {
|
|
printf("No ROOT filesystem server!\r\n");
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
|
|
/* Fill in nfsdiskless.myif */
|
|
sprintf(&nfsdiskless.myif.ifra_name,"ed0");
|
|
nfsdiskless.myif.ifra_addr.sa_len = sizeof(struct sockaddr);
|
|
nfsdiskless.myif.ifra_addr.sa_family = AF_INET;
|
|
addr = htonl(arptable[ARP_CLIENT].ipaddr);
|
|
bcopy(&addr, &nfsdiskless.myif.ifra_addr.sa_data[2], 4);
|
|
broadcast = (addr & netmask) | ~netmask;
|
|
nfsdiskless.myif.ifra_broadaddr.sa_len = sizeof(struct sockaddr);
|
|
nfsdiskless.myif.ifra_broadaddr.sa_family = AF_INET;
|
|
bcopy(&broadcast, &nfsdiskless.myif.ifra_broadaddr.sa_data[2], 4);
|
|
addr = htonl(arptable[ARP_GATEWAY].ipaddr);
|
|
if (addr) {
|
|
nfsdiskless.mygateway.sin_len = sizeof(struct sockaddr);
|
|
nfsdiskless.mygateway.sin_family = AF_INET;
|
|
bcopy(&addr, &nfsdiskless.mygateway.sin_addr, 4);
|
|
} else {
|
|
nfsdiskless.mygateway.sin_len = 0;
|
|
}
|
|
nfsdiskless.myif.ifra_mask.sa_len = sizeof(struct sockaddr);
|
|
nfsdiskless.myif.ifra_mask.sa_family = AF_UNSPEC;
|
|
bcopy(&netmask, &nfsdiskless.myif.ifra_mask.sa_data[2], 4);
|
|
|
|
rpc_id = currticks();
|
|
|
|
/* Lookup NFS/MOUNTD ports for SWAP using PORTMAP */
|
|
if (arptable[ARP_SWAPSERVER].ipaddr) {
|
|
char swapfs_fh[32], swapfile[32];
|
|
swap_nfs_port = rpclookup(ARP_SWAPSERVER, PROG_NFS, 2);
|
|
swap_mount_port = rpclookup(ARP_SWAPSERVER, PROG_MOUNT, 1);
|
|
if ((swap_nfs_port == -1) || (swap_mount_port == -1)) {
|
|
printf("Unable to get SWAP NFS/MOUNT ports\r\n");
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
if (err = nfs_mount(ARP_SWAPSERVER, swap_mount_port,
|
|
nfsdiskless.swap_hostnam, &swapfs_fh)) {
|
|
printf("Unable to mount SWAP filesystem: ");
|
|
nfs_err(err);
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
sprintf(swapfile,"swap.%I",arptable[ARP_CLIENT].ipaddr);
|
|
if (err = nfs_lookup(ARP_SWAPSERVER, swap_nfs_port,
|
|
&swapfs_fh, swapfile, &nfsdiskless.swap_fh)) {
|
|
printf("Unable to open %s: ",swapfile);
|
|
nfs_err(err);
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
nfsdiskless.swap_saddr.sin_len = sizeof(struct sockaddr_in);
|
|
nfsdiskless.swap_saddr.sin_family = AF_INET;
|
|
nfsdiskless.swap_saddr.sin_port = htons(swap_nfs_port);
|
|
nfsdiskless.swap_saddr.sin_addr.s_addr =
|
|
htonl(arptable[ARP_SWAPSERVER].ipaddr);
|
|
nfsdiskless.swap_args.timeo = 10;
|
|
nfsdiskless.swap_args.retrans = 100;
|
|
}
|
|
|
|
/* Lookup NFS/MOUNTD ports for ROOT using PORTMAP */
|
|
root_nfs_port = rpclookup(ARP_ROOTSERVER, PROG_NFS, 2);
|
|
root_mount_port = rpclookup(ARP_ROOTSERVER, PROG_MOUNT, 1);
|
|
if ((root_nfs_port == -1) || (root_mount_port == -1)) {
|
|
printf("Unable to get ROOT NFS/MOUNT ports\r\n");
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
if (err = nfs_mount(ARP_ROOTSERVER, root_mount_port,
|
|
nfsdiskless.root_hostnam, &nfsdiskless.root_fh)) {
|
|
printf("Unable to mount ROOT filesystem: ");
|
|
nfs_err(err);
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
nfsdiskless.root_saddr.sin_len = sizeof(struct sockaddr_in);
|
|
nfsdiskless.root_saddr.sin_family = AF_INET;
|
|
nfsdiskless.root_saddr.sin_port = htons(root_nfs_port);
|
|
nfsdiskless.root_saddr.sin_addr.s_addr =
|
|
htonl(arptable[ARP_ROOTSERVER].ipaddr);
|
|
nfsdiskless.root_args.timeo = 10;
|
|
nfsdiskless.root_args.retrans = 100;
|
|
nfsdiskless.root_time = 0;
|
|
|
|
if (err = nfs_lookup(ARP_ROOTSERVER, root_nfs_port,
|
|
&nfsdiskless.root_fh, *kernel == '/' ? kernel+1 : kernel,
|
|
&kernel_handle)) {
|
|
printf("Unable to open %s: ",kernel);
|
|
nfs_err(err);
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
|
|
/* Load the kernel using NFS */
|
|
printf("Loading %s...\r\n",kernel);
|
|
if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, &kernel_handle, 0,
|
|
sizeof(struct exec), &head)) < 0) {
|
|
printf("Unable to read %s: ",kernel);
|
|
nfs_err(err);
|
|
longjmp(jmp_bootmenu,1);
|
|
}
|
|
if (N_BADMAG(head)) {
|
|
printf("Bad executable format!\r\n");
|
|
longjmp(jmp_bootmenu, 1);
|
|
}
|
|
loadpoint = (char *)0x100000;
|
|
offset = N_TXTOFF(head);
|
|
printf("text=0x%X, ",head.a_text);
|
|
while (head.a_text > 0) {
|
|
read_size = head.a_text > NFS_READ_SIZE ?
|
|
NFS_READ_SIZE : head.a_text;
|
|
if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port,
|
|
&kernel_handle, offset, read_size, loadpoint)) !=
|
|
read_size) {
|
|
if (err < 0) {
|
|
printf("Unable to read text: ");
|
|
nfs_err(err);
|
|
}
|
|
longjmp(jmp_bootmenu, 1);
|
|
}
|
|
loadpoint += err;
|
|
head.a_text -= err;
|
|
offset += err;
|
|
}
|
|
while (((int)loadpoint) & CLOFSET)
|
|
*(loadpoint++) = 0;
|
|
printf("data=0x%X, ",head.a_data);
|
|
while (head.a_data > 0) {
|
|
read_size = head.a_data > NFS_READ_SIZE ?
|
|
NFS_READ_SIZE : head.a_data;
|
|
if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port,
|
|
&kernel_handle, offset, read_size, loadpoint)) !=
|
|
read_size) {
|
|
if (err < 0) {
|
|
printf("Unable to read data: ");
|
|
nfs_err(err);
|
|
}
|
|
longjmp(jmp_bootmenu, 1);
|
|
}
|
|
loadpoint += err;
|
|
head.a_data -= err;
|
|
offset += err;
|
|
}
|
|
printf("bss=0x%X, ",head.a_bss);
|
|
while(head.a_bss--) *(loadpoint++) = 0;
|
|
|
|
printf("entry=0x%X.\n\r",head.a_entry);
|
|
|
|
/* Jump to kernel */
|
|
bootinfo.version = 1;
|
|
bootinfo.kernelname = kernel;
|
|
bootinfo.nfs_diskless = &nfsdiskless;
|
|
kernelentry = (void *)(head.a_entry & 0x00FFFFFF);
|
|
(*kernelentry)(0,NODEV,0,0,0,&bootinfo,0,0,0);
|
|
printf("*** %s execute failure ***\n",kernel);
|
|
}
|
|
|
|
/**************************************************************************
|
|
POLLKBD - Check for Interrupt from keyboard
|
|
**************************************************************************/
|
|
pollkbd()
|
|
{
|
|
if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1);
|
|
}
|
|
|
|
/**************************************************************************
|
|
DEFAULT_NETMASK - Set a default netmask for IP address
|
|
**************************************************************************/
|
|
default_netmask()
|
|
{
|
|
int net = arptable[ARP_CLIENT].ipaddr >> 24;
|
|
if (net <= 127)
|
|
netmask = htonl(0xff000000);
|
|
else if (net < 192)
|
|
netmask = htonl(0xffff0000);
|
|
else
|
|
netmask = htonl(0xffffff00);
|
|
}
|
|
/**************************************************************************
|
|
UDP_TRANSMIT - Send a UDP datagram
|
|
**************************************************************************/
|
|
udp_transmit(destip, srcsock, destsock, len, buf)
|
|
unsigned long destip;
|
|
unsigned short srcsock, destsock;
|
|
int len;
|
|
char *buf;
|
|
{
|
|
struct iphdr *ip;
|
|
struct udphdr *udp;
|
|
struct arprequest arpreq;
|
|
int arpentry, i;
|
|
unsigned long time;
|
|
int retry = MAX_ARP_RETRIES;
|
|
|
|
ip = (struct iphdr *)buf;
|
|
udp = (struct udphdr *)(buf + sizeof(struct iphdr));
|
|
ip->verhdrlen = 0x45;
|
|
ip->service = 0;
|
|
ip->len = htons(len);
|
|
ip->ident = 0;
|
|
ip->frags = 0;
|
|
ip->ttl = 60;
|
|
ip->protocol = IP_UDP;
|
|
ip->chksum = 0;
|
|
convert_ipaddr(ip->src, &arptable[ARP_CLIENT].ipaddr);
|
|
convert_ipaddr(ip->dest, &destip);
|
|
ip->chksum = ipchksum(buf, sizeof(struct iphdr));
|
|
udp->src = htons(srcsock);
|
|
udp->dest = htons(destsock);
|
|
udp->len = htons(len - sizeof(struct iphdr));
|
|
udp->chksum = 0;
|
|
if (destip == IP_BROADCAST) {
|
|
eth_transmit(broadcast, IP, len, buf);
|
|
} else {
|
|
long h_netmask = ntohl(netmask);
|
|
/* Check to see if we need gateway */
|
|
if (((destip & h_netmask) !=
|
|
(arptable[ARP_CLIENT].ipaddr & h_netmask)) &&
|
|
arptable[ARP_GATEWAY].ipaddr)
|
|
destip = arptable[ARP_GATEWAY].ipaddr;
|
|
for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
|
|
if (arptable[arpentry].ipaddr == destip) break;
|
|
if (arpentry == MAX_ARP) {
|
|
printf("%I is not in my arp table!\n");
|
|
return(0);
|
|
}
|
|
for (i = 0; i<ETHER_ADDR_SIZE; i++)
|
|
if (arptable[arpentry].node[i]) break;
|
|
if (i == ETHER_ADDR_SIZE) { /* Need to do arp request */
|
|
arpreq.hwtype = htons(1);
|
|
arpreq.protocol = htons(IP);
|
|
arpreq.hwlen = ETHER_ADDR_SIZE;
|
|
arpreq.protolen = 4;
|
|
arpreq.opcode = htons(ARP_REQUEST);
|
|
bcopy(arptable[ARP_CLIENT].node, arpreq.shwaddr,
|
|
ETHER_ADDR_SIZE);
|
|
convert_ipaddr(arpreq.sipaddr,
|
|
&arptable[ARP_CLIENT].ipaddr);
|
|
bzero(arpreq.thwaddr, ETHER_ADDR_SIZE);
|
|
convert_ipaddr(arpreq.tipaddr, &destip);
|
|
while (retry--) {
|
|
eth_transmit(broadcast, ARP, sizeof(arpreq),
|
|
&arpreq);
|
|
if (await_reply(AWAIT_ARP, arpentry,
|
|
arpreq.tipaddr)) goto xmit;
|
|
}
|
|
return(0);
|
|
}
|
|
xmit: eth_transmit(arptable[arpentry].node, IP, len, buf);
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
/**************************************************************************
|
|
TFTP - Try to load configuation file
|
|
**************************************************************************/
|
|
tftp(name)
|
|
char *name;
|
|
{
|
|
struct tftp_t *tr;
|
|
int retry = MAX_TFTP_RETRIES;
|
|
static unsigned short isocket = 2000;
|
|
unsigned short osocket = TFTP;
|
|
unsigned short len, block=1;
|
|
struct tftp_t tp;
|
|
int code;
|
|
isocket++;
|
|
tp.opcode = htons(TFTP_RRQ);
|
|
len = (sprintf((char *)tp.u.rrq,"%s%c%s",name,0,"octet")
|
|
- ((char *)&tp)) + 1;
|
|
while(retry--) {
|
|
if (!udp_transmit(arptable[ARP_SERVER].ipaddr, isocket, osocket,
|
|
len, &tp)) return(0);
|
|
if (await_reply(AWAIT_TFTP, isocket, NULL)) {
|
|
tr = (struct tftp_t *)&packet[ETHER_HDR_SIZE];
|
|
if (tr->opcode == ntohs(TFTP_ERROR)) {
|
|
printf("TFTP error %d (%s)\r\n",
|
|
ntohs(tr->u.err.errcode),
|
|
tr->u.err.errmsg);
|
|
return(0);
|
|
} /* ACK PACKET */
|
|
if (tr->opcode != ntohs(TFTP_DATA)) return(0);
|
|
tp.opcode = htons(TFTP_ACK);
|
|
tp.u.ack.block = tr->u.data.block;
|
|
udp_transmit(arptable[ARP_SERVER].ipaddr, isocket,
|
|
osocket, TFTP_MIN_PACKET_SIZE, &tp);
|
|
len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
|
|
if (len >= 512) {
|
|
printf("Config file too large.\r\n");
|
|
config_buffer[0] = 0;
|
|
return(0);
|
|
} else {
|
|
bcopy(tr->u.data.download, config_buffer, len);
|
|
config_buffer[len] = 0;
|
|
}
|
|
return(1);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**************************************************************************
|
|
BOOTP - Get my IP address and load information
|
|
**************************************************************************/
|
|
bootp()
|
|
{
|
|
int retry = MAX_BOOTP_RETRIES;
|
|
struct bootp_t bp;
|
|
unsigned long starttime;
|
|
bzero(&bp, sizeof(struct bootp_t));
|
|
bp.bp_op = BOOTP_REQUEST;
|
|
bp.bp_htype = 1;
|
|
bp.bp_hlen = ETHER_ADDR_SIZE;
|
|
bp.bp_xid = starttime = currticks();
|
|
bcopy(arptable[ARP_CLIENT].node, bp.bp_hwaddr, ETHER_ADDR_SIZE);
|
|
while(retry--) {
|
|
udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER,
|
|
sizeof(struct bootp_t), &bp);
|
|
if (await_reply(AWAIT_BOOTP, 0, NULL))
|
|
return(1);
|
|
bp.bp_secs = htons((currticks()-starttime)/20);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
AWAIT_REPLY - Wait until we get a response for our request
|
|
**************************************************************************/
|
|
await_reply(type, ival, ptr)
|
|
int type, ival;
|
|
char *ptr;
|
|
{
|
|
unsigned long time;
|
|
struct iphdr *ip;
|
|
struct udphdr *udp;
|
|
struct arprequest *arpreply;
|
|
struct bootp_t *bootpreply;
|
|
struct rpc_t *rpc;
|
|
|
|
int protohdrlen = ETHER_HDR_SIZE + sizeof(struct iphdr) +
|
|
sizeof(struct udphdr);
|
|
time = currticks() + TIMEOUT;
|
|
while(time > currticks()) {
|
|
pollkbd();
|
|
if (eth_poll()) { /* We have something! */
|
|
/* Check for ARP - No IP hdr */
|
|
if ((type == AWAIT_ARP) &&
|
|
(packetlen >= ETHER_HDR_SIZE +
|
|
sizeof(struct arprequest)) &&
|
|
(((packet[12] << 8) | packet[13]) == ARP)) {
|
|
arpreply = (struct arprequest *)
|
|
&packet[ETHER_HDR_SIZE];
|
|
if ((arpreply->opcode == ntohs(ARP_REPLY)) &&
|
|
bcompare(arpreply->sipaddr, ptr, 4)) {
|
|
bcopy(arpreply->shwaddr,
|
|
arptable[ival].node,
|
|
ETHER_ADDR_SIZE);
|
|
return(1);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
/* Anything else has IP header */
|
|
if ((packetlen < protohdrlen) ||
|
|
(((packet[12] << 8) | packet[13]) != IP)) continue;
|
|
ip = (struct iphdr *)&packet[ETHER_HDR_SIZE];
|
|
if ((ip->verhdrlen != 0x45) ||
|
|
ipchksum(ip, sizeof(struct iphdr)) ||
|
|
(ip->protocol != IP_UDP)) continue;
|
|
udp = (struct udphdr *)&packet[ETHER_HDR_SIZE +
|
|
sizeof(struct iphdr)];
|
|
|
|
/* BOOTP ? */
|
|
bootpreply = (struct bootp_t *)&packet[ETHER_HDR_SIZE];
|
|
if ((type == AWAIT_BOOTP) &&
|
|
(packetlen >= (ETHER_HDR_SIZE +
|
|
sizeof(struct bootp_t))) &&
|
|
(ntohs(udp->dest) == BOOTP_CLIENT) &&
|
|
(bootpreply->bp_op == BOOTP_REPLY)) {
|
|
convert_ipaddr(&arptable[ARP_CLIENT].ipaddr,
|
|
bootpreply->bp_yiaddr);
|
|
default_netmask();
|
|
convert_ipaddr(&arptable[ARP_SERVER].ipaddr,
|
|
bootpreply->bp_siaddr);
|
|
bzero(arptable[ARP_SERVER].node,
|
|
ETHER_ADDR_SIZE); /* Kill arp */
|
|
convert_ipaddr(&arptable[ARP_GATEWAY].ipaddr,
|
|
bootpreply->bp_giaddr);
|
|
bzero(arptable[ARP_GATEWAY].node,
|
|
ETHER_ADDR_SIZE); /* Kill arp */
|
|
if (bootpreply->bp_file[0]) {
|
|
bcopy(bootpreply->bp_file,
|
|
kernel_buf, 128);
|
|
kernel = kernel_buf;
|
|
}
|
|
decode_rfc1048(bootpreply->bp_vend);
|
|
return(1);
|
|
}
|
|
|
|
/* TFTP ? */
|
|
if ((type == AWAIT_TFTP) &&
|
|
(ntohs(udp->dest) == ival)) return(1);
|
|
|
|
/* RPC */
|
|
rpc = (struct rpc_t *)&packet[ETHER_HDR_SIZE];
|
|
if ((type == AWAIT_RPC) &&
|
|
(ntohs(udp->dest) == RPC_SOCKET) &&
|
|
(ntohl(rpc->u.reply.id) == ival) &&
|
|
(ntohl(rpc->u.reply.type) == MSG_REPLY)) {
|
|
rpc_id++;
|
|
return(1);
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**************************************************************************
|
|
DECODE_RFC1048 - Decodes RFC1048 header
|
|
**************************************************************************/
|
|
decode_rfc1048(p)
|
|
unsigned char *p;
|
|
{
|
|
static char rfc1048_cookie[4] = RFC1048_COOKIE;
|
|
unsigned char *end = p + BOOTP_VENDOR_LEN,*q;
|
|
if (bcompare(p, rfc1048_cookie, 4)) { /* RFC 1048 header */
|
|
p += 4;
|
|
while(p < end) {
|
|
switch (*p) {
|
|
case RFC1048_PAD:
|
|
p++;
|
|
continue;
|
|
case RFC1048_END:
|
|
p = end;
|
|
continue;
|
|
case RFC1048_NETMASK:
|
|
bcopy(p+2,&netmask,4);
|
|
break;
|
|
case RFC1048_HOSTNAME:
|
|
bcopy(p+2, &nfsdiskless.my_hostnam, TAG_LEN(p));
|
|
hostnamelen = (TAG_LEN(p) + 3) & ~3;
|
|
break;
|
|
default:
|
|
printf("Unknown RFC1048-tag ");
|
|
for(q=p;q<p+2+TAG_LEN(p);q++)
|
|
printf("%x ",*q);
|
|
printf("\n\r");
|
|
}
|
|
p += TAG_LEN(p) + 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
IPCHKSUM - Checksum IP Header
|
|
**************************************************************************/
|
|
ipchksum(ip, len)
|
|
unsigned short *ip;
|
|
int len;
|
|
{
|
|
unsigned long sum = 0;
|
|
len >>= 1;
|
|
while (len--) {
|
|
sum += *(ip++);
|
|
if (sum > 0xFFFF)
|
|
sum -= 0xFFFF;
|
|
}
|
|
return((~sum) & 0x0000FFFF);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
CONVERT_IPADDR - Convert IP address from net to machine order
|
|
**************************************************************************/
|
|
convert_ipaddr(d, s)
|
|
char *d,*s;
|
|
{
|
|
*(d+3) = *s;
|
|
*(d+2) = *(s+1);
|
|
*(d+1) = *(s+2);
|
|
*d = *(s+3);
|
|
}
|