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