12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778 |
- /**************************************************************************
- 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 "nic.h"
- #include "elf.h" /* FOR EM_CURRENT */
-
- struct arptable_t arptable[MAX_ARP];
- #if MULTICAST_LEVEL2
- unsigned long last_igmpv1 = 0;
- struct igmptable_t igmptable[MAX_IGMP];
- #endif
- /* 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;
- 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, PCI_BUS_TYPE, 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 */
- #ifdef DNS_RESOLVER
- #define DHCPDISCOVER_PARAMS_DNS 1
- #else
- #define DHCPDISCOVER_PARAMS_DNS 0
- #endif /* DNS_RESOLVER */
- ( 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 */
- #ifdef DNS_RESOLVER
- ,RFC1533_DNS
- #endif
- };
- 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 */
- #ifdef DNS_RESOLVER
- #define DHCPREQUEST_PARAMS_DNS 1
- #else
- #define DHCPREQUEST_PARAMS_DNS 0
- #endif /* DNS_RESOLVER */
- ( 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
- #ifdef DNS_RESOLVER
- /* 1 DNS option */
- RFC1533_DNS,
- #endif
- #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 */
-
- static int dummy(void *unused __unused)
- {
- return (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 =
- {
- {
- 0, /* dev.disable */
- {
- 0,
- 0,
- PCI_BUS_TYPE,
- }, /* dev.devid */
- 0, /* index */
- 0, /* type */
- PROBE_FIRST, /* how_pobe */
- PROBE_NONE, /* to_probe */
- 0, /* failsafe */
- 0, /* type_index */
- {}, /* state */
- },
- (int (*)(struct nic *, int))dummy, /* poll */
- (void (*)(struct nic *, const char *,
- unsigned int, unsigned int,
- const char *))dummy, /* transmit */
- (void (*)(struct nic *,
- irq_action_t))dummy, /* irq */
- 0, /* flags */
- &rom, /* rom_info */
- arptable[ARP_CLIENT].node, /* node_addr */
- packet + ETH_DATA_ALIGN, /* packet */
- 0, /* packetlen */
- 0, /* ioaddr */
- 0, /* irqno */
- 0, /* priv_data */
- };
-
- #ifdef RARP_NOT_BOOTP
- static int rarp(void);
- #else
- static int bootp(void);
- #endif
- static unsigned short tcpudpchksum(struct iphdr *ip);
-
-
- int eth_probe(struct dev *dev)
- {
- return probe(dev);
- }
-
- int eth_poll(int retrieve)
- {
- return ((*nic.poll)(&nic, retrieve));
- }
-
- void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p)
- {
- (*nic.transmit)(&nic, d, t, s, p);
- if (t == ETH_P_IP) twiddle();
- }
-
- void eth_disable(void)
- {
- #ifdef MULTICAST_LEVEL2
- int i;
- for(i = 0; i < MAX_IGMP; i++) {
- leave_group(i);
- }
- #endif
- disable(&nic.dev);
- }
-
- void eth_irq (irq_action_t action)
- {
- (*nic.irq)(&nic,action);
- }
-
- /*
- * Find out what our boot parameters are
- */
- int eth_load_configuration(struct dev *dev __unused)
- {
- int server_found;
- /* 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");
- longjmp(restart_etherboot, -1);
- }
- return 0;
- }
-
-
- /**************************************************************************
- LOAD - Try to get booted
- **************************************************************************/
- int eth_load(struct dev *dev __unused)
- {
- const char *kernel;
- printf("\nMe: %@", arptable[ARP_CLIENT].ipaddr.s_addr );
- #ifndef NO_DHCP_SUPPORT
- printf(", DHCP: %@", dhcp_server );
- #ifdef PXE_EXPORT
- if (arptable[ARP_PROXYDHCP].ipaddr.s_addr)
- printf(" (& %@)",
- arptable[ARP_PROXYDHCP].ipaddr.s_addr);
- #endif /* PXE_EXPORT */
- #endif /* ! NO_DHCP_SUPPORT */
- printf(", TFTP: %@", arptable[ARP_SERVER].ipaddr.s_addr);
- if (BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr)
- printf(", Relay: %@",
- BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr);
- if (arptable[ARP_GATEWAY].ipaddr.s_addr)
- printf(", Gateway %@", arptable[ARP_GATEWAY].ipaddr.s_addr);
- #ifdef DNS_RESOLVER
- if (arptable[ARP_NAMESERVER].ipaddr.s_addr)
- printf(", Nameserver %@", arptable[ARP_NAMESERVER].ipaddr.s_addr);
- #endif
- putchar('\n');
-
- #ifdef MDEBUG
- printf("\n=>>"); getchar();
- #endif
-
- /* Now use TFTP to load file */
- #ifdef DOWNLOAD_PROTO_NFS
- rpc_init();
- #endif
- kernel = KERNEL_BUF[0] == '\0' ?
- #ifdef DEFAULT_BOOTFILE
- DEFAULT_BOOTFILE
- #else
- NULL
- #endif
- : KERNEL_BUF;
- if ( kernel ) {
- loadkernel(kernel); /* We don't return except on error */
- printf("Unable to load file.\n");
- } else {
- printf("No filename\n");
- }
- interruptible_sleep(2); /* lay off the server for a while */
- longjmp(restart_etherboot, -1);
- }
-
-
- /**************************************************************************
- 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(ARP_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 == IP_BROADCAST) {
- eth_transmit(broadcast, ETH_P_IP, len, buf);
- #ifdef MULTICAST_LEVEL1
- } 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);
- #endif
- } 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("%@ is not in my arp table!\n", 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(IP);
- arpreq.hwlen = ETH_ALEN;
- arpreq.protolen = 4;
- arpreq.opcode = htons(ARP_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;
- }
-
- #ifdef DOWNLOAD_PROTO_HTTP
- void build_tcp_hdr(unsigned long destip, unsigned int srcsock,
- unsigned int destsock, long send_seq, long recv_seq,
- int window, int flags, int ttl, int len, const void *buf)
- {
- struct iphdr *ip;
- struct tcphdr *tcp;
- ip = (struct iphdr *)buf;
- build_ip_hdr(destip, ttl, IP_TCP, 0, len, buf);
- tcp = (struct tcphdr *)(ip + 1);
- tcp->src = htons(srcsock);
- tcp->dst = htons(destsock);
- tcp->seq = htonl(send_seq);
- tcp->ack = htonl(recv_seq);
- tcp->ctrl = htons(flags + (5 << 12)); /* No TCP options */
- tcp->window = htons(window);
- tcp->chksum = 0;
- if ((tcp->chksum = tcpudpchksum(ip)) == 0)
- tcp->chksum = 0xffff;
- }
- #endif
-
-
- /**************************************************************************
- 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);
- }
-
- /**************************************************************************
- TCP_TRANSMIT - Send a TCP packet
- **************************************************************************/
- #ifdef DOWNLOAD_PROTO_HTTP
- int tcp_transmit(unsigned long destip, unsigned int srcsock,
- unsigned int destsock, long send_seq, long recv_seq,
- int window, int flags, int len, const void *buf)
- {
- build_tcp_hdr(destip, srcsock, destsock, send_seq, recv_seq,
- window, flags, 60, len, buf);
- return ip_transmit(len, buf);
- }
-
- int tcp_reset(struct iphdr *ip) {
- struct tcphdr *tcp = (struct tcphdr *)(ip + 1);
- char buf[sizeof(struct iphdr) + sizeof(struct tcphdr)];
-
- if (!(tcp->ctrl & htons(RST))) {
- long seq = ntohl(tcp->seq) + ntohs(ip->len) -
- sizeof(struct iphdr) -
- ((ntohs(tcp->ctrl) >> 10) & 0x3C);
- if (tcp->ctrl & htons(SYN|FIN))
- seq++;
- return tcp_transmit(ntohl(ip->src.s_addr),
- ntohs(tcp->dst), ntohs(tcp->src),
- tcp->ctrl&htons(ACK) ? ntohl(tcp->ack) : 0,
- seq, TCP_MAX_WINDOW, RST, sizeof(buf), buf);
- }
- return (1);
- }
- #endif
-
- /**************************************************************************
- 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 DOWNLOAD_PROTO_TFTP
- /**************************************************************************
- TFTP - Download extended BOOTP data, or kernel image
- **************************************************************************/
- static int await_tftp(int ival, void *ptr __unused,
- unsigned short ptype __unused, struct iphdr *ip, struct udphdr *udp,
- struct tcphdr *tcp __unused)
- {
- if (!udp) {
- return 0;
- }
- if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)
- return 0;
- if (ntohs(udp->dest) != ival)
- return 0;
- return 1;
- }
-
- int tftp ( const char *name,
- int (*fnc)(unsigned char *, unsigned int, unsigned int, int) )
- {
- struct tftpreq_info_t request_data =
- { name, TFTP_PORT, TFTP_MAX_PACKET };
- struct tftpreq_info_t *request = &request_data;
- struct tftpblk_info_t block;
- int rc;
-
- while ( tftp_block ( request, &block ) ) {
- request = NULL; /* Send request only once */
- rc = fnc ( block.data, block.block, block.len, block.eof );
- if ( rc <= 0 ) return (rc);
- if ( block.eof ) {
- /* fnc should not have returned */
- printf ( "TFTP download complete, but\n" );
- return (0);
- }
- }
- return (0);
- }
-
- int tftp_block ( struct tftpreq_info_t *request, struct tftpblk_info_t *block )
- {
- static unsigned short lport = 2000; /* local port */
- static unsigned short rport = TFTP_PORT; /* remote port */
- struct tftp_t *rcvd = NULL;
- static struct tftpreq_t xmit;
- static unsigned short xmitlen = 0;
- static unsigned short blockidx = 0; /* Last block received */
- static unsigned short retry = 0; /* Retry attempts on last block */
- static int blksize = 0;
- unsigned short recvlen = 0;
-
- /* If this is a new request (i.e. if name is set), fill in
- * transmit block with RRQ and send it.
- */
- if ( request ) {
- rx_qdrain(); /* Flush receive queue */
- xmit.opcode = htons(TFTP_RRQ);
- xmitlen = (void*)&xmit.u.rrq - (void*)&xmit +
- sprintf((char*)xmit.u.rrq, "%s%coctet%cblksize%c%d",
- request->name, 0, 0, 0, request->blksize)
- + 1; /* null terminator */
- blockidx = 0; /* Reset counters */
- retry = 0;
- blksize = TFTP_DEFAULTSIZE_PACKET;
- lport++; /* Use new local port */
- rport = request->port;
- if ( !udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, lport,
- rport, xmitlen, &xmit) )
- return (0);
- }
- /* Exit if no transfer in progress */
- if ( !blksize ) return (0);
- /* Loop to wait until we get a packet we're interested in */
- block->data = NULL; /* Used as flag */
- while ( block->data == NULL ) {
- long timeout = rfc2131_sleep_interval ( blockidx ? TFTP_REXMT :
- TIMEOUT, retry );
- if ( !await_reply(await_tftp, lport, NULL, timeout) ) {
- /* No packet received */
- if ( retry++ > MAX_TFTP_RETRIES ) break;
- /* Retransmit last packet */
- if ( !blockidx ) lport++; /* New lport if new RRQ */
- if ( !udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
- lport, rport, xmitlen, &xmit) )
- return (0);
- continue; /* Back to waiting for packet */
- }
- /* Packet has been received */
- rcvd = (struct tftp_t *)&nic.packet[ETH_HLEN];
- recvlen = ntohs(rcvd->udp.len) - sizeof(struct udphdr)
- - sizeof(rcvd->opcode);
- rport = ntohs(rcvd->udp.src);
- retry = 0; /* Reset retry counter */
- switch ( htons(rcvd->opcode) ) {
- case TFTP_ERROR : {
- printf ( "TFTP error %d (%s)\n",
- ntohs(rcvd->u.err.errcode),
- rcvd->u.err.errmsg );
- return (0); /* abort */
- }
- case TFTP_OACK : {
- const char *p = rcvd->u.oack.data;
- const char *e = p + recvlen - 10; /* "blksize\0\d\0" */
-
- *((char*)(p+recvlen-1)) = '\0'; /* Force final 0 */
- if ( blockidx || !request ) break; /* Too late */
- if ( recvlen <= TFTP_MAX_PACKET ) /* sanity */ {
- /* Check for blksize option honoured */
- while ( p < e ) {
- if ( strcasecmp("blksize",p) == 0 &&
- p[7] == '\0' ) {
- blksize = strtoul(p+8,&p,10);
- p++; /* skip null */
- }
- while ( *(p++) ) {};
- }
- }
- if ( blksize < TFTP_DEFAULTSIZE_PACKET || blksize > request->blksize ) {
- /* Incorrect blksize - error and abort */
- xmit.opcode = htons(TFTP_ERROR);
- xmit.u.err.errcode = 8;
- xmitlen = (void*)&xmit.u.err.errmsg
- - (void*)&xmit
- + sprintf((char*)xmit.u.err.errmsg,
- "RFC1782 error")
- + 1;
- udp_transmit(
- arptable[ARP_SERVER].ipaddr.s_addr,
- lport, rport, xmitlen, &xmit);
- return (0);
- }
- } break;
- case TFTP_DATA :
- if ( ntohs(rcvd->u.data.block) != ( blockidx + 1 ) )
- break; /* Re-ACK last block sent */
- if ( recvlen > ( blksize+sizeof(rcvd->u.data.block) ) )
- break; /* Too large; ignore */
- block->data = rcvd->u.data.download;
- block->block = ++blockidx;
- block->len = recvlen - sizeof(rcvd->u.data.block);
- block->eof = ( (unsigned short)block->len < blksize );
- /* If EOF, zero blksize to indicate transfer done */
- if ( block->eof ) blksize = 0;
- break;
- default: break; /* Do nothing */
- }
- /* Send ACK */
- xmit.opcode = htons(TFTP_ACK);
- xmit.u.ack.block = htons(blockidx);
- xmitlen = TFTP_MIN_PACKET;
- udp_transmit ( arptable[ARP_SERVER].ipaddr.s_addr,
- lport, rport, xmitlen, &xmit );
- }
- return ( block->data ? 1 : 0 );
- }
- #endif /* DOWNLOAD_PROTO_TFTP */
-
- #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_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
- decode_rfc1533(BOOTP_DATA_ADDR->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
- dhcp_machine_info[4] = nic.dev.devid.bus_type;
- dhcp_machine_info[5] = nic.dev.devid.vendor_id & 0xff;
- dhcp_machine_info[6] = ((nic.dev.devid.vendor_id) >> 8) & 0xff;
- dhcp_machine_info[7] = nic.dev.devid.device_id & 0xff;
- dhcp_machine_info[8] = ((nic.dev.devid.device_id) >> 8) & 0xff;
- #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(IP_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, timeout))
- return(1);
- #else
- while ( remaining_time > 0 ) {
- if (await_reply(await_bootp, 0, NULL, remaining_time)){
- }
- 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(IP_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 %@...", arptable[ARP_PROXYDHCP].ipaddr.s_addr);
- 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 */
-
- static 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;
- }
-
- #ifdef MULTICAST_LEVEL2
- static void send_igmp_reports(unsigned long now)
- {
- int i;
- for(i = 0; i < MAX_IGMP; i++) {
- if (igmptable[i].time && (now >= igmptable[i].time)) {
- struct igmp_ip_t igmp;
- igmp.router_alert[0] = 0x94;
- igmp.router_alert[1] = 0x04;
- igmp.router_alert[2] = 0;
- igmp.router_alert[3] = 0;
- build_ip_hdr(igmptable[i].group.s_addr,
- 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
- igmp.igmp.type = IGMPv2_REPORT;
- if (last_igmpv1 &&
- (now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
- igmp.igmp.type = IGMPv1_REPORT;
- }
- igmp.igmp.response_time = 0;
- igmp.igmp.chksum = 0;
- igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
- igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
- ip_transmit(sizeof(igmp), &igmp);
- #ifdef MDEBUG
- printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
- #endif
- /* Don't send another igmp report until asked */
- igmptable[i].time = 0;
- }
- }
- }
-
- static void process_igmp(struct iphdr *ip, unsigned long now)
- {
- struct igmp *igmp;
- int i;
- unsigned iplen;
- if (!ip || (ip->protocol == IP_IGMP) ||
- (nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
- return;
- }
- iplen = (ip->verhdrlen & 0xf)*4;
- igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
- if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
- return;
- if ((igmp->type == IGMP_QUERY) &&
- (ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
- unsigned long interval = IGMP_INTERVAL;
- if (igmp->response_time == 0) {
- last_igmpv1 = now;
- } else {
- interval = (igmp->response_time * TICKS_PER_SEC)/10;
- }
-
- #ifdef MDEBUG
- printf("Received IGMP query for: %@\n", igmp->group.s_addr);
- #endif
- for(i = 0; i < MAX_IGMP; i++) {
- uint32_t group = igmptable[i].group.s_addr;
- if ((group == 0) || (group == igmp->group.s_addr)) {
- unsigned long time;
- time = currticks() + rfc1112_sleep_interval(interval, 0);
- if (time < igmptable[i].time) {
- igmptable[i].time = time;
- }
- }
- }
- }
- if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
- (ip->dest.s_addr == igmp->group.s_addr)) {
- #ifdef MDEBUG
- printf("Received IGMP report for: %@\n", igmp->group.s_addr);
- #endif
- for(i = 0; i < MAX_IGMP; i++) {
- if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
- igmptable[i].time != 0) {
- igmptable[i].time = 0;
- }
- }
- }
- }
-
- void leave_group(int slot)
- {
- /* Be very stupid and always send a leave group message if
- * I have subscribed. Imperfect but it is standards
- * compliant, easy and reliable to implement.
- *
- * The optimal group leave method is to only send leave when,
- * we were the last host to respond to a query on this group,
- * and igmpv1 compatibility is not enabled.
- */
- if (igmptable[slot].group.s_addr) {
- struct igmp_ip_t igmp;
- igmp.router_alert[0] = 0x94;
- igmp.router_alert[1] = 0x04;
- igmp.router_alert[2] = 0;
- igmp.router_alert[3] = 0;
- build_ip_hdr(htonl(GROUP_ALL_HOSTS),
- 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
- igmp.igmp.type = IGMP_LEAVE;
- igmp.igmp.response_time = 0;
- igmp.igmp.chksum = 0;
- igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
- igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
- ip_transmit(sizeof(igmp), &igmp);
- #ifdef MDEBUG
- printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
- #endif
- }
- memset(&igmptable[slot], 0, sizeof(igmptable[0]));
- }
-
- void join_group(int slot, unsigned long group)
- {
- /* I have already joined */
- if (igmptable[slot].group.s_addr == group)
- return;
- if (igmptable[slot].group.s_addr) {
- leave_group(slot);
- }
- /* Only join a group if we are given a multicast ip, this way
- * code can be given a non-multicast (broadcast or unicast ip)
- * and still work...
- */
- if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
- igmptable[slot].group.s_addr = group;
- igmptable[slot].time = currticks();
- }
- }
- #else
- #define send_igmp_reports(now) do {} while(0)
- #define process_igmp(ip, now) do {} while(0)
- #endif
-
- #include "proto_eth_slow.c"
-
- /**************************************************************************
- TCP - Simple-minded TCP stack. Can only send data once and then
- receive the response. The algorithm for computing window
- sizes and delaying ack's is currently broken, and thus
- disabled. Performance would probably improve a little, if
- this gets fixed. FIXME
- **************************************************************************/
- #ifdef DOWNLOAD_PROTO_HTTP
- static int await_tcp(int ival, void *ptr, unsigned short ptype __unused,
- struct iphdr *ip, struct udphdr *udp __unused,
- struct tcphdr *tcp)
- {
- if (!tcp) {
- return 0;
- }
- if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)
- return 0;
- if (ntohs(tcp->dst) != ival) {
- tcp_reset(ip);
- return 0;
- }
- *(void **)ptr = tcp;
- return 1;
- }
-
- int tcp_transaction(unsigned long destip, unsigned int destsock, void *ptr,
- int (*send)(int len, void *buf, void *ptr),
- int (*recv)(int len, const void *buf, void *ptr)) {
- static uint16_t srcsock = 0;
- int rc = 1;
- long send_seq = currticks();
- long recv_seq = 0;
- int can_send = 0;
- int sent_all = 0;
- struct iphdr *ip;
- struct tcphdr *tcp;
- int ctrl = SYN;
- char buf[128]; /* Small outgoing buffer */
- long payload;
- int header_size;
- int window = 3*TCP_MIN_WINDOW;
- long last_ack = 0;
- long last_sent = 0;
- long rtt = 0;
- long srtt = 0;
- long rto = TCP_INITIAL_TIMEOUT;
- int retry = TCP_MAX_TIMEOUT/TCP_INITIAL_TIMEOUT;
- enum { CLOSED, SYN_RCVD, ESTABLISHED,
- FIN_WAIT_1, FIN_WAIT_2 } state = CLOSED;
-
- if (!srcsock) {
- srcsock = currticks();
- }
- if (++srcsock < 1024)
- srcsock += 1024;
-
- await_reply(await_qdrain, 0, NULL, 0);
-
- send_data:
- if (ctrl & ACK)
- last_ack = recv_seq;
- if (!tcp_transmit(destip, srcsock, destsock, send_seq,
- recv_seq, window, ctrl,
- sizeof(struct iphdr) + sizeof(struct tcphdr)+
- can_send, buf)) {
- return (0);
- }
- last_sent = currticks();
-
- recv_data:
- if (!await_reply(await_tcp, srcsock, &tcp,
- (state == ESTABLISHED && !can_send)
- ? TCP_MAX_TIMEOUT : rto)) {
- if (state == ESTABLISHED) {
- close:
- ctrl = FIN|ACK;
- state = FIN_WAIT_1;
- rc = 0;
- goto send_data;
- }
-
- if (state == FIN_WAIT_1 || state == FIN_WAIT_2)
- return (rc);
-
- if (--retry <= 0) {
- /* time out */
- if (state == SYN_RCVD) {
- tcp_transmit(destip, srcsock, destsock,
- send_seq, 0, window, RST,
- sizeof(struct iphdr) +
- sizeof(struct tcphdr), buf);
- }
- return (0);
- }
- /* retransmit */
- goto send_data;
- }
- got_data:
- retry = TCP_MAX_RETRY;
-
- if (tcp->ctrl & htons(ACK) ) {
- char *data;
- int syn_ack, consumed;
-
- if (state == FIN_WAIT_1 || state == FIN_WAIT_2) {
- state = FIN_WAIT_2;
- ctrl = ACK;
- goto consume_data;
- }
- syn_ack = state == CLOSED || state == SYN_RCVD;
- consumed = ntohl(tcp->ack) - send_seq - syn_ack;
- if (consumed < 0 || consumed > can_send) {
- tcp_reset((struct iphdr *)&nic.packet[ETH_HLEN]);
- goto recv_data;
- }
-
- rtt = currticks() - last_sent;
- srtt = !srtt ? rtt : (srtt*4 + rtt)/5;
- rto = srtt + srtt/2;
- if (rto < TCP_MIN_TIMEOUT)
- rto = TCP_MIN_TIMEOUT;
- else if (rto > TCP_MAX_TIMEOUT)
- rto = TCP_MAX_TIMEOUT;
-
- can_send -= consumed;
- send_seq += consumed + syn_ack;
- data = buf + sizeof(struct iphdr) + sizeof(struct tcphdr);
- if (can_send) {
- memmove(data, data + consumed, can_send);
- }
- if (!sent_all) {
- int more_data;
- data += can_send;
- more_data = buf + sizeof(buf) - data;
- if (more_data > 0) {
- more_data = send(more_data, data, ptr);
- can_send += more_data;
- }
- sent_all = !more_data;
- }
- if (state == SYN_RCVD) {
- state = ESTABLISHED;
- ctrl = PSH|ACK;
- goto consume_data;
- }
- if (tcp->ctrl & htons(RST))
- return (0);
- } else if (tcp->ctrl & htons(RST)) {
- if (state == CLOSED)
- goto recv_data;
- return (0);
- }
-
- consume_data:
- ip = (struct iphdr *)&nic.packet[ETH_HLEN];
- header_size = sizeof(struct iphdr) + ((ntohs(tcp->ctrl)>>10)&0x3C);
- payload = ntohs(ip->len) - header_size;
- if (payload > 0 && state == ESTABLISHED) {
- int old_bytes = recv_seq - (long)ntohl(tcp->seq);
- if (old_bytes >= 0 && payload - old_bytes > 0) {
- recv_seq += payload - old_bytes;
- if (state != FIN_WAIT_1 && state != FIN_WAIT_2 &&
- !recv(payload - old_bytes,
- &nic.packet[ETH_HLEN+header_size+old_bytes],
- ptr)) {
- goto close;
- }
- if ((state == ESTABLISHED || state == SYN_RCVD) &&
- !(tcp->ctrl & htons(FIN))) {
- int in_window = window - 2*TCP_MIN_WINDOW >
- recv_seq - last_ack;
- ctrl = can_send ? PSH|ACK : ACK;
- if (!can_send && in_window) {
- /* Window scaling is broken right now, just fall back to acknowledging every */
- /* packet immediately and unconditionally. FIXME */ /***/
- /* if (await_reply(await_tcp, srcsock,
- &tcp, rto))
- goto got_data;
- else */
- goto send_data;
- }
- if (!in_window) {
- window += TCP_MIN_WINDOW;
- if (window > TCP_MAX_WINDOW)
- window = TCP_MAX_WINDOW;
- }
- goto send_data;
- }
- } else {
- /* saw old data again, must have lost packets */
- window /= 2;
- if (window < 2*TCP_MIN_WINDOW)
- window = 2*TCP_MIN_WINDOW;
- }
- }
-
- if (tcp->ctrl & htons(FIN)) {
- if (state == ESTABLISHED) {
- ctrl = FIN|ACK;
- } else if (state == FIN_WAIT_1 || state == FIN_WAIT_2) {
- ctrl = ACK;
- } else {
- ctrl = RST;
- }
- return (tcp_transmit(destip, srcsock, destsock,
- send_seq, recv_seq + 1, window, ctrl,
- sizeof(struct iphdr) +
- sizeof(struct tcphdr), buf) &&
- (state == ESTABLISHED ||
- state == FIN_WAIT_1 || state == FIN_WAIT_2) &&
- !can_send);
- }
-
- if (state == CLOSED) {
- if (tcp->ctrl & htons(SYN)) {
- recv_seq = ntohl(tcp->seq) + 1;
- if (!(tcp->ctrl & htons(ACK))) {
- state = SYN_RCVD;
- ctrl = SYN|ACK|PSH;
- goto send_data;
- } else {
- state = ESTABLISHED;
- ctrl = PSH|ACK;
- }
- }
- }
-
- if (can_send || payload) {
- goto send_data;
- }
- goto recv_data;
- }
- #endif
-
- /**************************************************************************
- 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();
- send_eth_slow_reports(now);
- send_igmp_reports(now);
- result = eth_poll(1);
- if (result == 0) {
- /* We don't have anything */
-
- /* Check for abort key only if the Rx queue is empty -
- * as long as we have something to process, don't
- * assume that something failed. It is unlikely that
- * we have no processing time left between packets. */
- poll_interruptions();
- /* 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;
- #ifdef DOWNLOAD_PROTO_HTTP
- 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;
- }
-
- }
- #endif
- 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(ARP_REQUEST)) &&
- (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
- arpreply->opcode = htons(ARP_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: %@\n",tmp);
- #endif /* MDEBUG */
- }
- }
- process_eth_slow(ptype, now);
- process_igmp(ip, 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
- 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_ADDR->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 (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
- #ifdef DNS_RESOLVER
- 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));
- }
- #endif
- 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);
- 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;
- #ifdef BACKOFF_LIMIT
- if (exp > BACKOFF_LIMIT)
- exp = BACKOFF_LIMIT;
- #endif
- tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
- return tmo;
- }
-
- #ifdef MULTICAST_LEVEL2
- /**************************************************************************
- RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
- **************************************************************************/
- long rfc1112_sleep_interval(long base, int exp)
- {
- unsigned long divisor, tmo;
- #ifdef BACKOFF_LIMIT
- if (exp > BACKOFF_LIMIT)
- exp = BACKOFF_LIMIT;
- #endif
- divisor = RAND_MAX/(base << exp);
- tmo = random()/divisor;
- return tmo;
- }
- #endif /* MULTICAST_LEVEL_2 */
|