/**************************************************************************
ETHERBOOT -  BOOTP/TFTP Bootstrap Program

Author: Martin Renters
  Date: Dec/93

**************************************************************************/

#include "osdep.h"

/* These could be customised for different languages perhaps */
#define	ASK_PROMPT	"Boot from (N)etwork or from (L)ocal? "
#define	ANS_NETWORK	'N'
#define	ANS_LOCAL	'L'
#ifndef	ANS_DEFAULT		/* in case left out in Makefile */
#define	ANS_DEFAULT	ANS_NETWORK
#endif

#define	TAGGED_IMAGE		/* eventually optional */
#if	!defined(TAGGED_IMAGE) && !defined(AOUT_IMAGE) && !defined(ELF_IMAGE)
#define	TAGGED_IMAGE		/* choose at least one */
#endif

#define ESC		0x1B

#ifndef	DEFAULT_BOOTFILE
#define DEFAULT_BOOTFILE	"/tftpboot/kernel"
#endif

/* Clean up console settings... mainly CONSOLE_CRT and CONSOLE_SERIAL are used
 * in the sources (except start.S and serial.S which cannot include
 * etherboot.h).  At least one of the CONSOLE_xxx has to be set, and
 * CONSOLE_DUAL sets both CONSOLE_CRT and CONSOLE_SERIAL.  If none is set,
 * CONSOLE_CRT is assumed.  */
#ifdef	CONSOLE_DUAL
#undef CONSOLE_CRT
#define CONSOLE_CRT
#undef CONSOLE_SERIAL
#define CONSOLE_SERIAL
#endif
#if	defined(CONSOLE_CRT) && defined(CONSOLE_SERIAL)
#undef CONSOLE_DUAL
#define CONSOLE_DUAL
#endif
#if	!defined(CONSOLE_CRT) && !defined(CONSOLE_SERIAL)
#define CONSOLE_CRT
#endif

#ifndef	DOWNLOAD_PROTO_NFS
#undef DOWNLOAD_PROTO_TFTP
#define DOWNLOAD_PROTO_TFTP	/* default booting protocol */
#endif

#ifdef	DOWNLOAD_PROTO_TFTP
#define download(fname,loader) tftp((fname),(loader))
#endif
#ifdef	DOWNLOAD_PROTO_NFS
#define download(fname,loader) nfs((fname),(loader))
#endif

#ifndef	MAX_TFTP_RETRIES
#define MAX_TFTP_RETRIES	20
#endif

#ifndef	MAX_BOOTP_RETRIES
#define MAX_BOOTP_RETRIES	20
#endif

#ifndef	MAX_BOOTP_EXTLEN
#if	(RELOC < 0x94000)
/* Force internal buffer (if external buffer would overlap with our code...) */
#undef INTERNAL_BOOTP_DATA
#define INTERNAL_BOOTP_DATA
#endif
/* sizeof(struct bootp_t) == 0x240 */
#if	defined(INTERNAL_BOOTP_DATA) || (RELOC >= 0x94240)
#define MAX_BOOTP_EXTLEN	1024
#else
#define MAX_BOOTP_EXTLEN	(1024-sizeof(struct bootp_t))
#endif
#endif

#ifndef	MAX_ARP_RETRIES
#define MAX_ARP_RETRIES		20
#endif

#ifndef	MAX_RPC_RETRIES
#define MAX_RPC_RETRIES		20
#endif

#define	TICKS_PER_SEC		18

/* Inter-packet retry in ticks */
#define TIMEOUT			(10*TICKS_PER_SEC)

/* These settings have sense only if compiled with -DCONGESTED */
/* total retransmission timeout in ticks */
#define TFTP_TIMEOUT		(30*TICKS_PER_SEC)
/* packet retransmission timeout in ticks */
#define TFTP_REXMT		(3*TICKS_PER_SEC)

#ifndef	NULL
#define NULL	((void *)0)
#endif

#define TRUE		1
#define FALSE		0

#define ETHER_ADDR_SIZE		6	/* Size of Ethernet address */
#define ETHER_HDR_SIZE		14	/* Size of ethernet header */
#define ETH_MIN_PACKET		64
#define ETH_MAX_PACKET		1518

#define VENDOR_NONE	0
#define VENDOR_WD	1
#define VENDOR_NOVELL	2
#define VENDOR_3COM	3
#define VENDOR_3C509	4
#define VENDOR_CS89x0	5

#define FLAG_PIO	0x01
#define FLAG_16BIT	0x02
#define FLAG_790	0x04

#define ARP_CLIENT	0
#define ARP_SERVER	1
#define ARP_GATEWAY	2
#define ARP_ROOTSERVER	3
#define ARP_SWAPSERVER	4
#define MAX_ARP		ARP_SWAPSERVER+1

