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