18044SWilliam.Kucharski@Sun.COM /**************************************************************************
28044SWilliam.Kucharski@Sun.COM Etherboot - Network Bootstrap Program
38044SWilliam.Kucharski@Sun.COM
48044SWilliam.Kucharski@Sun.COM Literature dealing with the network protocols:
58044SWilliam.Kucharski@Sun.COM ARP - RFC826
68044SWilliam.Kucharski@Sun.COM RARP - RFC903
78044SWilliam.Kucharski@Sun.COM IP - RFC791
88044SWilliam.Kucharski@Sun.COM UDP - RFC768
98044SWilliam.Kucharski@Sun.COM BOOTP - RFC951, RFC2132 (vendor extensions)
108044SWilliam.Kucharski@Sun.COM DHCP - RFC2131, RFC2132 (options)
118044SWilliam.Kucharski@Sun.COM TFTP - RFC1350, RFC2347 (options), RFC2348 (blocksize), RFC2349 (tsize)
128044SWilliam.Kucharski@Sun.COM RPC - RFC1831, RFC1832 (XDR), RFC1833 (rpcbind/portmapper)
138044SWilliam.Kucharski@Sun.COM NFS - RFC1094, RFC1813 (v3, useful for clarifications, not implemented)
148044SWilliam.Kucharski@Sun.COM IGMP - RFC1112, RFC2113, RFC2365, RFC2236, RFC3171
158044SWilliam.Kucharski@Sun.COM
168044SWilliam.Kucharski@Sun.COM **************************************************************************/
178044SWilliam.Kucharski@Sun.COM #include "etherboot.h"
188044SWilliam.Kucharski@Sun.COM #include "grub.h"
198044SWilliam.Kucharski@Sun.COM #include "nic.h"
208044SWilliam.Kucharski@Sun.COM #include "elf.h" /* FOR EM_CURRENT */
218044SWilliam.Kucharski@Sun.COM #include "bootp.h"
228044SWilliam.Kucharski@Sun.COM #include "if_arp.h"
238044SWilliam.Kucharski@Sun.COM #include "tftp.h"
248044SWilliam.Kucharski@Sun.COM #include "timer.h"
258044SWilliam.Kucharski@Sun.COM #include "ip.h"
268044SWilliam.Kucharski@Sun.COM #include "udp.h"
278044SWilliam.Kucharski@Sun.COM
288044SWilliam.Kucharski@Sun.COM /* Currently no other module uses rom, but it is available */
298044SWilliam.Kucharski@Sun.COM struct rom_info rom;
308044SWilliam.Kucharski@Sun.COM struct arptable_t arptable[MAX_ARP];
318044SWilliam.Kucharski@Sun.COM #ifdef MULTICAST_LEVEL2
328044SWilliam.Kucharski@Sun.COM unsigned long last_igmpv1 = 0;
338044SWilliam.Kucharski@Sun.COM struct igmptable_t igmptable[MAX_IGMP];
348044SWilliam.Kucharski@Sun.COM #endif
358044SWilliam.Kucharski@Sun.COM static unsigned long netmask;
368044SWilliam.Kucharski@Sun.COM /* Used by nfs.c */
378044SWilliam.Kucharski@Sun.COM char *hostname = "";
388044SWilliam.Kucharski@Sun.COM int hostnamelen = 0;
398044SWilliam.Kucharski@Sun.COM /* Used by fsys_tftp.c */
408044SWilliam.Kucharski@Sun.COM int use_bios_pxe = 0;
418044SWilliam.Kucharski@Sun.COM static uint32_t xid;
428044SWilliam.Kucharski@Sun.COM static unsigned char *end_of_rfc1533 = NULL;
438044SWilliam.Kucharski@Sun.COM static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
448044SWilliam.Kucharski@Sun.COM static const in_addr zeroIP = { 0L };
458044SWilliam.Kucharski@Sun.COM static char rfc1533_venddata[MAX_RFC1533_VENDLEN];
468044SWilliam.Kucharski@Sun.COM static unsigned char rfc1533_cookie[4] = { RFC1533_COOKIE };
478044SWilliam.Kucharski@Sun.COM static unsigned char rfc1533_cookie_bootp[5] = { RFC1533_COOKIE, RFC1533_END };
488044SWilliam.Kucharski@Sun.COM static unsigned char rfc1533_cookie_dhcp[] = { RFC1533_COOKIE };
498044SWilliam.Kucharski@Sun.COM static int dhcp_reply;
508044SWilliam.Kucharski@Sun.COM static in_addr dhcp_server = { 0L };
518044SWilliam.Kucharski@Sun.COM static in_addr dhcp_addr = { 0L };
528044SWilliam.Kucharski@Sun.COM
538044SWilliam.Kucharski@Sun.COM static const unsigned char dhcpdiscover[] = {
548044SWilliam.Kucharski@Sun.COM RFC2132_MSG_TYPE, 1, DHCPDISCOVER,
558044SWilliam.Kucharski@Sun.COM RFC2132_MAX_SIZE, 2, /* request as much as we can */
568044SWilliam.Kucharski@Sun.COM ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
578044SWilliam.Kucharski@Sun.COM /* Vendor class identifier */
588044SWilliam.Kucharski@Sun.COM #ifdef SOLARIS_NETBOOT
598044SWilliam.Kucharski@Sun.COM RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
608044SWilliam.Kucharski@Sun.COM 'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
618044SWilliam.Kucharski@Sun.COM '0','0','2','0','0','1',
628044SWilliam.Kucharski@Sun.COM #else
638044SWilliam.Kucharski@Sun.COM RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
648044SWilliam.Kucharski@Sun.COM #endif
658044SWilliam.Kucharski@Sun.COM RFC2132_PARAM_LIST, 4, RFC1533_NETMASK, RFC1533_GATEWAY,
668044SWilliam.Kucharski@Sun.COM RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH, RFC1533_END
678044SWilliam.Kucharski@Sun.COM };
688044SWilliam.Kucharski@Sun.COM static const unsigned char dhcprequest [] = {
698044SWilliam.Kucharski@Sun.COM RFC2132_MSG_TYPE,1,DHCPREQUEST,
708044SWilliam.Kucharski@Sun.COM RFC2132_SRV_ID,4,0,0,0,0,
718044SWilliam.Kucharski@Sun.COM RFC2132_REQ_ADDR,4,0,0,0,0,
728044SWilliam.Kucharski@Sun.COM RFC2132_MAX_SIZE,2, /* request as much as we can */
738044SWilliam.Kucharski@Sun.COM ETH_MAX_MTU / 256, ETH_MAX_MTU % 256,
748044SWilliam.Kucharski@Sun.COM /* Vendor class identifier */
758044SWilliam.Kucharski@Sun.COM #ifdef SOLARIS_NETBOOT
768044SWilliam.Kucharski@Sun.COM RFC2132_VENDOR_CLASS_ID,32,'P','X','E','C','l','i','e','n','t',':',
778044SWilliam.Kucharski@Sun.COM 'A','r','c','h',':','0','0','0','0','0',':','U','N','D','I',':',
788044SWilliam.Kucharski@Sun.COM '0','0','2','0','0','1',
798044SWilliam.Kucharski@Sun.COM #else
808044SWilliam.Kucharski@Sun.COM RFC2132_VENDOR_CLASS_ID, 10, 'G', 'R', 'U', 'B', 'C', 'l', 'i', 'e', 'n', 't',
818044SWilliam.Kucharski@Sun.COM #endif
828044SWilliam.Kucharski@Sun.COM RFC2132_PARAM_LIST,
838044SWilliam.Kucharski@Sun.COM /* 4 standard + 2 vendortags */
848044SWilliam.Kucharski@Sun.COM 4 + 2,
858044SWilliam.Kucharski@Sun.COM /* Standard parameters */
868044SWilliam.Kucharski@Sun.COM RFC1533_NETMASK, RFC1533_GATEWAY,
878044SWilliam.Kucharski@Sun.COM RFC1533_HOSTNAME, RFC1533_EXTENSIONPATH,
888044SWilliam.Kucharski@Sun.COM /* Etherboot vendortags */
898044SWilliam.Kucharski@Sun.COM RFC1533_VENDOR_MAGIC,
908044SWilliam.Kucharski@Sun.COM RFC1533_VENDOR_CONFIGFILE,
918044SWilliam.Kucharski@Sun.COM RFC1533_END
928044SWilliam.Kucharski@Sun.COM };
938044SWilliam.Kucharski@Sun.COM
948044SWilliam.Kucharski@Sun.COM /* See nic.h */
958044SWilliam.Kucharski@Sun.COM int user_abort = 0;
968044SWilliam.Kucharski@Sun.COM int network_ready = 0;
978044SWilliam.Kucharski@Sun.COM
988044SWilliam.Kucharski@Sun.COM #ifdef REQUIRE_VCI_ETHERBOOT
998044SWilliam.Kucharski@Sun.COM int vci_etherboot;
1008044SWilliam.Kucharski@Sun.COM #endif
1018044SWilliam.Kucharski@Sun.COM
102*9037SJan.Setje-Eilers@Sun.COM char *bootfile = NULL;
103*9037SJan.Setje-Eilers@Sun.COM configfile_origin_t configfile_origin = CFG_HARDCODED;
104*9037SJan.Setje-Eilers@Sun.COM char *vendor_configfile = NULL;
105*9037SJan.Setje-Eilers@Sun.COM char vendor_configfile_len;
106*9037SJan.Setje-Eilers@Sun.COM
1078044SWilliam.Kucharski@Sun.COM static void update_network_configuration(void);
1088044SWilliam.Kucharski@Sun.COM
dummy(void * unused __unused)1098044SWilliam.Kucharski@Sun.COM static int dummy(void *unused __unused)
1108044SWilliam.Kucharski@Sun.COM {
1118044SWilliam.Kucharski@Sun.COM return (0);
1128044SWilliam.Kucharski@Sun.COM }
1138044SWilliam.Kucharski@Sun.COM
1148044SWilliam.Kucharski@Sun.COM /* Careful. We need an aligned buffer to avoid problems on machines
1158044SWilliam.Kucharski@Sun.COM * that care about alignment. To trivally align the ethernet data
1168044SWilliam.Kucharski@Sun.COM * (the ip hdr and arp requests) we offset the packet by 2 bytes.
1178044SWilliam.Kucharski@Sun.COM * leaving the ethernet data 16 byte aligned. Beyond this
1188044SWilliam.Kucharski@Sun.COM * we use memmove but this makes the common cast simple and fast.
1198044SWilliam.Kucharski@Sun.COM */
1208044SWilliam.Kucharski@Sun.COM static char packet[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned;
1218044SWilliam.Kucharski@Sun.COM
1228044SWilliam.Kucharski@Sun.COM struct nic nic =
1238044SWilliam.Kucharski@Sun.COM {
1248044SWilliam.Kucharski@Sun.COM {
1258044SWilliam.Kucharski@Sun.COM 0, /* dev.disable */
1268044SWilliam.Kucharski@Sun.COM {
1278044SWilliam.Kucharski@Sun.COM 0,
1288044SWilliam.Kucharski@Sun.COM 0,
1298044SWilliam.Kucharski@Sun.COM PCI_BUS_TYPE,
1308044SWilliam.Kucharski@Sun.COM }, /* dev.devid */
1318044SWilliam.Kucharski@Sun.COM 0, /* index */
1328044SWilliam.Kucharski@Sun.COM 0, /* type */
1338044SWilliam.Kucharski@Sun.COM PROBE_FIRST, /* how_pobe */
1348044SWilliam.Kucharski@Sun.COM PROBE_NONE, /* to_probe */
1358044SWilliam.Kucharski@Sun.COM 0, /* failsafe */
1368044SWilliam.Kucharski@Sun.COM 0, /* type_index */
1378044SWilliam.Kucharski@Sun.COM {}, /* state */
1388044SWilliam.Kucharski@Sun.COM },
1398044SWilliam.Kucharski@Sun.COM (int (*)(struct nic *, int))dummy, /* poll */
1408044SWilliam.Kucharski@Sun.COM (void (*)(struct nic *, const char *,
1418044SWilliam.Kucharski@Sun.COM unsigned int, unsigned int,
1428044SWilliam.Kucharski@Sun.COM const char *))dummy, /* transmit */
1438044SWilliam.Kucharski@Sun.COM (void (*)(struct nic *, irq_action_t))dummy, /* irq */
1448044SWilliam.Kucharski@Sun.COM 0, /* flags */
1458044SWilliam.Kucharski@Sun.COM &rom, /* rom_info */
1468044SWilliam.Kucharski@Sun.COM arptable[ARP_CLIENT].node, /* node_addr */
1478044SWilliam.Kucharski@Sun.COM packet + ETH_DATA_ALIGN, /* packet */
1488044SWilliam.Kucharski@Sun.COM 0, /* packetlen */
1498044SWilliam.Kucharski@Sun.COM 0, /* ioaddr */
1508044SWilliam.Kucharski@Sun.COM 0, /* irqno */
1518044SWilliam.Kucharski@Sun.COM NULL, /* priv_data */
1528044SWilliam.Kucharski@Sun.COM };
1538044SWilliam.Kucharski@Sun.COM
1548044SWilliam.Kucharski@Sun.COM
1558044SWilliam.Kucharski@Sun.COM
grub_eth_probe(void)1568044SWilliam.Kucharski@Sun.COM int grub_eth_probe(void)
1578044SWilliam.Kucharski@Sun.COM {
1588044SWilliam.Kucharski@Sun.COM static int probed = 0;
1598044SWilliam.Kucharski@Sun.COM struct dev *dev;
1608044SWilliam.Kucharski@Sun.COM
1618044SWilliam.Kucharski@Sun.COM EnterFunction("grub_eth_probe");
1628044SWilliam.Kucharski@Sun.COM
1638044SWilliam.Kucharski@Sun.COM if (probed)
1648044SWilliam.Kucharski@Sun.COM return 1;
1658044SWilliam.Kucharski@Sun.COM
1668044SWilliam.Kucharski@Sun.COM network_ready = 0;
1678044SWilliam.Kucharski@Sun.COM grub_memset((char *)arptable, 0, MAX_ARP * sizeof(struct arptable_t));
1688044SWilliam.Kucharski@Sun.COM dev = &nic.dev;
1698044SWilliam.Kucharski@Sun.COM dev->how_probe = -1;
1708044SWilliam.Kucharski@Sun.COM dev->type = NIC_DRIVER;
1718044SWilliam.Kucharski@Sun.COM dev->failsafe = 1;
1728044SWilliam.Kucharski@Sun.COM rom = *((struct rom_info *)ROM_INFO_LOCATION);
1738044SWilliam.Kucharski@Sun.COM
1748044SWilliam.Kucharski@Sun.COM probed = (eth_probe(dev) == PROBE_WORKED);
1758044SWilliam.Kucharski@Sun.COM
1768044SWilliam.Kucharski@Sun.COM LeaveFunction("grub_eth_probe");
1778044SWilliam.Kucharski@Sun.COM return probed;
1788044SWilliam.Kucharski@Sun.COM }
1798044SWilliam.Kucharski@Sun.COM
eth_probe(struct dev * dev)1808044SWilliam.Kucharski@Sun.COM int eth_probe(struct dev *dev)
1818044SWilliam.Kucharski@Sun.COM {
1828044SWilliam.Kucharski@Sun.COM return probe(dev);
1838044SWilliam.Kucharski@Sun.COM }
1848044SWilliam.Kucharski@Sun.COM
eth_poll(int retrieve)1858044SWilliam.Kucharski@Sun.COM int eth_poll(int retrieve)
1868044SWilliam.Kucharski@Sun.COM {
1878044SWilliam.Kucharski@Sun.COM return ((*nic.poll)(&nic, retrieve));
1888044SWilliam.Kucharski@Sun.COM }
1898044SWilliam.Kucharski@Sun.COM
eth_transmit(const char * d,unsigned int t,unsigned int s,const void * p)1908044SWilliam.Kucharski@Sun.COM void eth_transmit(const char *d, unsigned int t, unsigned int s, const void *p)
1918044SWilliam.Kucharski@Sun.COM {
1928044SWilliam.Kucharski@Sun.COM (*nic.transmit)(&nic, d, t, s, p);
1938044SWilliam.Kucharski@Sun.COM if (t == IP) twiddle();
1948044SWilliam.Kucharski@Sun.COM }
1958044SWilliam.Kucharski@Sun.COM
eth_disable(void)1968044SWilliam.Kucharski@Sun.COM void eth_disable(void)
1978044SWilliam.Kucharski@Sun.COM {
1988044SWilliam.Kucharski@Sun.COM #ifdef MULTICAST_LEVEL2
1998044SWilliam.Kucharski@Sun.COM int i;
2008044SWilliam.Kucharski@Sun.COM for(i = 0; i < MAX_IGMP; i++) {
2018044SWilliam.Kucharski@Sun.COM leave_group(i);
2028044SWilliam.Kucharski@Sun.COM }
2038044SWilliam.Kucharski@Sun.COM #endif
2048044SWilliam.Kucharski@Sun.COM disable(&nic.dev);
2058044SWilliam.Kucharski@Sun.COM }
2068044SWilliam.Kucharski@Sun.COM
eth_irq(irq_action_t action)2078044SWilliam.Kucharski@Sun.COM void eth_irq (irq_action_t action)
2088044SWilliam.Kucharski@Sun.COM {
2098044SWilliam.Kucharski@Sun.COM (*nic.irq)(&nic,action);
2108044SWilliam.Kucharski@Sun.COM }
2118044SWilliam.Kucharski@Sun.COM
2128044SWilliam.Kucharski@Sun.COM /**************************************************************************
2138044SWilliam.Kucharski@Sun.COM IPCHKSUM - Checksum IP Header
2148044SWilliam.Kucharski@Sun.COM **************************************************************************/
ipchksum(const void * data,unsigned long length)2158044SWilliam.Kucharski@Sun.COM uint16_t ipchksum(const void *data, unsigned long length)
2168044SWilliam.Kucharski@Sun.COM {
2178044SWilliam.Kucharski@Sun.COM unsigned long sum;
2188044SWilliam.Kucharski@Sun.COM unsigned long i;
2198044SWilliam.Kucharski@Sun.COM const uint8_t *ptr;
2208044SWilliam.Kucharski@Sun.COM
2218044SWilliam.Kucharski@Sun.COM /* In the most straight forward way possible,
2228044SWilliam.Kucharski@Sun.COM * compute an ip style checksum.
2238044SWilliam.Kucharski@Sun.COM */
2248044SWilliam.Kucharski@Sun.COM sum = 0;
2258044SWilliam.Kucharski@Sun.COM ptr = data;
2268044SWilliam.Kucharski@Sun.COM for(i = 0; i < length; i++) {
2278044SWilliam.Kucharski@Sun.COM unsigned long value;
2288044SWilliam.Kucharski@Sun.COM value = ptr[i];
2298044SWilliam.Kucharski@Sun.COM if (i & 1) {
2308044SWilliam.Kucharski@Sun.COM value <<= 8;
2318044SWilliam.Kucharski@Sun.COM }
2328044SWilliam.Kucharski@Sun.COM /* Add the new value */
2338044SWilliam.Kucharski@Sun.COM sum += value;
2348044SWilliam.Kucharski@Sun.COM /* Wrap around the carry */
2358044SWilliam.Kucharski@Sun.COM if (sum > 0xFFFF) {
2368044SWilliam.Kucharski@Sun.COM sum = (sum + (sum >> 16)) & 0xFFFF;
2378044SWilliam.Kucharski@Sun.COM }
2388044SWilliam.Kucharski@Sun.COM }
2398044SWilliam.Kucharski@Sun.COM return (~cpu_to_le16(sum)) & 0xFFFF;
2408044SWilliam.Kucharski@Sun.COM }
2418044SWilliam.Kucharski@Sun.COM
add_ipchksums(unsigned long offset,uint16_t sum,uint16_t new)2428044SWilliam.Kucharski@Sun.COM uint16_t add_ipchksums(unsigned long offset, uint16_t sum, uint16_t new)
2438044SWilliam.Kucharski@Sun.COM {
2448044SWilliam.Kucharski@Sun.COM unsigned long checksum;
2458044SWilliam.Kucharski@Sun.COM sum = ~sum & 0xFFFF;
2468044SWilliam.Kucharski@Sun.COM new = ~new & 0xFFFF;
2478044SWilliam.Kucharski@Sun.COM if (offset & 1) {
2488044SWilliam.Kucharski@Sun.COM /* byte swap the sum if it came from an odd offset
2498044SWilliam.Kucharski@Sun.COM * since the computation is endian independant this
2508044SWilliam.Kucharski@Sun.COM * works.
2518044SWilliam.Kucharski@Sun.COM */
2528044SWilliam.Kucharski@Sun.COM new = bswap_16(new);
2538044SWilliam.Kucharski@Sun.COM }
2548044SWilliam.Kucharski@Sun.COM checksum = sum + new;
2558044SWilliam.Kucharski@Sun.COM if (checksum > 0xFFFF) {
2568044SWilliam.Kucharski@Sun.COM checksum -= 0xFFFF;
2578044SWilliam.Kucharski@Sun.COM }
2588044SWilliam.Kucharski@Sun.COM return (~checksum) & 0xFFFF;
2598044SWilliam.Kucharski@Sun.COM }
2608044SWilliam.Kucharski@Sun.COM
2618044SWilliam.Kucharski@Sun.COM /**************************************************************************
2628044SWilliam.Kucharski@Sun.COM DEFAULT_NETMASK - Return default netmask for IP address
2638044SWilliam.Kucharski@Sun.COM **************************************************************************/
default_netmask(void)2648044SWilliam.Kucharski@Sun.COM static inline unsigned long default_netmask(void)
2658044SWilliam.Kucharski@Sun.COM {
2668044SWilliam.Kucharski@Sun.COM int net = ntohl(arptable[ARP_CLIENT].ipaddr.s_addr) >> 24;
2678044SWilliam.Kucharski@Sun.COM if (net <= 127)
2688044SWilliam.Kucharski@Sun.COM return(htonl(0xff000000));
2698044SWilliam.Kucharski@Sun.COM else if (net < 192)
2708044SWilliam.Kucharski@Sun.COM return(htonl(0xffff0000));
2718044SWilliam.Kucharski@Sun.COM else
2728044SWilliam.Kucharski@Sun.COM return(htonl(0xffffff00));
2738044SWilliam.Kucharski@Sun.COM }
2748044SWilliam.Kucharski@Sun.COM
2758044SWilliam.Kucharski@Sun.COM /**************************************************************************
2768044SWilliam.Kucharski@Sun.COM IP_TRANSMIT - Send an IP datagram
2778044SWilliam.Kucharski@Sun.COM **************************************************************************/
await_arp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip __unused,struct udphdr * udp __unused)2788044SWilliam.Kucharski@Sun.COM static int await_arp(int ival, void *ptr,
2798044SWilliam.Kucharski@Sun.COM unsigned short ptype, struct iphdr *ip __unused, struct udphdr *udp __unused)
2808044SWilliam.Kucharski@Sun.COM {
2818044SWilliam.Kucharski@Sun.COM struct arprequest *arpreply;
2828044SWilliam.Kucharski@Sun.COM if (ptype != ARP)
2838044SWilliam.Kucharski@Sun.COM return 0;
2848044SWilliam.Kucharski@Sun.COM if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
2858044SWilliam.Kucharski@Sun.COM return 0;
2868044SWilliam.Kucharski@Sun.COM arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
2878044SWilliam.Kucharski@Sun.COM
2888044SWilliam.Kucharski@Sun.COM if (arpreply->opcode != htons(ARP_REPLY))
2898044SWilliam.Kucharski@Sun.COM return 0;
2908044SWilliam.Kucharski@Sun.COM if (memcmp(arpreply->sipaddr, ptr, sizeof(in_addr)) != 0)
2918044SWilliam.Kucharski@Sun.COM return 0;
2928044SWilliam.Kucharski@Sun.COM memcpy(arptable[ival].node, arpreply->shwaddr, ETH_ALEN);
2938044SWilliam.Kucharski@Sun.COM return 1;
2948044SWilliam.Kucharski@Sun.COM }
2958044SWilliam.Kucharski@Sun.COM
ip_transmit(int len,const void * buf)2968044SWilliam.Kucharski@Sun.COM int ip_transmit(int len, const void *buf)
2978044SWilliam.Kucharski@Sun.COM {
2988044SWilliam.Kucharski@Sun.COM unsigned long destip;
2998044SWilliam.Kucharski@Sun.COM struct iphdr *ip;
3008044SWilliam.Kucharski@Sun.COM struct arprequest arpreq;
3018044SWilliam.Kucharski@Sun.COM int arpentry, i;
3028044SWilliam.Kucharski@Sun.COM int retry;
3038044SWilliam.Kucharski@Sun.COM
3048044SWilliam.Kucharski@Sun.COM ip = (struct iphdr *)buf;
3058044SWilliam.Kucharski@Sun.COM destip = ip->dest.s_addr;
3068044SWilliam.Kucharski@Sun.COM if (destip == IP_BROADCAST) {
3078044SWilliam.Kucharski@Sun.COM eth_transmit(broadcast, IP, len, buf);
3088044SWilliam.Kucharski@Sun.COM #ifdef MULTICAST_LEVEL1
3098044SWilliam.Kucharski@Sun.COM } else if ((destip & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
3108044SWilliam.Kucharski@Sun.COM unsigned char multicast[6];
3118044SWilliam.Kucharski@Sun.COM unsigned long hdestip;
3128044SWilliam.Kucharski@Sun.COM hdestip = ntohl(destip);
3138044SWilliam.Kucharski@Sun.COM multicast[0] = 0x01;
3148044SWilliam.Kucharski@Sun.COM multicast[1] = 0x00;
3158044SWilliam.Kucharski@Sun.COM multicast[2] = 0x5e;
3168044SWilliam.Kucharski@Sun.COM multicast[3] = (hdestip >> 16) & 0x7;
3178044SWilliam.Kucharski@Sun.COM multicast[4] = (hdestip >> 8) & 0xff;
3188044SWilliam.Kucharski@Sun.COM multicast[5] = hdestip & 0xff;
3198044SWilliam.Kucharski@Sun.COM eth_transmit(multicast, IP, len, buf);
3208044SWilliam.Kucharski@Sun.COM #endif
3218044SWilliam.Kucharski@Sun.COM } else {
3228044SWilliam.Kucharski@Sun.COM if (((destip & netmask) !=
3238044SWilliam.Kucharski@Sun.COM (arptable[ARP_CLIENT].ipaddr.s_addr & netmask)) &&
3248044SWilliam.Kucharski@Sun.COM arptable[ARP_GATEWAY].ipaddr.s_addr)
3258044SWilliam.Kucharski@Sun.COM destip = arptable[ARP_GATEWAY].ipaddr.s_addr;
3268044SWilliam.Kucharski@Sun.COM for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
3278044SWilliam.Kucharski@Sun.COM if (arptable[arpentry].ipaddr.s_addr == destip) break;
3288044SWilliam.Kucharski@Sun.COM if (arpentry == MAX_ARP) {
3298044SWilliam.Kucharski@Sun.COM printf("%@ is not in my arp table!\n", destip);
3308044SWilliam.Kucharski@Sun.COM return(0);
3318044SWilliam.Kucharski@Sun.COM }
3328044SWilliam.Kucharski@Sun.COM for (i = 0; i < ETH_ALEN; i++)
3338044SWilliam.Kucharski@Sun.COM if (arptable[arpentry].node[i])
3348044SWilliam.Kucharski@Sun.COM break;
3358044SWilliam.Kucharski@Sun.COM if (i == ETH_ALEN) { /* Need to do arp request */
3368044SWilliam.Kucharski@Sun.COM arpreq.hwtype = htons(1);
3378044SWilliam.Kucharski@Sun.COM arpreq.protocol = htons(IP);
3388044SWilliam.Kucharski@Sun.COM arpreq.hwlen = ETH_ALEN;
3398044SWilliam.Kucharski@Sun.COM arpreq.protolen = 4;
3408044SWilliam.Kucharski@Sun.COM arpreq.opcode = htons(ARP_REQUEST);
3418044SWilliam.Kucharski@Sun.COM memcpy(arpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
3428044SWilliam.Kucharski@Sun.COM memcpy(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
3438044SWilliam.Kucharski@Sun.COM memset(arpreq.thwaddr, 0, ETH_ALEN);
3448044SWilliam.Kucharski@Sun.COM memcpy(arpreq.tipaddr, &destip, sizeof(in_addr));
3458044SWilliam.Kucharski@Sun.COM for (retry = 1; retry <= MAX_ARP_RETRIES; retry++) {
3468044SWilliam.Kucharski@Sun.COM long timeout;
3478044SWilliam.Kucharski@Sun.COM eth_transmit(broadcast, ARP, sizeof(arpreq),
3488044SWilliam.Kucharski@Sun.COM &arpreq);
3498044SWilliam.Kucharski@Sun.COM timeout = rfc2131_sleep_interval(TIMEOUT, retry);
3508044SWilliam.Kucharski@Sun.COM if (await_reply(await_arp, arpentry,
3518044SWilliam.Kucharski@Sun.COM arpreq.tipaddr, timeout)) goto xmit;
3528044SWilliam.Kucharski@Sun.COM }
3538044SWilliam.Kucharski@Sun.COM return(0);
3548044SWilliam.Kucharski@Sun.COM }
3558044SWilliam.Kucharski@Sun.COM xmit:
3568044SWilliam.Kucharski@Sun.COM eth_transmit(arptable[arpentry].node, IP, len, buf);
3578044SWilliam.Kucharski@Sun.COM }
3588044SWilliam.Kucharski@Sun.COM return 1;
3598044SWilliam.Kucharski@Sun.COM }
3608044SWilliam.Kucharski@Sun.COM
build_ip_hdr(unsigned long destip,int ttl,int protocol,int option_len,int len,const void * buf)3618044SWilliam.Kucharski@Sun.COM void build_ip_hdr(unsigned long destip, int ttl, int protocol, int option_len,
3628044SWilliam.Kucharski@Sun.COM int len, const void *buf)
3638044SWilliam.Kucharski@Sun.COM {
3648044SWilliam.Kucharski@Sun.COM struct iphdr *ip;
3658044SWilliam.Kucharski@Sun.COM ip = (struct iphdr *)buf;
3668044SWilliam.Kucharski@Sun.COM ip->verhdrlen = 0x45;
3678044SWilliam.Kucharski@Sun.COM ip->verhdrlen += (option_len/4);
3688044SWilliam.Kucharski@Sun.COM ip->service = 0;
3698044SWilliam.Kucharski@Sun.COM ip->len = htons(len);
3708044SWilliam.Kucharski@Sun.COM ip->ident = 0;
3718044SWilliam.Kucharski@Sun.COM ip->frags = 0; /* Should we set don't fragment? */
3728044SWilliam.Kucharski@Sun.COM ip->ttl = ttl;
3738044SWilliam.Kucharski@Sun.COM ip->protocol = protocol;
3748044SWilliam.Kucharski@Sun.COM ip->chksum = 0;
3758044SWilliam.Kucharski@Sun.COM ip->src.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr;
3768044SWilliam.Kucharski@Sun.COM ip->dest.s_addr = destip;
3778044SWilliam.Kucharski@Sun.COM ip->chksum = ipchksum(buf, sizeof(struct iphdr) + option_len);
3788044SWilliam.Kucharski@Sun.COM }
3798044SWilliam.Kucharski@Sun.COM
udpchksum(struct iphdr * ip,struct udphdr * udp)3808044SWilliam.Kucharski@Sun.COM static uint16_t udpchksum(struct iphdr *ip, struct udphdr *udp)
3818044SWilliam.Kucharski@Sun.COM {
3828044SWilliam.Kucharski@Sun.COM struct udp_pseudo_hdr pseudo;
3838044SWilliam.Kucharski@Sun.COM uint16_t checksum;
3848044SWilliam.Kucharski@Sun.COM
3858044SWilliam.Kucharski@Sun.COM /* Compute the pseudo header */
3868044SWilliam.Kucharski@Sun.COM pseudo.src.s_addr = ip->src.s_addr;
3878044SWilliam.Kucharski@Sun.COM pseudo.dest.s_addr = ip->dest.s_addr;
3888044SWilliam.Kucharski@Sun.COM pseudo.unused = 0;
3898044SWilliam.Kucharski@Sun.COM pseudo.protocol = IP_UDP;
3908044SWilliam.Kucharski@Sun.COM pseudo.len = udp->len;
3918044SWilliam.Kucharski@Sun.COM
3928044SWilliam.Kucharski@Sun.COM /* Sum the pseudo header */
3938044SWilliam.Kucharski@Sun.COM checksum = ipchksum(&pseudo, 12);
3948044SWilliam.Kucharski@Sun.COM
3958044SWilliam.Kucharski@Sun.COM /* Sum the rest of the udp packet */
3968044SWilliam.Kucharski@Sun.COM checksum = add_ipchksums(12, checksum, ipchksum(udp, ntohs(udp->len)));
3978044SWilliam.Kucharski@Sun.COM return checksum;
3988044SWilliam.Kucharski@Sun.COM }
3998044SWilliam.Kucharski@Sun.COM
4008044SWilliam.Kucharski@Sun.COM
build_udp_hdr(unsigned long destip,unsigned int srcsock,unsigned int destsock,int ttl,int len,const void * buf)4018044SWilliam.Kucharski@Sun.COM void build_udp_hdr(unsigned long destip,
4028044SWilliam.Kucharski@Sun.COM unsigned int srcsock, unsigned int destsock, int ttl,
4038044SWilliam.Kucharski@Sun.COM int len, const void *buf)
4048044SWilliam.Kucharski@Sun.COM {
4058044SWilliam.Kucharski@Sun.COM struct iphdr *ip;
4068044SWilliam.Kucharski@Sun.COM struct udphdr *udp;
4078044SWilliam.Kucharski@Sun.COM ip = (struct iphdr *)buf;
4088044SWilliam.Kucharski@Sun.COM build_ip_hdr(destip, ttl, IP_UDP, 0, len, buf);
4098044SWilliam.Kucharski@Sun.COM udp = (struct udphdr *)((char *)buf + sizeof(struct iphdr));
4108044SWilliam.Kucharski@Sun.COM udp->src = htons(srcsock);
4118044SWilliam.Kucharski@Sun.COM udp->dest = htons(destsock);
4128044SWilliam.Kucharski@Sun.COM udp->len = htons(len - sizeof(struct iphdr));
4138044SWilliam.Kucharski@Sun.COM udp->chksum = 0;
4148044SWilliam.Kucharski@Sun.COM if ((udp->chksum = udpchksum(ip, udp)) == 0)
4158044SWilliam.Kucharski@Sun.COM udp->chksum = 0xffff;
4168044SWilliam.Kucharski@Sun.COM }
4178044SWilliam.Kucharski@Sun.COM
4188044SWilliam.Kucharski@Sun.COM
4198044SWilliam.Kucharski@Sun.COM /**************************************************************************
4208044SWilliam.Kucharski@Sun.COM UDP_TRANSMIT - Send an UDP datagram
4218044SWilliam.Kucharski@Sun.COM **************************************************************************/
udp_transmit(unsigned long destip,unsigned int srcsock,unsigned int destsock,int len,const void * buf)4228044SWilliam.Kucharski@Sun.COM int udp_transmit(unsigned long destip, unsigned int srcsock,
4238044SWilliam.Kucharski@Sun.COM unsigned int destsock, int len, const void *buf)
4248044SWilliam.Kucharski@Sun.COM {
4258044SWilliam.Kucharski@Sun.COM build_udp_hdr(destip, srcsock, destsock, 60, len, buf);
4268044SWilliam.Kucharski@Sun.COM return ip_transmit(len, buf);
4278044SWilliam.Kucharski@Sun.COM }
4288044SWilliam.Kucharski@Sun.COM
4298044SWilliam.Kucharski@Sun.COM /**************************************************************************
4308044SWilliam.Kucharski@Sun.COM QDRAIN - clear the nic's receive queue
4318044SWilliam.Kucharski@Sun.COM **************************************************************************/
await_qdrain(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp __unused)4328044SWilliam.Kucharski@Sun.COM static int await_qdrain(int ival __unused, void *ptr __unused,
4338044SWilliam.Kucharski@Sun.COM unsigned short ptype __unused,
4348044SWilliam.Kucharski@Sun.COM struct iphdr *ip __unused, struct udphdr *udp __unused)
4358044SWilliam.Kucharski@Sun.COM {
4368044SWilliam.Kucharski@Sun.COM return 0;
4378044SWilliam.Kucharski@Sun.COM }
4388044SWilliam.Kucharski@Sun.COM
rx_qdrain(void)4398044SWilliam.Kucharski@Sun.COM void rx_qdrain(void)
4408044SWilliam.Kucharski@Sun.COM {
4418044SWilliam.Kucharski@Sun.COM /* Clear out the Rx queue first. It contains nothing of interest,
4428044SWilliam.Kucharski@Sun.COM * except possibly ARP requests from the DHCP/TFTP server. We use
4438044SWilliam.Kucharski@Sun.COM * polling throughout Etherboot, so some time may have passed since we
4448044SWilliam.Kucharski@Sun.COM * last polled the receive queue, which may now be filled with
4458044SWilliam.Kucharski@Sun.COM * broadcast packets. This will cause the reply to the packets we are
4468044SWilliam.Kucharski@Sun.COM * about to send to be lost immediately. Not very clever. */
4478044SWilliam.Kucharski@Sun.COM await_reply(await_qdrain, 0, NULL, 0);
4488044SWilliam.Kucharski@Sun.COM }
4498044SWilliam.Kucharski@Sun.COM
4508044SWilliam.Kucharski@Sun.COM /**
4518044SWilliam.Kucharski@Sun.COM * rarp
4528044SWilliam.Kucharski@Sun.COM *
4538044SWilliam.Kucharski@Sun.COM * Get IP address by rarp. Just copy from etherboot
4548044SWilliam.Kucharski@Sun.COM **/
await_rarp(int ival,void * ptr,unsigned short ptype,struct iphdr * ip,struct udphdr * udp)4558044SWilliam.Kucharski@Sun.COM static int await_rarp(int ival, void *ptr, unsigned short ptype,
4568044SWilliam.Kucharski@Sun.COM struct iphdr *ip, struct udphdr *udp)
4578044SWilliam.Kucharski@Sun.COM {
4588044SWilliam.Kucharski@Sun.COM struct arprequest *arpreply;
4598044SWilliam.Kucharski@Sun.COM if (ptype != RARP)
4608044SWilliam.Kucharski@Sun.COM return 0;
4618044SWilliam.Kucharski@Sun.COM if (nic.packetlen < ETH_HLEN + sizeof(struct arprequest))
4628044SWilliam.Kucharski@Sun.COM return 0;
4638044SWilliam.Kucharski@Sun.COM arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
4648044SWilliam.Kucharski@Sun.COM if (arpreply->opcode != htons(RARP_REPLY))
4658044SWilliam.Kucharski@Sun.COM return 0;
4668044SWilliam.Kucharski@Sun.COM if (memcmp(arpreply->thwaddr, ptr, ETH_ALEN) == 0){
4678044SWilliam.Kucharski@Sun.COM memcpy(arptable[ARP_SERVER].node, arpreply->shwaddr, ETH_ALEN);
4688044SWilliam.Kucharski@Sun.COM memcpy(&arptable[ARP_SERVER].ipaddr, arpreply->sipaddr, sizeof(in_addr));
4698044SWilliam.Kucharski@Sun.COM memcpy(&arptable[ARP_CLIENT].ipaddr, arpreply->tipaddr, sizeof(in_addr));
4708044SWilliam.Kucharski@Sun.COM memset(&arptable[ARP_GATEWAY].ipaddr, 0, sizeof(in_addr));
4718044SWilliam.Kucharski@Sun.COM return 1;
4728044SWilliam.Kucharski@Sun.COM }
4738044SWilliam.Kucharski@Sun.COM return 0;
4748044SWilliam.Kucharski@Sun.COM }
4758044SWilliam.Kucharski@Sun.COM
rarp(void)4768044SWilliam.Kucharski@Sun.COM int rarp(void)
4778044SWilliam.Kucharski@Sun.COM {
4788044SWilliam.Kucharski@Sun.COM int retry;
4798044SWilliam.Kucharski@Sun.COM
4808044SWilliam.Kucharski@Sun.COM /* arp and rarp requests share the same packet structure. */
4818044SWilliam.Kucharski@Sun.COM struct arprequest rarpreq;
4828044SWilliam.Kucharski@Sun.COM
4838044SWilliam.Kucharski@Sun.COM if(!grub_eth_probe())
4848044SWilliam.Kucharski@Sun.COM return 0;
4858044SWilliam.Kucharski@Sun.COM network_ready = 0;
4868044SWilliam.Kucharski@Sun.COM
4878044SWilliam.Kucharski@Sun.COM memset(&rarpreq, 0, sizeof(rarpreq));
4888044SWilliam.Kucharski@Sun.COM
4898044SWilliam.Kucharski@Sun.COM rarpreq.hwtype = htons(1);
4908044SWilliam.Kucharski@Sun.COM rarpreq.protocol = htons(IP);
4918044SWilliam.Kucharski@Sun.COM rarpreq.hwlen = ETH_ALEN;
4928044SWilliam.Kucharski@Sun.COM rarpreq.protolen = 4;
4938044SWilliam.Kucharski@Sun.COM rarpreq.opcode = htons(RARP_REQUEST);
4948044SWilliam.Kucharski@Sun.COM memcpy(&rarpreq.shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4958044SWilliam.Kucharski@Sun.COM /* sipaddr is already zeroed out */
4968044SWilliam.Kucharski@Sun.COM memcpy(&rarpreq.thwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
4978044SWilliam.Kucharski@Sun.COM /* tipaddr is already zeroed out */
4988044SWilliam.Kucharski@Sun.COM
4998044SWilliam.Kucharski@Sun.COM for (retry = 0; retry < MAX_ARP_RETRIES; ++retry) {
5008044SWilliam.Kucharski@Sun.COM long timeout;
5018044SWilliam.Kucharski@Sun.COM eth_transmit(broadcast, RARP, sizeof(rarpreq), &rarpreq);
5028044SWilliam.Kucharski@Sun.COM
5038044SWilliam.Kucharski@Sun.COM timeout = rfc2131_sleep_interval(TIMEOUT, retry);
5048044SWilliam.Kucharski@Sun.COM if (await_reply(await_rarp, 0, rarpreq.shwaddr, timeout))
5058044SWilliam.Kucharski@Sun.COM break;
5068044SWilliam.Kucharski@Sun.COM if (user_abort)
5078044SWilliam.Kucharski@Sun.COM return 0;
5088044SWilliam.Kucharski@Sun.COM }
5098044SWilliam.Kucharski@Sun.COM
5108044SWilliam.Kucharski@Sun.COM if (retry == MAX_ARP_RETRIES) {
5118044SWilliam.Kucharski@Sun.COM return (0);
5128044SWilliam.Kucharski@Sun.COM }
5138044SWilliam.Kucharski@Sun.COM
5148044SWilliam.Kucharski@Sun.COM network_ready = 1;
5158044SWilliam.Kucharski@Sun.COM update_network_configuration();
5168044SWilliam.Kucharski@Sun.COM return (1);
5178044SWilliam.Kucharski@Sun.COM }
5188044SWilliam.Kucharski@Sun.COM
5198044SWilliam.Kucharski@Sun.COM /**
5208044SWilliam.Kucharski@Sun.COM * bootp
5218044SWilliam.Kucharski@Sun.COM *
5228044SWilliam.Kucharski@Sun.COM * Get IP address by bootp, segregate from bootp in etherboot.
5238044SWilliam.Kucharski@Sun.COM **/
await_bootp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)5248044SWilliam.Kucharski@Sun.COM static int await_bootp(int ival __unused, void *ptr __unused,
5258044SWilliam.Kucharski@Sun.COM unsigned short ptype __unused, struct iphdr *ip __unused,
5268044SWilliam.Kucharski@Sun.COM struct udphdr *udp)
5278044SWilliam.Kucharski@Sun.COM {
5288044SWilliam.Kucharski@Sun.COM struct bootp_t *bootpreply;
5298044SWilliam.Kucharski@Sun.COM int len; /* Length of vendor */
5308044SWilliam.Kucharski@Sun.COM
5318044SWilliam.Kucharski@Sun.COM if (!udp) {
5328044SWilliam.Kucharski@Sun.COM return 0;
5338044SWilliam.Kucharski@Sun.COM }
5348044SWilliam.Kucharski@Sun.COM bootpreply = (struct bootp_t *)
5358044SWilliam.Kucharski@Sun.COM &nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
5368044SWilliam.Kucharski@Sun.COM len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
5378044SWilliam.Kucharski@Sun.COM sizeof(struct udphdr) + sizeof(struct bootp_t) - BOOTP_VENDOR_LEN);
5388044SWilliam.Kucharski@Sun.COM if (len < 0) {
5398044SWilliam.Kucharski@Sun.COM return 0;
5408044SWilliam.Kucharski@Sun.COM }
5418044SWilliam.Kucharski@Sun.COM if (udp->dest != htons(BOOTP_CLIENT))
5428044SWilliam.Kucharski@Sun.COM return 0;
5438044SWilliam.Kucharski@Sun.COM if (bootpreply->bp_op != BOOTP_REPLY)
5448044SWilliam.Kucharski@Sun.COM return 0;
5458044SWilliam.Kucharski@Sun.COM if (bootpreply->bp_xid != xid)
5468044SWilliam.Kucharski@Sun.COM return 0;
5478044SWilliam.Kucharski@Sun.COM if (memcmp((char *)&bootpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
5488044SWilliam.Kucharski@Sun.COM return 0;
5498044SWilliam.Kucharski@Sun.COM if ((memcmp(broadcast, bootpreply->bp_hwaddr, ETH_ALEN) != 0) &&
5508044SWilliam.Kucharski@Sun.COM (memcmp(arptable[ARP_CLIENT].node, bootpreply->bp_hwaddr, ETH_ALEN) != 0)) {
5518044SWilliam.Kucharski@Sun.COM return 0;
5528044SWilliam.Kucharski@Sun.COM }
5538044SWilliam.Kucharski@Sun.COM
5548044SWilliam.Kucharski@Sun.COM #ifdef SOLARIS_NETBOOT
5558044SWilliam.Kucharski@Sun.COM /* fill in netinfo */
5568044SWilliam.Kucharski@Sun.COM dhcpack_length = len + sizeof (struct bootp_t) - BOOTP_VENDOR_LEN;
5578044SWilliam.Kucharski@Sun.COM memcpy((char *)dhcpack_buf, (char *)bootpreply, dhcpack_length);
5588044SWilliam.Kucharski@Sun.COM #endif
5598044SWilliam.Kucharski@Sun.COM
5608044SWilliam.Kucharski@Sun.COM arptable[ARP_CLIENT].ipaddr.s_addr = bootpreply->bp_yiaddr.s_addr;
5618044SWilliam.Kucharski@Sun.COM netmask = default_netmask();
5628044SWilliam.Kucharski@Sun.COM arptable[ARP_SERVER].ipaddr.s_addr = bootpreply->bp_siaddr.s_addr;
5638044SWilliam.Kucharski@Sun.COM memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
5648044SWilliam.Kucharski@Sun.COM arptable[ARP_GATEWAY].ipaddr.s_addr = bootpreply->bp_giaddr.s_addr;
5658044SWilliam.Kucharski@Sun.COM memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
566*9037SJan.Setje-Eilers@Sun.COM bootfile = bootpreply->bp_file;
5678044SWilliam.Kucharski@Sun.COM memcpy((char *)rfc1533_venddata, (char *)(bootpreply->bp_vend), len);
5688044SWilliam.Kucharski@Sun.COM decode_rfc1533(rfc1533_venddata, 0, len, 1);
5698044SWilliam.Kucharski@Sun.COM return(1);
5708044SWilliam.Kucharski@Sun.COM }
5718044SWilliam.Kucharski@Sun.COM
bootp(void)5728044SWilliam.Kucharski@Sun.COM int bootp(void)
5738044SWilliam.Kucharski@Sun.COM {
5748044SWilliam.Kucharski@Sun.COM int retry;
5758044SWilliam.Kucharski@Sun.COM struct bootpip_t ip;
5768044SWilliam.Kucharski@Sun.COM unsigned long starttime;
5778044SWilliam.Kucharski@Sun.COM
5788044SWilliam.Kucharski@Sun.COM EnterFunction("bootp");
5798044SWilliam.Kucharski@Sun.COM
5808044SWilliam.Kucharski@Sun.COM if(!grub_eth_probe())
5818044SWilliam.Kucharski@Sun.COM return 0;
5828044SWilliam.Kucharski@Sun.COM network_ready = 0;
5838044SWilliam.Kucharski@Sun.COM
5848044SWilliam.Kucharski@Sun.COM memset(&ip, 0, sizeof(struct bootpip_t));
5858044SWilliam.Kucharski@Sun.COM ip.bp.bp_op = BOOTP_REQUEST;
5868044SWilliam.Kucharski@Sun.COM ip.bp.bp_htype = 1;
5878044SWilliam.Kucharski@Sun.COM ip.bp.bp_hlen = ETH_ALEN;
5888044SWilliam.Kucharski@Sun.COM starttime = currticks();
5898044SWilliam.Kucharski@Sun.COM /* Use lower 32 bits of node address, more likely to be
5908044SWilliam.Kucharski@Sun.COM distinct than the time since booting */
5918044SWilliam.Kucharski@Sun.COM memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
5928044SWilliam.Kucharski@Sun.COM ip.bp.bp_xid = xid += htonl(starttime);
5938044SWilliam.Kucharski@Sun.COM /* bp_secs defaults to zero */
5948044SWilliam.Kucharski@Sun.COM memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
5958044SWilliam.Kucharski@Sun.COM memcpy(ip.bp.bp_vend, rfc1533_cookie_bootp, sizeof(rfc1533_cookie_bootp)); /* request RFC-style options */
5968044SWilliam.Kucharski@Sun.COM
5978044SWilliam.Kucharski@Sun.COM for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
5988044SWilliam.Kucharski@Sun.COM long timeout;
5998044SWilliam.Kucharski@Sun.COM
6008044SWilliam.Kucharski@Sun.COM rx_qdrain();
6018044SWilliam.Kucharski@Sun.COM
6028044SWilliam.Kucharski@Sun.COM udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
6038044SWilliam.Kucharski@Sun.COM sizeof(struct bootpip_t), &ip);
6048044SWilliam.Kucharski@Sun.COM timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
6058044SWilliam.Kucharski@Sun.COM if (await_reply(await_bootp, 0, NULL, timeout)){
6068044SWilliam.Kucharski@Sun.COM network_ready = 1;
6078044SWilliam.Kucharski@Sun.COM return(1);
6088044SWilliam.Kucharski@Sun.COM }
6098044SWilliam.Kucharski@Sun.COM if (user_abort)
6108044SWilliam.Kucharski@Sun.COM return 0;
6118044SWilliam.Kucharski@Sun.COM ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
6128044SWilliam.Kucharski@Sun.COM }
6138044SWilliam.Kucharski@Sun.COM return(0);
6148044SWilliam.Kucharski@Sun.COM }
6158044SWilliam.Kucharski@Sun.COM
6168044SWilliam.Kucharski@Sun.COM /**
6178044SWilliam.Kucharski@Sun.COM * dhcp
6188044SWilliam.Kucharski@Sun.COM *
6198044SWilliam.Kucharski@Sun.COM * Get IP address by dhcp, segregate from bootp in etherboot.
6208044SWilliam.Kucharski@Sun.COM **/
await_dhcp(int ival __unused,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip __unused,struct udphdr * udp)6218044SWilliam.Kucharski@Sun.COM static int await_dhcp(int ival __unused, void *ptr __unused,
6228044SWilliam.Kucharski@Sun.COM unsigned short ptype __unused, struct iphdr *ip __unused,
6238044SWilliam.Kucharski@Sun.COM struct udphdr *udp)
6248044SWilliam.Kucharski@Sun.COM {
6258044SWilliam.Kucharski@Sun.COM struct dhcp_t *dhcpreply;
6268044SWilliam.Kucharski@Sun.COM int len;
6278044SWilliam.Kucharski@Sun.COM
6288044SWilliam.Kucharski@Sun.COM if (!udp) {
6298044SWilliam.Kucharski@Sun.COM return 0;
6308044SWilliam.Kucharski@Sun.COM }
6318044SWilliam.Kucharski@Sun.COM dhcpreply = (struct dhcp_t *)
6328044SWilliam.Kucharski@Sun.COM &nic.packet[ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)];
6338044SWilliam.Kucharski@Sun.COM len = nic.packetlen - (ETH_HLEN + sizeof(struct iphdr) +
6348044SWilliam.Kucharski@Sun.COM sizeof(struct udphdr) + sizeof(struct dhcp_t) - DHCP_OPT_LEN);
6358044SWilliam.Kucharski@Sun.COM if (len < 0){
6368044SWilliam.Kucharski@Sun.COM return 0;
6378044SWilliam.Kucharski@Sun.COM }
6388044SWilliam.Kucharski@Sun.COM if (udp->dest != htons(BOOTP_CLIENT))
6398044SWilliam.Kucharski@Sun.COM return 0;
6408044SWilliam.Kucharski@Sun.COM if (dhcpreply->bp_op != BOOTP_REPLY)
6418044SWilliam.Kucharski@Sun.COM return 0;
6428044SWilliam.Kucharski@Sun.COM if (dhcpreply->bp_xid != xid)
6438044SWilliam.Kucharski@Sun.COM return 0;
6448044SWilliam.Kucharski@Sun.COM if (memcmp((char *)&dhcpreply->bp_siaddr, (char *)&zeroIP, sizeof(in_addr)) == 0)
6458044SWilliam.Kucharski@Sun.COM return 0;
6468044SWilliam.Kucharski@Sun.COM if ((memcmp(broadcast, dhcpreply->bp_hwaddr, ETH_ALEN) != 0) &&
6478044SWilliam.Kucharski@Sun.COM (memcmp(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN) != 0)) {
6488044SWilliam.Kucharski@Sun.COM return 0;
6498044SWilliam.Kucharski@Sun.COM }
6508044SWilliam.Kucharski@Sun.COM
6518044SWilliam.Kucharski@Sun.COM #ifdef SOLARIS_NETBOOT
6528044SWilliam.Kucharski@Sun.COM /* fill in netinfo */
6538044SWilliam.Kucharski@Sun.COM dhcpack_length = len + sizeof (struct dhcp_t) - DHCP_OPT_LEN;
6548044SWilliam.Kucharski@Sun.COM memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
6558044SWilliam.Kucharski@Sun.COM #endif
6568044SWilliam.Kucharski@Sun.COM arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6578044SWilliam.Kucharski@Sun.COM dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
6588044SWilliam.Kucharski@Sun.COM netmask = default_netmask();
6598044SWilliam.Kucharski@Sun.COM arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
6608044SWilliam.Kucharski@Sun.COM memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
6618044SWilliam.Kucharski@Sun.COM arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
6628044SWilliam.Kucharski@Sun.COM memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
663*9037SJan.Setje-Eilers@Sun.COM bootfile = dhcpreply->bp_file;
6648044SWilliam.Kucharski@Sun.COM memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
6658044SWilliam.Kucharski@Sun.COM decode_rfc1533(rfc1533_venddata, 0, len, 1);
6668044SWilliam.Kucharski@Sun.COM return(1);
6678044SWilliam.Kucharski@Sun.COM }
6688044SWilliam.Kucharski@Sun.COM
dhcp(void)6698044SWilliam.Kucharski@Sun.COM int dhcp(void)
6708044SWilliam.Kucharski@Sun.COM {
6718044SWilliam.Kucharski@Sun.COM int retry;
6728044SWilliam.Kucharski@Sun.COM int reqretry;
6738044SWilliam.Kucharski@Sun.COM struct dhcpip_t ip;
6748044SWilliam.Kucharski@Sun.COM unsigned long starttime;
6758044SWilliam.Kucharski@Sun.COM
6768044SWilliam.Kucharski@Sun.COM /* try bios pxe stack first */
6778044SWilliam.Kucharski@Sun.COM if (dhcp_undi())
6788044SWilliam.Kucharski@Sun.COM return 1;
6798044SWilliam.Kucharski@Sun.COM
6808044SWilliam.Kucharski@Sun.COM if(!grub_eth_probe())
6818044SWilliam.Kucharski@Sun.COM return 0;
6828044SWilliam.Kucharski@Sun.COM
6838044SWilliam.Kucharski@Sun.COM network_ready = 0;
6848044SWilliam.Kucharski@Sun.COM
6858044SWilliam.Kucharski@Sun.COM memset(&ip, 0, sizeof(ip));
6868044SWilliam.Kucharski@Sun.COM ip.bp.bp_op = BOOTP_REQUEST;
6878044SWilliam.Kucharski@Sun.COM ip.bp.bp_htype = 1;
6888044SWilliam.Kucharski@Sun.COM ip.bp.bp_hlen = ETH_ALEN;
6898044SWilliam.Kucharski@Sun.COM starttime = currticks();
6908044SWilliam.Kucharski@Sun.COM /* Use lower 32 bits of node address, more likely to be
6918044SWilliam.Kucharski@Sun.COM distinct than the time since booting */
6928044SWilliam.Kucharski@Sun.COM memcpy(&xid, &arptable[ARP_CLIENT].node[2], sizeof(xid));
6938044SWilliam.Kucharski@Sun.COM ip.bp.bp_xid = xid += htonl(starttime);
6948044SWilliam.Kucharski@Sun.COM memcpy(ip.bp.bp_hwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
6958044SWilliam.Kucharski@Sun.COM memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp); /* request RFC-style options */
6968044SWilliam.Kucharski@Sun.COM memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcpdiscover, sizeof dhcpdiscover);
6978044SWilliam.Kucharski@Sun.COM
6988044SWilliam.Kucharski@Sun.COM for (retry = 0; retry < MAX_BOOTP_RETRIES; ) {
6998044SWilliam.Kucharski@Sun.COM long timeout;
7008044SWilliam.Kucharski@Sun.COM
7018044SWilliam.Kucharski@Sun.COM rx_qdrain();
7028044SWilliam.Kucharski@Sun.COM
7038044SWilliam.Kucharski@Sun.COM udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7048044SWilliam.Kucharski@Sun.COM sizeof(ip), &ip);
7058044SWilliam.Kucharski@Sun.COM timeout = rfc2131_sleep_interval(TIMEOUT, retry++);
7068044SWilliam.Kucharski@Sun.COM if (await_reply(await_dhcp, 0, NULL, timeout)) {
7078044SWilliam.Kucharski@Sun.COM /* If not a DHCPOFFER then must be just a
7088044SWilliam.Kucharski@Sun.COM BOOTP reply, be backward compatible with
7098044SWilliam.Kucharski@Sun.COM BOOTP then. Jscott report a bug here, but I
7108044SWilliam.Kucharski@Sun.COM don't know how it happened */
7118044SWilliam.Kucharski@Sun.COM if (dhcp_reply != DHCPOFFER){
7128044SWilliam.Kucharski@Sun.COM network_ready = 1;
7138044SWilliam.Kucharski@Sun.COM return(1);
7148044SWilliam.Kucharski@Sun.COM }
7158044SWilliam.Kucharski@Sun.COM dhcp_reply = 0;
7168044SWilliam.Kucharski@Sun.COM memcpy(ip.bp.bp_vend, rfc1533_cookie_dhcp, sizeof rfc1533_cookie_dhcp);
7178044SWilliam.Kucharski@Sun.COM memcpy(ip.bp.bp_vend + sizeof rfc1533_cookie_dhcp, dhcprequest, sizeof dhcprequest);
7188044SWilliam.Kucharski@Sun.COM /* Beware: the magic numbers 9 and 15 depend on
7198044SWilliam.Kucharski@Sun.COM the layout of dhcprequest */
7208044SWilliam.Kucharski@Sun.COM memcpy(&ip.bp.bp_vend[9], &dhcp_server, sizeof(in_addr));
7218044SWilliam.Kucharski@Sun.COM memcpy(&ip.bp.bp_vend[15], &dhcp_addr, sizeof(in_addr));
7228044SWilliam.Kucharski@Sun.COM for (reqretry = 0; reqretry < MAX_BOOTP_RETRIES; ) {
7238044SWilliam.Kucharski@Sun.COM udp_transmit(IP_BROADCAST, BOOTP_CLIENT, BOOTP_SERVER,
7248044SWilliam.Kucharski@Sun.COM sizeof(ip), &ip);
7258044SWilliam.Kucharski@Sun.COM dhcp_reply=0;
7268044SWilliam.Kucharski@Sun.COM timeout = rfc2131_sleep_interval(TIMEOUT, reqretry++);
7278044SWilliam.Kucharski@Sun.COM if (await_reply(await_dhcp, 0, NULL, timeout))
7288044SWilliam.Kucharski@Sun.COM if (dhcp_reply == DHCPACK){
7298044SWilliam.Kucharski@Sun.COM network_ready = 1;
7308044SWilliam.Kucharski@Sun.COM return(1);
7318044SWilliam.Kucharski@Sun.COM }
7328044SWilliam.Kucharski@Sun.COM if (user_abort)
7338044SWilliam.Kucharski@Sun.COM return 0;
7348044SWilliam.Kucharski@Sun.COM }
7358044SWilliam.Kucharski@Sun.COM }
7368044SWilliam.Kucharski@Sun.COM if (user_abort)
7378044SWilliam.Kucharski@Sun.COM return 0;
7388044SWilliam.Kucharski@Sun.COM ip.bp.bp_secs = htons((currticks()-starttime)/TICKS_PER_SEC);
7398044SWilliam.Kucharski@Sun.COM }
7408044SWilliam.Kucharski@Sun.COM return(0);
7418044SWilliam.Kucharski@Sun.COM }
7428044SWilliam.Kucharski@Sun.COM
7438044SWilliam.Kucharski@Sun.COM #ifdef MULTICAST_LEVEL2
send_igmp_reports(unsigned long now)7448044SWilliam.Kucharski@Sun.COM static void send_igmp_reports(unsigned long now)
7458044SWilliam.Kucharski@Sun.COM {
7468044SWilliam.Kucharski@Sun.COM int i;
7478044SWilliam.Kucharski@Sun.COM for(i = 0; i < MAX_IGMP; i++) {
7488044SWilliam.Kucharski@Sun.COM if (igmptable[i].time && (now >= igmptable[i].time)) {
7498044SWilliam.Kucharski@Sun.COM struct igmp_ip_t igmp;
7508044SWilliam.Kucharski@Sun.COM igmp.router_alert[0] = 0x94;
7518044SWilliam.Kucharski@Sun.COM igmp.router_alert[1] = 0x04;
7528044SWilliam.Kucharski@Sun.COM igmp.router_alert[2] = 0;
7538044SWilliam.Kucharski@Sun.COM igmp.router_alert[3] = 0;
7548044SWilliam.Kucharski@Sun.COM build_ip_hdr(igmptable[i].group.s_addr,
7558044SWilliam.Kucharski@Sun.COM 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
7568044SWilliam.Kucharski@Sun.COM igmp.igmp.type = IGMPv2_REPORT;
7578044SWilliam.Kucharski@Sun.COM if (last_igmpv1 &&
7588044SWilliam.Kucharski@Sun.COM (now < last_igmpv1 + IGMPv1_ROUTER_PRESENT_TIMEOUT)) {
7598044SWilliam.Kucharski@Sun.COM igmp.igmp.type = IGMPv1_REPORT;
7608044SWilliam.Kucharski@Sun.COM }
7618044SWilliam.Kucharski@Sun.COM igmp.igmp.response_time = 0;
7628044SWilliam.Kucharski@Sun.COM igmp.igmp.chksum = 0;
7638044SWilliam.Kucharski@Sun.COM igmp.igmp.group.s_addr = igmptable[i].group.s_addr;
7648044SWilliam.Kucharski@Sun.COM igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp.igmp));
7658044SWilliam.Kucharski@Sun.COM ip_transmit(sizeof(igmp), &igmp);
7668044SWilliam.Kucharski@Sun.COM #ifdef MDEBUG
7678044SWilliam.Kucharski@Sun.COM printf("Sent IGMP report to: %@\n", igmp.igmp.group.s_addr);
7688044SWilliam.Kucharski@Sun.COM #endif
7698044SWilliam.Kucharski@Sun.COM /* Don't send another igmp report until asked */
7708044SWilliam.Kucharski@Sun.COM igmptable[i].time = 0;
7718044SWilliam.Kucharski@Sun.COM }
7728044SWilliam.Kucharski@Sun.COM }
7738044SWilliam.Kucharski@Sun.COM }
7748044SWilliam.Kucharski@Sun.COM
process_igmp(struct iphdr * ip,unsigned long now)7758044SWilliam.Kucharski@Sun.COM static void process_igmp(struct iphdr *ip, unsigned long now)
7768044SWilliam.Kucharski@Sun.COM {
7778044SWilliam.Kucharski@Sun.COM struct igmp *igmp;
7788044SWilliam.Kucharski@Sun.COM int i;
7798044SWilliam.Kucharski@Sun.COM unsigned iplen = 0;
7808044SWilliam.Kucharski@Sun.COM if (!ip || (ip->protocol == IP_IGMP) ||
7818044SWilliam.Kucharski@Sun.COM (nic.packetlen < sizeof(struct iphdr) + sizeof(struct igmp))) {
7828044SWilliam.Kucharski@Sun.COM return;
7838044SWilliam.Kucharski@Sun.COM }
7848044SWilliam.Kucharski@Sun.COM iplen = (ip->verhdrlen & 0xf)*4;
7858044SWilliam.Kucharski@Sun.COM igmp = (struct igmp *)&nic.packet[sizeof(struct iphdr)];
7868044SWilliam.Kucharski@Sun.COM if (ipchksum(igmp, ntohs(ip->len) - iplen) != 0)
7878044SWilliam.Kucharski@Sun.COM return;
7888044SWilliam.Kucharski@Sun.COM if ((igmp->type == IGMP_QUERY) &&
7898044SWilliam.Kucharski@Sun.COM (ip->dest.s_addr == htonl(GROUP_ALL_HOSTS))) {
7908044SWilliam.Kucharski@Sun.COM unsigned long interval = IGMP_INTERVAL;
7918044SWilliam.Kucharski@Sun.COM if (igmp->response_time == 0) {
7928044SWilliam.Kucharski@Sun.COM last_igmpv1 = now;
7938044SWilliam.Kucharski@Sun.COM } else {
7948044SWilliam.Kucharski@Sun.COM interval = (igmp->response_time * TICKS_PER_SEC)/10;
7958044SWilliam.Kucharski@Sun.COM }
7968044SWilliam.Kucharski@Sun.COM
7978044SWilliam.Kucharski@Sun.COM #ifdef MDEBUG
7988044SWilliam.Kucharski@Sun.COM printf("Received IGMP query for: %@\n", igmp->group.s_addr);
7998044SWilliam.Kucharski@Sun.COM #endif
8008044SWilliam.Kucharski@Sun.COM for(i = 0; i < MAX_IGMP; i++) {
8018044SWilliam.Kucharski@Sun.COM uint32_t group = igmptable[i].group.s_addr;
8028044SWilliam.Kucharski@Sun.COM if ((group == 0) || (group == igmp->group.s_addr)) {
8038044SWilliam.Kucharski@Sun.COM unsigned long time;
8048044SWilliam.Kucharski@Sun.COM time = currticks() + rfc1112_sleep_interval(interval, 0);
8058044SWilliam.Kucharski@Sun.COM if (time < igmptable[i].time) {
8068044SWilliam.Kucharski@Sun.COM igmptable[i].time = time;
8078044SWilliam.Kucharski@Sun.COM }
8088044SWilliam.Kucharski@Sun.COM }
8098044SWilliam.Kucharski@Sun.COM }
8108044SWilliam.Kucharski@Sun.COM }
8118044SWilliam.Kucharski@Sun.COM if (((igmp->type == IGMPv1_REPORT) || (igmp->type == IGMPv2_REPORT)) &&
8128044SWilliam.Kucharski@Sun.COM (ip->dest.s_addr == igmp->group.s_addr)) {
8138044SWilliam.Kucharski@Sun.COM #ifdef MDEBUG
8148044SWilliam.Kucharski@Sun.COM printf("Received IGMP report for: %@\n", igmp->group.s_addr);
8158044SWilliam.Kucharski@Sun.COM #endif
8168044SWilliam.Kucharski@Sun.COM for(i = 0; i < MAX_IGMP; i++) {
8178044SWilliam.Kucharski@Sun.COM if ((igmptable[i].group.s_addr == igmp->group.s_addr) &&
8188044SWilliam.Kucharski@Sun.COM igmptable[i].time != 0) {
8198044SWilliam.Kucharski@Sun.COM igmptable[i].time = 0;
8208044SWilliam.Kucharski@Sun.COM }
8218044SWilliam.Kucharski@Sun.COM }
8228044SWilliam.Kucharski@Sun.COM }
8238044SWilliam.Kucharski@Sun.COM }
8248044SWilliam.Kucharski@Sun.COM
leave_group(int slot)8258044SWilliam.Kucharski@Sun.COM void leave_group(int slot)
8268044SWilliam.Kucharski@Sun.COM {
8278044SWilliam.Kucharski@Sun.COM /* Be very stupid and always send a leave group message if
8288044SWilliam.Kucharski@Sun.COM * I have subscribed. Imperfect but it is standards
8298044SWilliam.Kucharski@Sun.COM * compliant, easy and reliable to implement.
8308044SWilliam.Kucharski@Sun.COM *
8318044SWilliam.Kucharski@Sun.COM * The optimal group leave method is to only send leave when,
8328044SWilliam.Kucharski@Sun.COM * we were the last host to respond to a query on this group,
8338044SWilliam.Kucharski@Sun.COM * and igmpv1 compatibility is not enabled.
8348044SWilliam.Kucharski@Sun.COM */
8358044SWilliam.Kucharski@Sun.COM if (igmptable[slot].group.s_addr) {
8368044SWilliam.Kucharski@Sun.COM struct igmp_ip_t igmp;
8378044SWilliam.Kucharski@Sun.COM igmp.router_alert[0] = 0x94;
8388044SWilliam.Kucharski@Sun.COM igmp.router_alert[1] = 0x04;
8398044SWilliam.Kucharski@Sun.COM igmp.router_alert[2] = 0;
8408044SWilliam.Kucharski@Sun.COM igmp.router_alert[3] = 0;
8418044SWilliam.Kucharski@Sun.COM build_ip_hdr(htonl(GROUP_ALL_HOSTS),
8428044SWilliam.Kucharski@Sun.COM 1, IP_IGMP, sizeof(igmp.router_alert), sizeof(igmp), &igmp);
8438044SWilliam.Kucharski@Sun.COM igmp.igmp.type = IGMP_LEAVE;
8448044SWilliam.Kucharski@Sun.COM igmp.igmp.response_time = 0;
8458044SWilliam.Kucharski@Sun.COM igmp.igmp.chksum = 0;
8468044SWilliam.Kucharski@Sun.COM igmp.igmp.group.s_addr = igmptable[slot].group.s_addr;
8478044SWilliam.Kucharski@Sun.COM igmp.igmp.chksum = ipchksum(&igmp.igmp, sizeof(igmp));
8488044SWilliam.Kucharski@Sun.COM ip_transmit(sizeof(igmp), &igmp);
8498044SWilliam.Kucharski@Sun.COM #ifdef MDEBUG
8508044SWilliam.Kucharski@Sun.COM printf("Sent IGMP leave for: %@\n", igmp.igmp.group.s_addr);
8518044SWilliam.Kucharski@Sun.COM #endif
8528044SWilliam.Kucharski@Sun.COM }
8538044SWilliam.Kucharski@Sun.COM memset(&igmptable[slot], 0, sizeof(igmptable[0]));
8548044SWilliam.Kucharski@Sun.COM }
8558044SWilliam.Kucharski@Sun.COM
join_group(int slot,unsigned long group)8568044SWilliam.Kucharski@Sun.COM void join_group(int slot, unsigned long group)
8578044SWilliam.Kucharski@Sun.COM {
8588044SWilliam.Kucharski@Sun.COM /* I have already joined */
8598044SWilliam.Kucharski@Sun.COM if (igmptable[slot].group.s_addr == group)
8608044SWilliam.Kucharski@Sun.COM return;
8618044SWilliam.Kucharski@Sun.COM if (igmptable[slot].group.s_addr) {
8628044SWilliam.Kucharski@Sun.COM leave_group(slot);
8638044SWilliam.Kucharski@Sun.COM }
8648044SWilliam.Kucharski@Sun.COM /* Only join a group if we are given a multicast ip, this way
8658044SWilliam.Kucharski@Sun.COM * code can be given a non-multicast (broadcast or unicast ip)
8668044SWilliam.Kucharski@Sun.COM * and still work...
8678044SWilliam.Kucharski@Sun.COM */
8688044SWilliam.Kucharski@Sun.COM if ((group & htonl(MULTICAST_MASK)) == htonl(MULTICAST_NETWORK)) {
8698044SWilliam.Kucharski@Sun.COM igmptable[slot].group.s_addr = group;
8708044SWilliam.Kucharski@Sun.COM igmptable[slot].time = currticks();
8718044SWilliam.Kucharski@Sun.COM }
8728044SWilliam.Kucharski@Sun.COM }
8738044SWilliam.Kucharski@Sun.COM #else
8748044SWilliam.Kucharski@Sun.COM #define send_igmp_reports(now);
8758044SWilliam.Kucharski@Sun.COM #define process_igmp(ip, now)
8768044SWilliam.Kucharski@Sun.COM #endif
8778044SWilliam.Kucharski@Sun.COM
8788044SWilliam.Kucharski@Sun.COM /**************************************************************************
8798044SWilliam.Kucharski@Sun.COM AWAIT_REPLY - Wait until we get a response for our request
8808044SWilliam.Kucharski@Sun.COM ************f**************************************************************/
await_reply(reply_t reply,int ival,void * ptr,long timeout)8818044SWilliam.Kucharski@Sun.COM int await_reply(reply_t reply, int ival, void *ptr, long timeout)
8828044SWilliam.Kucharski@Sun.COM {
8838044SWilliam.Kucharski@Sun.COM unsigned long time, now;
8848044SWilliam.Kucharski@Sun.COM struct iphdr *ip;
8858044SWilliam.Kucharski@Sun.COM unsigned iplen = 0;
8868044SWilliam.Kucharski@Sun.COM struct udphdr *udp;
8878044SWilliam.Kucharski@Sun.COM unsigned short ptype;
8888044SWilliam.Kucharski@Sun.COM int result;
8898044SWilliam.Kucharski@Sun.COM
8908044SWilliam.Kucharski@Sun.COM user_abort = 0;
8918044SWilliam.Kucharski@Sun.COM
8928044SWilliam.Kucharski@Sun.COM time = timeout + currticks();
8938044SWilliam.Kucharski@Sun.COM /* The timeout check is done below. The timeout is only checked if
8948044SWilliam.Kucharski@Sun.COM * there is no packet in the Rx queue. This assumes that eth_poll()
8958044SWilliam.Kucharski@Sun.COM * needs a negligible amount of time.
8968044SWilliam.Kucharski@Sun.COM */
8978044SWilliam.Kucharski@Sun.COM for (;;) {
8988044SWilliam.Kucharski@Sun.COM now = currticks();
8998044SWilliam.Kucharski@Sun.COM send_igmp_reports(now);
9008044SWilliam.Kucharski@Sun.COM result = eth_poll(1);
9018044SWilliam.Kucharski@Sun.COM if (result == 0) {
9028044SWilliam.Kucharski@Sun.COM /* We don't have anything */
9038044SWilliam.Kucharski@Sun.COM
9048044SWilliam.Kucharski@Sun.COM /* Check for abort key only if the Rx queue is empty -
9058044SWilliam.Kucharski@Sun.COM * as long as we have something to process, don't
9068044SWilliam.Kucharski@Sun.COM * assume that something failed. It is unlikely that
9078044SWilliam.Kucharski@Sun.COM * we have no processing time left between packets. */
9088044SWilliam.Kucharski@Sun.COM poll_interruptions();
9098044SWilliam.Kucharski@Sun.COM /* Do the timeout after at least a full queue walk. */
9108044SWilliam.Kucharski@Sun.COM if ((timeout == 0) || (currticks() > time) || user_abort == 1) {
9118044SWilliam.Kucharski@Sun.COM break;
9128044SWilliam.Kucharski@Sun.COM }
9138044SWilliam.Kucharski@Sun.COM continue;
9148044SWilliam.Kucharski@Sun.COM }
9158044SWilliam.Kucharski@Sun.COM
9168044SWilliam.Kucharski@Sun.COM /* We have something! */
9178044SWilliam.Kucharski@Sun.COM
9188044SWilliam.Kucharski@Sun.COM /* Find the Ethernet packet type */
9198044SWilliam.Kucharski@Sun.COM if (nic.packetlen >= ETH_HLEN) {
9208044SWilliam.Kucharski@Sun.COM ptype = ((unsigned short) nic.packet[12]) << 8
9218044SWilliam.Kucharski@Sun.COM | ((unsigned short) nic.packet[13]);
9228044SWilliam.Kucharski@Sun.COM } else continue; /* what else could we do with it? */
9238044SWilliam.Kucharski@Sun.COM /* Verify an IP header */
9248044SWilliam.Kucharski@Sun.COM ip = 0;
9258044SWilliam.Kucharski@Sun.COM if ((ptype == IP) && (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr))) {
9268044SWilliam.Kucharski@Sun.COM unsigned ipoptlen;
9278044SWilliam.Kucharski@Sun.COM ip = (struct iphdr *)&nic.packet[ETH_HLEN];
9288044SWilliam.Kucharski@Sun.COM if ((ip->verhdrlen < 0x45) || (ip->verhdrlen > 0x4F))
9298044SWilliam.Kucharski@Sun.COM continue;
9308044SWilliam.Kucharski@Sun.COM iplen = (ip->verhdrlen & 0xf) * 4;
9318044SWilliam.Kucharski@Sun.COM if (ipchksum(ip, iplen) != 0)
9328044SWilliam.Kucharski@Sun.COM continue;
9338044SWilliam.Kucharski@Sun.COM if (ip->frags & htons(0x3FFF)) {
9348044SWilliam.Kucharski@Sun.COM static int warned_fragmentation = 0;
9358044SWilliam.Kucharski@Sun.COM if (!warned_fragmentation) {
9368044SWilliam.Kucharski@Sun.COM printf("ALERT: got a fragmented packet - reconfigure your server\n");
9378044SWilliam.Kucharski@Sun.COM warned_fragmentation = 1;
9388044SWilliam.Kucharski@Sun.COM }
9398044SWilliam.Kucharski@Sun.COM continue;
9408044SWilliam.Kucharski@Sun.COM }
9418044SWilliam.Kucharski@Sun.COM if (ntohs(ip->len) > ETH_MAX_MTU)
9428044SWilliam.Kucharski@Sun.COM continue;
9438044SWilliam.Kucharski@Sun.COM
9448044SWilliam.Kucharski@Sun.COM ipoptlen = iplen - sizeof(struct iphdr);
9458044SWilliam.Kucharski@Sun.COM if (ipoptlen) {
9468044SWilliam.Kucharski@Sun.COM /* Delete the ip options, to guarantee
9478044SWilliam.Kucharski@Sun.COM * good alignment, and make etherboot simpler.
9488044SWilliam.Kucharski@Sun.COM */
9498044SWilliam.Kucharski@Sun.COM memmove(&nic.packet[ETH_HLEN + sizeof(struct iphdr)],
9508044SWilliam.Kucharski@Sun.COM &nic.packet[ETH_HLEN + iplen],
9518044SWilliam.Kucharski@Sun.COM nic.packetlen - ipoptlen);
9528044SWilliam.Kucharski@Sun.COM nic.packetlen -= ipoptlen;
9538044SWilliam.Kucharski@Sun.COM }
9548044SWilliam.Kucharski@Sun.COM }
9558044SWilliam.Kucharski@Sun.COM udp = 0;
9568044SWilliam.Kucharski@Sun.COM if (ip && (ip->protocol == IP_UDP) &&
9578044SWilliam.Kucharski@Sun.COM (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr))) {
9588044SWilliam.Kucharski@Sun.COM udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)];
9598044SWilliam.Kucharski@Sun.COM
9608044SWilliam.Kucharski@Sun.COM /* Make certain we have a reasonable packet length */
9618044SWilliam.Kucharski@Sun.COM if (ntohs(udp->len) > (ntohs(ip->len) - iplen))
9628044SWilliam.Kucharski@Sun.COM continue;
9638044SWilliam.Kucharski@Sun.COM
9648044SWilliam.Kucharski@Sun.COM if (udp->chksum && udpchksum(ip, udp)) {
9658044SWilliam.Kucharski@Sun.COM printf("UDP checksum error\n");
9668044SWilliam.Kucharski@Sun.COM continue;
9678044SWilliam.Kucharski@Sun.COM }
9688044SWilliam.Kucharski@Sun.COM }
9698044SWilliam.Kucharski@Sun.COM result = reply(ival, ptr, ptype, ip, udp);
9708044SWilliam.Kucharski@Sun.COM if (result > 0) {
9718044SWilliam.Kucharski@Sun.COM return result;
9728044SWilliam.Kucharski@Sun.COM }
9738044SWilliam.Kucharski@Sun.COM
9748044SWilliam.Kucharski@Sun.COM /* If it isn't a packet the upper layer wants see if there is a default
9758044SWilliam.Kucharski@Sun.COM * action. This allows us reply to arp and igmp queryies.
9768044SWilliam.Kucharski@Sun.COM */
9778044SWilliam.Kucharski@Sun.COM if ((ptype == ARP) &&
9788044SWilliam.Kucharski@Sun.COM (nic.packetlen >= ETH_HLEN + sizeof(struct arprequest))) {
9798044SWilliam.Kucharski@Sun.COM struct arprequest *arpreply;
9808044SWilliam.Kucharski@Sun.COM unsigned long tmp;
9818044SWilliam.Kucharski@Sun.COM
9828044SWilliam.Kucharski@Sun.COM arpreply = (struct arprequest *)&nic.packet[ETH_HLEN];
9838044SWilliam.Kucharski@Sun.COM memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9848044SWilliam.Kucharski@Sun.COM if ((arpreply->opcode == htons(ARP_REQUEST)) &&
9858044SWilliam.Kucharski@Sun.COM (tmp == arptable[ARP_CLIENT].ipaddr.s_addr)) {
9868044SWilliam.Kucharski@Sun.COM arpreply->opcode = htons(ARP_REPLY);
9878044SWilliam.Kucharski@Sun.COM memcpy(arpreply->tipaddr, arpreply->sipaddr, sizeof(in_addr));
9888044SWilliam.Kucharski@Sun.COM memcpy(arpreply->thwaddr, arpreply->shwaddr, ETH_ALEN);
9898044SWilliam.Kucharski@Sun.COM memcpy(arpreply->sipaddr, &arptable[ARP_CLIENT].ipaddr, sizeof(in_addr));
9908044SWilliam.Kucharski@Sun.COM memcpy(arpreply->shwaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
9918044SWilliam.Kucharski@Sun.COM eth_transmit(arpreply->thwaddr, ARP,
9928044SWilliam.Kucharski@Sun.COM sizeof(struct arprequest),
9938044SWilliam.Kucharski@Sun.COM arpreply);
9948044SWilliam.Kucharski@Sun.COM #ifdef MDEBUG
9958044SWilliam.Kucharski@Sun.COM memcpy(&tmp, arpreply->tipaddr, sizeof(in_addr));
9968044SWilliam.Kucharski@Sun.COM printf("Sent ARP reply to: %@\n",tmp);
9978044SWilliam.Kucharski@Sun.COM #endif /* MDEBUG */
9988044SWilliam.Kucharski@Sun.COM }
9998044SWilliam.Kucharski@Sun.COM }
10008044SWilliam.Kucharski@Sun.COM process_igmp(ip, now);
10018044SWilliam.Kucharski@Sun.COM }
10028044SWilliam.Kucharski@Sun.COM return(0);
10038044SWilliam.Kucharski@Sun.COM }
10048044SWilliam.Kucharski@Sun.COM
10058044SWilliam.Kucharski@Sun.COM #ifdef REQUIRE_VCI_ETHERBOOT
10068044SWilliam.Kucharski@Sun.COM /**************************************************************************
10078044SWilliam.Kucharski@Sun.COM FIND_VCI_ETHERBOOT - Looks for "Etherboot" in Vendor Encapsulated Identifiers
10088044SWilliam.Kucharski@Sun.COM On entry p points to byte count of VCI options
10098044SWilliam.Kucharski@Sun.COM **************************************************************************/
find_vci_etherboot(unsigned char * p)10108044SWilliam.Kucharski@Sun.COM static int find_vci_etherboot(unsigned char *p)
10118044SWilliam.Kucharski@Sun.COM {
10128044SWilliam.Kucharski@Sun.COM unsigned char *end = p + 1 + *p;
10138044SWilliam.Kucharski@Sun.COM
10148044SWilliam.Kucharski@Sun.COM for (p++; p < end; ) {
10158044SWilliam.Kucharski@Sun.COM if (*p == RFC2132_VENDOR_CLASS_ID) {
10168044SWilliam.Kucharski@Sun.COM if (strncmp("Etherboot", p + 2, sizeof("Etherboot") - 1) == 0)
10178044SWilliam.Kucharski@Sun.COM return (1);
10188044SWilliam.Kucharski@Sun.COM } else if (*p == RFC1533_END)
10198044SWilliam.Kucharski@Sun.COM return (0);
10208044SWilliam.Kucharski@Sun.COM p += TAG_LEN(p) + 2;
10218044SWilliam.Kucharski@Sun.COM }
10228044SWilliam.Kucharski@Sun.COM return (0);
10238044SWilliam.Kucharski@Sun.COM }
10248044SWilliam.Kucharski@Sun.COM #endif /* REQUIRE_VCI_ETHERBOOT */
10258044SWilliam.Kucharski@Sun.COM
10268044SWilliam.Kucharski@Sun.COM /**
10278044SWilliam.Kucharski@Sun.COM * decode_rfc1533
10288044SWilliam.Kucharski@Sun.COM *
10298044SWilliam.Kucharski@Sun.COM * Decodes RFC1533 header
10308044SWilliam.Kucharski@Sun.COM **/
decode_rfc1533(unsigned char * p,unsigned int block,unsigned int len,int eof)10318044SWilliam.Kucharski@Sun.COM int decode_rfc1533(unsigned char *p, unsigned int block, unsigned int len, int eof)
10328044SWilliam.Kucharski@Sun.COM {
10338044SWilliam.Kucharski@Sun.COM static unsigned char *extdata = NULL, *extend = NULL;
10348044SWilliam.Kucharski@Sun.COM unsigned char *extpath = NULL;
10358044SWilliam.Kucharski@Sun.COM unsigned char *endp;
10368044SWilliam.Kucharski@Sun.COM
10378044SWilliam.Kucharski@Sun.COM if (block == 0) {
10388044SWilliam.Kucharski@Sun.COM end_of_rfc1533 = NULL;
10398044SWilliam.Kucharski@Sun.COM if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10408044SWilliam.Kucharski@Sun.COM return(0); /* no RFC 1533 header found */
10418044SWilliam.Kucharski@Sun.COM p += 4;
10428044SWilliam.Kucharski@Sun.COM endp = p + len;
10438044SWilliam.Kucharski@Sun.COM } else {
10448044SWilliam.Kucharski@Sun.COM if (block == 1) {
10458044SWilliam.Kucharski@Sun.COM if (memcmp(p, rfc1533_cookie, sizeof(rfc1533_cookie)))
10468044SWilliam.Kucharski@Sun.COM return(0); /* no RFC 1533 header found */
10478044SWilliam.Kucharski@Sun.COM p += 4;
10488044SWilliam.Kucharski@Sun.COM len -= 4; }
10498044SWilliam.Kucharski@Sun.COM if (extend + len <= (unsigned char *)
10508044SWilliam.Kucharski@Sun.COM rfc1533_venddata + sizeof(rfc1533_venddata)) {
10518044SWilliam.Kucharski@Sun.COM memcpy(extend, p, len);
10528044SWilliam.Kucharski@Sun.COM extend += len;
10538044SWilliam.Kucharski@Sun.COM } else {
10548044SWilliam.Kucharski@Sun.COM printf("Overflow in vendor data buffer! Aborting...\n");
10558044SWilliam.Kucharski@Sun.COM *extdata = RFC1533_END;
10568044SWilliam.Kucharski@Sun.COM return(0);
10578044SWilliam.Kucharski@Sun.COM }
10588044SWilliam.Kucharski@Sun.COM p = extdata; endp = extend;
10598044SWilliam.Kucharski@Sun.COM }
10608044SWilliam.Kucharski@Sun.COM if (!eof)
10618044SWilliam.Kucharski@Sun.COM return 1;
10628044SWilliam.Kucharski@Sun.COM while (p < endp) {
10638044SWilliam.Kucharski@Sun.COM unsigned char c = *p;
10648044SWilliam.Kucharski@Sun.COM if (c == RFC1533_PAD) {
10658044SWilliam.Kucharski@Sun.COM p++;
10668044SWilliam.Kucharski@Sun.COM continue;
10678044SWilliam.Kucharski@Sun.COM }
10688044SWilliam.Kucharski@Sun.COM else if (c == RFC1533_END) {
10698044SWilliam.Kucharski@Sun.COM end_of_rfc1533 = endp = p;
10708044SWilliam.Kucharski@Sun.COM continue;
10718044SWilliam.Kucharski@Sun.COM }
10728044SWilliam.Kucharski@Sun.COM else if (c == RFC1533_NETMASK)
10738044SWilliam.Kucharski@Sun.COM memcpy(&netmask, p+2, sizeof(in_addr));
10748044SWilliam.Kucharski@Sun.COM else if (c == RFC1533_GATEWAY) {
10758044SWilliam.Kucharski@Sun.COM /* This is a little simplistic, but it will
10768044SWilliam.Kucharski@Sun.COM usually be sufficient.
10778044SWilliam.Kucharski@Sun.COM Take only the first entry */
10788044SWilliam.Kucharski@Sun.COM if (TAG_LEN(p) >= sizeof(in_addr))
10798044SWilliam.Kucharski@Sun.COM memcpy(&arptable[ARP_GATEWAY].ipaddr, p+2, sizeof(in_addr));
10808044SWilliam.Kucharski@Sun.COM }
10818044SWilliam.Kucharski@Sun.COM else if (c == RFC1533_EXTENSIONPATH)
10828044SWilliam.Kucharski@Sun.COM extpath = p;
10838044SWilliam.Kucharski@Sun.COM else if (c == RFC2132_MSG_TYPE)
10848044SWilliam.Kucharski@Sun.COM dhcp_reply=*(p+2);
10858044SWilliam.Kucharski@Sun.COM else if (c == RFC2132_SRV_ID)
10868044SWilliam.Kucharski@Sun.COM memcpy(&dhcp_server, p+2, sizeof(in_addr));
10878044SWilliam.Kucharski@Sun.COM else if (c == RFC1533_HOSTNAME) {
10888044SWilliam.Kucharski@Sun.COM hostname = p + 2;
10898044SWilliam.Kucharski@Sun.COM hostnamelen = *(p + 1);
10908044SWilliam.Kucharski@Sun.COM }
10918044SWilliam.Kucharski@Sun.COM else if (c == RFC1533_VENDOR_CONFIGFILE){
10928044SWilliam.Kucharski@Sun.COM int l = TAG_LEN (p);
10938044SWilliam.Kucharski@Sun.COM
10948044SWilliam.Kucharski@Sun.COM /* Eliminate the trailing NULs according to RFC 2132. */
10958044SWilliam.Kucharski@Sun.COM while (*(p + 2 + l - 1) == '\000' && l > 0)
10968044SWilliam.Kucharski@Sun.COM l--;
10978044SWilliam.Kucharski@Sun.COM
10988044SWilliam.Kucharski@Sun.COM /* XXX: Should check if LEN is less than the maximum length
10998044SWilliam.Kucharski@Sun.COM of CONFIG_FILE. This kind of robustness will be a goal
11008044SWilliam.Kucharski@Sun.COM in GRUB 1.0. */
11018044SWilliam.Kucharski@Sun.COM memcpy (config_file, p + 2, l);
11028044SWilliam.Kucharski@Sun.COM config_file[l] = 0;
1103*9037SJan.Setje-Eilers@Sun.COM vendor_configfile = p + 2;
1104*9037SJan.Setje-Eilers@Sun.COM vendor_configfile_len = l;
1105*9037SJan.Setje-Eilers@Sun.COM configfile_origin = CFG_150;
11068044SWilliam.Kucharski@Sun.COM }
11078044SWilliam.Kucharski@Sun.COM else {
11088044SWilliam.Kucharski@Sun.COM ;
11098044SWilliam.Kucharski@Sun.COM }
11108044SWilliam.Kucharski@Sun.COM p += TAG_LEN(p) + 2;
11118044SWilliam.Kucharski@Sun.COM }
11128044SWilliam.Kucharski@Sun.COM extdata = extend = endp;
11138044SWilliam.Kucharski@Sun.COM if (block <= 0 && extpath != NULL) {
11148044SWilliam.Kucharski@Sun.COM char fname[64];
11158044SWilliam.Kucharski@Sun.COM if (TAG_LEN(extpath) >= sizeof(fname)){
11168044SWilliam.Kucharski@Sun.COM printf("Overflow in vendor data buffer! Aborting...\n");
11178044SWilliam.Kucharski@Sun.COM *extdata = RFC1533_END;
11188044SWilliam.Kucharski@Sun.COM return(0);
11198044SWilliam.Kucharski@Sun.COM }
11208044SWilliam.Kucharski@Sun.COM memcpy(fname, extpath+2, TAG_LEN(extpath));
11218044SWilliam.Kucharski@Sun.COM fname[(int)TAG_LEN(extpath)] = '\0';
11228044SWilliam.Kucharski@Sun.COM printf("Loading BOOTP-extension file: %s\n",fname);
11238044SWilliam.Kucharski@Sun.COM tftp_file_read(fname, decode_rfc1533);
11248044SWilliam.Kucharski@Sun.COM }
11258044SWilliam.Kucharski@Sun.COM return 1; /* proceed with next block */
11268044SWilliam.Kucharski@Sun.COM }
11278044SWilliam.Kucharski@Sun.COM
11288044SWilliam.Kucharski@Sun.COM
11298044SWilliam.Kucharski@Sun.COM /* FIXME double check TWO_SECOND_DIVISOR */
11308044SWilliam.Kucharski@Sun.COM #define TWO_SECOND_DIVISOR (RAND_MAX/TICKS_PER_SEC)
11318044SWilliam.Kucharski@Sun.COM /**************************************************************************
11328044SWilliam.Kucharski@Sun.COM RFC2131_SLEEP_INTERVAL - sleep for expotentially longer times (base << exp) +- 1 sec)
11338044SWilliam.Kucharski@Sun.COM **************************************************************************/
rfc2131_sleep_interval(long base,int exp)11348044SWilliam.Kucharski@Sun.COM long rfc2131_sleep_interval(long base, int exp)
11358044SWilliam.Kucharski@Sun.COM {
11368044SWilliam.Kucharski@Sun.COM unsigned long tmo;
11378044SWilliam.Kucharski@Sun.COM #ifdef BACKOFF_LIMIT
11388044SWilliam.Kucharski@Sun.COM if (exp > BACKOFF_LIMIT)
11398044SWilliam.Kucharski@Sun.COM exp = BACKOFF_LIMIT;
11408044SWilliam.Kucharski@Sun.COM #endif
11418044SWilliam.Kucharski@Sun.COM tmo = (base << exp) + (TICKS_PER_SEC - (random()/TWO_SECOND_DIVISOR));
11428044SWilliam.Kucharski@Sun.COM return tmo;
11438044SWilliam.Kucharski@Sun.COM }
11448044SWilliam.Kucharski@Sun.COM
11458044SWilliam.Kucharski@Sun.COM #ifdef MULTICAST_LEVEL2
11468044SWilliam.Kucharski@Sun.COM /**************************************************************************
11478044SWilliam.Kucharski@Sun.COM RFC1112_SLEEP_INTERVAL - sleep for expotentially longer times, up to (base << exp)
11488044SWilliam.Kucharski@Sun.COM **************************************************************************/
rfc1112_sleep_interval(long base,int exp)11498044SWilliam.Kucharski@Sun.COM long rfc1112_sleep_interval(long base, int exp)
11508044SWilliam.Kucharski@Sun.COM {
11518044SWilliam.Kucharski@Sun.COM unsigned long divisor, tmo;
11528044SWilliam.Kucharski@Sun.COM #ifdef BACKOFF_LIMIT
11538044SWilliam.Kucharski@Sun.COM if (exp > BACKOFF_LIMIT)
11548044SWilliam.Kucharski@Sun.COM exp = BACKOFF_LIMIT;
11558044SWilliam.Kucharski@Sun.COM #endif
11568044SWilliam.Kucharski@Sun.COM divisor = RAND_MAX/(base << exp);
11578044SWilliam.Kucharski@Sun.COM tmo = random()/divisor;
11588044SWilliam.Kucharski@Sun.COM return tmo;
11598044SWilliam.Kucharski@Sun.COM }
11608044SWilliam.Kucharski@Sun.COM #endif /* MULTICAST_LEVEL_2 */
11618044SWilliam.Kucharski@Sun.COM /* ifconfig - configure network interface. */
11628044SWilliam.Kucharski@Sun.COM int
ifconfig(char * ip,char * sm,char * gw,char * svr)11638044SWilliam.Kucharski@Sun.COM ifconfig (char *ip, char *sm, char *gw, char *svr)
11648044SWilliam.Kucharski@Sun.COM {
11658044SWilliam.Kucharski@Sun.COM in_addr tmp;
11668044SWilliam.Kucharski@Sun.COM
11678044SWilliam.Kucharski@Sun.COM if (sm)
11688044SWilliam.Kucharski@Sun.COM {
11698044SWilliam.Kucharski@Sun.COM if (! inet_aton (sm, &tmp))
11708044SWilliam.Kucharski@Sun.COM return 0;
11718044SWilliam.Kucharski@Sun.COM
11728044SWilliam.Kucharski@Sun.COM netmask = tmp.s_addr;
11738044SWilliam.Kucharski@Sun.COM }
11748044SWilliam.Kucharski@Sun.COM
11758044SWilliam.Kucharski@Sun.COM if (ip)
11768044SWilliam.Kucharski@Sun.COM {
11778044SWilliam.Kucharski@Sun.COM if (! inet_aton (ip, &arptable[ARP_CLIENT].ipaddr))
11788044SWilliam.Kucharski@Sun.COM return 0;
11798044SWilliam.Kucharski@Sun.COM
11808044SWilliam.Kucharski@Sun.COM if (! netmask && ! sm)
11818044SWilliam.Kucharski@Sun.COM netmask = default_netmask ();
11828044SWilliam.Kucharski@Sun.COM }
11838044SWilliam.Kucharski@Sun.COM
11848044SWilliam.Kucharski@Sun.COM if (gw && ! inet_aton (gw, &arptable[ARP_GATEWAY].ipaddr))
11858044SWilliam.Kucharski@Sun.COM return 0;
11868044SWilliam.Kucharski@Sun.COM
11878044SWilliam.Kucharski@Sun.COM /* Clear out the ARP entry. */
11888044SWilliam.Kucharski@Sun.COM grub_memset (arptable[ARP_GATEWAY].node, 0, ETH_ALEN);
11898044SWilliam.Kucharski@Sun.COM
11908044SWilliam.Kucharski@Sun.COM if (svr && ! inet_aton (svr, &arptable[ARP_SERVER].ipaddr))
11918044SWilliam.Kucharski@Sun.COM return 0;
11928044SWilliam.Kucharski@Sun.COM
11938044SWilliam.Kucharski@Sun.COM /* Likewise. */
11948044SWilliam.Kucharski@Sun.COM grub_memset (arptable[ARP_SERVER].node, 0, ETH_ALEN);
11958044SWilliam.Kucharski@Sun.COM
11968044SWilliam.Kucharski@Sun.COM if (ip || sm)
11978044SWilliam.Kucharski@Sun.COM {
11988044SWilliam.Kucharski@Sun.COM if (IP_BROADCAST == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
11998044SWilliam.Kucharski@Sun.COM || netmask == (netmask | arptable[ARP_CLIENT].ipaddr.s_addr)
12008044SWilliam.Kucharski@Sun.COM || ! netmask)
12018044SWilliam.Kucharski@Sun.COM network_ready = 0;
12028044SWilliam.Kucharski@Sun.COM else
12038044SWilliam.Kucharski@Sun.COM network_ready = 1;
12048044SWilliam.Kucharski@Sun.COM }
12058044SWilliam.Kucharski@Sun.COM
12068044SWilliam.Kucharski@Sun.COM update_network_configuration();
12078044SWilliam.Kucharski@Sun.COM return 1;
12088044SWilliam.Kucharski@Sun.COM }
12098044SWilliam.Kucharski@Sun.COM
12108044SWilliam.Kucharski@Sun.COM /*
12118044SWilliam.Kucharski@Sun.COM * print_network_configuration
12128044SWilliam.Kucharski@Sun.COM *
12138044SWilliam.Kucharski@Sun.COM * Output the network configuration. It may broke the graphic console now.:-(
12148044SWilliam.Kucharski@Sun.COM */
print_network_configuration(void)12158044SWilliam.Kucharski@Sun.COM void print_network_configuration (void)
12168044SWilliam.Kucharski@Sun.COM {
12178044SWilliam.Kucharski@Sun.COM EnterFunction("print_network_configuration");
12188044SWilliam.Kucharski@Sun.COM if (! network_ready)
12198044SWilliam.Kucharski@Sun.COM grub_printf ("Network interface not initialized yet.\n");
12208044SWilliam.Kucharski@Sun.COM else {
1221*9037SJan.Setje-Eilers@Sun.COM if (hostnamelen == 0)
1222*9037SJan.Setje-Eilers@Sun.COM etherboot_printf ("Hostname: not set\n");
1223*9037SJan.Setje-Eilers@Sun.COM else
1224*9037SJan.Setje-Eilers@Sun.COM etherboot_printf ("Hostname: %s\n", hostname);
1225*9037SJan.Setje-Eilers@Sun.COM
12268044SWilliam.Kucharski@Sun.COM etherboot_printf ("Address: %@\n", arptable[ARP_CLIENT].ipaddr.s_addr);
12278044SWilliam.Kucharski@Sun.COM etherboot_printf ("Netmask: %@\n", netmask);
1228*9037SJan.Setje-Eilers@Sun.COM etherboot_printf ("Gateway: %@\n", arptable[ARP_GATEWAY].ipaddr.s_addr);
12298044SWilliam.Kucharski@Sun.COM etherboot_printf ("Server: %@\n", arptable[ARP_SERVER].ipaddr.s_addr);
1230*9037SJan.Setje-Eilers@Sun.COM if (vendor_configfile == NULL) {
1231*9037SJan.Setje-Eilers@Sun.COM etherboot_printf ("Site Option 150: not set\n");
1232*9037SJan.Setje-Eilers@Sun.COM } else {
1233*9037SJan.Setje-Eilers@Sun.COM /*
1234*9037SJan.Setje-Eilers@Sun.COM * vendor_configfile points into the packet and
1235*9037SJan.Setje-Eilers@Sun.COM * is not NULL terminated, so it needs to be
1236*9037SJan.Setje-Eilers@Sun.COM * patched up before printing it out
1237*9037SJan.Setje-Eilers@Sun.COM */
1238*9037SJan.Setje-Eilers@Sun.COM char c = vendor_configfile[vendor_configfile_len];
1239*9037SJan.Setje-Eilers@Sun.COM vendor_configfile[vendor_configfile_len] = '\0';
1240*9037SJan.Setje-Eilers@Sun.COM etherboot_printf ("Site Option 150: %s\n",
1241*9037SJan.Setje-Eilers@Sun.COM vendor_configfile);
1242*9037SJan.Setje-Eilers@Sun.COM vendor_configfile[vendor_configfile_len] = c;
1243*9037SJan.Setje-Eilers@Sun.COM }
1244*9037SJan.Setje-Eilers@Sun.COM
1245*9037SJan.Setje-Eilers@Sun.COM if (bootfile == NULL)
1246*9037SJan.Setje-Eilers@Sun.COM etherboot_printf ("BootFile: not set\n");
1247*9037SJan.Setje-Eilers@Sun.COM else
1248*9037SJan.Setje-Eilers@Sun.COM etherboot_printf ("BootFile: %s\n", bootfile);
1249*9037SJan.Setje-Eilers@Sun.COM
1250*9037SJan.Setje-Eilers@Sun.COM etherboot_printf ("GRUB menu file: %s", config_file);
1251*9037SJan.Setje-Eilers@Sun.COM switch (configfile_origin) {
1252*9037SJan.Setje-Eilers@Sun.COM case CFG_HARDCODED:
1253*9037SJan.Setje-Eilers@Sun.COM etherboot_printf (" from hardcoded default\n");
1254*9037SJan.Setje-Eilers@Sun.COM break;
1255*9037SJan.Setje-Eilers@Sun.COM case CFG_150:
1256*9037SJan.Setje-Eilers@Sun.COM etherboot_printf (" from Site Option 150\n");
1257*9037SJan.Setje-Eilers@Sun.COM break;
1258*9037SJan.Setje-Eilers@Sun.COM case CFG_MAC:
1259*9037SJan.Setje-Eilers@Sun.COM etherboot_printf (" inferred from system MAC\n");
1260*9037SJan.Setje-Eilers@Sun.COM break;
1261*9037SJan.Setje-Eilers@Sun.COM case CFG_BOOTFILE:
1262*9037SJan.Setje-Eilers@Sun.COM etherboot_printf (" inferred from BootFile\n");
1263*9037SJan.Setje-Eilers@Sun.COM break;
1264*9037SJan.Setje-Eilers@Sun.COM default:
1265*9037SJan.Setje-Eilers@Sun.COM etherboot_printf ("\n");
1266*9037SJan.Setje-Eilers@Sun.COM }
12678044SWilliam.Kucharski@Sun.COM }
12688044SWilliam.Kucharski@Sun.COM LeaveFunction("print_network_configuration");
12698044SWilliam.Kucharski@Sun.COM }
12708044SWilliam.Kucharski@Sun.COM
12718044SWilliam.Kucharski@Sun.COM /*
12728044SWilliam.Kucharski@Sun.COM * update_network_configuration
12738044SWilliam.Kucharski@Sun.COM *
12748044SWilliam.Kucharski@Sun.COM * Update network configuration for diskless clients (Solaris only)
12758044SWilliam.Kucharski@Sun.COM */
update_network_configuration(void)12768044SWilliam.Kucharski@Sun.COM static void update_network_configuration (void)
12778044SWilliam.Kucharski@Sun.COM {
12788044SWilliam.Kucharski@Sun.COM #ifdef SOLARIS_NETBOOT
12798044SWilliam.Kucharski@Sun.COM struct sol_netinfo {
12808044SWilliam.Kucharski@Sun.COM uint8_t sn_infotype;
12818044SWilliam.Kucharski@Sun.COM uint8_t sn_mactype;
12828044SWilliam.Kucharski@Sun.COM uint8_t sn_maclen;
12838044SWilliam.Kucharski@Sun.COM uint8_t sn_padding;
12848044SWilliam.Kucharski@Sun.COM unsigned long sn_ciaddr;
12858044SWilliam.Kucharski@Sun.COM unsigned long sn_siaddr;
12868044SWilliam.Kucharski@Sun.COM unsigned long sn_giaddr;
12878044SWilliam.Kucharski@Sun.COM unsigned long sn_netmask;
12888044SWilliam.Kucharski@Sun.COM uint8_t sn_macaddr[1];
12898044SWilliam.Kucharski@Sun.COM } *sip;
12908044SWilliam.Kucharski@Sun.COM
12918044SWilliam.Kucharski@Sun.COM if (! network_ready)
12928044SWilliam.Kucharski@Sun.COM return;
12938044SWilliam.Kucharski@Sun.COM
12948044SWilliam.Kucharski@Sun.COM sip = (struct sol_netinfo *)dhcpack_buf;
12958044SWilliam.Kucharski@Sun.COM sip->sn_infotype = 0xf0; /* something not BOOTP_REPLY */
12968044SWilliam.Kucharski@Sun.COM sip->sn_mactype = 4; /* DL_ETHER */
12978044SWilliam.Kucharski@Sun.COM sip->sn_maclen = ETH_ALEN;
12988044SWilliam.Kucharski@Sun.COM sip->sn_ciaddr = arptable[ARP_CLIENT].ipaddr.s_addr;
12998044SWilliam.Kucharski@Sun.COM sip->sn_siaddr = arptable[ARP_SERVER].ipaddr.s_addr;
13008044SWilliam.Kucharski@Sun.COM sip->sn_giaddr = arptable[ARP_GATEWAY].ipaddr.s_addr;
13018044SWilliam.Kucharski@Sun.COM sip->sn_netmask = netmask;
13028044SWilliam.Kucharski@Sun.COM memcpy(sip->sn_macaddr, arptable[ARP_CLIENT].node, ETH_ALEN);
13038044SWilliam.Kucharski@Sun.COM dhcpack_length = sizeof (*sip) + sip->sn_maclen - 1;
13048044SWilliam.Kucharski@Sun.COM #endif /* SOLARIS_NETBOOT */
13058044SWilliam.Kucharski@Sun.COM }
13068044SWilliam.Kucharski@Sun.COM
13078044SWilliam.Kucharski@Sun.COM /**
13088044SWilliam.Kucharski@Sun.COM * cleanup_net
13098044SWilliam.Kucharski@Sun.COM *
13108044SWilliam.Kucharski@Sun.COM * Mark network unusable, and disable NICs
13118044SWilliam.Kucharski@Sun.COM */
cleanup_net(void)13128044SWilliam.Kucharski@Sun.COM void cleanup_net (void)
13138044SWilliam.Kucharski@Sun.COM {
13148044SWilliam.Kucharski@Sun.COM if (network_ready){
13158044SWilliam.Kucharski@Sun.COM /* Stop receiving packets. */
13168044SWilliam.Kucharski@Sun.COM if (use_bios_pxe)
13178044SWilliam.Kucharski@Sun.COM undi_pxe_disable();
13188044SWilliam.Kucharski@Sun.COM else
13198044SWilliam.Kucharski@Sun.COM eth_disable ();
13208044SWilliam.Kucharski@Sun.COM network_ready = 0;
13218044SWilliam.Kucharski@Sun.COM }
13228044SWilliam.Kucharski@Sun.COM }
13238044SWilliam.Kucharski@Sun.COM
13248044SWilliam.Kucharski@Sun.COM /*******************************************************************
13258044SWilliam.Kucharski@Sun.COM * dhcp implementation reusing the BIOS pxe stack
13268044SWilliam.Kucharski@Sun.COM */
13278044SWilliam.Kucharski@Sun.COM static void
dhcp_copy(struct dhcp_t * dhcpreply)13288044SWilliam.Kucharski@Sun.COM dhcp_copy(struct dhcp_t *dhcpreply)
13298044SWilliam.Kucharski@Sun.COM {
13308044SWilliam.Kucharski@Sun.COM unsigned long time;
13318044SWilliam.Kucharski@Sun.COM int ret, len = DHCP_OPT_LEN;
13328044SWilliam.Kucharski@Sun.COM
13338044SWilliam.Kucharski@Sun.COM /* fill in netinfo */
13348044SWilliam.Kucharski@Sun.COM dhcpack_length = sizeof (struct dhcp_t);
13358044SWilliam.Kucharski@Sun.COM memcpy((char *)dhcpack_buf, (char *)dhcpreply, dhcpack_length);
13368044SWilliam.Kucharski@Sun.COM
13378044SWilliam.Kucharski@Sun.COM memcpy(arptable[ARP_CLIENT].node, dhcpreply->bp_hwaddr, ETH_ALEN);
13388044SWilliam.Kucharski@Sun.COM arptable[ARP_CLIENT].ipaddr.s_addr = dhcpreply->bp_yiaddr.s_addr;
13398044SWilliam.Kucharski@Sun.COM dhcp_addr.s_addr = dhcpreply->bp_yiaddr.s_addr;
13408044SWilliam.Kucharski@Sun.COM netmask = default_netmask();
13418044SWilliam.Kucharski@Sun.COM arptable[ARP_SERVER].ipaddr.s_addr = dhcpreply->bp_siaddr.s_addr;
13428044SWilliam.Kucharski@Sun.COM memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); /* Kill arp */
13438044SWilliam.Kucharski@Sun.COM arptable[ARP_GATEWAY].ipaddr.s_addr = dhcpreply->bp_giaddr.s_addr;
13448044SWilliam.Kucharski@Sun.COM memset(arptable[ARP_GATEWAY].node, 0, ETH_ALEN); /* Kill arp */
1345*9037SJan.Setje-Eilers@Sun.COM bootfile = dhcpreply->bp_file;
13468044SWilliam.Kucharski@Sun.COM memcpy((char *)rfc1533_venddata, (char *)(dhcpreply->bp_vend), len);
13478044SWilliam.Kucharski@Sun.COM decode_rfc1533(rfc1533_venddata, 0, len, 1);
13488044SWilliam.Kucharski@Sun.COM }
13498044SWilliam.Kucharski@Sun.COM
dhcp_undi(void)13508044SWilliam.Kucharski@Sun.COM int dhcp_undi(void)
13518044SWilliam.Kucharski@Sun.COM {
13528044SWilliam.Kucharski@Sun.COM struct dhcp_t *dhcpreply;
13538044SWilliam.Kucharski@Sun.COM
13548044SWilliam.Kucharski@Sun.COM if (!undi_bios_pxe((void **)&dhcpreply))
13558044SWilliam.Kucharski@Sun.COM return 0;
13568044SWilliam.Kucharski@Sun.COM
13578044SWilliam.Kucharski@Sun.COM dhcp_copy(dhcpreply);
13588044SWilliam.Kucharski@Sun.COM network_ready = 1;
13598044SWilliam.Kucharski@Sun.COM use_bios_pxe = 1;
13608044SWilliam.Kucharski@Sun.COM return (1);
13618044SWilliam.Kucharski@Sun.COM }
1362