#define	RARP_REQUEST	3
#define	RARP_REPLY	4

#define IP		0x0800
#define ARP		0x0806
#define	RARP		0x8035

#define BOOTP_SERVER	67
#define BOOTP_CLIENT	68
#define TFTP_PORT	69
#define SUNRPC_PORT	111

#define IP_UDP		17
/* Same after going through htonl */
#define IP_BROADCAST	0xFFFFFFFF

#define ARP_REQUEST	1
#define ARP_REPLY	2

#define BOOTP_REQUEST	1
#define BOOTP_REPLY	2

#define TAG_LEN(p)		(*((p)+1))
#define RFC1533_COOKIE		99, 130, 83, 99
#define RFC1533_PAD		0
#define RFC1533_NETMASK		1
#define RFC1533_TIMEOFFSET	2
#define RFC1533_GATEWAY		3
#define RFC1533_TIMESERVER	4
#define RFC1533_IEN116NS	5
#define RFC1533_DNS		6
#define RFC1533_LOGSERVER	7
#define RFC1533_COOKIESERVER	8
#define RFC1533_LPRSERVER	9
#define RFC1533_IMPRESSSERVER	10
#define RFC1533_RESOURCESERVER	11
#define RFC1533_HOSTNAME	12
#define RFC1533_BOOTFILESIZE	13
#define RFC1533_MERITDUMPFILE	14
#define RFC1533_DOMAINNAME	15
#define RFC1533_SWAPSERVER	16
#define RFC1533_ROOTPATH	17
#define RFC1533_EXTENSIONPATH	18
#define RFC1533_IPFORWARDING	19
#define RFC1533_IPSOURCEROUTING	20
#define RFC1533_IPPOLICYFILTER	21
#define RFC1533_IPMAXREASSEMBLY	22
#define RFC1533_IPTTL		23
#define RFC1533_IPMTU		24
#define RFC1533_IPMTUPLATEAU	25
#define RFC1533_INTMTU		26
#define RFC1533_INTLOCALSUBNETS	27
#define RFC1533_INTBROADCAST	28
#define RFC1533_INTICMPDISCOVER	29
#define RFC1533_INTICMPRESPOND	30
#define RFC1533_INTROUTEDISCOVER 31
#define RFC1533_INTROUTESOLICIT	32
#define RFC1533_INTSTATICROUTES	33
#define RFC1533_LLTRAILERENCAP	34
#define RFC1533_LLARPCACHETMO	35
#define RFC1533_LLETHERNETENCAP	36
#define RFC1533_TCPTTL		37
#define RFC1533_TCPKEEPALIVETMO	38
#define RFC1533_TCPKEEPALIVEGB	39
#define RFC1533_NISDOMAIN	40
#define RFC1533_NISSERVER	41
#define RFC1533_NTPSERVER	42
#define RFC1533_VENDOR		43
#define RFC1533_NBNS		44
#define RFC1533_NBDD		45
#define RFC1533_NBNT		46
#define RFC1533_NBSCOPE		47
#define RFC1533_XFS		48
#define RFC1533_XDM		49
#ifndef	NO_DHCP_SUPPORT
#define RFC2132_REQ_ADDR	50
#define RFC2132_MSG_TYPE	53
#define RFC2132_SRV_ID		54
#define RFC2132_PARAM_LIST	55
#define RFC2132_MAX_SIZE	57

#define DHCPDISCOVER		1
#define DHCPOFFER		2
#define DHCPREQUEST		3
#define DHCPACK			5
#endif				/* NO_DHCP_SUPPORT */

#define RFC1533_VENDOR_MAJOR	0
#define RFC1533_VENDOR_MINOR	0

#define RFC1533_VENDOR_MAGIC	128
#define RFC1533_VENDOR_ADDPARM	129
#ifdef	IMAGE_FREEBSD
#define RFC1533_VENDOR_HOWTO    132
#endif
#define RFC1533_VENDOR_MNUOPTS	160
#define RFC1533_VENDOR_SELECTION 176
#define RFC1533_VENDOR_MOTD	184
#define RFC1533_VENDOR_NUMOFMOTD 8
#define RFC1533_VENDOR_IMG	192
#define RFC1533_VENDOR_NUMOFIMG	16

#define RFC1533_END		255
#define BOOTP_VENDOR_LEN	64
#ifndef	NO_DHCP_SUPPORT
#define DHCP_OPT_LEN		312
#endif				/* NO_DHCP_SUPPORT */

#define	TFTP_DEFAULTSIZE_PACKET	512
#define	TFTP_MAX_PACKET		1432	/* 512 */

