Home | History | Annotate | Line # | Download | only in ndbootd
ndbootd.c revision 1.10
      1  1.10     lukem /*	$NetBSD: ndbootd.c,v 1.10 2005/06/02 11:29:01 lukem Exp $	*/
      2   1.2  fredette 
      3   1.1  fredette /* ndbootd.c - the Sun Network Disk (nd) daemon: */
      4   1.1  fredette 
      5   1.1  fredette /*
      6   1.1  fredette  * Copyright (c) 2001 Matthew Fredette.  All rights reserved.
      7   1.1  fredette  *
      8   1.1  fredette  * Redistribution and use in source and binary forms, with or without
      9   1.1  fredette  * modification, are permitted provided that the following conditions
     10   1.1  fredette  * are met:
     11   1.1  fredette  *   1. Redistributions of source code must retain the above copyright
     12   1.1  fredette  *      notice, this list of conditions and the following disclaimer.
     13   1.1  fredette  *   2. Redistributions in binary form must reproduce the above copyright
     14   1.1  fredette  *      notice, this list of conditions and the following disclaimer in the
     15   1.1  fredette  *      documentation and/or other materials provided with the distribution.
     16   1.1  fredette  *   3. All advertising materials mentioning features or use of this software
     17   1.1  fredette  *      must display the following acknowledgement:
     18   1.1  fredette  *        This product includes software developed by Matthew Fredette.
     19   1.1  fredette  *   4. The name of Matthew Fredette may not be used to endorse or promote
     20   1.1  fredette  *      products derived from this software without specific prior written
     21   1.1  fredette  *      permission.
     22   1.1  fredette  *
     23   1.1  fredette  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     24   1.1  fredette  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     25   1.1  fredette  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     26   1.1  fredette  */
     27   1.1  fredette 
     28   1.4  fredette /* <<Header: /data/home/fredette/project/THE-WEIGHT-CVS/ndbootd/ndbootd.c,v 1.9 2001/06/13 21:19:11 fredette Exp >> */
     29   1.1  fredette 
     30   1.1  fredette /*
     31   1.1  fredette  * <<Log: ndbootd.c,v >>
     32   1.4  fredette  * Revision 1.9  2001/06/13 21:19:11  fredette
     33   1.4  fredette  * (main): Don't assume that a successful, but short, read
     34   1.4  fredette  * leaves a zero in errno.  Instead, just check for the short
     35   1.4  fredette  * read by looking at the byte count that read returned.
     36   1.4  fredette  *
     37   1.3  fredette  * Revision 1.8  2001/05/23 02:35:36  fredette
     38   1.3  fredette  * Changed many debugging printfs to compile quietly on the
     39   1.3  fredette  * alpha.  Patch from Andrew Brown <atatat (at) atatdot.net>.
     40   1.3  fredette  *
     41   1.1  fredette  * Revision 1.7  2001/05/22 13:13:20  fredette
     42   1.1  fredette  * Ran indent(1) with NetBSD's KNF-approximating profile.
     43   1.1  fredette  *
     44   1.1  fredette  * Revision 1.6  2001/05/22 12:53:40  fredette
     45   1.1  fredette  * [HAVE_STRICT_ALIGNMENT]: Added code to copy packet headers
     46   1.1  fredette  * between the buffer and local variables, to satisfy
     47   1.1  fredette  * alignment constraints.
     48   1.1  fredette  *
     49   1.1  fredette  * Revision 1.5  2001/05/15 14:43:24  fredette
     50   1.1  fredette  * Now have prototypes for the allocation functions.
     51   1.1  fredette  * (main): Now handle boot blocks that aren't an integral
     52   1.1  fredette  * multiple of the block size.
     53   1.1  fredette  *
     54   1.1  fredette  * Revision 1.4  2001/05/09 20:53:38  fredette
     55   1.1  fredette  * (main): Now insert a small delay before sending each packet.
     56   1.1  fredette  * Sending packets too quickly apparently overwhelms clients.
     57   1.1  fredette  * Added new single-letter versions of all options that didn't
     58   1.1  fredette  * already have them.  Expanded some debug messages, and fixed
     59   1.1  fredette  * others to display Ethernet addresses correctly.
     60   1.1  fredette  *
     61   1.1  fredette  * Revision 1.3  2001/01/31 17:35:50  fredette
     62   1.1  fredette  * (main): Fixed various printf argument lists.
     63   1.1  fredette  *
     64   1.1  fredette  * Revision 1.2  2001/01/30 15:35:38  fredette
     65   1.1  fredette  * Now, ndbootd assembles disk images for clients on-the-fly.
     66   1.1  fredette  * Defined many new macros related to this.
     67   1.1  fredette  * (main): Added support for the --boot2 option.  Turned the
     68   1.1  fredette  * original disk-image filename into the filename of the
     69   1.1  fredette  * first-stage boot program.  Now do better multiple-client
     70   1.1  fredette  * support, especially when it comes to checking if a client
     71   1.1  fredette  * is really ours.  Now assemble client-specific disk images
     72   1.1  fredette  * on-the-fly, potentially serving each client a different
     73   1.1  fredette  * second-stage boot.
     74   1.1  fredette  *
     75   1.1  fredette  * Revision 1.1  2001/01/29 15:12:13  fredette
     76   1.1  fredette  * Added.
     77   1.1  fredette  *
     78   1.1  fredette  */
     79   1.1  fredette 
     80   1.5   thorpej #include <sys/cdefs.h>
     81   1.5   thorpej #if 0
     82   1.4  fredette static const char _ndbootd_c_rcsid[] = "<<Id: ndbootd.c,v 1.9 2001/06/13 21:19:11 fredette Exp >>";
     83   1.5   thorpej #else
     84  1.10     lukem __RCSID("$NetBSD: ndbootd.c,v 1.10 2005/06/02 11:29:01 lukem Exp $");
     85   1.5   thorpej #endif
     86   1.1  fredette 
     87   1.1  fredette /* includes: */
     88   1.1  fredette #include "ndbootd.h"
     89   1.1  fredette 
     90   1.1  fredette /* the number of blocks that Sun-2 PROMs load, starting from block
     91   1.1  fredette    zero: */
     92   1.1  fredette #define NDBOOTD_PROM_BLOCK_COUNT (16)
     93   1.1  fredette 
     94   1.1  fredette /* the first block number of the (dummy) Sun disklabel: */
     95   1.1  fredette #define NDBOOTD_SUNDK_BLOCK_FIRST (0)
     96   1.1  fredette 
     97   1.1  fredette /* the number of blocks in the (dummy) Sun disklabel: */
     98   1.1  fredette #define NDBOOTD_SUNDK_BLOCK_COUNT (1)
     99   1.1  fredette 
    100   1.1  fredette /* the first block number of the first-stage boot program.
    101   1.1  fredette    the first-stage boot program begins right after the (dummy)
    102   1.1  fredette    Sun disklabel: */
    103   1.1  fredette #define NDBOOTD_BOOT1_BLOCK_FIRST (NDBOOTD_SUNDK_BLOCK_FIRST + NDBOOTD_SUNDK_BLOCK_COUNT)
    104   1.1  fredette 
    105   1.1  fredette /* the number of blocks in the first-stage boot program: */
    106   1.1  fredette #define NDBOOTD_BOOT1_BLOCK_COUNT (NDBOOTD_PROM_BLOCK_COUNT - NDBOOTD_BOOT1_BLOCK_FIRST)
    107   1.1  fredette 
    108   1.1  fredette /* the first block number of any second-stage boot program.
    109   1.1  fredette    any second-stage boot program begins right after the first-stage boot program: */
    110   1.1  fredette #define NDBOOTD_BOOT2_BLOCK_FIRST (NDBOOTD_BOOT1_BLOCK_FIRST + NDBOOTD_BOOT1_BLOCK_COUNT)
    111   1.1  fredette 
    112   1.1  fredette /* this macro returns the number of bytes available in an object starting at a given offset: */
    113   1.1  fredette #define NDBOOTD_BYTES_AVAIL(block_number, byte_offset, obj_block_first, obj_block_count) \
    114   1.1  fredette   ((((ssize_t) (obj_block_count) - (ssize_t) ((block_number) - (obj_block_first))) * NDBOOT_BSIZE) - (ssize_t) (byte_offset))
    115   1.1  fredette 
    116   1.1  fredette /* this determines how long we can cache file descriptors and RARP
    117   1.1  fredette    information: */
    118   1.1  fredette #define NDBOOTD_CLIENT_TTL_SECONDS (10)
    119   1.1  fredette 
    120   1.1  fredette /* this determines how long we wait before sending a packet: */
    121   1.7   mycroft #define NDBOOTD_SEND_DELAY_NSECONDS (10000000)
    122   1.1  fredette 
    123   1.1  fredette /* this macro helps us size a struct ifreq: */
    124   1.1  fredette #ifdef HAVE_SOCKADDR_SA_LEN
    125   1.8    itojun #define SIZEOF_IFREQ(ifr) (sizeof((ifr)->ifr_name) + (ifr)->ifr_addr.sa_len)
    126   1.1  fredette #else				/* !HAVE_SOCKADDR_SA_LEN */
    127   1.8    itojun #define SIZEOF_IFREQ(ifr) (sizeof((ifr)->ifr_name) + sizeof(struct sockaddr))
    128   1.1  fredette #endif				/* !HAVE_SOCKADDR_SA_LEN */
    129   1.1  fredette 
    130   1.1  fredette /* prototypes: */
    131   1.1  fredette void *ndbootd_malloc _NDBOOTD_P((size_t));
    132   1.1  fredette void *ndbootd_malloc0 _NDBOOTD_P((size_t));
    133   1.1  fredette void *ndbootd_memdup _NDBOOTD_P((void *, size_t));
    134   1.1  fredette 
    135   1.1  fredette /* globals: */
    136   1.1  fredette const char *_ndbootd_argv0;
    137   1.1  fredette #ifdef _NDBOOTD_DO_DEBUG
    138   1.1  fredette int _ndbootd_debug;
    139   1.1  fredette #endif				/* _NDBOOTD_DO_DEBUG */
    140   1.1  fredette 
    141   1.1  fredette /* allocators: */
    142   1.1  fredette void *
    143   1.1  fredette ndbootd_malloc(size_t size)
    144   1.1  fredette {
    145   1.1  fredette 	void *buffer;
    146   1.1  fredette 	if ((buffer = malloc(size)) == NULL) {
    147   1.1  fredette 		abort();
    148   1.1  fredette 	}
    149   1.1  fredette 	return (buffer);
    150   1.1  fredette }
    151   1.1  fredette void *
    152   1.1  fredette ndbootd_malloc0(size_t size)
    153   1.1  fredette {
    154   1.1  fredette 	void *buffer;
    155   1.1  fredette 	buffer = ndbootd_malloc(size);
    156   1.1  fredette 	memset(buffer, 0, size);
    157   1.1  fredette 	return (buffer);
    158   1.1  fredette }
    159   1.1  fredette void *
    160   1.1  fredette ndbootd_memdup(void *buffer0, size_t size)
    161   1.1  fredette {
    162   1.1  fredette 	void *buffer1;
    163   1.1  fredette 	buffer1 = ndbootd_malloc(size);
    164   1.1  fredette 	memcpy(buffer1, buffer0, size);
    165   1.1  fredette 	return (buffer1);
    166   1.1  fredette }
    167   1.1  fredette #define ndbootd_free free
    168   1.1  fredette #define ndbootd_new(t, c) ((t *) ndbootd_malloc(sizeof(t) * (c)))
    169   1.1  fredette #define ndbootd_new0(t, c) ((t *) ndbootd_malloc0(sizeof(t) * (c)))
    170   1.1  fredette #define ndbootd_dup(t, b, c) ((t *) ndbootd_memdup(b, c))
    171   1.1  fredette 
    172   1.1  fredette /* this calculates an IP packet header checksum: */
    173   1.1  fredette static void
    174   1.1  fredette _ndbootd_ip_cksum(struct ip * ip_packet)
    175   1.1  fredette {
    176   1.1  fredette 	u_int16_t *_word, word;
    177   1.1  fredette 	u_int32_t checksum;
    178   1.1  fredette 	unsigned int byte_count, bytes_left;
    179   1.1  fredette 
    180   1.1  fredette 	/* we assume that the IP packet header is 16-bit aligned: */
    181   1.1  fredette 	assert((((unsigned long) ip_packet) % sizeof(word)) == 0);
    182   1.1  fredette 
    183   1.1  fredette 	/* initialize for the checksum: */
    184   1.1  fredette 	checksum = 0;
    185   1.1  fredette 
    186   1.1  fredette 	/* sum up the packet contents: */
    187   1.1  fredette 	_word = (u_int16_t *) ip_packet;
    188   1.1  fredette 	byte_count = ip_packet->ip_hl << 2;
    189   1.1  fredette 	for (bytes_left = byte_count; bytes_left >= sizeof(*_word);) {
    190   1.1  fredette 		checksum += *(_word++);
    191   1.1  fredette 		bytes_left -= sizeof(*_word);
    192   1.1  fredette 	}
    193   1.1  fredette 	word = 0;
    194   1.1  fredette 	memcpy(&word, _word, bytes_left);
    195   1.1  fredette 	checksum += word;
    196   1.1  fredette 
    197   1.1  fredette 	/* finish the checksum: */
    198   1.1  fredette 	checksum = (checksum >> 16) + (checksum & 0xffff);
    199   1.1  fredette 	checksum += (checksum >> 16);
    200   1.6       scw 	checksum = ~checksum;
    201   1.6       scw 	ip_packet->ip_sum = checksum;
    202   1.1  fredette }
    203   1.1  fredette /* this finds a network interface: */
    204   1.1  fredette static struct ndbootd_interface *
    205   1.1  fredette _ndbootd_find_interface(const char *ifr_name_user)
    206   1.1  fredette {
    207   1.8    itojun 	struct ifreq ifr;
    208   1.1  fredette #ifdef HAVE_AF_LINK
    209   1.1  fredette 	struct sockaddr_dl *sadl;
    210   1.1  fredette #endif				/* HAVE_AF_LINK */
    211   1.1  fredette 	struct ndbootd_interface *interface;
    212   1.8    itojun 	struct ifaddrs *ifap, *ifa, *ifa_user;
    213   1.1  fredette 
    214   1.1  fredette 	/* read the interface list: */
    215   1.8    itojun 	if (getifaddrs(&ifap) != 0) {
    216   1.1  fredette 		return (NULL);
    217   1.1  fredette 	}
    218   1.1  fredette 
    219   1.1  fredette 	/* walk the interface list: */
    220   1.8    itojun 	ifa_user = NULL;
    221   1.8    itojun 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    222   1.1  fredette 		/* ignore this interface if it doesn't do IP: */
    223   1.8    itojun 		if (ifa->ifa_addr->sa_family != AF_INET) {
    224   1.1  fredette 			continue;
    225   1.1  fredette 		}
    226   1.1  fredette 
    227   1.1  fredette 		/* ignore this interface if it isn't up and running: */
    228   1.8    itojun 		if ((ifa->ifa_flags & (IFF_UP | IFF_RUNNING)) !=
    229   1.8    itojun 		    (IFF_UP | IFF_RUNNING)) {
    230   1.1  fredette 			continue;
    231   1.1  fredette 		}
    232   1.1  fredette 		/* if we don't have an interface yet, take this one depending
    233   1.1  fredette 		 * on whether the user asked for an interface by name or not.
    234   1.1  fredette 		 * if he did, and this is it, take this one.  if he didn't,
    235   1.1  fredette 		 * and this isn't a loopback interface, take this one: */
    236   1.8    itojun 		if (ifa_user == NULL
    237   1.1  fredette 		    && (ifr_name_user != NULL
    238   1.8    itojun 			? !strcmp(ifa->ifa_name, ifr_name_user)
    239   1.8    itojun 			: !(ifa->ifa_flags & IFF_LOOPBACK))) {
    240   1.8    itojun 			ifa_user = ifa;
    241   1.1  fredette 		}
    242   1.1  fredette 	}
    243   1.1  fredette 
    244   1.1  fredette 	/* if we don't have an interface to return: */
    245   1.9     lukem 	if (ifa == NULL || ifa_user == NULL) {
    246   1.8    itojun 		freeifaddrs(ifap);
    247   1.9     lukem 		errno = ENOENT;
    248   1.1  fredette 		return (NULL);
    249   1.1  fredette 	}
    250   1.1  fredette 	/* start the interface description: */
    251   1.1  fredette 	interface = ndbootd_new0(struct ndbootd_interface, 1);
    252   1.1  fredette 
    253   1.1  fredette #ifdef HAVE_AF_LINK
    254   1.1  fredette 
    255   1.1  fredette 	/* we must be able to find an AF_LINK ifreq that gives us the
    256   1.1  fredette 	 * interface's Ethernet address. */
    257   1.8    itojun 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    258   1.9     lukem 		if (ifa->ifa_addr->sa_family != AF_LINK) {
    259   1.9     lukem 			continue;
    260   1.9     lukem 		}
    261   1.9     lukem 		/* if this is the hardware address we want */
    262   1.9     lukem 		if (!strcmp(ifa->ifa_name, ifa_user->ifa_name)) {
    263   1.1  fredette 			break;
    264   1.1  fredette 		}
    265   1.1  fredette 	}
    266   1.8    itojun 	if (ifa == NULL) {
    267   1.8    itojun 		freeifaddrs(ifap);
    268   1.1  fredette 		free(interface);
    269   1.9     lukem 		errno = ENOENT;
    270   1.1  fredette 		return (NULL);
    271   1.1  fredette 	}
    272   1.1  fredette 	/* copy out the Ethernet address: */
    273   1.8    itojun 	sadl = (struct sockaddr_dl *)ifa->ifa_addr;
    274   1.1  fredette 	memcpy(interface->ndbootd_interface_ether, LLADDR(sadl), sadl->sdl_alen);
    275   1.1  fredette 
    276   1.1  fredette #else				/* !HAVE_AF_LINK */
    277   1.1  fredette #error "must have AF_LINK for now"
    278   1.1  fredette #endif				/* !HAVE_AF_LINK */
    279   1.1  fredette 
    280   1.1  fredette 	/* finish this interface and return it: */
    281   1.8    itojun 	strlcpy(ifr.ifr_name, ifa_user->ifa_name, sizeof(ifr.ifr_name));
    282   1.8    itojun 	assert(sizeof(ifr.ifr_addr) >= ifa_user->ifa_addr->sa_len);
    283   1.8    itojun 	memcpy(&ifr.ifr_addr, ifa_user->ifa_addr, ifa_user->ifa_addr->sa_len);
    284   1.8    itojun 	interface->ndbootd_interface_ifreq = (struct ifreq *) ndbootd_memdup(&ifr, SIZEOF_IFREQ(&ifr));
    285   1.1  fredette 	interface->ndbootd_interface_fd = -1;
    286   1.8    itojun 	freeifaddrs(ifap);
    287   1.1  fredette 	return (interface);
    288   1.1  fredette }
    289   1.1  fredette 
    290   1.1  fredette int
    291   1.1  fredette main(int argc, char *argv[])
    292   1.1  fredette {
    293   1.1  fredette 	int argv_i;
    294   1.1  fredette 	int show_usage;
    295   1.1  fredette 	const char *interface_name;
    296   1.1  fredette 	const char *boot1_file_name;
    297   1.1  fredette 	const char *boot2_x_name;
    298   1.1  fredette 	char *boot2_file_name;
    299   1.1  fredette 	int boot2_x_name_is_dir;
    300   1.1  fredette 	time_t last_open_time;
    301   1.1  fredette 	int boot1_fd;
    302   1.1  fredette 	int boot2_fd;
    303   1.1  fredette 	time_t last_rarp_time;
    304   1.1  fredette 	char last_client_ether[ETHER_ADDR_LEN];
    305   1.1  fredette 	struct in_addr last_client_ip;
    306   1.1  fredette 	struct stat stat_buffer;
    307   1.1  fredette 	int32_t boot1_block_count;
    308   1.1  fredette 	int32_t boot2_block_count;
    309   1.1  fredette 	size_t boot1_byte_count;
    310   1.1  fredette 	size_t boot2_byte_count;
    311   1.1  fredette 	ssize_t byte_count_read;
    312   1.1  fredette 	struct ndbootd_interface *interface;
    313   1.1  fredette 	char pid_buffer[(sizeof(pid_t) * 3) + 2];
    314   1.1  fredette 	unsigned char packet_buffer[sizeof(struct ether_header) + IP_MAXPACKET];
    315   1.1  fredette 	unsigned char disk_buffer[NDBOOT_MAX_BYTE_COUNT];
    316   1.1  fredette 	char hostname_buffer[MAXHOSTNAMELEN + 1];
    317   1.1  fredette 	struct hostent *the_hostent;
    318   1.1  fredette 	ssize_t packet_length;
    319   1.1  fredette 	time_t now;
    320   1.1  fredette 	struct ether_header *ether_packet;
    321   1.1  fredette 	struct ip *ip_packet;
    322   1.1  fredette 	struct ndboot_packet *nd_packet;
    323   1.1  fredette #ifdef HAVE_STRICT_ALIGNMENT
    324   1.1  fredette 	struct ether_header ether_packet_buffer;
    325   1.1  fredette 	unsigned char ip_packet_buffer[IP_MAXPACKET];
    326   1.1  fredette 	struct ndboot_packet nd_packet_buffer;
    327   1.1  fredette #endif				/* HAVE_STRICT_ALIGNMENT */
    328   1.1  fredette 	int nd_window_size;
    329   1.1  fredette 	int nd_window_filled;
    330   1.1  fredette 	off_t file_offset;
    331   1.1  fredette 	size_t disk_buffer_offset;
    332   1.1  fredette 	size_t block_number;
    333   1.1  fredette 	size_t byte_offset;
    334   1.1  fredette 	ssize_t byte_count;
    335   1.1  fredette 	ssize_t byte_count_wanted;
    336   1.7   mycroft 	struct timespec send_delay;
    337   1.1  fredette 	int fd;
    338   1.1  fredette 
    339   1.1  fredette 	/* check our command line: */
    340   1.1  fredette 	if ((_ndbootd_argv0 = strrchr(argv[0], '/')) == NULL)
    341   1.1  fredette 		_ndbootd_argv0 = argv[0];
    342   1.1  fredette 	else
    343   1.1  fredette 		_ndbootd_argv0++;
    344   1.1  fredette 	show_usage = FALSE;
    345   1.1  fredette #ifdef _NDBOOTD_DO_DEBUG
    346   1.1  fredette 	_ndbootd_debug = FALSE;
    347   1.1  fredette #endif				/* _NDBOOTD_DO_DEBUG */
    348   1.1  fredette 	boot1_file_name = NULL;
    349   1.1  fredette 	boot2_x_name = NULL;
    350   1.1  fredette 	interface_name = NULL;
    351   1.1  fredette 	nd_window_size = NDBOOT_WINDOW_SIZE_DEFAULT;
    352   1.1  fredette 	for (argv_i = 1; argv_i < argc; argv_i++) {
    353   1.1  fredette 		if (argv[argv_i][0] != '-'
    354   1.1  fredette 		    || argv[argv_i][1] == '\0') {
    355   1.1  fredette 			break;
    356   1.1  fredette 		} else if (!strcmp(argv[argv_i], "-s")
    357   1.1  fredette 		    || !strcmp(argv[argv_i], "--boot2")) {
    358   1.1  fredette 			if (++argv_i < argc) {
    359   1.1  fredette 				boot2_x_name = argv[argv_i];
    360   1.1  fredette 			} else {
    361   1.1  fredette 				show_usage = TRUE;
    362   1.1  fredette 				break;
    363   1.1  fredette 			}
    364   1.1  fredette 		} else if (!strcmp(argv[argv_i], "-i")
    365   1.1  fredette 		    || !strcmp(argv[argv_i], "--interface")) {
    366   1.1  fredette 			if (++argv_i < argc) {
    367   1.1  fredette 				interface_name = argv[argv_i];
    368   1.1  fredette 			} else {
    369   1.1  fredette 				show_usage = TRUE;
    370   1.1  fredette 				break;
    371   1.1  fredette 			}
    372   1.1  fredette 		} else if (!strcmp(argv[argv_i], "-w")
    373   1.1  fredette 		    || !strcmp(argv[argv_i], "--window-size")) {
    374   1.1  fredette 			if (++argv_i == argc || (nd_window_size = atoi(argv[argv_i])) <= 0) {
    375   1.1  fredette 				show_usage = TRUE;
    376   1.1  fredette 				break;
    377   1.1  fredette 			}
    378   1.1  fredette 		}
    379   1.1  fredette #ifdef _NDBOOTD_DO_DEBUG
    380   1.1  fredette 		else if (!strcmp(argv[argv_i], "-d")
    381   1.1  fredette 		    || !strcmp(argv[argv_i], "--debug")) {
    382   1.1  fredette 			_ndbootd_debug = TRUE;
    383   1.1  fredette 		}
    384   1.1  fredette #endif				/* _NDBOOTD_DO_DEBUG */
    385   1.1  fredette 		else {
    386   1.1  fredette 			if (strcmp(argv[argv_i], "-h")
    387   1.1  fredette 			    && strcmp(argv[argv_i], "--help")) {
    388   1.1  fredette 				fprintf(stderr, "%s error: unknown switch '%s'\n",
    389   1.1  fredette 				    _ndbootd_argv0, argv[argv_i]);
    390   1.1  fredette 			}
    391   1.1  fredette 			show_usage = TRUE;
    392   1.1  fredette 			break;
    393   1.1  fredette 		}
    394   1.1  fredette 	}
    395   1.1  fredette 	if (argv_i + 1 == argc) {
    396   1.1  fredette 		boot1_file_name = argv[argv_i];
    397   1.1  fredette 	} else {
    398   1.1  fredette 		show_usage = TRUE;
    399   1.1  fredette 	}
    400   1.1  fredette 
    401   1.1  fredette 	if (show_usage) {
    402   1.1  fredette 		fprintf(stderr, "\
    403   1.1  fredette usage: %s [OPTIONS] BOOT1-BIN\n\
    404   1.1  fredette where OPTIONS are:\n\
    405   1.1  fredette   -s, --boot2 { BOOT2-BIN | DIR }\n\
    406   1.1  fredette                           find a second-stage boot program in the file\n\
    407   1.1  fredette                           BOOT2-BIN or in the directory DIR\n\
    408   1.1  fredette   -i, --interface NAME    use interface NAME\n\
    409   1.1  fredette   -w, --window-size COUNT \n\
    410   1.1  fredette                           send at most COUNT unacknowledged packets [default=%d]\n",
    411   1.1  fredette 		    _ndbootd_argv0,
    412   1.1  fredette 		    NDBOOT_WINDOW_SIZE_DEFAULT);
    413   1.1  fredette #ifdef _NDBOOTD_DO_DEBUG
    414   1.1  fredette 		fprintf(stderr, "\
    415   1.1  fredette   -d, --debug             set debug mode\n");
    416   1.1  fredette #endif				/* _NDBOOTD_DO_DEBUG */
    417   1.1  fredette 		exit(1);
    418   1.1  fredette 	}
    419   1.1  fredette 	/* if we have been given a name for the second-stage boot, see if it's
    420   1.1  fredette 	 * a filename or a directory: */
    421   1.1  fredette 	boot2_x_name_is_dir = FALSE;
    422   1.1  fredette 	if (boot2_x_name != NULL) {
    423   1.1  fredette 		if (stat(boot2_x_name, &stat_buffer) < 0) {
    424   1.1  fredette 			fprintf(stderr, "%s error: could not stat %s: %s\n",
    425   1.1  fredette 			    _ndbootd_argv0, boot2_x_name, strerror(errno));
    426   1.1  fredette 			exit(1);
    427   1.1  fredette 		}
    428   1.1  fredette 		if (S_ISDIR(stat_buffer.st_mode)) {
    429   1.1  fredette 			boot2_x_name_is_dir = TRUE;
    430   1.1  fredette 		} else if (!S_ISREG(stat_buffer.st_mode)) {
    431   1.1  fredette 			fprintf(stderr, "%s error: %s is neither a regular file nor a directory\n",
    432   1.1  fredette 			    _ndbootd_argv0, boot2_x_name);
    433   1.1  fredette 			exit(1);
    434   1.1  fredette 		}
    435   1.1  fredette 	}
    436   1.1  fredette 	/* find the interface we will use: */
    437   1.1  fredette 	if ((interface = _ndbootd_find_interface(interface_name)) == NULL) {
    438   1.1  fredette 		fprintf(stderr, "%s error: could not find the interface to use: %s\n",
    439   1.1  fredette 		    _ndbootd_argv0, strerror(errno));
    440   1.1  fredette 		exit(1);
    441   1.1  fredette 	}
    442   1.1  fredette 	_NDBOOTD_DEBUG((fp, "opening interface %s", interface->ndbootd_interface_ifreq->ifr_name));
    443   1.1  fredette 
    444   1.1  fredette 	/* open the network interface: */
    445   1.1  fredette 	if (ndbootd_raw_open(interface)) {
    446   1.1  fredette 		fprintf(stderr, "%s error: could not open the %s interface: %s\n",
    447   1.1  fredette 		    _ndbootd_argv0, interface->ndbootd_interface_ifreq->ifr_name, strerror(errno));
    448   1.1  fredette 		exit(1);
    449   1.1  fredette 	}
    450   1.1  fredette 	_NDBOOTD_DEBUG((fp, "opened interface %s (ip %s ether %02x:%02x:%02x:%02x:%02x:%02x)",
    451   1.1  fredette 		interface->ndbootd_interface_ifreq->ifr_name,
    452   1.1  fredette 		inet_ntoa(((struct sockaddr_in *) & interface->ndbootd_interface_ifreq->ifr_addr)->sin_addr),
    453   1.1  fredette 		((unsigned char *) interface->ndbootd_interface_ether)[0],
    454   1.1  fredette 		((unsigned char *) interface->ndbootd_interface_ether)[1],
    455   1.1  fredette 		((unsigned char *) interface->ndbootd_interface_ether)[2],
    456   1.1  fredette 		((unsigned char *) interface->ndbootd_interface_ether)[3],
    457   1.1  fredette 		((unsigned char *) interface->ndbootd_interface_ether)[4],
    458   1.1  fredette 		((unsigned char *) interface->ndbootd_interface_ether)[5]));
    459   1.1  fredette 
    460   1.1  fredette 	/* become a daemon: */
    461   1.1  fredette #ifdef _NDBOOTD_DO_DEBUG
    462   1.1  fredette 	if (!_ndbootd_debug)
    463   1.1  fredette #endif				/* _NDBOOTD_DO_DEBUG */
    464   1.1  fredette 	{
    465   1.1  fredette 
    466   1.1  fredette 		/* fork and exit: */
    467   1.1  fredette 		switch (fork()) {
    468   1.1  fredette 		case 0:
    469   1.1  fredette 			break;
    470   1.1  fredette 		case -1:
    471   1.1  fredette 			fprintf(stderr, "%s error: could not fork: %s\n",
    472   1.1  fredette 			    _ndbootd_argv0, strerror(errno));
    473   1.1  fredette 			exit(1);
    474   1.1  fredette 		default:
    475   1.1  fredette 			exit(0);
    476   1.1  fredette 		}
    477   1.1  fredette 
    478   1.1  fredette 		/* close all file descriptors: */
    479   1.1  fredette #ifdef HAVE_GETDTABLESIZE
    480   1.1  fredette 		fd = getdtablesize();
    481   1.1  fredette #else				/* !HAVE_GETDTABLESIZE */
    482   1.1  fredette 		fd = -1;
    483   1.1  fredette #endif				/* !HAVE_GETDTABLESIZE */
    484   1.1  fredette 		for (; fd >= 0; fd--) {
    485   1.1  fredette 			if (fd != interface->ndbootd_interface_fd) {
    486   1.1  fredette 				close(fd);
    487   1.1  fredette 			}
    488   1.1  fredette 		}
    489   1.1  fredette 
    490   1.1  fredette #ifdef HAVE_SETSID
    491   1.1  fredette 		/* become our own session: */
    492   1.1  fredette 		setsid();
    493   1.1  fredette #endif				/* HAVE_SETSID */
    494   1.1  fredette 	}
    495   1.1  fredette 	/* write the pid file: */
    496   1.1  fredette 	if ((fd = open(NDBOOTD_PID_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644)) >= 0) {
    497   1.1  fredette 		sprintf(pid_buffer, "%u\n", getpid());
    498   1.1  fredette 		write(fd, pid_buffer, strlen(pid_buffer));
    499   1.1  fredette 		close(fd);
    500   1.1  fredette 	}
    501   1.1  fredette #ifdef HAVE_STRICT_ALIGNMENT
    502   1.1  fredette 	/* we will be dealing with all packet headers in separate buffers, to
    503   1.1  fredette 	 * make sure everything is correctly aligned: */
    504   1.1  fredette 	ether_packet = &ether_packet_buffer;
    505   1.1  fredette 	ip_packet = (struct ip *) & ip_packet_buffer[0];
    506   1.1  fredette 	nd_packet = &nd_packet_buffer;
    507   1.1  fredette #else				/* !HAVE_STRICT_ALIGNMENT */
    508   1.1  fredette 	/* we will always find the Ethernet header and the IP packet at the
    509   1.1  fredette 	 * front of the buffer: */
    510   1.1  fredette 	ether_packet = (struct ether_header *) packet_buffer;
    511   1.1  fredette 	ip_packet = (struct ip *) (ether_packet + 1);
    512   1.1  fredette #endif				/* !HAVE_STRICT_ALIGNMENT */
    513   1.1  fredette 
    514   1.1  fredette 	/* initialize our state: */
    515   1.1  fredette 	last_rarp_time = 0;
    516   1.1  fredette 	last_open_time = 0;
    517   1.1  fredette 	boot1_fd = -1;
    518   1.1  fredette 	boot2_file_name = NULL;
    519   1.1  fredette 	boot2_fd = -1;
    520  1.10     lukem 	boot1_block_count = 0;		/* XXXGCC -Wuninitialized */
    521  1.10     lukem 	boot2_block_count = 0;		/* XXXGCC -Wuninitialized */
    522  1.10     lukem 	boot1_byte_count = 0;		/* XXXGCC -Wuninitialized */
    523  1.10     lukem 	boot2_byte_count = 0;		/* XXXGCC -Wuninitialized */
    524   1.1  fredette 
    525   1.1  fredette 	/* loop processing packets: */
    526   1.1  fredette 	for (;;) {
    527   1.1  fredette 
    528   1.1  fredette 		/* receive another packet: */
    529   1.1  fredette 		packet_length = ndbootd_raw_read(interface, packet_buffer, sizeof(packet_buffer));
    530   1.1  fredette 		if (packet_length < 0) {
    531   1.1  fredette 			_NDBOOTD_DEBUG((fp, "failed to receive packet: %s", strerror(errno)));
    532   1.1  fredette 			exit(1);
    533   1.1  fredette 			continue;
    534   1.1  fredette 		}
    535   1.1  fredette 		now = time(NULL);
    536   1.1  fredette 
    537   1.1  fredette 		/* check the Ethernet and IP parts of the packet: */
    538   1.1  fredette 		if (packet_length
    539   1.1  fredette 		    < (sizeof(struct ether_header)
    540   1.1  fredette 			+ sizeof(struct ip)
    541   1.1  fredette 			+ sizeof(struct ndboot_packet))) {
    542   1.3  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a too-short packet of length %ld", (long) packet_length));
    543   1.1  fredette 			continue;
    544   1.1  fredette 		}
    545   1.1  fredette #ifdef HAVE_STRICT_ALIGNMENT
    546   1.1  fredette 		memcpy(ether_packet, packet_buffer, sizeof(struct ether_header));
    547   1.1  fredette 		memcpy(ip_packet, packet_buffer + sizeof(struct ether_header),
    548   1.1  fredette 		    (((struct ip *) (packet_buffer + sizeof(struct ether_header)))->ip_hl << 2));
    549   1.1  fredette #endif				/* !HAVE_STRICT_ALIGNMENT */
    550   1.1  fredette 		if (ether_packet->ether_type != htons(ETHERTYPE_IP)
    551   1.1  fredette 		    || ip_packet->ip_p != IPPROTO_ND) {
    552   1.1  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with the wrong Ethernet or IP protocol"));
    553   1.1  fredette 			continue;
    554   1.1  fredette 		}
    555   1.1  fredette 		_ndbootd_ip_cksum(ip_packet);
    556   1.1  fredette 		if (ip_packet->ip_sum != 0) {
    557   1.1  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with a bad IP checksum"));
    558   1.1  fredette 			continue;
    559   1.1  fredette 		}
    560   1.1  fredette 		if (packet_length
    561   1.1  fredette 		    != (sizeof(struct ether_header)
    562   1.1  fredette 			+ (ip_packet->ip_hl << 2)
    563   1.1  fredette 			+ sizeof(struct ndboot_packet))) {
    564   1.3  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad total length %ld", (long) packet_length));
    565   1.1  fredette 			continue;
    566   1.1  fredette 		}
    567   1.1  fredette 		/* if we need to, refresh our RARP cache: */
    568   1.1  fredette 		if ((last_rarp_time + NDBOOTD_CLIENT_TTL_SECONDS) < now
    569   1.1  fredette 		    || memcmp(last_client_ether, ether_packet->ether_shost, ETHER_ADDR_LEN)) {
    570   1.1  fredette 
    571   1.1  fredette 			/* turn the Ethernet address into a hostname: */
    572   1.1  fredette 			if (ether_ntohost(hostname_buffer, (struct ether_addr *) ether_packet->ether_shost)) {
    573   1.1  fredette 				_NDBOOTD_DEBUG((fp, "could not resolve %02x:%02x:%02x:%02x:%02x:%02x into a hostname: %s",
    574   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[0],
    575   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[1],
    576   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[2],
    577   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[3],
    578   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[4],
    579   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[5],
    580   1.1  fredette 					strerror(errno)));
    581   1.1  fredette 				continue;
    582   1.1  fredette 			}
    583   1.1  fredette 			/* turn the hostname into an IP address: */
    584   1.1  fredette 			hostname_buffer[sizeof(hostname_buffer) - 1] = '\0';
    585   1.1  fredette 			if ((the_hostent = gethostbyname(hostname_buffer)) == NULL
    586   1.1  fredette 			    || the_hostent->h_addrtype != AF_INET) {
    587   1.1  fredette 				_NDBOOTD_DEBUG((fp, "could not resolve %s into an IP address: %s",
    588   1.1  fredette 					hostname_buffer,
    589   1.1  fredette 					strerror(errno)));
    590   1.1  fredette 				continue;
    591   1.1  fredette 			}
    592   1.1  fredette 			/* save these new results in our RARP cache: */
    593   1.1  fredette 			last_rarp_time = now;
    594   1.1  fredette 			memcpy(last_client_ether, ether_packet->ether_shost, ETHER_ADDR_LEN);
    595   1.1  fredette 			memcpy(&last_client_ip, the_hostent->h_addr, sizeof(last_client_ip));
    596   1.1  fredette 			_NDBOOTD_DEBUG((fp, "IP address for %02x:%02x:%02x:%02x:%02x:%02x is %s",
    597   1.1  fredette 				((unsigned char *) last_client_ether)[0],
    598   1.1  fredette 				((unsigned char *) last_client_ether)[1],
    599   1.1  fredette 				((unsigned char *) last_client_ether)[2],
    600   1.1  fredette 				((unsigned char *) last_client_ether)[3],
    601   1.1  fredette 				((unsigned char *) last_client_ether)[4],
    602   1.1  fredette 				((unsigned char *) last_client_ether)[5],
    603   1.1  fredette 				inet_ntoa(last_client_ip)));
    604   1.1  fredette 
    605   1.1  fredette 			/* this will cause the file descriptor cache to be
    606   1.1  fredette 			 * reloaded, the next time we make it that far: */
    607   1.1  fredette 			last_open_time = 0;
    608   1.1  fredette 		}
    609   1.1  fredette 		/* if this IP packet was broadcast, rewrite the source IP
    610   1.1  fredette 		 * address to be the client, else, check that the client is
    611   1.1  fredette 		 * using the correct IP addresses: */
    612   1.1  fredette 		if (ip_packet->ip_dst.s_addr == htonl(0)) {
    613   1.1  fredette 			ip_packet->ip_src = last_client_ip;
    614   1.1  fredette 		} else {
    615   1.1  fredette 			if (ip_packet->ip_src.s_addr !=
    616   1.1  fredette 			    last_client_ip.s_addr) {
    617   1.1  fredette 				_NDBOOTD_DEBUG((fp, "machine %02x:%02x:%02x:%02x:%02x:%02x is using the wrong IP address\n",
    618   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[0],
    619   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[1],
    620   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[2],
    621   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[3],
    622   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[4],
    623   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[5]));
    624   1.1  fredette 				continue;
    625   1.1  fredette 			}
    626   1.1  fredette 			if (ip_packet->ip_dst.s_addr
    627   1.1  fredette 			    != ((struct sockaddr_in *) & interface->ndbootd_interface_ifreq->ifr_addr)->sin_addr.s_addr) {
    628   1.1  fredette 				_NDBOOTD_DEBUG((fp, "machine %02x:%02x:%02x:%02x:%02x:%02x is sending to the wrong IP address\n",
    629   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[0],
    630   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[1],
    631   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[2],
    632   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[3],
    633   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[4],
    634   1.1  fredette 					((unsigned char *) ether_packet->ether_shost)[5]));
    635   1.1  fredette 				continue;
    636   1.1  fredette 			}
    637   1.1  fredette 		}
    638   1.1  fredette 
    639   1.1  fredette 		/* if we need to, refresh our "cache" of file descriptors for
    640   1.1  fredette 		 * the boot programs: */
    641   1.1  fredette 		if ((last_open_time + NDBOOTD_CLIENT_TTL_SECONDS) < now) {
    642   1.1  fredette 
    643   1.1  fredette 			/* close any previously opened programs: */
    644   1.1  fredette 			if (boot1_fd >= 0) {
    645   1.1  fredette 				close(boot1_fd);
    646   1.1  fredette 			}
    647   1.1  fredette 			if (boot2_file_name != NULL) {
    648   1.1  fredette 				free(boot2_file_name);
    649   1.1  fredette 			}
    650   1.1  fredette 			if (boot2_fd >= 0) {
    651   1.1  fredette 				close(boot2_fd);
    652   1.1  fredette 			}
    653   1.1  fredette 			/* open the first-stage boot program: */
    654   1.1  fredette 			if ((boot1_fd = open(boot1_file_name, O_RDONLY)) < 0) {
    655   1.1  fredette 				_NDBOOTD_DEBUG((fp, "could not open %s: %s",
    656   1.1  fredette 					boot1_file_name, strerror(errno)));
    657   1.1  fredette 				continue;
    658   1.1  fredette 			}
    659   1.1  fredette 			if (fstat(boot1_fd, &stat_buffer) < 0) {
    660   1.1  fredette 				_NDBOOTD_DEBUG((fp, "could not stat %s: %s",
    661   1.1  fredette 					boot1_file_name, strerror(errno)));
    662   1.1  fredette 				continue;
    663   1.1  fredette 			}
    664   1.1  fredette 			boot1_byte_count = stat_buffer.st_size;
    665   1.1  fredette 			boot1_block_count = (boot1_byte_count + (NDBOOT_BSIZE - 1)) / NDBOOT_BSIZE;
    666   1.1  fredette 			if (boot1_block_count > NDBOOTD_BOOT1_BLOCK_COUNT) {
    667   1.1  fredette 				_NDBOOTD_DEBUG((fp, "first-stage boot program %s has too many blocks (%d, max is %d)",
    668   1.1  fredette 					boot1_file_name, boot1_block_count, NDBOOTD_BOOT1_BLOCK_COUNT));
    669   1.1  fredette 			}
    670   1.1  fredette 			_NDBOOTD_DEBUG((fp, "first-stage boot program %s has %d blocks",
    671   1.1  fredette 				boot1_file_name, boot1_block_count));
    672   1.1  fredette 
    673   1.1  fredette 			/* open any second-stage boot program: */
    674   1.1  fredette 			if (boot2_x_name != NULL) {
    675   1.1  fredette 
    676   1.1  fredette 				/* determine what the name of the second-stage
    677   1.1  fredette 				 * boot program will be: */
    678   1.1  fredette 				if (boot2_x_name_is_dir) {
    679   1.1  fredette 					if ((boot2_file_name = malloc(strlen(boot2_x_name) + strlen("/00000000.SUN2") + 1)) != NULL) {
    680   1.1  fredette 						sprintf(boot2_file_name, "%s/%02X%02X%02X%02X.SUN2",
    681   1.1  fredette 						    boot2_x_name,
    682   1.1  fredette 						    ((unsigned char *) &last_client_ip)[0],
    683   1.1  fredette 						    ((unsigned char *) &last_client_ip)[1],
    684   1.1  fredette 						    ((unsigned char *) &last_client_ip)[2],
    685   1.1  fredette 						    ((unsigned char *) &last_client_ip)[3]);
    686   1.1  fredette 					}
    687   1.1  fredette 				} else {
    688   1.1  fredette 					boot2_file_name = strdup(boot2_x_name);
    689   1.1  fredette 				}
    690   1.1  fredette 				if (boot2_file_name == NULL) {
    691   1.1  fredette 					abort();
    692   1.1  fredette 				}
    693   1.1  fredette 				/* open the second-stage boot program: */
    694   1.1  fredette 				if ((boot2_fd = open(boot2_file_name, O_RDONLY)) < 0) {
    695   1.1  fredette 					_NDBOOTD_DEBUG((fp, "could not open %s: %s",
    696   1.1  fredette 						boot2_file_name, strerror(errno)));
    697   1.1  fredette 					continue;
    698   1.1  fredette 				}
    699   1.1  fredette 				if (fstat(boot2_fd, &stat_buffer) < 0) {
    700   1.1  fredette 					_NDBOOTD_DEBUG((fp, "could not stat %s: %s",
    701   1.1  fredette 						boot2_file_name, strerror(errno)));
    702   1.1  fredette 					continue;
    703   1.1  fredette 				}
    704   1.1  fredette 				boot2_byte_count = stat_buffer.st_size;
    705   1.1  fredette 				boot2_block_count = (boot2_byte_count + (NDBOOT_BSIZE - 1)) / NDBOOT_BSIZE;
    706   1.1  fredette 				_NDBOOTD_DEBUG((fp, "second-stage boot program %s has %d blocks",
    707   1.1  fredette 					boot2_file_name, boot2_block_count));
    708   1.1  fredette 			}
    709   1.1  fredette 			/* success: */
    710   1.1  fredette 			last_open_time = now;
    711   1.1  fredette 		}
    712   1.1  fredette 		/* check the nd packet: */
    713   1.1  fredette #ifdef HAVE_STRICT_ALIGNMENT
    714   1.1  fredette 		memcpy(nd_packet, packet_buffer + sizeof(struct ether_header) + (ip_packet->ip_hl << 2), sizeof(struct ndboot_packet));
    715   1.1  fredette #else				/* !HAVE_STRICT_ALIGNMENT */
    716   1.1  fredette 		nd_packet = (struct ndboot_packet *) (((char *) ip_packet) + (ip_packet->ip_hl << 2));
    717   1.1  fredette #endif				/* !HAVE_STRICT_ALIGNMENT */
    718   1.1  fredette 
    719   1.1  fredette 		/* dump a bunch of debug information: */
    720   1.1  fredette 		_NDBOOTD_DEBUG((fp, "recv: op 0x%02x minor 0x%02x error %d vers %d seq %d blk %d bcount %d off %d count %d",
    721   1.1  fredette 			nd_packet->ndboot_packet_op,
    722   1.1  fredette 			nd_packet->ndboot_packet_minor,
    723   1.1  fredette 			nd_packet->ndboot_packet_error,
    724   1.1  fredette 			nd_packet->ndboot_packet_disk_version,
    725   1.1  fredette 			(int) ntohl(nd_packet->ndboot_packet_sequence),
    726   1.1  fredette 			(int) ntohl(nd_packet->ndboot_packet_block_number),
    727   1.1  fredette 			(int) ntohl(nd_packet->ndboot_packet_byte_count),
    728   1.1  fredette 			(int) ntohl(nd_packet->ndboot_packet_current_byte_offset),
    729   1.1  fredette 			(int) ntohl(nd_packet->ndboot_packet_current_byte_count)));
    730   1.1  fredette 
    731   1.1  fredette 		/* ignore this packet if it has a bad opcode, a bad minor
    732   1.1  fredette 		 * number, a bad disk version, a bad block number, a bad byte
    733   1.1  fredette 		 * count, a bad current byte offset, or a bad current byte
    734   1.1  fredette 		 * count: */
    735   1.1  fredette 		/* FIXME - for some of these conditions, we probably should
    736   1.1  fredette 		 * return an NDBOOT_OP_ERROR packet: */
    737   1.1  fredette 		if ((nd_packet->ndboot_packet_op & NDBOOT_OP_MASK) != NDBOOT_OP_READ) {
    738   1.1  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad op %d",
    739   1.1  fredette 				nd_packet->ndboot_packet_op & NDBOOT_OP_MASK));
    740   1.1  fredette 			continue;
    741   1.1  fredette 		}
    742   1.1  fredette 		if (nd_packet->ndboot_packet_minor != NDBOOT_MINOR_NDP0) {
    743   1.1  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with device minor %d",
    744   1.1  fredette 				nd_packet->ndboot_packet_minor));
    745   1.1  fredette 			continue;
    746   1.1  fredette 		}
    747   1.1  fredette 		if (nd_packet->ndboot_packet_disk_version != 0) {
    748   1.1  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with disk version %d",
    749   1.1  fredette 				nd_packet->ndboot_packet_disk_version));
    750   1.1  fredette 			continue;
    751   1.1  fredette 		}
    752   1.1  fredette 		if (ntohl(nd_packet->ndboot_packet_block_number) < 0) {
    753   1.1  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad block number %d",
    754   1.1  fredette 				(int) ntohl(nd_packet->ndboot_packet_block_number)));
    755   1.1  fredette 			continue;
    756   1.1  fredette 		}
    757   1.1  fredette 		if (ntohl(nd_packet->ndboot_packet_byte_count) <= 0 ||
    758   1.1  fredette 		    ntohl(nd_packet->ndboot_packet_byte_count) > NDBOOT_MAX_BYTE_COUNT) {
    759   1.1  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad byte count %d",
    760   1.1  fredette 				(int) ntohl(nd_packet->ndboot_packet_byte_count)));
    761   1.1  fredette 			continue;
    762   1.1  fredette 		}
    763   1.1  fredette 		if (ntohl(nd_packet->ndboot_packet_current_byte_offset) < 0 ||
    764   1.1  fredette 		    ntohl(nd_packet->ndboot_packet_current_byte_offset)
    765   1.1  fredette 		    >= ntohl(nd_packet->ndboot_packet_byte_count)) {
    766   1.1  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad current offset %d",
    767   1.1  fredette 				(int) ntohl(nd_packet->ndboot_packet_current_byte_offset)));
    768   1.1  fredette 			continue;
    769   1.1  fredette 		}
    770   1.1  fredette 		if (ntohl(nd_packet->ndboot_packet_current_byte_count) < 0 ||
    771   1.1  fredette 		    ntohl(nd_packet->ndboot_packet_current_byte_count)
    772   1.1  fredette 		    > (ntohl(nd_packet->ndboot_packet_byte_count)
    773   1.1  fredette 			- ntohl(nd_packet->ndboot_packet_current_byte_offset))) {
    774   1.1  fredette 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad current count %d",
    775   1.1  fredette 				(int) ntohl(nd_packet->ndboot_packet_current_byte_count)));
    776   1.1  fredette 			continue;
    777   1.1  fredette 		}
    778   1.1  fredette 		/* if we were given a current byte count of zero, rewrite it
    779   1.1  fredette 		 * to be the maximum: */
    780   1.1  fredette 		if (ntohl(nd_packet->ndboot_packet_current_byte_count) == 0) {
    781   1.1  fredette 			nd_packet->ndboot_packet_current_byte_count =
    782   1.1  fredette 			    htonl(ntohl(nd_packet->ndboot_packet_byte_count)
    783   1.1  fredette 			    - ntohl(nd_packet->ndboot_packet_current_byte_offset));
    784   1.1  fredette 		}
    785   1.1  fredette 		/* read the data: */
    786   1.1  fredette 		disk_buffer_offset = 0;
    787   1.1  fredette 		block_number = ntohl(nd_packet->ndboot_packet_block_number);
    788   1.1  fredette 		byte_offset = ntohl(nd_packet->ndboot_packet_current_byte_offset);
    789   1.1  fredette 		byte_count = ntohl(nd_packet->ndboot_packet_current_byte_count);
    790   1.1  fredette 		for (; byte_count > 0;) {
    791   1.1  fredette 
    792   1.1  fredette 			/* adjust the current block number and byte offset
    793   1.1  fredette 			 * such that the byte offset is always < NDBOOT_BSIZE: */
    794   1.1  fredette 			block_number += (byte_offset / NDBOOT_BSIZE);
    795   1.1  fredette 			byte_offset = byte_offset % NDBOOT_BSIZE;
    796   1.1  fredette 
    797   1.1  fredette 			/* dispatch on the beginning block number: */
    798   1.1  fredette 			byte_count_read = 0;
    799   1.1  fredette 
    800   1.1  fredette 			/* the (dummy) Sun disk label: */
    801   1.1  fredette 			if (block_number >= NDBOOTD_SUNDK_BLOCK_FIRST
    802   1.1  fredette 			    && block_number < (NDBOOTD_SUNDK_BLOCK_FIRST + NDBOOTD_SUNDK_BLOCK_COUNT)) {
    803   1.1  fredette 				byte_count_read = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset,
    804   1.1  fredette 					NDBOOTD_SUNDK_BLOCK_FIRST, NDBOOTD_SUNDK_BLOCK_COUNT),
    805   1.1  fredette 				    byte_count);
    806   1.1  fredette 			}
    807   1.1  fredette 			/* the first-stage boot program: */
    808   1.1  fredette 			else if (block_number >= NDBOOTD_BOOT1_BLOCK_FIRST
    809   1.1  fredette 			    && block_number < (NDBOOTD_BOOT1_BLOCK_FIRST + NDBOOTD_BOOT1_BLOCK_COUNT)) {
    810   1.1  fredette 
    811   1.1  fredette 				/* if any real part of the first-stage boot
    812   1.1  fredette 				 * program is needed to satisfy the request,
    813   1.1  fredette 				 * read it (otherwise we return garbage as
    814   1.1  fredette 				 * padding): */
    815   1.1  fredette 				byte_count_wanted = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset,
    816   1.1  fredette 					NDBOOTD_BOOT1_BLOCK_FIRST, boot1_block_count),
    817   1.1  fredette 				    byte_count);
    818   1.1  fredette 				if (byte_count_wanted > 0) {
    819   1.1  fredette 
    820   1.1  fredette 					file_offset = ((block_number - NDBOOTD_BOOT1_BLOCK_FIRST) * NDBOOT_BSIZE) + byte_offset;
    821   1.1  fredette 					if (lseek(boot1_fd, file_offset, SEEK_SET) < 0) {
    822   1.3  fredette 						_NDBOOTD_DEBUG((fp, "could not seek %s to block %ld offset %ld: %s",
    823   1.1  fredette 							boot1_file_name,
    824   1.3  fredette 							(long) (block_number - NDBOOTD_BOOT1_BLOCK_FIRST),
    825   1.3  fredette 							(long) byte_offset,
    826   1.1  fredette 							strerror(errno)));
    827   1.1  fredette 						break;
    828   1.1  fredette 					}
    829   1.1  fredette 					byte_count_read = read(boot1_fd, disk_buffer + disk_buffer_offset, byte_count_wanted);
    830   1.1  fredette 					/* pretend that the size of the
    831   1.1  fredette 					 * first-stage boot program is a
    832   1.1  fredette 					 * multiple of NDBOOT_BSIZE: */
    833   1.1  fredette 					if (byte_count_read != byte_count_wanted
    834   1.4  fredette 					    && byte_count_read > 0
    835   1.1  fredette 					    && file_offset + byte_count_read == boot1_byte_count) {
    836   1.1  fredette 						byte_count_read = byte_count_wanted;
    837   1.1  fredette 					}
    838   1.1  fredette 					if (byte_count_read != byte_count_wanted) {
    839   1.3  fredette 						_NDBOOTD_DEBUG((fp, "could not read %ld bytes at block %ld offset %ld from %s: %s (read %ld bytes)",
    840   1.3  fredette 							(long) byte_count_wanted,
    841   1.3  fredette 							(long) (block_number - NDBOOTD_BOOT1_BLOCK_FIRST),
    842   1.3  fredette 							(long) byte_offset,
    843   1.1  fredette 							boot1_file_name,
    844   1.1  fredette 							strerror(errno),
    845   1.3  fredette 							(long) byte_count_read));
    846   1.1  fredette 						break;
    847   1.1  fredette 					}
    848   1.1  fredette 				}
    849   1.1  fredette 				/* the number of bytes we read, including any
    850   1.1  fredette 				 * padding garbage: */
    851   1.1  fredette 				byte_count_read = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset,
    852   1.1  fredette 					NDBOOTD_BOOT1_BLOCK_FIRST, NDBOOTD_BOOT1_BLOCK_COUNT),
    853   1.1  fredette 				    byte_count);
    854   1.1  fredette 			}
    855   1.1  fredette 			/* any second-stage boot program: */
    856   1.1  fredette 			else if (block_number >= NDBOOTD_BOOT2_BLOCK_FIRST) {
    857   1.1  fredette 
    858   1.1  fredette 				/* if any real part of any first-stage boot
    859   1.1  fredette 				 * program is needed to satisfy the request,
    860   1.1  fredette 				 * read it (otherwise we return garbage as
    861   1.1  fredette 				 * padding): */
    862   1.1  fredette 				byte_count_wanted = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset,
    863   1.1  fredette 					NDBOOTD_BOOT2_BLOCK_FIRST, boot2_block_count),
    864   1.1  fredette 				    byte_count);
    865   1.1  fredette 				if (boot2_fd >= 0
    866   1.1  fredette 				    && byte_count_wanted > 0) {
    867   1.1  fredette 
    868   1.1  fredette 					file_offset = ((block_number - NDBOOTD_BOOT2_BLOCK_FIRST) * NDBOOT_BSIZE) + byte_offset;
    869   1.1  fredette 					if (lseek(boot2_fd, file_offset, SEEK_SET) < 0) {
    870   1.3  fredette 						_NDBOOTD_DEBUG((fp, "could not seek %s to block %ld offset %ld: %s",
    871   1.1  fredette 							boot2_file_name,
    872   1.3  fredette 							(long) (block_number - NDBOOTD_BOOT2_BLOCK_FIRST),
    873   1.3  fredette 							(long) byte_offset,
    874   1.1  fredette 							strerror(errno)));
    875   1.1  fredette 						break;
    876   1.1  fredette 					}
    877   1.1  fredette 					byte_count_read = read(boot2_fd, disk_buffer + disk_buffer_offset, byte_count_wanted);
    878   1.1  fredette 					/* pretend that the size of the
    879   1.1  fredette 					 * second-stage boot program is a
    880   1.1  fredette 					 * multiple of NDBOOT_BSIZE: */
    881   1.1  fredette 					if (byte_count_read != byte_count_wanted
    882   1.4  fredette 					    && byte_count_read > 0
    883   1.1  fredette 					    && file_offset + byte_count_read == boot2_byte_count) {
    884   1.1  fredette 						byte_count_read = byte_count_wanted;
    885   1.1  fredette 					}
    886   1.1  fredette 					if (byte_count_read != byte_count_wanted) {
    887   1.3  fredette 						_NDBOOTD_DEBUG((fp, "could not read %ld bytes at block %ld offset %ld from %s: %s (read %ld bytes)",
    888   1.3  fredette 							(long) byte_count_wanted,
    889   1.3  fredette 							(long) (block_number - NDBOOTD_BOOT2_BLOCK_FIRST),
    890   1.3  fredette 							(long) byte_offset,
    891   1.1  fredette 							boot2_file_name,
    892   1.1  fredette 							strerror(errno),
    893   1.3  fredette 							(long) byte_count_read));
    894   1.1  fredette 						break;
    895   1.1  fredette 					}
    896   1.1  fredette 				}
    897   1.1  fredette 				/* the number of bytes we read, including any
    898   1.1  fredette 				 * padding garbage: */
    899   1.1  fredette 				byte_count_read = byte_count;
    900   1.1  fredette 			}
    901   1.1  fredette 			/* update for the amount that we read: */
    902   1.1  fredette 			assert(byte_count_read > 0);
    903   1.1  fredette 			disk_buffer_offset += byte_count_read;
    904   1.1  fredette 			byte_offset += byte_count_read;
    905   1.1  fredette 			byte_count -= byte_count_read;
    906   1.1  fredette 		}
    907   1.1  fredette 		if (byte_count > 0) {
    908   1.1  fredette 			/* an error occurred: */
    909   1.1  fredette 			continue;
    910   1.1  fredette 		}
    911   1.1  fredette 		/* set the Ethernet and IP destination and source addresses,
    912   1.1  fredette 		 * and the IP TTL: */
    913   1.1  fredette 		memcpy(ether_packet->ether_dhost, ether_packet->ether_shost, ETHER_ADDR_LEN);
    914   1.1  fredette 		memcpy(ether_packet->ether_shost, interface->ndbootd_interface_ether, ETHER_ADDR_LEN);
    915   1.1  fredette #ifdef HAVE_STRICT_ALIGNMENT
    916   1.1  fredette 		memcpy(packet_buffer, ether_packet, sizeof(struct ether_header));
    917   1.1  fredette #endif				/* !HAVE_STRICT_ALIGNMENT */
    918   1.1  fredette 		ip_packet->ip_dst = ip_packet->ip_src;
    919   1.1  fredette 		ip_packet->ip_src = ((struct sockaddr_in *) & interface->ndbootd_interface_ifreq->ifr_addr)->sin_addr;
    920   1.1  fredette 		ip_packet->ip_ttl = 4;
    921   1.1  fredette 
    922   1.1  fredette 		/* return the data: */
    923   1.1  fredette 		nd_window_filled = 0;
    924   1.1  fredette 		disk_buffer_offset = 0;
    925   1.1  fredette 		byte_count = ntohl(nd_packet->ndboot_packet_current_byte_count);
    926   1.1  fredette 		for (;;) {
    927   1.1  fredette 
    928   1.1  fredette 			/* set the byte count on this packet: */
    929   1.1  fredette 			nd_packet->ndboot_packet_current_byte_count = htonl(MIN(byte_count, NDBOOT_MAX_PACKET_DATA));
    930   1.1  fredette 
    931   1.1  fredette 			/* set our opcode.  the opcode is always
    932   1.1  fredette 			 * NDBOOT_OP_READ, ORed with NDBOOT_OP_FLAG_DONE |
    933   1.1  fredette 			 * NDBOOT_OP_FLAG_WAIT if this packet finishes the
    934   1.1  fredette 			 * request, or ORed with NDBOOT_OP_FLAG_WAIT if this
    935   1.1  fredette 			 * packet fills the window: */
    936   1.1  fredette 			nd_window_filled++;
    937   1.1  fredette 			nd_packet->ndboot_packet_op =
    938   1.1  fredette 			    (NDBOOT_OP_READ
    939   1.1  fredette 			    | ((ntohl(nd_packet->ndboot_packet_current_byte_offset)
    940   1.1  fredette 				    + ntohl(nd_packet->ndboot_packet_current_byte_count))
    941   1.1  fredette 				== ntohl(nd_packet->ndboot_packet_byte_count)
    942   1.1  fredette 				? (NDBOOT_OP_FLAG_DONE
    943   1.1  fredette 				    | NDBOOT_OP_FLAG_WAIT)
    944   1.1  fredette 				: (nd_window_filled == nd_window_size
    945   1.1  fredette 				    ? NDBOOT_OP_FLAG_WAIT
    946   1.1  fredette 				    : 0)));
    947   1.1  fredette 
    948   1.1  fredette 			/* copy the data into the packet: */
    949   1.1  fredette 			memcpy(packet_buffer +
    950   1.1  fredette 			    sizeof(struct ether_header) + (ip_packet->ip_hl << 2) + sizeof(struct ndboot_packet),
    951   1.1  fredette 			    disk_buffer + disk_buffer_offset,
    952   1.1  fredette 			    ntohl(nd_packet->ndboot_packet_current_byte_count));
    953   1.1  fredette 
    954   1.1  fredette 			/* finish the IP packet and calculate the checksum: */
    955   1.1  fredette 			ip_packet->ip_len = htons((ip_packet->ip_hl << 2)
    956   1.1  fredette 			    + sizeof(struct ndboot_packet)
    957   1.1  fredette 			    + ntohl(nd_packet->ndboot_packet_current_byte_count));
    958   1.1  fredette 			ip_packet->ip_sum = 0;
    959   1.1  fredette 			_ndbootd_ip_cksum(ip_packet);
    960   1.1  fredette 
    961   1.1  fredette #ifdef HAVE_STRICT_ALIGNMENT
    962   1.1  fredette 			memcpy(packet_buffer + sizeof(struct ether_header), ip_packet, ip_packet->ip_hl << 2);
    963   1.1  fredette 			memcpy(packet_buffer + sizeof(struct ether_header) + (ip_packet->ip_hl << 2), nd_packet, sizeof(struct ndboot_packet));
    964   1.1  fredette #endif				/* !HAVE_STRICT_ALIGNMENT */
    965   1.1  fredette 
    966   1.1  fredette 			/* dump a bunch of debug information: */
    967   1.1  fredette 			_NDBOOTD_DEBUG((fp, "send: op 0x%02x minor 0x%02x error %d vers %d seq %d blk %d bcount %d off %d count %d (win %d)",
    968   1.1  fredette 				nd_packet->ndboot_packet_op,
    969   1.1  fredette 				nd_packet->ndboot_packet_minor,
    970   1.1  fredette 				nd_packet->ndboot_packet_error,
    971   1.1  fredette 				nd_packet->ndboot_packet_disk_version,
    972   1.1  fredette 				(int) ntohl(nd_packet->ndboot_packet_sequence),
    973   1.1  fredette 				(int) ntohl(nd_packet->ndboot_packet_block_number),
    974   1.1  fredette 				(int) ntohl(nd_packet->ndboot_packet_byte_count),
    975   1.1  fredette 				(int) ntohl(nd_packet->ndboot_packet_current_byte_offset),
    976   1.1  fredette 				(int) ntohl(nd_packet->ndboot_packet_current_byte_count),
    977   1.1  fredette 				nd_window_filled - 1));
    978   1.1  fredette 
    979   1.1  fredette 			/* delay before sending the packet: */
    980   1.1  fredette 			send_delay.tv_sec = 0;
    981   1.7   mycroft 			send_delay.tv_nsec = NDBOOTD_SEND_DELAY_NSECONDS;
    982   1.7   mycroft 			nanosleep(&send_delay, NULL);
    983   1.1  fredette 
    984   1.1  fredette 			/* transmit the packet: */
    985   1.1  fredette 			if (ndbootd_raw_write(interface, packet_buffer,
    986   1.1  fredette 				sizeof(struct ether_header) + (ip_packet->ip_hl << 2) + sizeof(struct ndboot_packet) + ntohl(nd_packet->ndboot_packet_current_byte_count)) < 0) {
    987   1.1  fredette 				_NDBOOTD_DEBUG((fp, "could not write a packet: %s",
    988   1.1  fredette 					strerror(errno)));
    989   1.1  fredette 			}
    990   1.1  fredette 			/* if we set NDBOOT_OP_FLAG_DONE or
    991   1.1  fredette 			 * NDBOOT_OP_FLAG_WAIT in the packet we just sent,
    992   1.1  fredette 			 * we're done sending: */
    993   1.1  fredette 			if (nd_packet->ndboot_packet_op != NDBOOT_OP_READ) {
    994   1.1  fredette 				break;
    995   1.1  fredette 			}
    996   1.1  fredette 			/* advance to the next packet: */
    997   1.1  fredette 			byte_count -= ntohl(nd_packet->ndboot_packet_current_byte_count);
    998   1.1  fredette 			disk_buffer_offset += ntohl(nd_packet->ndboot_packet_current_byte_count);
    999   1.1  fredette 			nd_packet->ndboot_packet_current_byte_offset =
   1000   1.1  fredette 			    htonl(ntohl(nd_packet->ndboot_packet_current_byte_offset)
   1001   1.1  fredette 			    + ntohl(nd_packet->ndboot_packet_current_byte_count));
   1002   1.1  fredette 		}
   1003   1.1  fredette 	}
   1004   1.1  fredette 	/* NOTREACHED */
   1005   1.1  fredette }
   1006   1.1  fredette /* the raw Ethernet access code: */
   1007   1.2  fredette #include "config/ndbootd-bpf.c"
   1008