11b8adde7SWilliam Kucharski /**************************************************************************
21b8adde7SWilliam Kucharski Etherboot - Network Bootstrap Program
31b8adde7SWilliam Kucharski
41b8adde7SWilliam Kucharski Literature dealing with the network protocols:
51b8adde7SWilliam Kucharski ARP - RFC826
61b8adde7SWilliam Kucharski RARP - RFC903
71b8adde7SWilliam Kucharski IP - RFC791
81b8adde7SWilliam Kucharski UDP - RFC768
91b8adde7SWilliam Kucharski BOOTP - RFC951, RFC2132 (vendor extensions)
101b8adde7SWilliam Kucharski DHCP - RFC2131, RFC2132 (options)
111b8adde7SWilliam Kucharski TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
121b8adde7SWilliam Kucharski RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
131b8adde7SWilliam Kucharski NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
141b8adde7SWilliam Kucharski IGMP - RFC1112, RFC2113, RFC2365, RFC2236, RFC3171
151b8adde7SWilliam Kucharski
161b8adde7SWilliam Kucharski **************************************************************************/
171b8adde7SWilliam Kucharski #include "etherboot.h"
181b8adde7SWilliam Kucharski #include "grub.h"
191b8adde7SWilliam Kucharski #include "nic.h"
201b8adde7SWilliam Kucharski #include "elf.h" /* FOR EM_CURRENT */
211b8adde7SWilliam Kucharski #include "bootp.h"
221b8adde7SWilliam Kucharski #include "if_arp.h"
231b8adde7SWilliam Kucharski #include "tftp.h"
241b8adde7SWilliam Kucharski #include "timer.h"
251b8adde7SWilliam Kucharski #include "ip.h"
261b8adde7SWilliam Kucharski #include "udp.h"
271b8adde7SWilliam Kucharski
281b8adde7SWilliam Kucharski /* Currently no other module uses rom, but it is available */
291b8adde7SWilliam Kucharski struct rom_info rom;
301b8adde7SWilliam Kucharski struct arptable_t arptable[MAX_ARP];
311b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
321b8adde7SWilliam Kucharski unsigned long last_igmpv1 = 0;
331b8adde7SWilliam Kucharski struct igmptable_t igmptable[MAX_IGMP];
341b8adde7SWilliam Kucharski #endif
351b8adde7SWilliam Kucharski static unsigned long netmask;
361b8adde7SWilliam Kucharski /* Used by nfs.c */
371b8adde7SWilliam Kucharski char *hostname = "";
381b8adde7SWilliam Kucharski int hostnamelen = 0;
391b8adde7SWilliam Kucharski /* Used by fsys_tftp.c */
401b8adde7SWilliam Kucharski int use_bios_pxe = 0;
411b8adde7SWilliam Kucharski static uint32_t xid;
421b8adde7SWilliam Kucharski static unsigned char *end_of_rfc1533 = NULL;
431b8adde7SWilliam Kucharski static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
441b8adde7SWilliam Kucharski static const in_addr zeroIP = { 0L };
451b8adde7SWilliam Kucharski static char rfc1533_venddata[MAX_RFC1533_VENDLEN];
461b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie[4] = { RFC1533_COOKIE };
471b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie_bootp[5] = { RFC1533_COOKIE, RFC1533_END };
481b8adde7SWilliam Kucharski static unsigned char rfc1533_cookie_dhcp[] = { RFC1533_COOKIE };
491b8adde7SWilliam Kucharski static int dhcp_reply;
501b8adde7SWilliam Kucharski static in_addr dhcp_server = { 0L };
511b8adde7SWilliam Kucharski static in_addr dhcp_addr = { 0L };
521b8adde7SWilliam Kucharski
531b8adde7SWilliam Kucharski static const unsigned char dhcpdiscover[] = {
541b8adde7SWilliam Kucharski RFC2132_MSG_TYPE, 1, DHCPDISCOVER,
551b8adde7SWilliam Kucharski RFC2132_MAX_SIZE, 2, /* request as much as we can */
561b8adde7SWilliam Kucharski ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
571b8adde7SWilliam Kucharski /* Vendor class identifier */
581b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
591b8adde7SWilliam Kucharski RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
601b8adde7SWilliam Kucharski 'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
611b8adde7SWilliam Kucharski '0','0','2','0','0','1',
621b8adde7SWilliam Kucharski #else
631b8adde7SWilliam Kucharski RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
641b8adde7SWilliam Kucharski #endif
651b8adde7SWilliam Kucharski RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY,
661b8adde7SWilliam Kucharski RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, RFC1533_END
671b8adde7SWilliam Kucharski };
681b8adde7SWilliam Kucharski static const unsigned char dhcprequest [] = {
691b8adde7SWilliam Kucharski RFC2132_MSG_TYPE,1,DHCPREQUEST,
701b8adde7SWilliam Kucharski RFC2132_SRV_ID,4,0,0,0,0,
711b8adde7SWilliam Kucharski RFC2132_REQ_ADDR,4,0,0,0,0,
721b8adde7SWilliam Kucharski RFC2132_MAX_SIZE,2, /* request as much as we can */
731b8adde7SWilliam Kucharski ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
741b8adde7SWilliam Kucharski /* Vendor class identifier */
751b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
761b8adde7SWilliam Kucharski RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
771b8adde7SWilliam Kucharski 'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
781b8adde7SWilliam Kucharski '0','0','2','0','0','1',
791b8adde7SWilliam Kucharski #else
801b8adde7SWilliam Kucharski RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
811b8adde7SWilliam Kucharski #endif
821b8adde7SWilliam Kucharski RFC2132_PARAM_LIST,
831b8adde7SWilliam Kucharski /* 4 standard + 2 vendortags */
841b8adde7SWilliam Kucharski 4 + 2,
851b8adde7SWilliam Kucharski /* Standard parameters */
861b8adde7SWilliam Kucharski RFC1533_NETMASK, RFC1533_GATEWAY,
871b8adde7SWilliam Kucharski RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
881b8adde7SWilliam Kucharski /* Etherboot vendortags */
891b8adde7SWilliam Kucharski RFC1533_VENDOR_MAGIC,
901b8adde7SWilliam Kucharski RFC1533_VENDOR_CONFIGFILE,
911b8adde7SWilliam Kucharski RFC1533_END
921b8adde7SWilliam Kucharski };
931b8adde7SWilliam Kucharski
941b8adde7SWilliam Kucharski /* See nic.h */
951b8adde7SWilliam Kucharski int user_abort = 0;
961b8adde7SWilliam Kucharski int network_ready = 0;
971b8adde7SWilliam Kucharski
981b8adde7SWilliam Kucharski #ifdef REQUIRE_VCI_ETHERBOOT
991b8adde7SWilliam Kucharski int vci_etherboot;
1001b8adde7SWilliam Kucharski #endif
1011b8adde7SWilliam Kucharski
102*2506833eSJan Setje-Eilers char *bootfile = NULL;
103*2506833eSJan Setje-Eilers configfile_origin_t configfile_origin = CFG_HARDCODED;
104*2506833eSJan Setje-Eilers char *vendor_configfile = NULL;
105*2506833eSJan Setje-Eilers char vendor_configfile_len;
106*2506833eSJan Setje-Eilers
1071b8adde7SWilliam Kucharski static void update_network_configuration(void);
1081b8adde7SWilliam Kucharski
dummy(void * unused __unused)1091b8adde7SWilliam Kucharski static int dummy(void *unused __unused)
1101b8adde7SWilliam Kucharski {
1111b8adde7SWilliam Kucharski return (0);
1121b8adde7SWilliam Kucharski }
1131b8adde7SWilliam Kucharski
1141b8adde7SWilliam Kucharski /* Careful. We need an aligned buffer to avoid problems on machines
1151b8adde7SWilliam Kucharski * that care about alignment. To trivally align the ethernet data
1161b8adde7SWilliam Kucharski * (the ip hdr and arp requests) we offset the packet by 2 bytes.
1171b8adde7SWilliam Kucharski * leaving the ethernet data 16 byte aligned. Beyond this
1181b8adde7SWilliam Kucharski * we use memmove but this makes the common cast simple and fast.
1191b8adde7SWilliam Kucharski */
1201b8adde7SWilliam Kucharski static char packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned;
1211b8adde7SWilliam Kucharski
1221b8adde7SWilliam Kucharski struct nic nic =
1231b8adde7SWilliam Kucharski {
1241b8adde7SWilliam Kucharski {
1251b8adde7SWilliam Kucharski 0, /* dev.disable */
1261b8adde7SWilliam Kucharski {
1271b8adde7SWilliam Kucharski 0,
1281b8adde7SWilliam Kucharski 0,
1291b8adde7SWilliam Kucharski PCI_BUS_TYPE,
1301b8adde7SWilliam Kucharski }, /* dev.devid */
1311b8adde7SWilliam Kucharski 0, /* index */
1321b8adde7SWilliam Kucharski 0, /* type */
1331b8adde7SWilliam Kucharski PROBE_FIRST, /* how_pobe */
1341b8adde7SWilliam Kucharski PROBE_NONE, /* to_probe */
1351b8adde7SWilliam Kucharski 0, /* failsafe */
1361b8adde7SWilliam Kucharski 0, /* type_index */
1371b8adde7SWilliam Kucharski {}, /* state */
1381b8adde7SWilliam Kucharski },
1391b8adde7SWilliam Kucharski (int (*)(struct nic *, int))dummy, /* poll */
1401b8adde7SWilliam Kucharski (void (*)(struct nic *, const char *,
1411b8adde7SWilliam Kucharski unsigned int, unsigned int,
1421b8adde7SWilliam Kucharski const char *))dummy, /* transmit */
1431b8adde7SWilliam Kucharski (void (*)(struct nic *, irq_action_t))dummy, /* irq */
1441b8adde7SWilliam Kucharski 0, /* flags */
1451b8adde7SWilliam Kucharski &rom, /* rom_info */
1461b8adde7SWilliam Kucharski arptable[ARP_CLIENT].node, /* node_addr */
1471b8adde7SWilliam Kucharski packet + ETH_DATA_ALIGN, /* packet */
1481b8adde7SWilliam Kucharski 0, /* packetlen */
1491b8adde7SWilliam Kucharski 0, /* ioaddr */
1501b8adde7SWilliam Kucharski 0, /* irqno */
1511b8adde7SWilliam Kucharski NULL, /* priv_data */
1521b8adde7SWilliam Kucharski };
1531b8adde7SWilliam Kucharski
1541b8adde7SWilliam Kucharski
1551b8adde7SWilliam Kucharski
grub_eth_probe(void)1561b8adde7SWilliam Kucharski int grub_eth_probe(void)
1571b8adde7SWilliam Kucharski {
1581b8adde7SWilliam Kucharski static int probed = 0;
1591b8adde7SWilliam Kucharski struct dev *dev;
1601b8adde7SWilliam Kucharski
1611b8adde7SWilliam Kucharski EnterFunction("grub_eth_probe");
1621b8adde7SWilliam Kucharski
1631b8adde7SWilliam Kucharski if (probed)
1641b8adde7SWilliam Kucharski return 1;
1651b8adde7SWilliam Kucharski
1661b8adde7SWilliam Kucharski network_ready = 0;
1671b8adde7SWilliam Kucharski grub_memset((char *)arptable, 0, MAX_ARP * sizeof(struct arptable_t));
1681b8adde7SWilliam Kucharski dev = &nic.dev;
1691b8adde7SWilliam Kucharski dev->how_probe = -1;
1701b8adde7SWilliam Kucharski dev->type = NIC_DRIVER;
1711b8adde7SWilliam Kucharski dev->failsafe = 1;
1721b8adde7SWilliam Kucharski rom = *((struct rom_info *)ROM_INFO_LOCATION);
1731b8adde7SWilliam Kucharski
1741b8adde7SWilliam Kucharski probed = (eth_probe(dev) == PROBE_WORKED);
1751b8adde7SWilliam Kucharski
1761b8adde7SWilliam Kucharski LeaveFunction("grub_eth_probe");
1771b8adde7SWilliam Kucharski return probed;
1781b8adde7SWilliam Kucharski }
1791b8adde7SWilliam Kucharski
eth_probe(struct dev * dev)1801b8adde7SWilliam Kucharski int eth_probe(struct dev *dev)
1811b8adde7SWilliam Kucharski {
1821b8adde7SWilliam Kucharski return probe(dev);
1831b8adde7SWilliam Kucharski }
1841b8adde7SWilliam Kucharski
eth_poll(int retrieve)1851b8adde7SWilliam Kucharski int eth_poll(int retrieve)
1861b8adde7SWilliam Kucharski {
1871b8adde7SWilliam Kucharski return ((*nic.poll)(&nic, retrieve));
1881b8adde7SWilliam Kucharski }
1891b8adde7SWilliam Kucharski
eth_transmit(const char * d,unsigned int t,unsigned int s,const void * p)1901b8adde7SWilliam Kucharski void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p)
1911b8adde7SWilliam Kucharski {
1921b8adde7SWilliam Kucharski (*nic.transmit)(&nic, d, t, s, p);
1931b8adde7SWilliam Kucharski if (t == IP) twiddle();
1941b8adde7SWilliam Kucharski }
1951b8adde7SWilliam Kucharski
eth_disable(void)1961b8adde7SWilliam Kucharski void eth_disable(void)
1971b8adde7SWilliam Kucharski {
1981b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
1991b8adde7SWilliam Kucharski int i;
2001b8adde7SWilliam Kucharski for(i = 0; i < MAX_IGMP; i++) {
2011b8adde7SWilliam Kucharski leave_group(i);
2021b8adde7SWilliam Kucharski }
2031b8adde7SWilliam Kucharski #endif
2041b8adde7SWilliam Kucharski disable(&nic.dev);
2051b8adde7SWilliam Kucharski }
2061b8adde7SWilliam Kucharski
eth_irq(irq_action_t action)2071b8adde7SWilliam Kucharski void eth_irq (irq_action_t action)
2081b8adde7SWilliam Kucharski {
2091b8adde7SWilliam Kucharski (*nic.irq)(&nic,action);
2101b8adde7SWilliam Kucharski }
2111b8adde7SWilliam Kucharski
2121b8adde7SWilliam Kucharski /**************************************************************************
2131b8adde7SWilliam Kucharski IPCHKSUM - Checksum IP Header
2141b8adde7SWilliam Kucharski **************************************************************************/
ipchksum(const void * data,unsigned long length)2151b8adde7SWilliam Kucharski uint16_t ipchksum(const void *data, unsigned long length)
2161b8adde7SWilliam Kucharski {
2171b8adde7SWilliam Kucharski unsigned long sum;
2181b8adde7SWilliam Kucharski unsigned long i;
2191b8adde7SWilliam Kucharski const uint8_t *ptr;
2201b8adde7SWilliam Kucharski
2211b8adde7SWilliam Kucharski /* In the most straight forward way possible,
2221b8adde7SWilliam Kucharski * compute an ip style checksum.
2231b8adde7SWilliam Kucharski */
2241b8adde7SWilliam Kucharski sum = 0;
2251b8adde7SWilliam Kucharski ptr = data;
2261b8adde7SWilliam Kucharski for(i = 0; i < length; i++) {
2271b8adde7SWilliam Kucharski unsigned long value;
2281b8adde7SWilliam Kucharski value = ptr[i];
2291b8adde7SWilliam Kucharski if (i & 1) {
2301b8adde7SWilliam Kucharski value <<= 8;
2311b8adde7SWilliam Kucharski }
2321b8adde7SWilliam Kucharski /* Add the new value */
2331b8adde7SWilliam Kucharski sum += value;
2341b8adde7SWilliam Kucharski /* Wrap around the carry */
2351b8adde7SWilliam Kucharski if (sum > 0xFFFF) {
2361b8adde7SWilliam Kucharski sum = (sum + (sum >> 16)) & 0xFFFF;
2371b8adde7SWilliam Kucharski }
2381b8adde7SWilliam Kucharski }
2391b8adde7SWilliam Kucharski return (~cpu_to_le16(sum)) & 0xFFFF;
2401b8adde7SWilliam Kucharski }
2411b8adde7SWilliam Kucharski
add_ipchksums(unsigned long offset,uint16_t sum,uint16_t new)2421b8adde7SWilliam Kucharski uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
2431b8adde7SWilliam Kucharski {
2441b8adde7SWilliam Kucharski unsigned long checksum;
2451b8adde7SWilliam Kucharski sum = ~sum & 0xFFFF;
2461b8adde7SWilliam Kucharski new = ~new & 0xFFFF;
2471b8adde7SWilliam Kucharski if (offset & 1) {
2481b8adde7SWilliam Kucharski /* byte swap the sum if it came from an odd offset
2491b8adde7SWilliam Kucharski * since the computation is endian independant this
2501b8adde7SWilliam Kucharski * works.
2511b8adde7SWilliam Kucharski */
2521b8adde7SWilliam Kucharski new = bswap_16(new);
2531b8adde7SWilliam Kucharski }
2541b8adde7SWilliam Kucharski checksum = sum + new;
2551b8adde7SWilliam Kucharski if (checksum > 0xFFFF) {
2561b8adde7SWilliam Kucharski checksum -= 0xFFFF;
2571b8adde7SWilliam Kucharski }
2581b8adde7SWilliam Kucharski return (~checksum) & 0xFFFF;
2591b8adde7SWilliam Kucharski }
2601b8adde7SWilliam Kucharski
2611b8adde7SWilliam Kucharski /**************************************************************************
2621b8adde7SWilliam Kucharski DEFAULT_NETMASK - Return default netmask for IP address
2631b8adde7SWilliam Kucharski **************************************************************************/
default_netmask(void)2641b8adde7SWilliam Kucharski static inline unsigned long default_netmask(void)
2651b8adde7SWilliam Kucharski {
2661b8adde7SWilliam Kucharski int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
2671b8adde7SWilliam Kucharski if (net <= 127)
2681b8adde7SWilliam Kucharski return(htonl(0xff000000));
2691b8adde7SWilliam Kucharski else if (net < 192)
2701b8adde7SWilliam Kucharski return(htonl(0xffff0000));
2711b8adde7SWilliam Kucharski else
2721b8adde7SWilliam Kucharski return(htonl(0xffffff00));
2731b8adde7SWilliam Kucharski }
2741b8adde7SWilliam Kucharski
2751b8adde7SWilliam Kucharski /**************************************************************************
2761b8adde7SWilliam Kucharski IP_TRANSMIT - Send an IP datagram
2771b8adde7SWilliam Kucharski **************************************************************************/
await_arp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip __unused,struct udphdr * udp __unused)2781b8adde7SWilliam Kucharski static int await_arp(int ival, void *ptr,
2791b8adde7SWilliam Kucharski unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused)
2801b8adde7SWilliam Kucharski {
2811b8adde7SWilliam Kucharski struct arprequest *arpreply;
2821b8adde7SWilliam Kucharski if (ptype != ARP)
2831b8adde7SWilliam Kucharski return 0;
2841b8adde7SWilliam Kucharski if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
2851b8adde7SWilliam Kucharski return 0;
2861b8adde7SWilliam Kucharski arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
2871b8adde7SWilliam Kucharski
2881b8adde7SWilliam Kucharski if (arpreply->opcode != htons(ARP_REPLY))
2891b8adde7SWilliam Kucharski return 0;
2901b8adde7SWilliam Kucharski if (memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) != 0)
2911b8adde7SWilliam Kucharski return 0;
2921b8adde7SWilliam Kucharski memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN);
2931b8adde7SWilliam Kucharski return 1;
2941b8adde7SWilliam Kucharski }
2951b8adde7SWilliam Kucharski
ip_transmit(int len,const void * buf)2961b8adde7SWilliam Kucharski int ip_transmit(int len, const void *buf)
2971b8adde7SWilliam Kucharski {
2981b8adde7SWilliam Kucharski unsigned long destip;
2991b8adde7SWilliam Kucharski struct iphdr *ip;
3001b8adde7SWilliam Kucharski struct arprequest arpreq;
3011b8adde7SWilliam Kucharski int arpentry, i;
3021b8adde7SWilliam Kucharski int retry;
3031b8adde7SWilliam Kucharski
3041b8adde7SWilliam Kucharski ip = (struct iphdr *)buf;
3051b8adde7SWilliam Kucharski destip = ip->dest.s_addr;
3061b8adde7SWilliam Kucharski if (destip == IP_BROADCAST) {
3071b8adde7SWilliam Kucharski eth_transmit(broadcast, IP, len, buf);
3081b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL1
3091b8adde7SWilliam Kucharski } else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
3101b8adde7SWilliam Kucharski unsigned char multicast[6];
3111b8adde7SWilliam Kucharski unsigned long hdestip;
3121b8adde7SWilliam Kucharski hdestip = ntohl(destip);
3131b8adde7SWilliam Kucharski multicast[0] = 0x01;
3141b8adde7SWilliam Kucharski multicast[1] = 0x00;
3151b8adde7SWilliam Kucharski multicast[2] = 0x5e;
3161b8adde7SWilliam Kucharski multicast[3] = (hdestip >> 16) & 0x7;
3171b8adde7SWilliam Kucharski multicast[4] = (hdestip >> 8) & 0xff;
3181b8adde7SWilliam Kucharski multicast[5] = hdestip & 0xff;
3191b8adde7SWilliam Kucharski eth_transmit(multicast, IP, len, buf);
3201b8adde7SWilliam Kucharski #endif
3211b8adde7SWilliam Kucharski } else {
3221b8adde7SWilliam Kucharski if (((destip & netmask) !=
3231b8adde7SWilliam Kucharski (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
3241b8adde7SWilliam Kucharski arptable[ARP_GATEWAY].ipaddr.s_addr)
3251b8adde7SWilliam Kucharski destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
3261b8adde7SWilliam Kucharski for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
3271b8adde7SWilliam Kucharski if (arptable[arpentry].ipaddr.s_addr == destip) break;
3281b8adde7SWilliam Kucharski if (arpentry == MAX_ARP) {
3291b8adde7SWilliam Kucharski printf("%@ is not in my arp table!\n", destip);
3301b8adde7SWilliam Kucharski return(0);
3311b8adde7SWilliam Kucharski }
3321b8adde7SWilliam Kucharski for (i = 0; i < ETH_ALEN; i++)
3331b8adde7SWilliam Kucharski if (arptable[arpentry].node[i])
3341b8adde7SWilliam Kucharski break;
3351b8adde7SWilliam Kucharski if (i == ETH_ALEN) { /* Need to do arp request */
3361b8adde7SWilliam Kucharski arpreq.hwtype = htons(1);
3371b8adde7SWilliam Kucharski arpreq.protocol = htons(IP);
3381b8adde7SWilliam Kucharski arpreq.hwlen = ETH_ALEN;
3391b8adde7SWilliam Kucharski arpreq.protolen = 4;
3401b8adde7SWilliam Kucharski arpreq.opcode = htons(ARP_REQUEST);
3411b8adde7SWilliam Kucharski memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
3421b8adde7SWilliam Kucharski memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
3431b8adde7SWilliam Kucharski memset(arpreq.thwaddr, 0, ETH_ALEN);
3441b8adde7SWilliam Kucharski memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
3451b8adde7SWilliam Kucharski for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
3461b8adde7SWilliam Kucharski long timeout;
3471b8adde7SWilliam Kucharski eth_transmit(broadcast, ARP, sizeof(arpreq),
3481b8adde7SWilliam Kucharski &arpreq);
3491b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, retry);
3501b8adde7SWilliam Kucharski if (await_reply(await_arp, arpentry,
3511b8adde7SWilliam Kucharski arpreq.tipaddr, timeout)) goto xmit;
3521b8adde7SWilliam Kucharski }
3531b8adde7SWilliam Kucharski return(0);
3541b8adde7SWilliam Kucharski }
3551b8adde7SWilliam Kucharski xmit:
3561b8adde7SWilliam Kucharski eth_transmit(arptable[arpentry].node, IP, len, buf);
3571b8adde7SWilliam Kucharski }
3581b8adde7SWilliam Kucharski return 1;
3591b8adde7SWilliam Kucharski }
3601b8adde7SWilliam Kucharski
build_ip_hdr(unsigned long destip,int ttl,int protocol,int option_len,int len,const void * buf)3611b8adde7SWilliam Kucharski void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len,
3621b8adde7SWilliam Kucharski int len, const void *buf)
3631b8adde7SWilliam Kucharski {
3641b8adde7SWilliam Kucharski struct iphdr *ip;
3651b8adde7SWilliam Kucharski ip = (struct iphdr *)buf;
3661b8adde7SWilliam Kucharski ip->verhdrlen = 0x45;
3671b8adde7SWilliam Kucharski ip->verhdrlen += (option_len/4);
3681b8adde7SWilliam Kucharski ip->service = 0;
3691b8adde7SWilliam Kucharski ip->len = htons(len);
3701b8adde7SWilliam Kucharski ip->ident = 0;
3711b8adde7SWilliam Kucharski ip->frags = 0; /* Should we set don't fragment? */
3721b8adde7SWilliam Kucharski ip->ttl = ttl;
3731b8adde7SWilliam Kucharski ip->protocol = protocol;
3741b8adde7SWilliam Kucharski ip->chksum = 0;
3751b8adde7SWilliam Kucharski ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
3761b8adde7SWilliam Kucharski ip->dest.s_addr = destip;
3771b8adde7SWilliam Kucharski ip->chksum = ipchksum(buf, sizeof(struct iphdr) + option_len);
3781b8adde7SWilliam Kucharski }
3791b8adde7SWilliam Kucharski
udpchksum(struct iphdr * ip,struct udphdr * udp)3801b8adde7SWilliam Kucharski static uint16_t udpchksum(struct iphdr *ip, struct udphdr *udp)
3811b8adde7SWilliam Kucharski {
3821b8adde7SWilliam Kucharski struct udp_pseudo_hdr pseudo;
3831b8adde7SWilliam Kucharski uint16_t checksum;
3841b8adde7SWilliam Kucharski
3851b8adde7SWilliam Kucharski /* Compute the pseudo header */
3861b8adde7SWilliam Kucharski pseudo.src.s_addr = ip->src.s_addr;
3871b8adde7SWilliam Kucharski pseudo.dest.s_addr = ip->dest.s_addr;
3881b8adde7SWilliam Kucharski pseudo.unused = 0;
3891b8adde7SWilliam Kucharski pseudo.protocol = IP_UDP;
3901b8adde7SWilliam Kucharski pseudo.len = udp->len;
3911b8adde7SWilliam Kucharski
3921b8adde7SWilliam Kucharski /* Sum the pseudo header */
3931b8adde7SWilliam Kucharski checksum = ipchksum(&pseudo, 12);
3941b8adde7SWilliam Kucharski
3951b8adde7SWilliam Kucharski /* Sum the rest of the udp packet */
3961b8adde7SWilliam Kucharski checksum = add_ipchksums(12, checksum, ipchksum(udp, ntohs(udp->len)));
3971b8adde7SWilliam Kucharski return checksum;
3981b8adde7SWilliam Kucharski }
3991b8adde7SWilliam Kucharski
4001b8adde7SWilliam Kucharski
build_udp_hdr(unsigned long destip,unsigned int srcsock,unsigned int destsock,int ttl,int len,const void * buf)4011b8adde7SWilliam Kucharski void build_udp_hdr(unsigned long destip,
4021b8adde7SWilliam Kucharski unsigned int srcsock, unsigned int destsock, int ttl,
4031b8adde7SWilliam Kucharski int len, const void *buf)
4041b8adde7SWilliam Kucharski {
4051b8adde7SWilliam Kucharski struct iphdr *ip;
4061b8adde7SWilliam Kucharski struct udphdr *udp;
4071b8adde7SWilliam Kucharski ip = (struct iphdr *)buf;
4081b8adde7SWilliam Kucharski build_ip_hdr(destip, ttl, IP_UDP, 0, len, buf);
4091b8adde7SWilliam Kucharski udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr));
4101b8adde7SWilliam Kucharski udp->src = htons(srcsock);
4111b8adde7SWilliam Kucharski udp->dest = htons(destsock);
4121b8adde7SWilliam Kucharski udp->len = htons(len - sizeof(struct iphdr));
4131b8adde7SWilliam Kucharski udp->chksum = 0;
4141b8adde7SWilliam Kucharski if ((udp->chksum = udpchksum(ip, udp)) == 0)
4151b8adde7SWilliam Kucharski udp->chksum = 0xffff;
4161b8adde7SWilliam Kucharski }
4171b8adde7SWilliam Kucharski
4181b8adde7SWilliam Kucharski
4191b8adde7SWilliam Kucharski /**************************************************************************
4201b8adde7SWilliam Kucharski UDP_TRANSMIT - Send an UDP datagram
4211b8adde7SWilliam Kucharski **************************************************************************/
udp_transmit(unsigned long destip,unsigned int srcsock,unsigned int destsock,int len,const void * buf)4221b8adde7SWilliam Kucharski int udp_transmit(unsigned long destip, unsigned int srcsock,
4231b8adde7SWilliam Kucharski unsigned int destsock, int len, const void *buf)
4241b8adde7SWilliam Kucharski {
4251b8adde7SWilliam Kucharski build_udp_hdr(destip, srcsock, destsock, 60, len, buf);
4261b8adde7SWilliam Kucharski return ip_transmit(len, buf);
4271b8adde7SWilliam Kucharski }
4281b8adde7SWilliam Kucharski
4291b8adde7SWilliam Kucharski /**************************************************************************
4301b8adde7SWilliam Kucharski QDRAIN - clear the nic's receive queue
4311b8adde7SWilliam Kucharski **************************************************************************/
await_qdrain(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp __unused)4321b8adde7SWilliam Kucharski static int await_qdrain(int ival __unused, void *ptr __unused,
4331b8adde7SWilliam Kucharski unsigned short ptype __unused,
4341b8adde7SWilliam Kucharski struct iphdr *ip __unused, struct udphdr *udp __unused)
4351b8adde7SWilliam Kucharski {
4361b8adde7SWilliam Kucharski return 0;
4371b8adde7SWilliam Kucharski }
4381b8adde7SWilliam Kucharski
rx_qdrain(void)4391b8adde7SWilliam Kucharski void rx_qdrain(void)
4401b8adde7SWilliam Kucharski {
4411b8adde7SWilliam Kucharski /* Clear out the Rx queue first. It contains nothing of interest,
4421b8adde7SWilliam Kucharski * except possibly ARP requests from the DHCP/TFTP server. We use
4431b8adde7SWilliam Kucharski * polling throughout Etherboot, so some time may have passed since we
4441b8adde7SWilliam Kucharski * last polled the receive queue, which may now be filled with
4451b8adde7SWilliam Kucharski * broadcast packets. This will cause the reply to the packets we are
4461b8adde7SWilliam Kucharski * about to send to be lost immediately. Not very clever. */
4471b8adde7SWilliam Kucharski await_reply(await_qdrain, 0, NULL, 0);
4481b8adde7SWilliam Kucharski }
4491b8adde7SWilliam Kucharski
4501b8adde7SWilliam Kucharski /**
4511b8adde7SWilliam Kucharski * rarp
4521b8adde7SWilliam Kucharski *
4531b8adde7SWilliam Kucharski * Get IP address by rarp. Just copy from etherboot
4541b8adde7SWilliam Kucharski **/
await_rarp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip,struct udphdr * udp)4551b8adde7SWilliam Kucharski static int await_rarp(int ival, void *ptr, unsigned short ptype,
4561b8adde7SWilliam Kucharski struct iphdr *ip, struct udphdr *udp)
4571b8adde7SWilliam Kucharski {
4581b8adde7SWilliam Kucharski struct arprequest *arpreply;
4591b8adde7SWilliam Kucharski if (ptype != RARP)
4601b8adde7SWilliam Kucharski return 0;
4611b8adde7SWilliam Kucharski if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
4621b8adde7SWilliam Kucharski return 0;
4631b8adde7SWilliam Kucharski arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
4641b8adde7SWilliam Kucharski if (arpreply->opcode != htons(RARP_REPLY))
4651b8adde7SWilliam Kucharski return 0;
4661b8adde7SWilliam Kucharski if (memcmp(arpreply->thwaddr, ptr, ETH_ALEN) == 0){
4671b8adde7SWilliam Kucharski memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN);
4681b8adde7SWilliam Kucharski memcpy(&arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
4691b8adde7SWilliam Kucharski memcpy(&arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
4701b8adde7SWilliam Kucharski memset(&arptable[ARP_GATEWAY].ipaddr, 0, sizeof(in_addr));
4711b8adde7SWilliam Kucharski return 1;
4721b8adde7SWilliam Kucharski }
4731b8adde7SWilliam Kucharski return 0;
4741b8adde7SWilliam Kucharski }
4751b8adde7SWilliam Kucharski
rarp(void)4761b8adde7SWilliam Kucharski int rarp(void)
4771b8adde7SWilliam Kucharski {
4781b8adde7SWilliam Kucharski int retry;
4791b8adde7SWilliam Kucharski
4801b8adde7SWilliam Kucharski /* arp and rarp requests share the same packet structure. */
4811b8adde7SWilliam Kucharski struct arprequest rarpreq;
4821b8adde7SWilliam Kucharski
4831b8adde7SWilliam Kucharski if(!grub_eth_probe())
4841b8adde7SWilliam Kucharski return 0;
4851b8adde7SWilliam Kucharski network_ready = 0;
4861b8adde7SWilliam Kucharski
4871b8adde7SWilliam Kucharski memset(&rarpreq, 0, sizeof(rarpreq));
4881b8adde7SWilliam Kucharski
4891b8adde7SWilliam Kucharski rarpreq.hwtype = htons(1);
4901b8adde7SWilliam Kucharski rarpreq.protocol = htons(IP);
4911b8adde7SWilliam Kucharski rarpreq.hwlen = ETH_ALEN;
4921b8adde7SWilliam Kucharski rarpreq.protolen = 4;
4931b8adde7SWilliam Kucharski rarpreq.opcode = htons(RARP_REQUEST);
4941b8adde7SWilliam Kucharski memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4951b8adde7SWilliam Kucharski /* sipaddr is already zeroed out */
4961b8adde7SWilliam Kucharski memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4971b8adde7SWilliam Kucharski /* tipaddr is already zeroed out */
4981b8adde7SWilliam Kucharski
4991b8adde7SWilliam Kucharski for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) {
5001b8adde7SWilliam Kucharski long timeout;
5011b8adde7SWilliam Kucharski eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
5021b8adde7SWilliam Kucharski
5031b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, retry);
5041b8adde7SWilliam Kucharski if (await_reply(await_rarp, 0, rarpreq.shwaddr, timeout))
5051b8adde7SWilliam Kucharski break;
5061b8adde7SWilliam Kucharski if (user_abort)
5071b8adde7SWilliam Kucharski return 0;
5081b8adde7SWilliam Kucharski }
5091b8adde7SWilliam Kucharski
5101b8adde7SWilliam Kucharski if (retry == MAX_ARP_RETRIES) {
5111b8adde7SWilliam Kucharski return (0);
5121b8adde7SWilliam Kucharski }
5131b8adde7SWilliam Kucharski
5141b8adde7SWilliam Kucharski network_ready = 1;
5151b8adde7SWilliam Kucharski update_network_configuration();
5161b8adde7SWilliam Kucharski return (1);
5171b8adde7SWilliam Kucharski }
5181b8adde7SWilliam Kucharski
5191b8adde7SWilliam Kucharski /**
5201b8adde7SWilliam Kucharski * bootp
5211b8adde7SWilliam Kucharski *
5221b8adde7SWilliam Kucharski * Get IP address by bootp, segregate from bootp in etherboot.
5231b8adde7SWilliam Kucharski **/
await_bootp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)5241b8adde7SWilliam Kucharski static int await_bootp(int ival __unused, void *ptr __unused,
5251b8adde7SWilliam Kucharski unsigned short ptype __unused, struct iphdr *ip __unused,
5261b8adde7SWilliam Kucharski struct udphdr *udp)
5271b8adde7SWilliam Kucharski {
5281b8adde7SWilliam Kucharski struct bootp_t *bootpreply;
5291b8adde7SWilliam Kucharski int len; /* Length of vendor */
5301b8adde7SWilliam Kucharski
5311b8adde7SWilliam Kucharski if (!udp) {
5321b8adde7SWilliam Kucharski return 0;
5331b8adde7SWilliam Kucharski }
5341b8adde7SWilliam Kucharski bootpreply = (struct bootp_t *)
5351b8adde7SWilliam Kucharski &nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
5361b8adde7SWilliam Kucharski len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
5371b8adde7SWilliam Kucharski sizeof(struct udphdr) + sizeof(struct bootp_t) - BOOTP_VENDOR_LEN);
5381b8adde7SWilliam Kucharski if (len < 0) {
5391b8adde7SWilliam Kucharski return 0;
5401b8adde7SWilliam Kucharski }
5411b8adde7SWilliam Kucharski if (udp->dest != htons(BOOTP_CLIENT))
5421b8adde7SWilliam Kucharski return 0;
5431b8adde7SWilliam Kucharski if (bootpreply->bp_op != BOOTP_REPLY)
5441b8adde7SWilliam Kucharski return 0;
5451b8adde7SWilliam Kucharski if (bootpreply->bp_xid != xid)
5461b8adde7SWilliam Kucharski return 0;
5471b8adde7SWilliam Kucharski if (memcmp((char *)&bootpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
5481b8adde7SWilliam Kucharski return 0;
5491b8adde7SWilliam Kucharski if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) &&
5501b8adde7SWilliam Kucharski (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) {
5511b8adde7SWilliam Kucharski return 0;
5521b8adde7SWilliam Kucharski }
5531b8adde7SWilliam Kucharski
5541b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
5551b8adde7SWilliam Kucharski /* fill in netinfo */
5561b8adde7SWilliam Kucharski dhcpack_length = len + sizeof (struct bootp_t) - BOOTP_VENDOR_LEN;
5571b8adde7SWilliam Kucharski memcpy((char *)dhcpack_buf, (char *)bootpreply, dhcpack_length);
5581b8adde7SWilliam Kucharski #endif
5591b8adde7SWilliam Kucharski
5601b8adde7SWilliam Kucharski arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
5611b8adde7SWilliam Kucharski netmask = default_netmask();
5621b8adde7SWilliam Kucharski arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
5631b8adde7SWilliam Kucharski memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
5641b8adde7SWilliam Kucharski arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
5651b8adde7SWilliam Kucharski memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
566*2506833eSJan Setje-Eilers bootfile = bootpreply->bp_file;
5671b8adde7SWilliam Kucharski memcpy((char *)rfc1533_venddata, (char *)(bootpreply->bp_vend), len);
5681b8adde7SWilliam Kucharski decode_rfc1533(rfc1533_venddata, 0, len, 1);
5691b8adde7SWilliam Kucharski return(1);
5701b8adde7SWilliam Kucharski }
5711b8adde7SWilliam Kucharski
bootp(void)5721b8adde7SWilliam Kucharski int bootp(void)
5731b8adde7SWilliam Kucharski {
5741b8adde7SWilliam Kucharski int retry;
5751b8adde7SWilliam Kucharski struct bootpip_t ip;
5761b8adde7SWilliam Kucharski unsigned long starttime;
5771b8adde7SWilliam Kucharski
5781b8adde7SWilliam Kucharski EnterFunction("bootp");
5791b8adde7SWilliam Kucharski
5801b8adde7SWilliam Kucharski if(!grub_eth_probe())
5811b8adde7SWilliam Kucharski return 0;
5821b8adde7SWilliam Kucharski network_ready = 0;
5831b8adde7SWilliam Kucharski
5841b8adde7SWilliam Kucharski memset(&ip, 0, sizeof(struct bootpip_t));
5851b8adde7SWilliam Kucharski ip.bp.bp_op = BOOTP_REQUEST;
5861b8adde7SWilliam Kucharski ip.bp.bp_htype = 1;
5871b8adde7SWilliam Kucharski ip.bp.bp_hlen = ETH_ALEN;
5881b8adde7SWilliam Kucharski starttime = currticks();
5891b8adde7SWilliam Kucharski /* Use lower 32 bits of node address, more likely to be
5901b8adde7SWilliam Kucharski distinct than the time since booting */
5911b8adde7SWilliam Kucharski memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
5921b8adde7SWilliam Kucharski ip.bp.bp_xid = xid += htonl(starttime);
5931b8adde7SWilliam Kucharski /* bp_secs defaults to zero */
5941b8adde7SWilliam Kucharski memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
5951b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend, rfc1533_cookie_bootp, sizeof(rfc1533_cookie_bootp)); /* request RFC-style options */
5961b8adde7SWilliam Kucharski
5971b8adde7SWilliam Kucharski for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
5981b8adde7SWilliam Kucharski long timeout;
5991b8adde7SWilliam Kucharski
6001b8adde7SWilliam Kucharski rx_qdrain();
6011b8adde7SWilliam Kucharski
6021b8adde7SWilliam Kucharski udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
6031b8adde7SWilliam Kucharski sizeof(struct bootpip_t), &ip);
6041b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
6051b8adde7SWilliam Kucharski if (await_reply(await_bootp, 0, NULL, timeout)){
6061b8adde7SWilliam Kucharski network_ready = 1;
6071b8adde7SWilliam Kucharski return(1);
6081b8adde7SWilliam Kucharski }
6091b8adde7SWilliam Kucharski if (user_abort)
6101b8adde7SWilliam Kucharski return 0;
6111b8adde7SWilliam Kucharski ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
6121b8adde7SWilliam Kucharski }
6131b8adde7SWilliam Kucharski return(0);
6141b8adde7SWilliam Kucharski }
6151b8adde7SWilliam Kucharski
6161b8adde7SWilliam Kucharski /**
6171b8adde7SWilliam Kucharski * dhcp
6181b8adde7SWilliam Kucharski *
6191b8adde7SWilliam Kucharski * Get IP address by dhcp, segregate from bootp in etherboot.
6201b8adde7SWilliam Kucharski **/
await_dhcp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)6211b8adde7SWilliam Kucharski static int await_dhcp(int ival __unused, void *ptr __unused,
6221b8adde7SWilliam Kucharski unsigned short ptype __unused, struct iphdr *ip __unused,
6231b8adde7SWilliam Kucharski struct udphdr *udp)
6241b8adde7SWilliam Kucharski {
6251b8adde7SWilliam Kucharski struct dhcp_t *dhcpreply;
6261b8adde7SWilliam Kucharski int len;
6271b8adde7SWilliam Kucharski
6281b8adde7SWilliam Kucharski if (!udp) {
6291b8adde7SWilliam Kucharski return 0;
6301b8adde7SWilliam Kucharski }
6311b8adde7SWilliam Kucharski dhcpreply = (struct dhcp_t *)
6321b8adde7SWilliam Kucharski &nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
6331b8adde7SWilliam Kucharski len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
6341b8adde7SWilliam Kucharski sizeof(struct udphdr) + sizeof(struct dhcp_t) - DHCP_OPT_LEN);
6351b8adde7SWilliam Kucharski if (len < 0){
6361b8adde7SWilliam Kucharski return 0;
6371b8adde7SWilliam Kucharski }
6381b8adde7SWilliam Kucharski if (udp->dest != htons(BOOTP_CLIENT))
6391b8adde7SWilliam Kucharski return 0;
6401b8adde7SWilliam Kucharski if (dhcpreply->bp_op != BOOTP_REPLY)
6411b8adde7SWilliam Kucharski return 0;
6421b8adde7SWilliam Kucharski if (dhcpreply->bp_xid != xid)
6431b8adde7SWilliam Kucharski return 0;
6441b8adde7SWilliam Kucharski if (memcmp((char *)&dhcpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
6451b8adde7SWilliam Kucharski return 0;
6461b8adde7SWilliam Kucharski if ((memcmp(broadcast, dhcpreply->bp_hwaddr, ETH_ALEN) != 0) &&
6471b8adde7SWilliam Kucharski (memcmp(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN) != 0)) {
6481b8adde7SWilliam Kucharski return 0;
6491b8adde7SWilliam Kucharski }
6501b8adde7SWilliam Kucharski
6511b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
6521b8adde7SWilliam Kucharski /* fill in netinfo */
6531b8adde7SWilliam Kucharski dhcpack_length = len + sizeof (struct dhcp_t) - DHCP_OPT_LEN;
6541b8adde7SWilliam Kucharski memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
6551b8adde7SWilliam Kucharski #endif
6561b8adde7SWilliam Kucharski arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6571b8adde7SWilliam Kucharski dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6581b8adde7SWilliam Kucharski netmask = default_netmask();
6591b8adde7SWilliam Kucharski arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
6601b8adde7SWilliam Kucharski memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
6611b8adde7SWilliam Kucharski arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
6621b8adde7SWilliam Kucharski memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
663*2506833eSJan Setje-Eilers bootfile = dhcpreply->bp_file;
6641b8adde7SWilliam Kucharski memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
6651b8adde7SWilliam Kucharski decode_rfc1533(rfc1533_venddata, 0, len, 1);
6661b8adde7SWilliam Kucharski return(1);
6671b8adde7SWilliam Kucharski }
6681b8adde7SWilliam Kucharski
dhcp(void)6691b8adde7SWilliam Kucharski int dhcp(void)
6701b8adde7SWilliam Kucharski {
6711b8adde7SWilliam Kucharski int retry;
6721b8adde7SWilliam Kucharski int reqretry;
6731b8adde7SWilliam Kucharski struct dhcpip_t ip;
6741b8adde7SWilliam Kucharski unsigned long starttime;
6751b8adde7SWilliam Kucharski
6761b8adde7SWilliam Kucharski /* try bios pxe stack first */
6771b8adde7SWilliam Kucharski if (dhcp_undi())
6781b8adde7SWilliam Kucharski return 1;
6791b8adde7SWilliam Kucharski
6801b8adde7SWilliam Kucharski if(!grub_eth_probe())
6811b8adde7SWilliam Kucharski return 0;
6821b8adde7SWilliam Kucharski
6831b8adde7SWilliam Kucharski network_ready = 0;
6841b8adde7SWilliam Kucharski
6851b8adde7SWilliam Kucharski memset(&ip, 0, sizeof(ip));
6861b8adde7SWilliam Kucharski ip.bp.bp_op = BOOTP_REQUEST;
6871b8adde7SWilliam Kucharski ip.bp.bp_htype = 1;
6881b8adde7SWilliam Kucharski ip.bp.bp_hlen = ETH_ALEN;
6891b8adde7SWilliam Kucharski starttime = currticks();
6901b8adde7SWilliam Kucharski /* Use lower 32 bits of node address, more likely to be
6911b8adde7SWilliam Kucharski distinct than the time since booting */
6921b8adde7SWilliam Kucharski memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
6931b8adde7SWilliam Kucharski ip.bp.bp_xid = xid += htonl(starttime);
6941b8adde7SWilliam Kucharski memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
6951b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp); /* request RFC-style options */
6961b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcpdiscover, sizeof dhcpdiscover);
6971b8adde7SWilliam Kucharski
6981b8adde7SWilliam Kucharski for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
6991b8adde7SWilliam Kucharski long timeout;
7001b8adde7SWilliam Kucharski
7011b8adde7SWilliam Kucharski rx_qdrain();
7021b8adde7SWilliam Kucharski
7031b8adde7SWilliam Kucharski udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7041b8adde7SWilliam Kucharski sizeof(ip), &ip);
7051b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
7061b8adde7SWilliam Kucharski if (await_reply(await_dhcp, 0, NULL, timeout)) {
7071b8adde7SWilliam Kucharski /* If not a DHCPOFFER then must be just a
7081b8adde7SWilliam Kucharski BOOTP reply, be backward compatible with
7091b8adde7SWilliam Kucharski BOOTP then. Jscott report a bug here, but I
7101b8adde7SWilliam Kucharski don't know how it happened */
7111b8adde7SWilliam Kucharski if (dhcp_reply != DHCPOFFER){
7121b8adde7SWilliam Kucharski network_ready = 1;
7131b8adde7SWilliam Kucharski return(1);
7141b8adde7SWilliam Kucharski }
7151b8adde7SWilliam Kucharski dhcp_reply = 0;
7161b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp);
7171b8adde7SWilliam Kucharski memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcprequest, sizeof dhcprequest);
7181b8adde7SWilliam Kucharski /* Beware: the magic numbers 9 and 15 depend on
7191b8adde7SWilliam Kucharski the layout of dhcprequest */
7201b8adde7SWilliam Kucharski memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr));
7211b8adde7SWilliam Kucharski memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr));
7221b8adde7SWilliam Kucharski for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) {
7231b8adde7SWilliam Kucharski udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7241b8adde7SWilliam Kucharski sizeof(ip), &ip);
7251b8adde7SWilliam Kucharski dhcp_reply=0;
7261b8adde7SWilliam Kucharski timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++);
7271b8adde7SWilliam Kucharski if (await_reply(await_dhcp, 0, NULL, timeout))
7281b8adde7SWilliam Kucharski if (dhcp_reply == DHCPACK){
7291b8adde7SWilliam Kucharski network_ready = 1;
7301b8adde7SWilliam Kucharski return(1);
7311b8adde7SWilliam Kucharski }
7321b8adde7SWilliam Kucharski if (user_abort)
7331b8adde7SWilliam Kucharski return 0;
7341b8adde7SWilliam Kucharski }
7351b8adde7SWilliam Kucharski }
7361b8adde7SWilliam Kucharski if (user_abort)
7371b8adde7SWilliam Kucharski return 0;
7381b8adde7SWilliam Kucharski ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
7391b8adde7SWilliam Kucharski }
7401b8adde7SWilliam Kucharski return(0);
7411b8adde7SWilliam Kucharski }
7421b8adde7SWilliam Kucharski
7431b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
send_igmp_reports(unsigned long now)7441b8adde7SWilliam Kucharski static void send_igmp_reports(unsigned long now)
7451b8adde7SWilliam Kucharski {
7461b8adde7SWilliam Kucharski int i;
7471b8adde7SWilliam Kucharski for(i = 0; i < MAX_IGMP; i++) {
7481b8adde7SWilliam Kucharski if (igmptable[i].time && (now >= igmptable[i].time)) {
7491b8adde7SWilliam Kucharski struct igmp_ip_t igmp;
7501b8adde7SWilliam Kucharski igmp.router_alert[0] = 0x94;
7511b8adde7SWilliam Kucharski igmp.router_alert[1] = 0x04;
7521b8adde7SWilliam Kucharski igmp.router_alert[2] = 0;
7531b8adde7SWilliam Kucharski igmp.router_alert[3] = 0;
7541b8adde7SWilliam Kucharski build_ip_hdr(igmptable[i].group.s_addr,
7551b8adde7SWilliam Kucharski 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
7561b8adde7SWilliam Kucharski igmp.igmp.type = IGMPv2_REPORT;
7571b8adde7SWilliam Kucharski if (last_igmpv1 &&
7581b8adde7SWilliam Kucharski (now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
7591b8adde7SWilliam Kucharski igmp.igmp.type = IGMPv1_REPORT;
7601b8adde7SWilliam Kucharski }
7611b8adde7SWilliam Kucharski igmp.igmp.response_time = 0;
7621b8adde7SWilliam Kucharski igmp.igmp.chksum = 0;
7631b8adde7SWilliam Kucharski igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
7641b8adde7SWilliam Kucharski igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
7651b8adde7SWilliam Kucharski ip_transmit(sizeof(igmp), &igmp);
7661b8adde7SWilliam Kucharski #ifdef MDEBUG
7671b8adde7SWilliam Kucharski printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
7681b8adde7SWilliam Kucharski #endif
7691b8adde7SWilliam Kucharski /* Don't send another igmp report until asked */
7701b8adde7SWilliam Kucharski igmptable[i].time = 0;
7711b8adde7SWilliam Kucharski }
7721b8adde7SWilliam Kucharski }
7731b8adde7SWilliam Kucharski }
7741b8adde7SWilliam Kucharski
process_igmp(struct iphdr * ip,unsigned long now)7751b8adde7SWilliam Kucharski static void process_igmp(struct iphdr *ip, unsigned long now)
7761b8adde7SWilliam Kucharski {
7771b8adde7SWilliam Kucharski struct igmp *igmp;
7781b8adde7SWilliam Kucharski int i;
7791b8adde7SWilliam Kucharski unsigned iplen = 0;
7801b8adde7SWilliam Kucharski if (!ip || (ip->protocol == IP_IGMP) ||
7811b8adde7SWilliam Kucharski (nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
7821b8adde7SWilliam Kucharski return;
7831b8adde7SWilliam Kucharski }
7841b8adde7SWilliam Kucharski iplen = (ip->verhdrlen & 0xf)*4;
7851b8adde7SWilliam Kucharski igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
7861b8adde7SWilliam Kucharski if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
7871b8adde7SWilliam Kucharski return;
7881b8adde7SWilliam Kucharski if ((igmp->type == IGMP_QUERY) &&
7891b8adde7SWilliam Kucharski (ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
7901b8adde7SWilliam Kucharski unsigned long interval = IGMP_INTERVAL;
7911b8adde7SWilliam Kucharski if (igmp->response_time == 0) {
7921b8adde7SWilliam Kucharski last_igmpv1 = now;
7931b8adde7SWilliam Kucharski } else {
7941b8adde7SWilliam Kucharski interval = (igmp->response_time * TICKS_PER_SEC)/10;
7951b8adde7SWilliam Kucharski }
7961b8adde7SWilliam Kucharski
7971b8adde7SWilliam Kucharski #ifdef MDEBUG
7981b8adde7SWilliam Kucharski printf("Received IGMP query for: %@\n", igmp->group.s_addr);
7991b8adde7SWilliam Kucharski #endif
8001b8adde7SWilliam Kucharski for(i = 0; i < MAX_IGMP; i++) {
8011b8adde7SWilliam Kucharski uint32_t group = igmptable[i].group.s_addr;
8021b8adde7SWilliam Kucharski if ((group == 0) || (group == igmp->group.s_addr)) {
8031b8adde7SWilliam Kucharski unsigned long time;
8041b8adde7SWilliam Kucharski time = currticks() + rfc1112_sleep_interval(interval, 0);
8051b8adde7SWilliam Kucharski if (time < igmptable[i].time) {
8061b8adde7SWilliam Kucharski igmptable[i].time = time;
8071b8adde7SWilliam Kucharski }
8081b8adde7SWilliam Kucharski }
8091b8adde7SWilliam Kucharski }
8101b8adde7SWilliam Kucharski }
8111b8adde7SWilliam Kucharski if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
8121b8adde7SWilliam Kucharski (ip->dest.s_addr == igmp->group.s_addr)) {
8131b8adde7SWilliam Kucharski #ifdef MDEBUG
8141b8adde7SWilliam Kucharski printf("Received IGMP report for: %@\n", igmp->group.s_addr);
8151b8adde7SWilliam Kucharski #endif
8161b8adde7SWilliam Kucharski for(i = 0; i < MAX_IGMP; i++) {
8171b8adde7SWilliam Kucharski if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
8181b8adde7SWilliam Kucharski igmptable[i].time != 0) {
8191b8adde7SWilliam Kucharski igmptable[i].time = 0;
8201b8adde7SWilliam Kucharski }
8211b8adde7SWilliam Kucharski }
8221b8adde7SWilliam Kucharski }
8231b8adde7SWilliam Kucharski }
8241b8adde7SWilliam Kucharski
leave_group(int slot)8251b8adde7SWilliam Kucharski void leave_group(int slot)
8261b8adde7SWilliam Kucharski {
8271b8adde7SWilliam Kucharski /* Be very stupid and always send a leave group message if
8281b8adde7SWilliam Kucharski * I have subscribed. Imperfect but it is standards
8291b8adde7SWilliam Kucharski * compliant, easy and reliable to implement.
8301b8adde7SWilliam Kucharski *
8311b8adde7SWilliam Kucharski * The optimal group leave method is to only send leave when,
8321b8adde7SWilliam Kucharski * we were the last host to respond to a query on this group,
8331b8adde7SWilliam Kucharski * and igmpv1 compatibility is not enabled.
8341b8adde7SWilliam Kucharski */
8351b8adde7SWilliam Kucharski if (igmptable[slot].group.s_addr) {
8361b8adde7SWilliam Kucharski struct igmp_ip_t igmp;
8371b8adde7SWilliam Kucharski igmp.router_alert[0] = 0x94;
8381b8adde7SWilliam Kucharski igmp.router_alert[1] = 0x04;
8391b8adde7SWilliam Kucharski igmp.router_alert[2] = 0;
8401b8adde7SWilliam Kucharski igmp.router_alert[3] = 0;
8411b8adde7SWilliam Kucharski build_ip_hdr(htonl(GROUP_ALL_HOSTS),
8421b8adde7SWilliam Kucharski 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
8431b8adde7SWilliam Kucharski igmp.igmp.type = IGMP_LEAVE;
8441b8adde7SWilliam Kucharski igmp.igmp.response_time = 0;
8451b8adde7SWilliam Kucharski igmp.igmp.chksum = 0;
8461b8adde7SWilliam Kucharski igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
8471b8adde7SWilliam Kucharski igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
8481b8adde7SWilliam Kucharski ip_transmit(sizeof(igmp), &igmp);
8491b8adde7SWilliam Kucharski #ifdef MDEBUG
8501b8adde7SWilliam Kucharski printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
8511b8adde7SWilliam Kucharski #endif
8521b8adde7SWilliam Kucharski }
8531b8adde7SWilliam Kucharski memset(&igmptable[slot], 0, sizeof(igmptable[0]));
8541b8adde7SWilliam Kucharski }
8551b8adde7SWilliam Kucharski
join_group(int slot,unsigned long group)8561b8adde7SWilliam Kucharski void join_group(int slot, unsigned long group)
8571b8adde7SWilliam Kucharski {
8581b8adde7SWilliam Kucharski /* I have already joined */
8591b8adde7SWilliam Kucharski if (igmptable[slot].group.s_addr == group)
8601b8adde7SWilliam Kucharski return;
8611b8adde7SWilliam Kucharski if (igmptable[slot].group.s_addr) {
8621b8adde7SWilliam Kucharski leave_group(slot);
8631b8adde7SWilliam Kucharski }
8641b8adde7SWilliam Kucharski /* Only join a group if we are given a multicast ip, this way
8651b8adde7SWilliam Kucharski * code can be given a non-multicast (broadcast or unicast ip)
8661b8adde7SWilliam Kucharski * and still work...
8671b8adde7SWilliam Kucharski */
8681b8adde7SWilliam Kucharski if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
8691b8adde7SWilliam Kucharski igmptable[slot].group.s_addr = group;
8701b8adde7SWilliam Kucharski igmptable[slot].time = currticks();
8711b8adde7SWilliam Kucharski }
8721b8adde7SWilliam Kucharski }
8731b8adde7SWilliam Kucharski #else
8741b8adde7SWilliam Kucharski #define send_igmp_reports(now);
8751b8adde7SWilliam Kucharski #define process_igmp(ip, now)
8761b8adde7SWilliam Kucharski #endif
8771b8adde7SWilliam Kucharski
8781b8adde7SWilliam Kucharski /**************************************************************************
8791b8adde7SWilliam Kucharski AWAIT_REPLY - Wait until we get a response for our request
8801b8adde7SWilliam Kucharski ************f**************************************************************/
await_reply(reply_t reply,int ival,void * ptr,long timeout)8811b8adde7SWilliam Kucharski int await_reply(reply_t reply, int ival, void *ptr, long timeout)
8821b8adde7SWilliam Kucharski {
8831b8adde7SWilliam Kucharski unsigned long time, now;
8841b8adde7SWilliam Kucharski struct iphdr *ip;
8851b8adde7SWilliam Kucharski unsigned iplen = 0;
8861b8adde7SWilliam Kucharski struct udphdr *udp;
8871b8adde7SWilliam Kucharski unsigned short ptype;
8881b8adde7SWilliam Kucharski int result;
8891b8adde7SWilliam Kucharski
8901b8adde7SWilliam Kucharski user_abort = 0;
8911b8adde7SWilliam Kucharski
8921b8adde7SWilliam Kucharski time = timeout + currticks();
8931b8adde7SWilliam Kucharski /* The timeout check is done below. The timeout is only checked if
8941b8adde7SWilliam Kucharski * there is no packet in the Rx queue. This assumes that eth_poll()
8951b8adde7SWilliam Kucharski * needs a negligible amount of time.
8961b8adde7SWilliam Kucharski */
8971b8adde7SWilliam Kucharski for (;;) {
8981b8adde7SWilliam Kucharski now = currticks();
8991b8adde7SWilliam Kucharski send_igmp_reports(now);
9001b8adde7SWilliam Kucharski result = eth_poll(1);
9011b8adde7SWilliam Kucharski if (result == 0) {
9021b8adde7SWilliam Kucharski /* We don't have anything */
9031b8adde7SWilliam Kucharski
9041b8adde7SWilliam Kucharski /* Check for abort key only if the Rx queue is empty -
9051b8adde7SWilliam Kucharski * as long as we have something to process, don't
9061b8adde7SWilliam Kucharski * assume that something failed. It is unlikely that
9071b8adde7SWilliam Kucharski * we have no processing time left between packets. */
9081b8adde7SWilliam Kucharski poll_interruptions();
9091b8adde7SWilliam Kucharski /* Do the timeout after at least a full queue walk. */
9101b8adde7SWilliam Kucharski if ((timeout == 0) || (currticks() > time) || user_abort == 1) {
9111b8adde7SWilliam Kucharski break;
9121b8adde7SWilliam Kucharski }
9131b8adde7SWilliam Kucharski continue;
9141b8adde7SWilliam Kucharski }
9151b8adde7SWilliam Kucharski
9161b8adde7SWilliam Kucharski /* We have something! */
9171b8adde7SWilliam Kucharski
9181b8adde7SWilliam Kucharski /* Find the Ethernet packet type */
9191b8adde7SWilliam Kucharski if (nic.packetlen >= ETH_HLEN) {
9201b8adde7SWilliam Kucharski ptype = ((unsigned short) nic.packet[12]) << 8
9211b8adde7SWilliam Kucharski | ((unsigned short) nic.packet[13]);
9221b8adde7SWilliam Kucharski } else continue; /* what else could we do with it? */
9231b8adde7SWilliam Kucharski /* Verify an IP header */
9241b8adde7SWilliam Kucharski ip = 0;
9251b8adde7SWilliam Kucharski if ((ptype == IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
9261b8adde7SWilliam Kucharski unsigned ipoptlen;
9271b8adde7SWilliam Kucharski ip = (struct iphdr *)&nic.packet[ETH_HLEN];
9281b8adde7SWilliam Kucharski if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F))
9291b8adde7SWilliam Kucharski continue;
9301b8adde7SWilliam Kucharski iplen = (ip->verhdrlen & 0xf) * 4;
9311b8adde7SWilliam Kucharski if (ipchksum(ip, iplen) != 0)
9321b8adde7SWilliam Kucharski continue;
9331b8adde7SWilliam Kucharski if (ip->frags & htons(0x3FFF)) {
9341b8adde7SWilliam Kucharski static int warned_fragmentation = 0;
9351b8adde7SWilliam Kucharski if (!warned_fragmentation) {
9361b8adde7SWilliam Kucharski printf("ALERT: got a fragmented packet - reconfigure your server\n");
9371b8adde7SWilliam Kucharski warned_fragmentation = 1;
9381b8adde7SWilliam Kucharski }
9391b8adde7SWilliam Kucharski continue;
9401b8adde7SWilliam Kucharski }
9411b8adde7SWilliam Kucharski if (ntohs(ip->len) > ETH_MAX_MTU)
9421b8adde7SWilliam Kucharski continue;
9431b8adde7SWilliam Kucharski
9441b8adde7SWilliam Kucharski ipoptlen = iplen - sizeof(struct iphdr);
9451b8adde7SWilliam Kucharski if (ipoptlen) {
9461b8adde7SWilliam Kucharski /* Delete the ip options, to guarantee
9471b8adde7SWilliam Kucharski * good alignment, and make etherboot simpler.
9481b8adde7SWilliam Kucharski */
9491b8adde7SWilliam Kucharski memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)],
9501b8adde7SWilliam Kucharski &nic.packet[ETH_HLEN + iplen],
9511b8adde7SWilliam Kucharski nic.packetlen - ipoptlen);
9521b8adde7SWilliam Kucharski nic.packetlen -= ipoptlen;
9531b8adde7SWilliam Kucharski }
9541b8adde7SWilliam Kucharski }
9551b8adde7SWilliam Kucharski udp = 0;
9561b8adde7SWilliam Kucharski if (ip && (ip->protocol == IP_UDP) &&
9571b8adde7SWilliam Kucharski (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) {
9581b8adde7SWilliam Kucharski udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
9591b8adde7SWilliam Kucharski
9601b8adde7SWilliam Kucharski /* Make certain we have a reasonable packet length */
9611b8adde7SWilliam Kucharski if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
9621b8adde7SWilliam Kucharski continue;
9631b8adde7SWilliam Kucharski
9641b8adde7SWilliam Kucharski if (udp->chksum && udpchksum(ip, udp)) {
9651b8adde7SWilliam Kucharski printf("UDP checksum error\n");
9661b8adde7SWilliam Kucharski continue;
9671b8adde7SWilliam Kucharski }
9681b8adde7SWilliam Kucharski }
9691b8adde7SWilliam Kucharski result = reply(ival, ptr, ptype, ip, udp);
9701b8adde7SWilliam Kucharski if (result > 0) {
9711b8adde7SWilliam Kucharski return result;
9721b8adde7SWilliam Kucharski }
9731b8adde7SWilliam Kucharski
9741b8adde7SWilliam Kucharski /* If it isn't a packet the upper layer wants see if there is a default
9751b8adde7SWilliam Kucharski * action. This allows us reply to arp and igmp queryies.
9761b8adde7SWilliam Kucharski */
9771b8adde7SWilliam Kucharski if ((ptype == ARP) &&
9781b8adde7SWilliam Kucharski (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
9791b8adde7SWilliam Kucharski struct arprequest *arpreply;
9801b8adde7SWilliam Kucharski unsigned long tmp;
9811b8adde7SWilliam Kucharski
9821b8adde7SWilliam Kucharski arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
9831b8adde7SWilliam Kucharski memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9841b8adde7SWilliam Kucharski if ((arpreply->opcode == htons(ARP_REQUEST)) &&
9851b8adde7SWilliam Kucharski (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
9861b8adde7SWilliam Kucharski arpreply->opcode = htons(ARP_REPLY);
9871b8adde7SWilliam Kucharski memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
9881b8adde7SWilliam Kucharski memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
9891b8adde7SWilliam Kucharski memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
9901b8adde7SWilliam Kucharski memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
9911b8adde7SWilliam Kucharski eth_transmit(arpreply->thwaddr, ARP,
9921b8adde7SWilliam Kucharski sizeof(struct arprequest),
9931b8adde7SWilliam Kucharski arpreply);
9941b8adde7SWilliam Kucharski #ifdef MDEBUG
9951b8adde7SWilliam Kucharski memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9961b8adde7SWilliam Kucharski printf("Sent ARP reply to: %@\n",tmp);
9971b8adde7SWilliam Kucharski #endif /* MDEBUG */
9981b8adde7SWilliam Kucharski }
9991b8adde7SWilliam Kucharski }
10001b8adde7SWilliam Kucharski process_igmp(ip, now);
10011b8adde7SWilliam Kucharski }
10021b8adde7SWilliam Kucharski return(0);
10031b8adde7SWilliam Kucharski }
10041b8adde7SWilliam Kucharski
10051b8adde7SWilliam Kucharski #ifdef REQUIRE_VCI_ETHERBOOT
10061b8adde7SWilliam Kucharski /**************************************************************************
10071b8adde7SWilliam Kucharski FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers
10081b8adde7SWilliam Kucharski On entry p points to byte count of VCI options
10091b8adde7SWilliam Kucharski **************************************************************************/
find_vci_etherboot(unsigned char * p)10101b8adde7SWilliam Kucharski static int find_vci_etherboot(unsigned char *p)
10111b8adde7SWilliam Kucharski {
10121b8adde7SWilliam Kucharski unsigned char *end = p + 1 + *p;
10131b8adde7SWilliam Kucharski
10141b8adde7SWilliam Kucharski for (p++; p < end; ) {
10151b8adde7SWilliam Kucharski if (*p == RFC2132_VENDOR_CLASS_ID) {
10161b8adde7SWilliam Kucharski if (strncmp("Etherboot", p + 2, sizeof("Etherboot") - 1) == 0)
10171b8adde7SWilliam Kucharski return (1);
10181b8adde7SWilliam Kucharski } else if (*p == RFC1533_END)
10191b8adde7SWilliam Kucharski return (0);
10201b8adde7SWilliam Kucharski p += TAG_LEN(p) + 2;
10211b8adde7SWilliam Kucharski }
10221b8adde7SWilliam Kucharski return (0);
10231b8adde7SWilliam Kucharski }
10241b8adde7SWilliam Kucharski #endif /* REQUIRE_VCI_ETHERBOOT */
10251b8adde7SWilliam Kucharski
10261b8adde7SWilliam Kucharski /**
10271b8adde7SWilliam Kucharski * decode_rfc1533
10281b8adde7SWilliam Kucharski *
10291b8adde7SWilliam Kucharski * Decodes RFC1533 header
10301b8adde7SWilliam Kucharski **/
decode_rfc1533(unsigned char * p,unsigned int block,unsigned int len,int eof)10311b8adde7SWilliam Kucharski int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof)
10321b8adde7SWilliam Kucharski {
10331b8adde7SWilliam Kucharski static unsigned char *extdata = NULL, *extend = NULL;
10341b8adde7SWilliam Kucharski unsigned char *extpath = NULL;
10351b8adde7SWilliam Kucharski unsigned char *endp;
10361b8adde7SWilliam Kucharski
10371b8adde7SWilliam Kucharski if (block == 0) {
10381b8adde7SWilliam Kucharski end_of_rfc1533 = NULL;
10391b8adde7SWilliam Kucharski if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10401b8adde7SWilliam Kucharski return(0); /* no RFC 1533 header found */
10411b8adde7SWilliam Kucharski p += 4;
10421b8adde7SWilliam Kucharski endp = p + len;
10431b8adde7SWilliam Kucharski } else {
10441b8adde7SWilliam Kucharski if (block == 1) {
10451b8adde7SWilliam Kucharski if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10461b8adde7SWilliam Kucharski return(0); /* no RFC 1533 header found */
10471b8adde7SWilliam Kucharski p += 4;
10481b8adde7SWilliam Kucharski len -= 4; }
10491b8adde7SWilliam Kucharski if (extend + len <= (unsigned char *)
10501b8adde7SWilliam Kucharski rfc1533_venddata + sizeof(rfc1533_venddata)) {
10511b8adde7SWilliam Kucharski memcpy(extend, p, len);
10521b8adde7SWilliam Kucharski extend += len;
10531b8adde7SWilliam Kucharski } else {
10541b8adde7SWilliam Kucharski printf("Overflow in vendor data buffer! Aborting...\n");
10551b8adde7SWilliam Kucharski *extdata = RFC1533_END;
10561b8adde7SWilliam Kucharski return(0);
10571b8adde7SWilliam Kucharski }
10581b8adde7SWilliam Kucharski p = extdata; endp = extend;
10591b8adde7SWilliam Kucharski }
10601b8adde7SWilliam Kucharski if (!eof)
10611b8adde7SWilliam Kucharski return 1;
10621b8adde7SWilliam Kucharski while (p < endp) {
10631b8adde7SWilliam Kucharski unsigned char c = *p;
10641b8adde7SWilliam Kucharski if (c == RFC1533_PAD) {
10651b8adde7SWilliam Kucharski p++;
10661b8adde7SWilliam Kucharski continue;
10671b8adde7SWilliam Kucharski }
10681b8adde7SWilliam Kucharski else if (c == RFC1533_END) {
10691b8adde7SWilliam Kucharski end_of_rfc1533 = endp = p;
10701b8adde7SWilliam Kucharski continue;
10711b8adde7SWilliam Kucharski }
10721b8adde7SWilliam Kucharski else if (c == RFC1533_NETMASK)
10731b8adde7SWilliam Kucharski memcpy(&netmask, p+2, sizeof(in_addr));
10741b8adde7SWilliam Kucharski else if (c == RFC1533_GATEWAY) {
10751b8adde7SWilliam Kucharski /* This is a little simplistic, but it will
10761b8adde7SWilliam Kucharski usually be sufficient.
10771b8adde7SWilliam Kucharski Take only the first entry */
10781b8adde7SWilliam Kucharski if (TAG_LEN(p) >= sizeof(in_addr))
10791b8adde7SWilliam Kucharski memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
10801b8adde7SWilliam Kucharski }
10811b8adde7SWilliam Kucharski else if (c == RFC1533_EXTENSIONPATH)
10821b8adde7SWilliam Kucharski extpath = p;
10831b8adde7SWilliam Kucharski else if (c == RFC2132_MSG_TYPE)
10841b8adde7SWilliam Kucharski dhcp_reply=*(p+2);
10851b8adde7SWilliam Kucharski else if (c == RFC2132_SRV_ID)
10861b8adde7SWilliam Kucharski memcpy(&dhcp_server, p+2, sizeof(in_addr));
10871b8adde7SWilliam Kucharski else if (c == RFC1533_HOSTNAME) {
10881b8adde7SWilliam Kucharski hostname = p + 2;
10891b8adde7SWilliam Kucharski hostnamelen = *(p + 1);
10901b8adde7SWilliam Kucharski }
10911b8adde7SWilliam Kucharski else if (c == RFC1533_VENDOR_CONFIGFILE){
10921b8adde7SWilliam Kucharski int l = TAG_LEN (p);
10931b8adde7SWilliam Kucharski
10941b8adde7SWilliam Kucharski /* Eliminate the trailing NULs according to RFC 2132. */
10951b8adde7SWilliam Kucharski while (*(p + 2 + l - 1) == '\000' && l > 0)
10961b8adde7SWilliam Kucharski l--;
10971b8adde7SWilliam Kucharski
10981b8adde7SWilliam Kucharski /* XXX: Should check if LEN is less than the maximum length
10991b8adde7SWilliam Kucharski of CONFIG_FILE. This kind of robustness will be a goal
11001b8adde7SWilliam Kucharski in GRUB 1.0. */
11011b8adde7SWilliam Kucharski memcpy (config_file, p + 2, l);
11021b8adde7SWilliam Kucharski config_file[l] = 0;
1103*2506833eSJan Setje-Eilers vendor_configfile = p + 2;
1104*2506833eSJan Setje-Eilers vendor_configfile_len = l;
1105*2506833eSJan Setje-Eilers configfile_origin = CFG_150;
11061b8adde7SWilliam Kucharski }
11071b8adde7SWilliam Kucharski else {
11081b8adde7SWilliam Kucharski ;
11091b8adde7SWilliam Kucharski }
11101b8adde7SWilliam Kucharski p += TAG_LEN(p) + 2;
11111b8adde7SWilliam Kucharski }
11121b8adde7SWilliam Kucharski extdata = extend = endp;
11131b8adde7SWilliam Kucharski if (block <= 0 && extpath != NULL) {
11141b8adde7SWilliam Kucharski char fname[64];
11151b8adde7SWilliam Kucharski if (TAG_LEN(extpath) >= sizeof(fname)){
11161b8adde7SWilliam Kucharski printf("Overflow in vendor data buffer! Aborting...\n");
11171b8adde7SWilliam Kucharski *extdata = RFC1533_END;
11181b8adde7SWilliam Kucharski return(0);
11191b8adde7SWilliam Kucharski }
11201b8adde7SWilliam Kucharski memcpy(fname, extpath+2, TAG_LEN(extpath));
11211b8adde7SWilliam Kucharski fname[(int)TAG_LEN(extpath)] = '\0';
11221b8adde7SWilliam Kucharski printf("Loading BOOTP-extension file: %s\n",fname);
11231b8adde7SWilliam Kucharski tftp_file_read(fname, decode_rfc1533);
11241b8adde7SWilliam Kucharski }
11251b8adde7SWilliam Kucharski return 1; /* proceed with next block */
11261b8adde7SWilliam Kucharski }
11271b8adde7SWilliam Kucharski
11281b8adde7SWilliam Kucharski
11291b8adde7SWilliam Kucharski /* FIXME double check TWO_SECOND_DIVISOR */
11301b8adde7SWilliam Kucharski #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC)
11311b8adde7SWilliam Kucharski /**************************************************************************
11321b8adde7SWilliam Kucharski RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec)
11331b8adde7SWilliam Kucharski **************************************************************************/
rfc2131_sleep_interval(long base,int exp)11341b8adde7SWilliam Kucharski long rfc2131_sleep_interval(long base, int exp)
11351b8adde7SWilliam Kucharski {
11361b8adde7SWilliam Kucharski unsigned long tmo;
11371b8adde7SWilliam Kucharski #ifdef BACKOFF_LIMIT
11381b8adde7SWilliam Kucharski if (exp > BACKOFF_LIMIT)
11391b8adde7SWilliam Kucharski exp = BACKOFF_LIMIT;
11401b8adde7SWilliam Kucharski #endif
11411b8adde7SWilliam Kucharski tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
11421b8adde7SWilliam Kucharski return tmo;
11431b8adde7SWilliam Kucharski }
11441b8adde7SWilliam Kucharski
11451b8adde7SWilliam Kucharski #ifdef MULTICAST_LEVEL2
11461b8adde7SWilliam Kucharski /**************************************************************************
11471b8adde7SWilliam Kucharski RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
11481b8adde7SWilliam Kucharski **************************************************************************/
rfc1112_sleep_interval(long base,int exp)11491b8adde7SWilliam Kucharski long rfc1112_sleep_interval(long base, int exp)
11501b8adde7SWilliam Kucharski {
11511b8adde7SWilliam Kucharski unsigned long divisor, tmo;
11521b8adde7SWilliam Kucharski #ifdef BACKOFF_LIMIT
11531b8adde7SWilliam Kucharski if (exp > BACKOFF_LIMIT)
11541b8adde7SWilliam Kucharski exp = BACKOFF_LIMIT;
11551b8adde7SWilliam Kucharski #endif
11561b8adde7SWilliam Kucharski divisor = RAND_MAX/(base << exp);
11571b8adde7SWilliam Kucharski tmo = random()/divisor;
11581b8adde7SWilliam Kucharski return tmo;
11591b8adde7SWilliam Kucharski }
11601b8adde7SWilliam Kucharski #endif /* MULTICAST_LEVEL_2 */
11611b8adde7SWilliam Kucharski /* ifconfig - configure network interface. */
11621b8adde7SWilliam Kucharski int
ifconfig(char * ip,char * sm,char * gw,char * svr)11631b8adde7SWilliam Kucharski ifconfig (char *ip, char *sm, char *gw, char *svr)
11641b8adde7SWilliam Kucharski {
11651b8adde7SWilliam Kucharski in_addr tmp;
11661b8adde7SWilliam Kucharski
11671b8adde7SWilliam Kucharski if (sm)
11681b8adde7SWilliam Kucharski {
11691b8adde7SWilliam Kucharski if (! inet_aton (sm, &tmp))
11701b8adde7SWilliam Kucharski return 0;
11711b8adde7SWilliam Kucharski
11721b8adde7SWilliam Kucharski netmask = tmp.s_addr;
11731b8adde7SWilliam Kucharski }
11741b8adde7SWilliam Kucharski
11751b8adde7SWilliam Kucharski if (ip)
11761b8adde7SWilliam Kucharski {
11771b8adde7SWilliam Kucharski if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
11781b8adde7SWilliam Kucharski return 0;
11791b8adde7SWilliam Kucharski
11801b8adde7SWilliam Kucharski if (! netmask && ! sm)
11811b8adde7SWilliam Kucharski netmask = default_netmask ();
11821b8adde7SWilliam Kucharski }
11831b8adde7SWilliam Kucharski
11841b8adde7SWilliam Kucharski if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
11851b8adde7SWilliam Kucharski return 0;
11861b8adde7SWilliam Kucharski
11871b8adde7SWilliam Kucharski /* Clear out the ARP entry. */
11881b8adde7SWilliam Kucharski grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
11891b8adde7SWilliam Kucharski
11901b8adde7SWilliam Kucharski if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
11911b8adde7SWilliam Kucharski return 0;
11921b8adde7SWilliam Kucharski
11931b8adde7SWilliam Kucharski /* Likewise. */
11941b8adde7SWilliam Kucharski grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
11951b8adde7SWilliam Kucharski
11961b8adde7SWilliam Kucharski if (ip || sm)
11971b8adde7SWilliam Kucharski {
11981b8adde7SWilliam Kucharski if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
11991b8adde7SWilliam Kucharski || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
12001b8adde7SWilliam Kucharski || ! netmask)
12011b8adde7SWilliam Kucharski network_ready = 0;
12021b8adde7SWilliam Kucharski else
12031b8adde7SWilliam Kucharski network_ready = 1;
12041b8adde7SWilliam Kucharski }
12051b8adde7SWilliam Kucharski
12061b8adde7SWilliam Kucharski update_network_configuration();
12071b8adde7SWilliam Kucharski return 1;
12081b8adde7SWilliam Kucharski }
12091b8adde7SWilliam Kucharski
12101b8adde7SWilliam Kucharski /*
12111b8adde7SWilliam Kucharski * print_network_configuration
12121b8adde7SWilliam Kucharski *
12131b8adde7SWilliam Kucharski * Output the network configuration. It may broke the graphic console now.:-(
12141b8adde7SWilliam Kucharski */
print_network_configuration(void)12151b8adde7SWilliam Kucharski void print_network_configuration (void)
12161b8adde7SWilliam Kucharski {
12171b8adde7SWilliam Kucharski EnterFunction("print_network_configuration");
12181b8adde7SWilliam Kucharski if (! network_ready)
12191b8adde7SWilliam Kucharski grub_printf ("Network interface not initialized yet.\n");
12201b8adde7SWilliam Kucharski else {
1221*2506833eSJan Setje-Eilers if (hostnamelen == 0)
1222*2506833eSJan Setje-Eilers etherboot_printf ("Hostname: not set\n");
1223*2506833eSJan Setje-Eilers else
1224*2506833eSJan Setje-Eilers etherboot_printf ("Hostname: %s\n", hostname);
1225*2506833eSJan Setje-Eilers
12261b8adde7SWilliam Kucharski etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr);
12271b8adde7SWilliam Kucharski etherboot_printf ("Netmask: %@\n", netmask);
12281b8adde7SWilliam Kucharski etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr);
1229*2506833eSJan Setje-Eilers etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr);
1230*2506833eSJan Setje-Eilers if (vendor_configfile == NULL) {
1231*2506833eSJan Setje-Eilers etherboot_printf ("Site Option 150: not set\n");
1232*2506833eSJan Setje-Eilers } else {
1233*2506833eSJan Setje-Eilers /*
1234*2506833eSJan Setje-Eilers * vendor_configfile points into the packet and
1235*2506833eSJan Setje-Eilers * is not NULL terminated, so it needs to be
1236*2506833eSJan Setje-Eilers * patched up before printing it out
1237*2506833eSJan Setje-Eilers */
1238*2506833eSJan Setje-Eilers char c = vendor_configfile[vendor_configfile_len];
1239*2506833eSJan Setje-Eilers vendor_configfile[vendor_configfile_len] = '\0';
1240*2506833eSJan Setje-Eilers etherboot_printf ("Site Option 150: %s\n",
1241*2506833eSJan Setje-Eilers vendor_configfile);
1242*2506833eSJan Setje-Eilers vendor_configfile[vendor_configfile_len] = c;
1243*2506833eSJan Setje-Eilers }
1244*2506833eSJan Setje-Eilers
1245*2506833eSJan Setje-Eilers if (bootfile == NULL)
1246*2506833eSJan Setje-Eilers etherboot_printf ("BootFile: not set\n");
1247*2506833eSJan Setje-Eilers else
1248*2506833eSJan Setje-Eilers etherboot_printf ("BootFile: %s\n", bootfile);
1249*2506833eSJan Setje-Eilers
1250*2506833eSJan Setje-Eilers etherboot_printf ("GRUB menu file: %s", config_file);
1251*2506833eSJan Setje-Eilers switch (configfile_origin) {
1252*2506833eSJan Setje-Eilers case CFG_HARDCODED:
1253*2506833eSJan Setje-Eilers etherboot_printf (" from hardcoded default\n");
1254*2506833eSJan Setje-Eilers break;
1255*2506833eSJan Setje-Eilers case CFG_150:
1256*2506833eSJan Setje-Eilers etherboot_printf (" from Site Option 150\n");
1257*2506833eSJan Setje-Eilers break;
1258*2506833eSJan Setje-Eilers case CFG_MAC:
1259*2506833eSJan Setje-Eilers etherboot_printf (" inferred from system MAC\n");
1260*2506833eSJan Setje-Eilers break;
1261*2506833eSJan Setje-Eilers case CFG_BOOTFILE:
1262*2506833eSJan Setje-Eilers etherboot_printf (" inferred from BootFile\n");
1263*2506833eSJan Setje-Eilers break;
1264*2506833eSJan Setje-Eilers default:
1265*2506833eSJan Setje-Eilers etherboot_printf ("\n");
1266*2506833eSJan Setje-Eilers }
12671b8adde7SWilliam Kucharski }
12681b8adde7SWilliam Kucharski LeaveFunction("print_network_configuration");
12691b8adde7SWilliam Kucharski }
12701b8adde7SWilliam Kucharski
12711b8adde7SWilliam Kucharski /*
12721b8adde7SWilliam Kucharski * update_network_configuration
12731b8adde7SWilliam Kucharski *
12741b8adde7SWilliam Kucharski * Update network configuration for diskless clients (Solaris only)
12751b8adde7SWilliam Kucharski */
update_network_configuration(void)12761b8adde7SWilliam Kucharski static void update_network_configuration (void)
12771b8adde7SWilliam Kucharski {
12781b8adde7SWilliam Kucharski #ifdef SOLARIS_NETBOOT
12791b8adde7SWilliam Kucharski struct sol_netinfo {
12801b8adde7SWilliam Kucharski uint8_t sn_infotype;
12811b8adde7SWilliam Kucharski uint8_t sn_mactype;
12821b8adde7SWilliam Kucharski uint8_t sn_maclen;
12831b8adde7SWilliam Kucharski uint8_t sn_padding;
12841b8adde7SWilliam Kucharski unsigned long sn_ciaddr;
12851b8adde7SWilliam Kucharski unsigned long sn_siaddr;
12861b8adde7SWilliam Kucharski unsigned long sn_giaddr;
12871b8adde7SWilliam Kucharski unsigned long sn_netmask;
12881b8adde7SWilliam Kucharski uint8_t sn_macaddr[1];
12891b8adde7SWilliam Kucharski } *sip;
12901b8adde7SWilliam Kucharski
12911b8adde7SWilliam Kucharski if (! network_ready)
12921b8adde7SWilliam Kucharski return;
12931b8adde7SWilliam Kucharski
12941b8adde7SWilliam Kucharski sip = (struct sol_netinfo *)dhcpack_buf;
12951b8adde7SWilliam Kucharski sip->sn_infotype = 0xf0; /* something not BOOTP_REPLY */
12961b8adde7SWilliam Kucharski sip->sn_mactype = 4; /* DL_ETHER */
12971b8adde7SWilliam Kucharski sip->sn_maclen = ETH_ALEN;
12981b8adde7SWilliam Kucharski sip->sn_ciaddr = arptable[ARP_CLIENT].ipaddr.s_addr;
12991b8adde7SWilliam Kucharski sip->sn_siaddr = arptable[ARP_SERVER].ipaddr.s_addr;
13001b8adde7SWilliam Kucharski sip->sn_giaddr = arptable[ARP_GATEWAY].ipaddr.s_addr;
13011b8adde7SWilliam Kucharski sip->sn_netmask = netmask;
13021b8adde7SWilliam Kucharski memcpy(sip->sn_macaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
13031b8adde7SWilliam Kucharski dhcpack_length = sizeof (*sip) + sip->sn_maclen - 1;
13041b8adde7SWilliam Kucharski #endif /* SOLARIS_NETBOOT */
13051b8adde7SWilliam Kucharski }
13061b8adde7SWilliam Kucharski
13071b8adde7SWilliam Kucharski /**
13081b8adde7SWilliam Kucharski * cleanup_net
13091b8adde7SWilliam Kucharski *
13101b8adde7SWilliam Kucharski * Mark network unusable, and disable NICs
13111b8adde7SWilliam Kucharski */
cleanup_net(void)13121b8adde7SWilliam Kucharski void cleanup_net (void)
13131b8adde7SWilliam Kucharski {
13141b8adde7SWilliam Kucharski if (network_ready){
13151b8adde7SWilliam Kucharski /* Stop receiving packets. */
13161b8adde7SWilliam Kucharski if (use_bios_pxe)
13171b8adde7SWilliam Kucharski undi_pxe_disable();
13181b8adde7SWilliam Kucharski else
13191b8adde7SWilliam Kucharski eth_disable ();
13201b8adde7SWilliam Kucharski network_ready = 0;
13211b8adde7SWilliam Kucharski }
13221b8adde7SWilliam Kucharski }
13231b8adde7SWilliam Kucharski
13241b8adde7SWilliam Kucharski /*******************************************************************
13251b8adde7SWilliam Kucharski * dhcp implementation reusing the BIOS pxe stack
13261b8adde7SWilliam Kucharski */
13271b8adde7SWilliam Kucharski static void
dhcp_copy(struct dhcp_t * dhcpreply)13281b8adde7SWilliam Kucharski dhcp_copy(struct dhcp_t *dhcpreply)
13291b8adde7SWilliam Kucharski {
13301b8adde7SWilliam Kucharski unsigned long time;
13311b8adde7SWilliam Kucharski int ret, len = DHCP_OPT_LEN;
13321b8adde7SWilliam Kucharski
13331b8adde7SWilliam Kucharski /* fill in netinfo */
13341b8adde7SWilliam Kucharski dhcpack_length = sizeof (struct dhcp_t);
13351b8adde7SWilliam Kucharski memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
13361b8adde7SWilliam Kucharski
13371b8adde7SWilliam Kucharski memcpy(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN);
13381b8adde7SWilliam Kucharski arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
13391b8adde7SWilliam Kucharski dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
13401b8adde7SWilliam Kucharski netmask = default_netmask();
13411b8adde7SWilliam Kucharski arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
13421b8adde7SWilliam Kucharski memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
13431b8adde7SWilliam Kucharski arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
13441b8adde7SWilliam Kucharski memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
1345*2506833eSJan Setje-Eilers bootfile = dhcpreply->bp_file;
13461b8adde7SWilliam Kucharski memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
13471b8adde7SWilliam Kucharski decode_rfc1533(rfc1533_venddata, 0, len, 1);
13481b8adde7SWilliam Kucharski }
13491b8adde7SWilliam Kucharski
dhcp_undi(void)13501b8adde7SWilliam Kucharski int dhcp_undi(void)
13511b8adde7SWilliam Kucharski {
13521b8adde7SWilliam Kucharski struct dhcp_t *dhcpreply;
13531b8adde7SWilliam Kucharski
13541b8adde7SWilliam Kucharski if (!undi_bios_pxe((void **)&dhcpreply))
13551b8adde7SWilliam Kucharski return 0;
13561b8adde7SWilliam Kucharski
13571b8adde7SWilliam Kucharski dhcp_copy(dhcpreply);
13581b8adde7SWilliam Kucharski network_ready = 1;
13591b8adde7SWilliam Kucharski use_bios_pxe = 1;
13601b8adde7SWilliam Kucharski return (1);
13611b8adde7SWilliam Kucharski }
1362