#define TFTP_RRQ	1
#define TFTP_WRQ	2
#define TFTP_DATA	3
#define TFTP_ACK	4
#define TFTP_ERROR	5
#define TFTP_OACK	6

#define TFTP_CODE_EOF	1
#define TFTP_CODE_MORE	2
#define TFTP_CODE_ERROR	3
#define TFTP_CODE_BOOT	4
#define TFTP_CODE_CFG	5

#define AWAIT_ARP	0
#define AWAIT_BOOTP	1
#define AWAIT_TFTP	2
#define AWAIT_RARP	3
#define AWAIT_RPC	4
#define AWAIT_QDRAIN	5	/* drain queue, process ARP requests */

typedef struct {
	unsigned long s_addr;
} in_addr;

struct arptable_t {
	in_addr ipaddr;
	unsigned char node[6];
};

/*
 * A pity sipaddr and tipaddr are not longword aligned or we could use
 * in_addr. No, I don't want to use #pragma packed.
 */
struct arprequest {
	unsigned short hwtype;
	unsigned short protocol;
	char hwlen;
	char protolen;
	unsigned short opcode;
	char shwaddr[6];
	char sipaddr[4];
	char thwaddr[6];
	char tipaddr[4];
};

struct iphdr {
	char verhdrlen;
	char service;
	unsigned short len;
	unsigned short ident;
	unsigned short frags;
	char ttl;
	char protocol;
	unsigned short chksum;
	in_addr src;
	in_addr dest;
};

struct udphdr {
	unsigned short src;
	unsigned short dest;
	unsigned short len;
	unsigned short chksum;
};

struct bootp_t {
	struct iphdr ip;
	struct udphdr udp;
	char bp_op;
	char bp_htype;
	char bp_hlen;
	char bp_hops;
	unsigned long bp_xid;
	unsigned short bp_secs;
	unsigned short unused;
	in_addr bp_ciaddr;
	in_addr bp_yiaddr;
	in_addr bp_siaddr;
	in_addr bp_giaddr;
	char bp_hwaddr[16];
	char bp_sname[64];
	char bp_file[128];
#ifdef	NO_DHCP_SUPPORT
	char bp_vend[BOOTP_VENDOR_LEN];
#else
	char bp_vend[DHCP_OPT_LEN];
#endif				/* NO_DHCP_SUPPORT */
};

struct bootpd_t {
	struct bootp_t bootp_reply;
	unsigned char bootp_extension[MAX_BOOTP_EXTLEN];
};

struct tftp_t {
	struct iphdr ip;
	struct udphdr udp;
	unsigned short opcode;
	union {
		char rrq[TFTP_DEFAULTSIZE_PACKET];
		struct {
			unsigned short block;
			char download[TFTP_MAX_PACKET];
		} data;
		struct {
			unsigned short block;
		} ack;
		struct {
			unsigned short errcode;
			char errmsg[TFTP_DEFAULTSIZE_PACKET];
		} err;
		struct {
			char data[TFTP_DEFAULTSIZE_PACKET + 2];
		} oack;
	} u;
};

#define TFTP_MIN_PACKET	(sizeof(struct iphdr) + sizeof(struct udphdr) + 4)

struct rpc_t {
	struct iphdr ip;
	struct udphdr udp;
	union {
		char data[300];	/* longest RPC call must fit!!!! */
		struct {
			long id;
			long type;
			long rpcvers;
			long prog;
			long vers;
			long proc;
			long data[1];
		} call;
		struct {
			long id;
			long type;
			long rstatus;
			long verifier;
			long v2;
			long astatus;
			long data[1];
		} reply;
	} u;
};

#define PROG_PORTMAP	100000
#define PROG_NFS	100003
#define PROG_MOUNT	100005

#define MSG_CALL	0
#define MSG_REPLY	1

#define PORTMAP_GETPORT	3

#define MOUNT_ADDENTRY	1
#define MOUNT_UMOUNTALL	4

#define NFS_LOOKUP	4
#define NFS_READ	6

#define NFS_FHSIZE	32

#define NFSERR_PERM	1
#define NFSERR_NOENT	2
#define NFSERR_ACCES	13

/* Block size used for NFS read accesses.  A RPC reply packet (including  all
 * headers) must fit within a single Ethernet frame to avoid fragmentation.
 * Chosen to be a power of two, as most NFS servers are optimized for this.  */
#define NFS_READ_SIZE	1024

#define	FLOPPY_BOOT_LOCATION	0x7c00

#define	ROM_INFO_LOCATION	0x7dfa
/* at end of floppy boot block */

