1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210 |
- #if 0
-
- /*
- This file is (or should be) completely obsolete. It is thus
- commented out with the "#if 0" above, to make sure that no
- functions from it are in use. --mdc 2006-09-18
- */
-
- /**************************************************************************
- Etherboot - Network Bootstrap Program
-
- Literature dealing with the network protocols:
- ARP - RFC826
- RARP - RFC903
- IP - RFC791
- UDP - RFC768
- BOOTP - RFC951, RFC2132 (vendor extensions)
- DHCP - RFC2131, RFC2132, RFC3004 (options)
- TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
- RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
- NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
- IGMP - RFC1112, RFC2113, RFC2365, RFC2236, RFC3171
-
- **************************************************************************/
- #include "etherboot.h"
- #include "console.h"
- #include "url.h"
- #include "gpxe/in.h"
- #include "gpxe/netdevice.h"
- #include "proto.h"
- #include "resolv.h"
- #include "dev.h"
- #include "nic.h"
- #include "background.h"
- #include "elf.h" /* FOR EM_CURRENT */
-
- struct arprequest {
- uint16_t hwtype;
- uint16_t protocol;
- uint8_t hwlen;
- uint8_t protolen;
- uint16_t opcode;
- uint8_t shwaddr[6];
- uint8_t sipaddr[4];
- uint8_t thwaddr[6];
- uint8_t tipaddr[4];
- } PACKED;
-
- struct arptable_t arptable[MAX_ARP];
- /* Put rom_info in .nocompress section so romprefix.S can write to it */
- struct rom_info rom __attribute__ ((section (".text16.nocompress"))) = {0,0};
- static unsigned long netmask;
- /* Used by nfs.c */
- char *hostname = "";
- int hostnamelen = 0;
- static uint32_t xid;
- unsigned char *end_of_rfc1533 = NULL;
- unsigned char *addparam;
- int addparamlen;
-
- #ifdef IMAGE_FREEBSD
- int freebsd_howto = 0;
- char freebsd_kernel_env[FREEBSD_KERNEL_ENV_SIZE];
- #endif /* IMAGE_FREEBSD */
-
- static int vendorext_isvalid;
- static const unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* äEth */
- static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- static const in_addr zeroIP = { 0L };
-
- struct bootpd_t bootp_data;
-
- #ifdef NO_DHCP_SUPPORT
- static unsigned char rfc1533_cookie[5] = { RFC1533_COOKIE, RFC1533_END };
- #else /* !NO_DHCP_SUPPORT */
- static int dhcp_reply;
- static in_addr dhcp_server = { 0L };
- static in_addr dhcp_addr = { 0L };
- static unsigned char rfc1533_cookie[] = { RFC1533_COOKIE };
- #define DHCP_MACHINE_INFO_SIZE (sizeof dhcp_machine_info)
- static unsigned char dhcp_machine_info[] = {
- /* Our enclosing DHCP tag */
- RFC1533_VENDOR_ETHERBOOT_ENCAP, 11,
- /* Our boot device */
- RFC1533_VENDOR_NIC_DEV_ID, 5, 0, 0, 0, 0, 0,
- /* Our current architecture */
- RFC1533_VENDOR_ARCH, 2, EM_CURRENT & 0xff, (EM_CURRENT >> 8) & 0xff,
- #ifdef EM_CURRENT_64
- /* The 64bit version of our current architecture */
- RFC1533_VENDOR_ARCH, 2, EM_CURRENT_64 & 0xff, (EM_CURRENT_64 >> 8) & 0xff,
- #undef DHCP_MACHINE_INFO_SIZE
- #define DHCP_MACHINE_INFO_SIZE (sizeof(dhcp_machine_info) - (EM_CURRENT_64_PRESENT? 0: 4))
- #endif /* EM_CURRENT_64 */
- };
- static const unsigned char dhcpdiscover[] = {
- RFC2132_MSG_TYPE,1,DHCPDISCOVER,
- RFC2132_MAX_SIZE,2, /* request as much as we can */
- ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
- #ifdef PXE_DHCP_STRICT
- RFC3679_PXE_CLIENT_UUID,RFC3679_PXE_CLIENT_UUID_LENGTH,RFC3679_PXE_CLIENT_UUID_DEFAULT,
- RFC3679_PXE_CLIENT_ARCH,RFC3679_PXE_CLIENT_ARCH_LENGTH,RFC3679_PXE_CLIENT_ARCH_IAX86PC,
- RFC3679_PXE_CLIENT_NDI, RFC3679_PXE_CLIENT_NDI_LENGTH, RFC3679_PXE_CLIENT_NDI_21,
- RFC2132_VENDOR_CLASS_ID,RFC2132_VENDOR_CLASS_ID_PXE_LENGTH,RFC2132_VENDOR_CLASS_ID_PXE,
- #else
- RFC2132_VENDOR_CLASS_ID,13,'E','t','h','e','r','b','o','o','t',
- '-',VERSION_MAJOR+'0','.',VERSION_MINOR+'0',
- #endif /* PXE_DHCP_STRICT */
- #ifdef DHCP_CLIENT_ID
- /* Client ID Option */
- RFC2132_CLIENT_ID, ( DHCP_CLIENT_ID_LEN + 1 ),
- DHCP_CLIENT_ID_TYPE, DHCP_CLIENT_ID,
- #endif /* DHCP_CLIENT_ID */
- #ifdef DHCP_USER_CLASS
- /* User Class Option */
- RFC3004_USER_CLASS, DHCP_USER_CLASS_LEN, DHCP_USER_CLASS,
- #endif /* DHCP_USER_CLASS */
- RFC2132_PARAM_LIST,
- #define DHCPDISCOVER_PARAMS_BASE 4
- #ifdef PXE_DHCP_STRICT
- #define DHCPDISCOVER_PARAMS_PXE ( 1 + 8 )
- #else
- #define DHCPDISCOVER_PARAMS_PXE 0
- #endif /* PXE_DHCP_STRICT */
- #define DHCPDISCOVER_PARAMS_DNS 1
- ( DHCPDISCOVER_PARAMS_BASE +
- DHCPDISCOVER_PARAMS_PXE+
- DHCPDISCOVER_PARAMS_DNS ),
- RFC1533_NETMASK,
- RFC1533_GATEWAY,
- RFC1533_HOSTNAME,
- RFC1533_VENDOR,
- #ifdef PXE_DHCP_STRICT
- ,RFC2132_VENDOR_CLASS_ID,
- RFC1533_VENDOR_PXE_OPT128,
- RFC1533_VENDOR_PXE_OPT129,
- RFC1533_VENDOR_PXE_OPT130,
- RFC1533_VENDOR_PXE_OPT131,
- RFC1533_VENDOR_PXE_OPT132,
- RFC1533_VENDOR_PXE_OPT133,
- RFC1533_VENDOR_PXE_OPT134,
- RFC1533_VENDOR_PXE_OPT135,
- #endif /* PXE_DHCP_STRICT */
- RFC1533_DNS
- };
- static const unsigned char dhcprequest [] = {
- RFC2132_MSG_TYPE,1,DHCPREQUEST,
- RFC2132_SRV_ID,4,0,0,0,0,
- RFC2132_REQ_ADDR,4,0,0,0,0,
- RFC2132_MAX_SIZE,2, /* request as much as we can */
- ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
- #ifdef PXE_DHCP_STRICT
- RFC3679_PXE_CLIENT_UUID,RFC3679_PXE_CLIENT_UUID_LENGTH,RFC3679_PXE_CLIENT_UUID_DEFAULT,
- RFC3679_PXE_CLIENT_ARCH,RFC3679_PXE_CLIENT_ARCH_LENGTH,RFC3679_PXE_CLIENT_ARCH_IAX86PC,
- RFC3679_PXE_CLIENT_NDI, RFC3679_PXE_CLIENT_NDI_LENGTH, RFC3679_PXE_CLIENT_NDI_21,
- RFC2132_VENDOR_CLASS_ID,RFC2132_VENDOR_CLASS_ID_PXE_LENGTH,RFC2132_VENDOR_CLASS_ID_PXE,
- #else
- RFC2132_VENDOR_CLASS_ID,13,'E','t','h','e','r','b','o','o','t',
- '-',VERSION_MAJOR+'0','.',VERSION_MINOR+'0',
- #endif /* PXE_DHCP_STRICT */
- #ifdef DHCP_CLIENT_ID
- /* Client ID Option */
- RFC2132_CLIENT_ID, ( DHCP_CLIENT_ID_LEN + 1 ),
- DHCP_CLIENT_ID_TYPE, DHCP_CLIENT_ID,
- #endif /* DHCP_CLIENT_ID */
- #ifdef DHCP_USER_CLASS
- /* User Class Option */
- RFC3004_USER_CLASS, DHCP_USER_CLASS_LEN, DHCP_USER_CLASS,
- #endif /* DHCP_USER_CLASS */
- /* request parameters */
- RFC2132_PARAM_LIST,
- #define DHCPREQUEST_PARAMS_BASE 5
- #ifdef PXE_DHCP_STRICT
- #define DHCPREQUEST_PARAMS_PXE 1
- #define DHCPREQUEST_PARAMS_VENDOR_PXE 8
- #define DHCPREQUEST_PARAMS_VENDOR_EB 0
- #else
- #define DHCPREQUEST_PARAMS_PXE 0
- #define DHCPREQUEST_PARAMS_VENDOR_PXE 0
- #define DHCPREQUEST_PARAMS_VENDOR_EB 4
- #endif /* PXE_DHCP_STRICT */
- #ifdef IMAGE_FREEBSD
- #define DHCPREQUEST_PARAMS_FREEBSD 2
- #else
- #define DHCPREQUEST_PARAMS_FREEBSD 0
- #endif /* IMAGE_FREEBSD */
- #define DHCPREQUEST_PARAMS_DNS 1
- ( DHCPREQUEST_PARAMS_BASE +
- DHCPREQUEST_PARAMS_PXE +
- DHCPREQUEST_PARAMS_VENDOR_PXE +
- DHCPREQUEST_PARAMS_VENDOR_EB +
- DHCPREQUEST_PARAMS_DNS +
- DHCPREQUEST_PARAMS_FREEBSD ),
- /* 5 Standard parameters */
- RFC1533_NETMASK,
- RFC1533_GATEWAY,
- RFC1533_HOSTNAME,
- RFC1533_VENDOR,
- RFC1533_ROOTPATH, /* only passed to the booted image */
- #ifndef PXE_DHCP_STRICT
- /* 4 Etherboot vendortags */
- RFC1533_VENDOR_MAGIC,
- RFC1533_VENDOR_ADDPARM,
- RFC1533_VENDOR_ETHDEV,
- RFC1533_VENDOR_ETHERBOOT_ENCAP,
- #endif /* ! PXE_DHCP_STRICT */
- #ifdef IMAGE_FREEBSD
- /* 2 FreeBSD options */
- RFC1533_VENDOR_HOWTO,
- RFC1533_VENDOR_KERNEL_ENV,
- #endif
- /* 1 DNS option */
- RFC1533_DNS,
- #ifdef PXE_DHCP_STRICT
- RFC2132_VENDOR_CLASS_ID,
- RFC1533_VENDOR_PXE_OPT128,
- RFC1533_VENDOR_PXE_OPT129,
- RFC1533_VENDOR_PXE_OPT130,
- RFC1533_VENDOR_PXE_OPT131,
- RFC1533_VENDOR_PXE_OPT132,
- RFC1533_VENDOR_PXE_OPT133,
- RFC1533_VENDOR_PXE_OPT134,
- RFC1533_VENDOR_PXE_OPT135,
- #endif /* PXE_DHCP_STRICT */
- };
- #ifdef PXE_EXPORT
- static const unsigned char proxydhcprequest [] = {
- RFC2132_MSG_TYPE,1,DHCPREQUEST,
- RFC2132_MAX_SIZE,2, /* request as much as we can */
- ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
- #ifdef PXE_DHCP_STRICT
- RFC3679_PXE_CLIENT_UUID,RFC3679_PXE_CLIENT_UUID_LENGTH,RFC3679_PXE_CLIENT_UUID_DEFAULT,
- RFC3679_PXE_CLIENT_ARCH,RFC3679_PXE_CLIENT_ARCH_LENGTH,RFC3679_PXE_CLIENT_ARCH_IAX86PC,
- RFC3679_PXE_CLIENT_NDI, RFC3679_PXE_CLIENT_NDI_LENGTH, RFC3679_PXE_CLIENT_NDI_21,
- RFC2132_VENDOR_CLASS_ID,RFC2132_VENDOR_CLASS_ID_PXE_LENGTH,RFC2132_VENDOR_CLASS_ID_PXE,
- #endif /* PXE_DHCP_STRICT */
- };
- #endif
-
- #ifdef REQUIRE_VCI_ETHERBOOT
- int vci_etherboot;
- #endif
- #endif /* NO_DHCP_SUPPORT */
-
- #ifdef RARP_NOT_BOOTP
- static int rarp(void);
- #else
- static int bootp(void);
- #endif
-
-
- /*
- * Find out what our boot parameters are
- */
- static int nic_configure ( struct type_dev *type_dev ) {
- struct nic *nic = ( struct nic * ) type_dev;
- int server_found;
-
- if ( ! nic->nic_op->connect ( nic ) ) {
- printf ( "No connection to network\n" );
- return 0;
- }
-
- /* Find a server to get BOOTP reply from */
- #ifdef RARP_NOT_BOOTP
- printf("Searching for server (RARP)...");
- #else
- #ifndef NO_DHCP_SUPPORT
- printf("Searching for server (DHCP)...");
- #else
- printf("Searching for server (BOOTP)...");
- #endif
- #endif
-
- #ifdef RARP_NOT_BOOTP
- server_found = rarp();
- #else
- server_found = bootp();
- #endif
- if (!server_found) {
- printf("No Server found\n");
- return 0;
- }
-
- #if 0
- printf( "\nMe: %s", inet_ntoa ( arptable[ARP_CLIENT].ipaddr ) );
- #endif
- #ifndef NO_DHCP_SUPPORT
- printf( ", DHCP: %s", inet_ntoa (dhcp_server) );
- #ifdef PXE_EXPORT
- if (arptable[ARP_PROXYDHCP].ipaddr.s_addr)
- printf ( " (& %s)", inet_ntoa ( arptable[ARP_PROXYDHCP].ipaddr ) );
- #endif /* PXE_EXPORT */
- #endif /* ! NO_DHCP_SUPPORT */
- printf(", TFTP: %s", inet_ntoa ( arptable[ARP_SERVER].ipaddr ) );
- if (bootp_data.bootp_reply.bp_giaddr.s_addr)
- printf ( ", Relay: %s", inet_ntoa ( bootp_data.bootp_reply.bp_giaddr ) );
- if (arptable[ARP_GATEWAY].ipaddr.s_addr)
- printf ( ", Gateway %s", inet_ntoa (arptable[ARP_GATEWAY].ipaddr ) );
- if (arptable[ARP_NAMESERVER].ipaddr.s_addr)
- printf ( ", Nameserver %s", inet_ntoa ( arptable[ARP_NAMESERVER].ipaddr ) );
- putchar('\n');
-
- #ifdef MDEBUG
- printf("\n=>>"); getchar();
- #endif
-
- return 1;
- }
-
-
- /*
- * Download a file from the specified URL into the specified buffer
- *
- */
- int download_url ( char *url, struct buffer *buffer ) {
- struct protocol *proto;
- struct sockaddr_in server;
- char *filename;
-
- printf ( "Loading %s\n", url );
-
- /* Parse URL */
- if ( ! parse_url ( url, &proto, &server, &filename ) ) {
- DBG ( "Unusable URL %s\n", url );
- return 0;
- }
-
- /* Call protocol's method to download the file */
- return proto->load ( url, &server, filename, buffer );
- }
-
-
-
-
- /**************************************************************************
- LOAD - Try to get booted
- **************************************************************************/
- static int nic_load ( struct type_dev *type_dev, struct buffer *buffer ) {
- char *kernel;
-
- /* Now use TFTP to load file */
- kernel = KERNEL_BUF[0] == '\0' ?
- #ifdef DEFAULT_BOOTFILE
- DEFAULT_BOOTFILE
- #else
- NULL
- #endif
- : KERNEL_BUF;
- #ifdef ZPXE_SUFFIX_STRIP
- {
- int i = 0;
- while (kernel[i++]);
- if(i > 5) {
- if(kernel[i - 6] == '.' &&
- kernel[i - 5] == 'z' &&
- kernel[i - 4] == 'p' &&
- kernel[i - 3] == 'x' &&
- kernel[i - 2] == 'e') {
- printf("Trimming .zpxe extension\n");
- kernel[i - 6] = 0;
- }
- }
- }
- #endif
- if ( kernel ) {
- return download_url ( kernel, buffer );
- } else {
- printf("No filename\n");
- }
- return 0;
- }
-
- void nic_disable ( struct nic *nic __unused ) {
- #ifdef MULTICAST_LEVEL2
- int i;
- for(i = 0; i < MAX_IGMP; i++) {
- leave_group(i);
- }
- #endif
- }
-
- static char * nic_describe_device ( struct type_dev *type_dev ) {
- struct nic *nic = ( struct nic * ) type_dev;
- static char nic_description[] = "MAC 00:00:00:00:00:00";
-
- sprintf ( nic_description + 4, "%s", netdev_name ( nic ) );
- return nic_description;
- }
-
- /*
- * Device operations tables
- *
- */
- struct type_driver nic_driver = {
- .name = "NIC",
- .type_dev = ( struct type_dev * ) &nic,
- .describe_device = nic_describe_device,
- .configure = nic_configure,
- .load = nic_load,
- };
-
- #if 0
- /* Careful. We need an aligned buffer to avoid problems on machines
- * that care about alignment. To trivally align the ethernet data
- * (the ip hdr and arp requests) we offset the packet by 2 bytes.
- * leaving the ethernet data 16 byte aligned. Beyond this
- * we use memmove but this makes the common cast simple and fast.
- */
- static char packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned;
-
- struct nic nic = {
- .node_addr = arptable[ARP_CLIENT].node,
- .packet = packet + ETH_DATA_ALIGN,
- };
- #endif
-
-
- /**************************************************************************
- DEFAULT_NETMASK - Return default netmask for IP address
- **************************************************************************/
- static inline unsigned long default_netmask(void)
- {
- int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
- if (net <= 127)
- return(htonl(0xff000000));
- else if (net < 192)
- return(htonl(0xffff0000));
- else
- return(htonl(0xffffff00));
- }
-
- /**************************************************************************
- IP_TRANSMIT - Send an IP datagram
- **************************************************************************/
- static int await_arp(int ival, void *ptr,
- unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused,
- struct tcphdr *tcp __unused)
- {
- struct arprequest *arpreply;
- if (ptype != ETH_P_ARP)
- return 0;
- if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
- return 0;
- arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
-
- if (arpreply->opcode != htons(ARPOP_REPLY))
- return 0;
- if (memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) != 0)
- return 0;
- memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN);
- return 1;
- }
-
- int ip_transmit(int len, const void *buf)
- {
- unsigned long destip;
- struct iphdr *ip;
- struct arprequest arpreq;
- int arpentry, i;
- int retry;
-
- ip = (struct iphdr *)buf;
- destip = ip->dest.s_addr;
- if (destip == INADDR_BROADCAST) {
- eth_transmit(broadcast, ETH_P_IP, len, buf);
- } else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
- unsigned char multicast[6];
- unsigned long hdestip;
- hdestip = ntohl(destip);
- multicast[0] = 0x01;
- multicast[1] = 0x00;
- multicast[2] = 0x5e;
- multicast[3] = (hdestip >> 16) & 0x7;
- multicast[4] = (hdestip >> 8) & 0xff;
- multicast[5] = hdestip & 0xff;
- eth_transmit(multicast, ETH_P_IP, len, buf);
- } else {
- if (((destip & netmask) !=
- (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
- arptable[ARP_GATEWAY].ipaddr.s_addr)
- destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
- for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
- if (arptable[arpentry].ipaddr.s_addr == destip) break;
- if (arpentry == MAX_ARP) {
- printf ( "%s is not in my arp table!\n", inet_ntoa (destip) );
- return(0);
- }
- for (i = 0; i < ETH_ALEN; i++)
- if (arptable[arpentry].node[i])
- break;
- if (i == ETH_ALEN) { /* Need to do arp request */
- arpreq.hwtype = htons(1);
- arpreq.protocol = htons(ETH_P_IP);
- arpreq.hwlen = ETH_ALEN;
- arpreq.protolen = 4;
- arpreq.opcode = htons(ARPOP_REQUEST);
- memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
- memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
- memset(arpreq.thwaddr, 0, ETH_ALEN);
- memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
- for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
- long timeout;
- eth_transmit(broadcast, ETH_P_ARP, sizeof(arpreq),
- &arpreq);
- timeout = rfc2131_sleep_interval(TIMEOUT, retry);
- if (await_reply(await_arp, arpentry,
- arpreq.tipaddr, timeout)) goto xmit;
- }
- return(0);
- }
- xmit:
- eth_transmit(arptable[arpentry].node, ETH_P_IP, len, buf);
- }
- return 1;
- }
-
- void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len,
- int len, const void *buf)
- {
- struct iphdr *ip;
- ip = (struct iphdr *)buf;
- ip->verhdrlen = 0x45;
- ip->verhdrlen += (option_len/4);
- ip->service = 0;
- ip->len = htons(len);
- ip->ident = 0;
- ip->frags = 0; /* Should we set don't fragment? */
- ip->ttl = ttl;
- ip->protocol = protocol;
- ip->chksum = 0;
- ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
- ip->dest.s_addr = destip;
- ip->chksum = ipchksum(buf, sizeof(struct iphdr) + option_len);
- }
-
- void build_udp_hdr(unsigned long destip,
- unsigned int srcsock, unsigned int destsock, int ttl,
- int len, const void *buf)
- {
- struct iphdr *ip;
- struct udphdr *udp;
- ip = (struct iphdr *)buf;
- build_ip_hdr(destip, ttl, IP_UDP, 0, len, buf);
- udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr));
- udp->src = htons(srcsock);
- udp->dest = htons(destsock);
- udp->len = htons(len - sizeof(struct iphdr));
- udp->chksum = 0;
- if ((udp->chksum = tcpudpchksum(ip)) == 0)
- udp->chksum = 0xffff;
- }
-
- /**************************************************************************
- UDP_TRANSMIT - Send an UDP datagram
- **************************************************************************/
- int udp_transmit(unsigned long destip, unsigned int srcsock,
- unsigned int destsock, int len, const void *buf)
- {
- build_udp_hdr(destip, srcsock, destsock, 60, len, buf);
- return ip_transmit(len, buf);
- }
-
-
- /**************************************************************************
- QDRAIN - clear the nic's receive queue
- **************************************************************************/
- static int await_qdrain(int ival __unused, void *ptr __unused,
- unsigned short ptype __unused,
- struct iphdr *ip __unused, struct udphdr *udp __unused,
- struct tcphdr *tcp __unused)
- {
- return 0;
- }
-
- void rx_qdrain(void)
- {
- /* Clear out the Rx queue first. It contains nothing of interest,
- * except possibly ARP requests from the DHCP/TFTP server. We use
- * polling throughout Etherboot, so some time may have passed since we
- * last polled the receive queue, which may now be filled with
- * broadcast packets. This will cause the reply to the packets we are
- * about to send to be lost immediately. Not very clever. */
- await_reply(await_qdrain, 0, NULL, 0);
- }
-
- #ifdef RARP_NOT_BOOTP
- /**************************************************************************
- RARP - Get my IP address and load information
- **************************************************************************/
- static int await_rarp(int ival, void *ptr,
- unsigned short ptype, struct iphdr *ip, struct udphdr *udp,
- struct tcphdr *tcp __unused)
- {
- struct arprequest *arpreply;
- if (ptype != ETH_P_RARP)
- return 0;
- if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
- return 0;
- arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
- if (arpreply->opcode != htons(RARP_REPLY))
- return 0;
- if ((arpreply->opcode == htons(RARP_REPLY)) &&
- (memcmp(arpreply->thwaddr, ptr, ETH_ALEN) == 0)) {
- memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN);
- memcpy(&arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
- memcpy(&arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
- return 1;
- }
- return 0;
- }
-
- static int rarp(void)
- {
- int retry;
-
- /* arp and rarp requests share the same packet structure. */
- struct arprequest rarpreq;
-
- memset(&rarpreq, 0, sizeof(rarpreq));
-
- rarpreq.hwtype = htons(1);
- rarpreq.protocol = htons(IP);
- rarpreq.hwlen = ETH_ALEN;
- rarpreq.protolen = 4;
- rarpreq.opcode = htons(RARP_REQUEST);
- memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
- /* sipaddr is already zeroed out */
- memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
- /* tipaddr is already zeroed out */
-
- for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) {
- long timeout;
- eth_transmit(broadcast, ETH_P_RARP, sizeof(rarpreq), &rarpreq);
-
- timeout = rfc2131_sleep_interval(TIMEOUT, retry);
- if (await_reply(await_rarp, 0, rarpreq.shwaddr, timeout))
- break;
- }
-
- if (retry < MAX_ARP_RETRIES) {
- (void)sprintf(KERNEL_BUF, DEFAULT_KERNELPATH, arptable[ARP_CLIENT].ipaddr);
-
- return (1);
- }
- return (0);
- }
-
- #else
-
- /**************************************************************************
- BOOTP - Get my IP address and load information
- **************************************************************************/
- static int await_bootp(int ival __unused, void *ptr __unused,
- unsigned short ptype __unused, struct iphdr *ip __unused,
- struct udphdr *udp, struct tcphdr *tcp __unused)
- {
- struct bootp_t *bootpreply;
- if (!udp) {
- return 0;
- }
- bootpreply = (struct bootp_t *)&nic.packet[ETH_HLEN +
- sizeof(struct iphdr) + sizeof(struct udphdr)];
- if (nic.packetlen < ETH_HLEN + sizeof(struct iphdr) +
- sizeof(struct udphdr) +
- #ifdef NO_DHCP_SUPPORT
- sizeof(struct bootp_t)
- #else
- sizeof(struct bootp_t) - DHCP_OPT_LEN
- #endif /* NO_DHCP_SUPPORT */
- ) {
- return 0;
- }
- if (udp->dest != htons(BOOTP_CLIENT))
- return 0;
- if (bootpreply->bp_op != BOOTP_REPLY)
- return 0;
- if (bootpreply->bp_xid != xid)
- return 0;
- if (memcmp(&bootpreply->bp_siaddr, &zeroIP, sizeof(in_addr)) == 0)
- return 0;
- if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) &&
- (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) {
- return 0;
- }
- if ( bootpreply->bp_siaddr.s_addr ) {
- arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
- memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
- }
- if ( bootpreply->bp_giaddr.s_addr ) {
- arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
- memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
- }
- if (bootpreply->bp_yiaddr.s_addr) {
- /* Offer with an IP address */
- arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
- #ifndef NO_DHCP_SUPPORT
- dhcp_addr.s_addr = bootpreply->bp_yiaddr.s_addr;
- #endif /* NO_DHCP_SUPPORT */
- netmask = default_netmask();
- /* bootpreply->bp_file will be copied to KERNEL_BUF in the memcpy */
- memcpy((char *)&bootp_data, (char *)bootpreply, sizeof(struct bootpd_t));
- decode_rfc1533(bootp_data.bootp_reply.bp_vend, 0,
- #ifdef NO_DHCP_SUPPORT
- BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN,
- #else
- DHCP_OPT_LEN + MAX_BOOTP_EXTLEN,
- #endif /* NO_DHCP_SUPPORT */
- 1);
- #ifdef PXE_EXPORT
- } else {
- /* Offer without an IP address - use as ProxyDHCP server */
- arptable[ARP_PROXYDHCP].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
- memset(arptable[ARP_PROXYDHCP].node, 0, ETH_ALEN); /* Kill arp */
- /* Grab only the bootfile name from a ProxyDHCP packet */
- memcpy(KERNEL_BUF, bootpreply->bp_file, sizeof(KERNEL_BUF));
- #endif /* PXE_EXPORT */
- }
- #ifdef REQUIRE_VCI_ETHERBOOT
- if (!vci_etherboot)
- return (0);
- #endif
- return(1);
- }
-
- static int bootp(void)
- {
- int retry;
- #ifndef NO_DHCP_SUPPORT
- int reqretry;
- #endif /* NO_DHCP_SUPPORT */
- struct bootpip_t ip;
- unsigned long starttime;
- unsigned char *bp_vend;
-
- #ifndef NO_DHCP_SUPPORT
- * ( ( struct dhcp_dev_id * ) &dhcp_machine_info[4] ) = nic.dhcp_dev_id;
- #endif /* NO_DHCP_SUPPORT */
- memset(&ip, 0, sizeof(struct bootpip_t));
- ip.bp.bp_op = BOOTP_REQUEST;
- ip.bp.bp_htype = 1;
- ip.bp.bp_hlen = ETH_ALEN;
- starttime = currticks();
- /* Use lower 32 bits of node address, more likely to be
- distinct than the time since booting */
- memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
- ip.bp.bp_xid = xid += htonl(starttime);
- memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
- #ifdef NO_DHCP_SUPPORT
- memcpy(ip.bp.bp_vend, rfc1533_cookie, 5); /* request RFC-style options */
- #else
- memcpy(ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie); /* request RFC-style options */
- memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie, dhcpdiscover, sizeof dhcpdiscover);
- /* Append machine_info to end, in encapsulated option */
- bp_vend = ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcpdiscover;
- memcpy(bp_vend, dhcp_machine_info, DHCP_MACHINE_INFO_SIZE);
- bp_vend += DHCP_MACHINE_INFO_SIZE;
- *bp_vend++ = RFC1533_END;
- #endif /* NO_DHCP_SUPPORT */
-
- for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
- uint8_t my_hwaddr[ETH_ALEN];
- unsigned long stop_time;
- long remaining_time;
-
- rx_qdrain();
-
- /* Kill arptable to avoid keeping stale entries */
- memcpy ( my_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN );
- memset ( arptable, 0, sizeof(arptable) );
- memcpy ( arptable[ARP_CLIENT].node, my_hwaddr, ETH_ALEN );
-
- udp_transmit(INADDR_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
- sizeof(struct bootpip_t), &ip);
- remaining_time = rfc2131_sleep_interval(BOOTP_TIMEOUT, retry++);
- stop_time = currticks() + remaining_time;
- #ifdef NO_DHCP_SUPPORT
- if (await_reply(await_bootp, 0, NULL, remaining_time))
- return(1);
- #else
- while ( remaining_time > 0 ) {
- if (await_reply(await_bootp, 0, NULL, remaining_time)){
- if (arptable[ARP_CLIENT].ipaddr.s_addr)
- break;
- }
- remaining_time = stop_time - currticks();
- }
- if ( ! arptable[ARP_CLIENT].ipaddr.s_addr ) {
- printf("No IP address\n");
- continue;
- }
- /* If not a DHCPOFFER then must be just a BOOTP reply,
- * be backward compatible with BOOTP then */
- if (dhcp_reply != DHCPOFFER)
- return(1);
- dhcp_reply = 0;
- /* Construct the DHCPREQUEST packet */
- memcpy(ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
- memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie, dhcprequest, sizeof dhcprequest);
- /* Beware: the magic numbers 9 and 15 depend on
- the layout of dhcprequest */
- memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr));
- memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr));
- bp_vend = ip.bp.bp_vend + sizeof rfc1533_cookie + sizeof dhcprequest;
- /* Append machine_info to end, in encapsulated option */
- memcpy(bp_vend, dhcp_machine_info, DHCP_MACHINE_INFO_SIZE);
- bp_vend += DHCP_MACHINE_INFO_SIZE;
- *bp_vend++ = RFC1533_END;
- for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) {
- unsigned long timeout;
-
- udp_transmit(INADDR_BROADCAST, BOOTP_CLIENT,
- BOOTP_SERVER, sizeof(struct bootpip_t),
- &ip);
- dhcp_reply=0;
- timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++);
- if (!await_reply(await_bootp, 0, NULL, timeout))
- continue;
- if (dhcp_reply != DHCPACK)
- continue;
- dhcp_reply = 0;
- #ifdef PXE_EXPORT
- if ( arptable[ARP_PROXYDHCP].ipaddr.s_addr ) {
- /* Construct the ProxyDHCPREQUEST packet */
- memcpy(ip.bp.bp_vend, rfc1533_cookie, sizeof rfc1533_cookie);
- memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie, proxydhcprequest, sizeof proxydhcprequest);
- for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) {
- printf ( "\nSending ProxyDHCP request to %s...",
- inet_ntoa ( arptable[ARP_PROXYDHCP].ipaddr ) );
- udp_transmit(arptable[ARP_PROXYDHCP].ipaddr.s_addr, BOOTP_CLIENT, PROXYDHCP_SERVER,
- sizeof(struct bootpip_t), &ip);
- timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++);
- if (await_reply(await_bootp, 0, NULL, timeout)) {
- break;
- }
- }
- }
- #endif /* PXE_EXPORT */
- return(1);
- }
- #endif /* NO_DHCP_SUPPORT */
- ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
- }
- return(0);
- }
- #endif /* RARP_NOT_BOOTP */
-
- uint16_t tcpudpchksum(struct iphdr *ip)
- {
- struct udp_pseudo_hdr pseudo;
- uint16_t checksum;
-
- /* Compute the pseudo header */
- pseudo.src.s_addr = ip->src.s_addr;
- pseudo.dest.s_addr = ip->dest.s_addr;
- pseudo.unused = 0;
- pseudo.protocol = ip->protocol;
- pseudo.len = htons(ntohs(ip->len) - sizeof(struct iphdr));
-
- /* Sum the pseudo header */
- checksum = ipchksum(&pseudo, 12);
-
- /* Sum the rest of the tcp/udp packet */
- checksum = add_ipchksums(12, checksum, ipchksum(ip + 1,
- ntohs(ip->len) - sizeof(struct iphdr)));
- return checksum;
- }
-
-
- #include "proto_eth_slow.c"
-
-
- /**************************************************************************
- AWAIT_REPLY - Wait until we get a response for our request
- ************f**************************************************************/
- int await_reply(reply_t reply, int ival, void *ptr, long timeout)
- {
- unsigned long time, now;
- struct iphdr *ip;
- unsigned iplen = 0;
- struct udphdr *udp;
- struct tcphdr *tcp;
- unsigned short ptype;
- int result;
-
- time = timeout + currticks();
- /* The timeout check is done below. The timeout is only checked if
- * there is no packet in the Rx queue. This assumes that eth_poll()
- * needs a negligible amount of time.
- */
- for (;;) {
- now = currticks();
- background_send(now);
- send_eth_slow_reports(now);
- result = eth_poll(1);
- if (result == 0) {
- /* We don't have anything */
-
- /* Do the timeout after at least a full queue walk. */
- if ((timeout == 0) || (currticks() > time)) {
- break;
- }
- continue;
- }
-
- /* We have something! */
-
- /* Find the Ethernet packet type */
- if (nic.packetlen >= ETH_HLEN) {
- ptype = ((unsigned short) nic.packet[12]) << 8
- | ((unsigned short) nic.packet[13]);
- } else continue; /* what else could we do with it? */
- /* Verify an IP header */
- ip = 0;
- if ((ptype == ETH_P_IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
- unsigned ipoptlen;
- ip = (struct iphdr *)&nic.packet[ETH_HLEN];
- if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F))
- continue;
- iplen = (ip->verhdrlen & 0xf) * 4;
- if (ipchksum(ip, iplen) != 0)
- continue;
- if (ip->frags & htons(0x3FFF)) {
- static int warned_fragmentation = 0;
- if (!warned_fragmentation) {
- printf("ALERT: got a fragmented packet - reconfigure your server\n");
- warned_fragmentation = 1;
- }
- continue;
- }
- if (ntohs(ip->len) > ETH_MAX_MTU)
- continue;
-
- ipoptlen = iplen - sizeof(struct iphdr);
- if (ipoptlen) {
- /* Delete the ip options, to guarantee
- * good alignment, and make etherboot simpler.
- */
- memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)],
- &nic.packet[ETH_HLEN + iplen],
- nic.packetlen - ipoptlen);
- nic.packetlen -= ipoptlen;
- }
- }
- udp = 0;
- if (ip && (ip->protocol == IP_UDP) &&
- (nic.packetlen >=
- ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) {
- udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
-
- /* Make certain we have a reasonable packet length */
- if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
- continue;
-
- if (udp->chksum && tcpudpchksum(ip)) {
- printf("UDP checksum error\n");
- continue;
- }
- }
- tcp = 0;
- if (ip && (ip->protocol == IP_TCP) &&
- (nic.packetlen >=
- ETH_HLEN + sizeof(struct iphdr) + sizeof(struct tcphdr))){
- tcp = (struct tcphdr *)&nic.packet[ETH_HLEN +
- sizeof(struct iphdr)];
- /* Make certain we have a reasonable packet length */
- if (((ntohs(tcp->ctrl) >> 10) & 0x3C) >
- ntohs(ip->len) - (int)iplen)
- continue;
- if (tcpudpchksum(ip)) {
- printf("TCP checksum error\n");
- continue;
- }
-
- }
- result = reply(ival, ptr, ptype, ip, udp, tcp);
- if (result > 0) {
- return result;
- }
-
- /* If it isn't a packet the upper layer wants see if there is a default
- * action. This allows us reply to arp, igmp, and lacp queries.
- */
- if ((ptype == ETH_P_ARP) &&
- (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
- struct arprequest *arpreply;
- unsigned long tmp;
-
- arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
- memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
- if ((arpreply->opcode == htons(ARPOP_REQUEST)) &&
- (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
- arpreply->opcode = htons(ARPOP_REPLY);
- memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
- memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
- memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
- memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
- eth_transmit(arpreply->thwaddr, ETH_P_ARP,
- sizeof(struct arprequest),
- arpreply);
- #ifdef MDEBUG
- memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
- printf( "Sent ARP reply to: %s\n", inet_ntoa ( tmp ) );
- #endif /* MDEBUG */
- }
- }
- background_process(now, ptype, ip);
- process_eth_slow(ptype, now);
- }
- return(0);
- }
-
- #ifdef REQUIRE_VCI_ETHERBOOT
- /**************************************************************************
- FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers
- On entry p points to byte count of VCI options
- **************************************************************************/
- static int find_vci_etherboot(unsigned char *p)
- {
- unsigned char *end = p + 1 + *p;
-
- for (p++; p < end; ) {
- if (*p == RFC2132_VENDOR_CLASS_ID) {
- if (strncmp("Etherboot", p + 2, sizeof("Etherboot") - 1) == 0)
- return (1);
- } else if (*p == RFC1533_END)
- return (0);
- p += TAG_LEN(p) + 2;
- }
- return (0);
- }
- #endif /* REQUIRE_VCI_ETHERBOOT */
-
- /**************************************************************************
- DECODE_RFC1533 - Decodes RFC1533 header
- **************************************************************************/
- int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof)
- {
- static unsigned char *extdata = NULL, *extend = NULL;
- unsigned char *extpath = NULL;
- unsigned char *endp;
- static unsigned char in_encapsulated_options = 0;
-
- if (eof == -1) {
- /* Encapsulated option block */
- endp = p + len;
- }
- else if (block == 0) {
- #ifdef REQUIRE_VCI_ETHERBOOT
- vci_etherboot = 0;
- #endif
- end_of_rfc1533 = NULL;
- #ifdef IMAGE_FREEBSD
- /* yes this is a pain FreeBSD uses this for swap, however,
- there are cases when you don't want swap and then
- you want this set to get the extra features so lets
- just set if dealing with FreeBSD. I haven't run into
- any troubles with this but I have without it
- */
- vendorext_isvalid = 1;
- #ifdef FREEBSD_KERNEL_ENV
- memcpy(freebsd_kernel_env, FREEBSD_KERNEL_ENV,
- sizeof(FREEBSD_KERNEL_ENV));
- /* FREEBSD_KERNEL_ENV had better be a string constant */
- #else
- freebsd_kernel_env[0]='\0';
- #endif
- #else
- vendorext_isvalid = 0;
- #endif
- addparam = NULL;
- addparamlen = 0;
- if (memcmp(p, rfc1533_cookie, 4))
- return(0); /* no RFC 1533 header found */
- p += 4;
- endp = p + len;
- } else {
- if (block == 1) {
- if (memcmp(p, rfc1533_cookie, 4))
- return(0); /* no RFC 1533 header found */
- p += 4;
- len -= 4; }
- if (extend + len <= (unsigned char *)&(bootp_data.bootp_extension[MAX_BOOTP_EXTLEN])) {
- memcpy(extend, p, len);
- extend += len;
- } else {
- printf("Overflow in vendor data buffer! Aborting...\n");
- *extdata = RFC1533_END;
- return(0);
- }
- p = extdata; endp = extend;
- }
- if (!eof)
- return 1;
- while (p < endp) {
- unsigned char c = *p;
- if (c == RFC1533_PAD) {
- p++;
- continue;
- }
- else if (c == RFC1533_END) {
- end_of_rfc1533 = endp = p;
- continue;
- }
- else if (NON_ENCAP_OPT c == RFC1533_NETMASK)
- memcpy(&netmask, p+2, sizeof(in_addr));
- else if (NON_ENCAP_OPT c == RFC1533_GATEWAY) {
- /* This is a little simplistic, but it will
- usually be sufficient.
- Take only the first entry */
- if (TAG_LEN(p) >= sizeof(in_addr))
- memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
- }
- else if (c == RFC1533_EXTENSIONPATH)
- extpath = p;
- #ifndef NO_DHCP_SUPPORT
- #ifdef REQUIRE_VCI_ETHERBOOT
- else if (NON_ENCAP_OPT c == RFC1533_VENDOR) {
- vci_etherboot = find_vci_etherboot(p+1);
- #ifdef MDEBUG
- printf("vci_etherboot %d\n", vci_etherboot);
- #endif
- }
- #endif /* REQUIRE_VCI_ETHERBOOT */
- else if (NON_ENCAP_OPT c == RFC2132_MSG_TYPE)
- dhcp_reply=*(p+2);
- else if (NON_ENCAP_OPT c == RFC2132_SRV_ID)
- memcpy(&dhcp_server, p+2, sizeof(in_addr));
- #endif /* NO_DHCP_SUPPORT */
- else if (NON_ENCAP_OPT c == RFC1533_HOSTNAME) {
- hostname = p + 2;
- hostnamelen = *(p + 1);
- }
- else if (ENCAP_OPT c == RFC1533_VENDOR_MAGIC
- && TAG_LEN(p) >= 6 &&
- !memcmp(p+2,vendorext_magic,4) &&
- p[6] == RFC1533_VENDOR_MAJOR
- )
- vendorext_isvalid++;
- else if (c == RFC1533_VENDOR_ADDPARM) {
- /* This tag intentionally works for BOTH the encapsulated and
- * non-encapsulated case, since the current menu code (in mknbi)
- * creates this tag without encapsulation. In the future both the
- * menu from mknbi and this code should learn about the proper
- * encapsulation (which will require substantial changes to various
- * stuff from mknbi, which will break compatibility with older
- * versions of Etherboot). */
- addparam = p + 2;
- addparamlen = *(p + 1);
- }
- else if (NON_ENCAP_OPT c == RFC1533_VENDOR_ETHERBOOT_ENCAP) {
- in_encapsulated_options = 1;
- decode_rfc1533(p+2, 0, TAG_LEN(p), -1);
- in_encapsulated_options = 0;
- }
- #ifdef IMAGE_FREEBSD
- else if (NON_ENCAP_OPT c == RFC1533_VENDOR_HOWTO)
- freebsd_howto = ((p[2]*256+p[3])*256+p[4])*256+p[5];
- else if (NON_ENCAP_OPT c == RFC1533_VENDOR_KERNEL_ENV){
- if(*(p + 1) < sizeof(freebsd_kernel_env)){
- memcpy(freebsd_kernel_env,p+2,*(p+1));
- }else{
- printf("Only support %ld bytes in Kernel Env\n",
- sizeof(freebsd_kernel_env));
- }
- }
- #endif
- else if (NON_ENCAP_OPT c == RFC1533_DNS) {
- // TODO: Copy the DNS IP somewhere reasonable
- if (TAG_LEN(p) >= sizeof(in_addr))
- memcpy(&arptable[ARP_NAMESERVER].ipaddr, p+2, sizeof(in_addr));
- }
- else {
- #if 0
- unsigned char *q;
- printf("Unknown RFC1533-tag ");
- for(q=p;q<p+2+TAG_LEN(p);q++)
- printf("%hhX ",*q);
- putchar('\n');
- #endif
- }
- p += TAG_LEN(p) + 2;
- }
- extdata = extend = endp;
- if (block <= 0 && extpath != NULL) {
- char fname[64];
- memcpy(fname, extpath+2, TAG_LEN(extpath));
- fname[(int)TAG_LEN(extpath)] = '\0';
- printf("Loading BOOTP-extension file: %s\n",fname);
- #warning "BOOTP extension files are broken"
- /* tftp(fname, decode_rfc1533); */
- }
- return 1; /* proceed with next block */
- }
-
-
- /* FIXME double check TWO_SECOND_DIVISOR */
- #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC)
- /**************************************************************************
- RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec)
- **************************************************************************/
- long rfc2131_sleep_interval(long base, int exp)
- {
- unsigned long tmo;
- if (exp > BACKOFF_LIMIT)
- exp = BACKOFF_LIMIT;
- tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
- return tmo;
- }
-
- #endif
|