/**************************************************************************
NETBOOT - BOOTP/TFTP Bootstrap Program
**************************************************************************/
#define ESC 0x1b /* ESC Key */
char broadcast
[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
struct nfs_diskless nfsdiskless
;
/**************************************************************************
**************************************************************************/
extern char edata
[], end
[];
for (p
=edata
; p
<end
; p
++) *p
= 0; /* Zero BSS */
printf("\n\rBoot from Network (Y/N) ? ");
if ((c
>= 'a') && (c
<= 'z')) c
&= 0x5F;
printf(" - bad response\n\r");
printf("\r\nBOOTP/TFTP bootstrap loader ESC for menu\n\r");
printf("\r\nSearching for adapter...");
printf("No adapter found.\r\n");
bootfile
= DEFAULT_BOOTFILE
;
if (setjmp(jmp_bootmenu
))
/**************************************************************************
**************************************************************************/
if (!arptable
[ARP_CLIENT
].ipaddr
|| !arptable
[ARP_SERVER
].ipaddr
) {
printf("\r\nSearching for server...\r\n");
printf("No Server found.\r\n");
printf("station IP %I, server IP %I\r\n",
arptable
[ARP_CLIENT
].ipaddr
,
arptable
[ARP_SERVER
].ipaddr
);
p
= putdec(p
, arptable
[ARP_CLIENT
].ipaddr
>>24);
p
= putdec(p
, arptable
[ARP_CLIENT
].ipaddr
>>16);
p
= putdec(p
, arptable
[ARP_CLIENT
].ipaddr
>>8);
p
= putdec(p
, arptable
[ARP_CLIENT
].ipaddr
);
printf("Loading %s...\r\n",cfg
);
if (!tftp(cfg
, TFTP_CODE_CFG
)) {
printf("Unable to load config file.\r\n");
printf("Loading %s...\r\n",bootfile
);
if (!tftp(bootfile
, TFTP_CODE_BOOT
)) {
printf("Unable to load boot file.\r\n");
if (!(head
.a_entry
& 0x00F00000)) { /* < 1MB kernel? */
printf("<1MB kernel. Relocating\r\n");
bcopy(0x100000, 0, 0x400); /* Relocate */
bcopy(0x100500, 0x500, ((int)loadpoint
) - 0x100500);
kernelentry
= (void *)(head
.a_entry
& 0x00FFFFFF);
(*kernelentry
)(0,0,0,0,&nfsdiskless
,0,0,0);
/**************************************************************************
POLLKBD - Check for Interrupt from keyboard
**************************************************************************/
if (iskey() && (getchar() == ESC
)) longjmp(jmp_bootmenu
,1);
/**************************************************************************
UDP_TRANSMIT - Send a UDP datagram
**************************************************************************/
udp_transmit(destip
, srcsock
, destsock
, len
, buf
)
unsigned short srcsock
, destsock
;
struct arprequest arpreq
, *arpreply
;
int retry
= MAX_ARP_RETRIES
;
ip
= (struct iphdr
*)buf
;
udp
= (struct udphdr
*)(buf
+ sizeof(struct iphdr
));
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
));
if (destip
== IP_BROADCAST
) {
eth_transmit(broadcast
, IP
, len
, buf
);
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");
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
.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
);
eth_transmit(broadcast
, ARP
, sizeof(arpreq
), &arpreq
);
time
= currticks() + TIMEOUT
;
while (time
> currticks()) {
if (eth_poll() && (packetlen
>= ETHER_HDR_SIZE
+ sizeof(arpreq
)) &&
(((packet
[12] << 8) | packet
[13]) == ARP
)) {
arpreply
= (struct arprequest
*)&packet
[ETHER_HDR_SIZE
];
if ((arpreply
->opcode
== ntohs(ARP_REPLY
)) &&
bcompare(arpreply
->sipaddr
,arpreq
.tipaddr
, 4)) {
bcopy(arpreply
->shwaddr
, arptable
[arpentry
].node
,ETHER_ADDR_SIZE
);
xmit
: eth_transmit(arptable
[arpentry
].node
, IP
, len
, buf
);
/**************************************************************************
TFTP - Try to load something
**************************************************************************/
int retry
= MAX_TFTP_RETRIES
;
static unsigned short isocket
= 2000;
unsigned short osocket
= TFTP
;
unsigned short len
, block
=1;
tp
.opcode
= htons(TFTP_RRQ
);
while (*name
) *(p
++) = *(name
++);
if (!udp_transmit(arptable
[ARP_SERVER
].ipaddr
, isocket
, osocket
,
next
: time
= currticks() + TIMEOUT
;
while(time
> currticks()) {
code
= tftp_data(&tp
, &block
, isocket
, &osocket
,
if (code
== TFTP_CODE_EOF
) return(1);
if (code
== TFTP_CODE_ERROR
) return(0);
len
= TFTP_MIN_PACKET_SIZE
;
retry
= MAX_TFTP_RETRIES
;
/**************************************************************************
TFTP_DATA - Check and handle incoming TFTP packets
**************************************************************************/
tftp_data(req
, block
, isocket
, osocket
, type
)
unsigned short *block
, isocket
, *osocket
;
if (!chkpacket(TFTP_MIN_PACKET_SIZE
, isocket
)) return(0);
tp
= (struct tftp_t
*)&packet
[ETHER_HDR_SIZE
];
if (tp
->opcode
== ntohs(TFTP_ERROR
)) {
printf("TFTP error %d (%s)\r\n", ntohs(tp
->u
.err
.errcode
),
longjmp(jmp_bootmenu
, 1);
if (tp
->opcode
!= htons(TFTP_DATA
)) return(0);
len
= ntohs(tp
->udp
.len
) - sizeof(struct udphdr
) -
(2*sizeof(unsigned short));
req
->opcode
= htons(TFTP_ACK
); /* Send ack */
req
->u
.ack
.block
= tp
->u
.data
.block
;
udp_transmit(arptable
[ARP_SERVER
].ipaddr
, isocket
, *osocket
,
TFTP_MIN_PACKET_SIZE
, req
);
if (*block
!= ntohs(tp
->u
.data
.block
)) return(TFTP_CODE_MORE
);
*osocket
= htons(tp
->udp
.src
);
if ((type
== TFTP_CODE_CFG
) &&
(len
== sizeof(struct nfs_diskless
))) {
bcopy(tp
->u
.data
.download
, &nfsdiskless
, sizeof(struct nfs_diskless
));
bcopy(tp
->u
.data
.download
, &head
, sizeof(struct exec
));
if ((type
== TFTP_CODE_BOOT
) &&
((len
< sizeof(struct exec
)) || (N_BADMAG(head
)))) {
printf("Not an executable.\r\n");
if (((head
.a_entry
& 0x00FFFFFF) == 0) &&
(head
.a_text
+ head
.a_data
>= RELOC
)) {
printf("Executable too large.\r\n");
/* We load above 1 mb so we don't clobber DOS */
loadpoint
= (char *)0x100000;
printf("text=0x%X", head
.a_text
);
printf(", data=0x%X",head
.a_data
);
while (((int)loadpoint
) & CLOFSET
)
printf(", bss=0x%X\r\n",head
.a_bss
);
return((head
.a_text
|| head
.a_data
) ? TFTP_CODE_MORE
: TFTP_CODE_EOF
);
/**************************************************************************
BOOTP - Get my IP address and load information
**************************************************************************/
int retry
= MAX_BOOTP_RETRIES
;
unsigned long time
, starttime
;
bzero(&bp
, sizeof(struct bootp_t
));
bp
.bp_op
= BOOTP_REQUEST
;
bp
.bp_hlen
= ETHER_ADDR_SIZE
;
bp
.bp_xid
= starttime
= currticks();
bcopy(arptable
[ARP_CLIENT
].node
, bp
.bp_hwaddr
, ETHER_ADDR_SIZE
);
udp_transmit(IP_BROADCAST
, 0, BOOTP_SERVER
,
sizeof(struct bootp_t
), &bp
);
time
= currticks() + TIMEOUT
;
while(time
> currticks()) {
if (eth_poll()) { /* We have something! */
reply
= (struct bootp_t
*)&packet
[ETHER_HDR_SIZE
];
if (((!chkpacket(sizeof(struct bootp_t
),
BOOTP_CLIENT
))) || (reply
->bp_op
!= BOOTP_REPLY
))
convert_ipaddr(&arptable
[ARP_CLIENT
].ipaddr
,
convert_ipaddr(&arptable
[ARP_SERVER
].ipaddr
,
bzero(arptable
[ARP_SERVER
].node
, ETHER_ADDR_SIZE
); /* Kill arp */
bcopy(reply
->bp_file
, bootname
, 128);
bp
.bp_secs
= htons((currticks()-starttime
)/20);
/**************************************************************************
IPCHKSUM - Checksum IP Header
**************************************************************************/
return((~sum
) & 0x0000FFFF);
/**************************************************************************
CHKPACKET - Quick check to see if incoming packet is good
**************************************************************************/
if (packetlen
< (ETHER_HDR_SIZE
+ size
)) return(0);
if (((packet
[12] << 8) | packet
[13]) != IP
) return(0);
ip
= (struct iphdr
*)&packet
[ETHER_HDR_SIZE
];
if (ip
->verhdrlen
!= 0x45) return(0);
if (ipchksum(ip
, sizeof(struct iphdr
))) return(0);
if (ip
->protocol
!= IP_UDP
) return(0);
udp
= (struct udphdr
*)&packet
[ETHER_HDR_SIZE
+ sizeof(struct iphdr
)];
if (ntohs(udp
->dest
) != type
) return(0);
/**************************************************************************
CONVERT_IPADDR - Convert IP address from net to machine order
**************************************************************************/