struct rom_info {
	unsigned short rom_segment;
	unsigned short rom_length;
};

/***************************************************************************
External prototypes
***************************************************************************/
/* main.c */
extern void print_bytes P((unsigned char *bytes, int len));
extern void load P((void));
extern int load_linux P((int root_mount_port, int swap_mount_port,
			 int root_nfs_port, char *kernel_handle));
extern int downloadkernel P((unsigned char *, int, int, int));
extern int tftp
P((const char *name, int (*)(unsigned char *, int, int, int)));
extern void rpc_init(void);
extern int nfs
P((const char *name, int (*)(unsigned char *, int, int, int)));
extern void nfs_umountall P((int));
extern int bootp P((void));
extern int rarp P((void));
extern int udp_transmit P((unsigned long destip, unsigned int srcsock,
			   unsigned int destsock, int len,
			   const void *buf));

extern int await_reply P((int type, int ival, void *ptr, int timeout));
extern int decode_rfc1533 P((unsigned char *, int, int, int));
extern unsigned short ipchksum P((unsigned short *, int len));
extern void rfc951_sleep P((int));
extern void cleanup_net P((void));
extern void cleanup P((void));

/* config.c */
extern void print_config(void);
extern void eth_reset(void);
extern int eth_probe(void);
extern int eth_poll(void);
extern void eth_transmit(const char *d, unsigned int t, unsigned int s,
			 const void *p);
extern void eth_disable(void);

/* bootmenu.c */
extern int execute P((char *string));
extern void bootmenu P((int));
extern void show_motd P((void));
extern void parse_menuopts P((char *, int));
extern int getoptvalue P((char **, int *, int *));
extern void selectImage P((char **));

/* osloader.c */
#if	defined(AOUT_IMAGE) || defined(ELF_IMAGE)
extern int howto;
#endif
extern int os_download P((unsigned int, unsigned char *, unsigned int));

/* misc.c */
extern void twiddle P((void));
extern void sleep P((int secs));
extern int strcasecmp P((char *a, char *b));
extern char *substr P((char *a, char *b));
extern int getdec P((char **));
extern void printf P((const char *, ...));
extern char *sprintf P((char *, const char *, ...));
extern int inet_aton P((char *p, in_addr * i));
extern void gateA20_set P((void));
extern void gateA20_unset P((void));
extern void putchar P((int));
extern int getchar P((void));
extern int iskey P((void));

/* start*.S */
extern int getc P((void));
extern void putc P((int));
extern int ischar P((void));
extern int getshift P((void));
extern unsigned int memsize P((void));
extern unsigned short basememsize P((void));
extern void disk_init P((void));
extern unsigned int disk_read P((int drv, int c, int h, int s, char *buf));
extern void xstart P((unsigned long, unsigned long, char *));
extern unsigned long currticks P((void));
extern int setjmp P((void *jmpbuf));
extern void longjmp P((void *jmpbuf, int where));
extern void exit P((int status));
extern void slowdownio P((void));

/* serial.S */
extern int serial_getc P((void));
extern void serial_putc P((int));
extern int serial_ischar P((void));
extern int serial_init P((void));

/* ansiesc.c */
extern void ansi_reset P((void));
extern void enable_cursor P((int));
extern void handleansi P((unsigned char));

/* md5.c */
extern void md5_put P((unsigned int ch));
extern void md5_done P((unsigned char *buf));

/* floppy.c */
extern int bootdisk P((int dev, int part));

/***************************************************************************
External variables
***************************************************************************/
/* main.c */
extern const char *kernel;
extern char kernel_buf[128];
extern struct rom_info rom;
extern int hostnamelen;
extern unsigned long netmask;
extern int jmp_bootmenu[10];
extern struct arptable_t arptable[MAX_ARP];
#ifdef	IMAGE_MENU
extern char *motd[RFC1533_VENDOR_NUMOFMOTD];
extern int menutmo, menudefault;
extern unsigned char *defparams;
extern int defparams_max;
#endif
#if	defined(ETHERBOOT32) && !defined(INTERNAL_BOOTP_DATA)
#define	BOOTP_DATA_ADDR	((struct bootpd_t *)0x93C00)
#else
extern struct bootpd_t bootp_data;
#define	BOOTP_DATA_ADDR	(&bootp_data)
#endif
extern unsigned char *end_of_rfc1533;
#ifdef	IMAGE_FREEBSD
extern int freebsd_howto;
#endif

/* config.c */
extern struct nic nic;

/* bootmenu.c */

/* osloader.c */

/* created by linker */
extern char _start[], _edata[], _end[];

/*
 * Local variables:
 *  c-basic-offset: 8
 * End:
 */