xref: /netbsd-src/usr.sbin/ndbootd/ndbootd.c (revision 1ef2e3bf13b0bb1b685c84b5a34ffd4e0269cabe)
1 /*	$NetBSD: ndbootd.c,v 1.13 2021/10/30 10:44:25 nia 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.13 2021/10/30 10:44:25 nia 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, size_t));
132 void *ndbootd_calloc _NDBOOTD_P((size_t, 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 *
ndbootd_malloc(size_t number,size_t size)143 ndbootd_malloc(size_t number, size_t size)
144 {
145 	void *buffer = NULL;
146 	if (reallocarr(&buffer, number, size) != 0) {
147 		abort();
148 	}
149 	return (buffer);
150 }
151 void *
ndbootd_calloc(size_t number,size_t size)152 ndbootd_calloc(size_t number, size_t size)
153 {
154 	void *buffer;
155 	if ((buffer = calloc(number, size)) == NULL) {
156 		abort();
157 	}
158 	return (buffer);
159 }
160 void *
ndbootd_memdup(void * buffer0,size_t size)161 ndbootd_memdup(void *buffer0, size_t size)
162 {
163 	void *buffer1;
164 	buffer1 = ndbootd_malloc(1, size);
165 	memcpy(buffer1, buffer0, size);
166 	return (buffer1);
167 }
168 #define ndbootd_free free
169 #define ndbootd_new(t, c) ((t *) ndbootd_malloc(c, sizeof(t)))
170 #define ndbootd_new0(t, c) ((t *) ndbootd_calloc(c, sizeof(t)))
171 #define ndbootd_dup(t, b, c) ((t *) ndbootd_memdup(b, c))
172 
173 /* this calculates an IP packet header checksum: */
174 static void
_ndbootd_ip_cksum(struct ip * ip_packet)175 _ndbootd_ip_cksum(struct ip * ip_packet)
176 {
177 	u_int16_t *_word, word;
178 	u_int32_t checksum;
179 	unsigned int byte_count, bytes_left;
180 
181 	/* we assume that the IP packet header is 16-bit aligned: */
182 	assert((((unsigned long) ip_packet) % sizeof(word)) == 0);
183 
184 	/* initialize for the checksum: */
185 	checksum = 0;
186 
187 	/* sum up the packet contents: */
188 	_word = (u_int16_t *) ip_packet;
189 	byte_count = ip_packet->ip_hl << 2;
190 	for (bytes_left = byte_count; bytes_left >= sizeof(*_word);) {
191 		checksum += *(_word++);
192 		bytes_left -= sizeof(*_word);
193 	}
194 	word = 0;
195 	memcpy(&word, _word, bytes_left);
196 	checksum += word;
197 
198 	/* finish the checksum: */
199 	checksum = (checksum >> 16) + (checksum & 0xffff);
200 	checksum += (checksum >> 16);
201 	ip_packet->ip_sum = (~checksum);
202 }
203 /* this finds a network interface: */
204 static struct ndbootd_interface *
_ndbootd_find_interface(const char * ifr_name_user)205 _ndbootd_find_interface(const char *ifr_name_user)
206 {
207 	struct ifreq ifr;
208 #ifdef HAVE_AF_LINK
209 	struct sockaddr_dl *sadl;
210 #endif				/* HAVE_AF_LINK */
211 	struct ndbootd_interface *interface;
212 	struct ifaddrs *ifap, *ifa, *ifa_user;
213 
214 	/* read the interface list: */
215 	if (getifaddrs(&ifap) != 0) {
216 		return (NULL);
217 	}
218 
219 	/* walk the interface list: */
220 	ifa_user = NULL;
221 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
222 		/* ignore this interface if it doesn't do IP: */
223 		if (ifa->ifa_addr->sa_family != AF_INET) {
224 			continue;
225 		}
226 
227 		/* ignore this interface if it isn't up and running: */
228 		if ((ifa->ifa_flags & (IFF_UP | IFF_RUNNING)) !=
229 		    (IFF_UP | IFF_RUNNING)) {
230 			continue;
231 		}
232 		/* if we don't have an interface yet, take this one depending
233 		 * on whether the user asked for an interface by name or not.
234 		 * if he did, and this is it, take this one.  if he didn't,
235 		 * and this isn't a loopback interface, take this one: */
236 		if (ifa_user == NULL
237 		    && (ifr_name_user != NULL
238 			? !strcmp(ifa->ifa_name, ifr_name_user)
239 			: !(ifa->ifa_flags & IFF_LOOPBACK))) {
240 			ifa_user = ifa;
241 		}
242 	}
243 
244 	/* if we don't have an interface to return: */
245 	if (ifa_user == NULL) {
246 		freeifaddrs(ifap);
247 		errno = ENOENT;
248 		return (NULL);
249 	}
250 	/* start the interface description: */
251 	interface = ndbootd_new0(struct ndbootd_interface, 1);
252 
253 #ifdef HAVE_AF_LINK
254 
255 	/* we must be able to find an AF_LINK ifreq that gives us the
256 	 * interface's Ethernet address. */
257 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
258 		if (ifa->ifa_addr->sa_family != AF_LINK) {
259 			continue;
260 		}
261 		/* if this is the hardware address we want */
262 		if (!strcmp(ifa->ifa_name, ifa_user->ifa_name)) {
263 			break;
264 		}
265 	}
266 	if (ifa == NULL) {
267 		freeifaddrs(ifap);
268 		free(interface);
269 		errno = ENOENT;
270 		return (NULL);
271 	}
272 	/* copy out the Ethernet address: */
273 	sadl = (struct sockaddr_dl *)ifa->ifa_addr;
274 	memcpy(interface->ndbootd_interface_ether, LLADDR(sadl), sadl->sdl_alen);
275 
276 #else				/* !HAVE_AF_LINK */
277 #error "must have AF_LINK for now"
278 #endif				/* !HAVE_AF_LINK */
279 
280 	/* finish this interface and return it: */
281 	strlcpy(ifr.ifr_name, ifa_user->ifa_name, sizeof(ifr.ifr_name));
282 	assert(sizeof(ifr.ifr_addr) >= ifa_user->ifa_addr->sa_len);
283 	memcpy(&ifr.ifr_addr, ifa_user->ifa_addr, ifa_user->ifa_addr->sa_len);
284 	interface->ndbootd_interface_ifreq = (struct ifreq *) ndbootd_memdup(&ifr, SIZEOF_IFREQ(&ifr));
285 	interface->ndbootd_interface_fd = -1;
286 	freeifaddrs(ifap);
287 	return (interface);
288 }
289 
290 int
main(int argc,char * argv[])291 main(int argc, char *argv[])
292 {
293 	int argv_i;
294 	int show_usage;
295 	const char *interface_name;
296 	const char *boot1_file_name;
297 	const char *boot2_x_name;
298 	char *boot2_file_name;
299 	int boot2_x_name_is_dir;
300 	time_t last_open_time;
301 	int boot1_fd;
302 	int boot2_fd;
303 	time_t last_rarp_time;
304 	char last_client_ether[ETHER_ADDR_LEN];
305 	struct in_addr last_client_ip;
306 	struct stat stat_buffer;
307 	int32_t boot1_block_count;
308 	int32_t boot2_block_count;
309 	size_t boot1_byte_count;
310 	size_t boot2_byte_count;
311 	ssize_t byte_count_read;
312 	struct ndbootd_interface *interface;
313 	char pid_buffer[(sizeof(pid_t) * 3) + 2];
314 	unsigned char packet_buffer[sizeof(struct ether_header) + IP_MAXPACKET];
315 	unsigned char disk_buffer[NDBOOT_MAX_BYTE_COUNT];
316 	char hostname_buffer[MAXHOSTNAMELEN + 1];
317 	struct hostent *the_hostent;
318 	ssize_t packet_length;
319 	time_t now;
320 	struct ether_header *ether_packet;
321 	struct ip *ip_packet;
322 	struct ndboot_packet *nd_packet;
323 #ifdef HAVE_STRICT_ALIGNMENT
324 	struct ether_header ether_packet_buffer;
325 	unsigned char ip_packet_buffer[IP_MAXPACKET];
326 	struct ndboot_packet nd_packet_buffer;
327 #endif				/* HAVE_STRICT_ALIGNMENT */
328 	int nd_window_size;
329 	int nd_window_filled;
330 	off_t file_offset;
331 	size_t disk_buffer_offset;
332 	size_t block_number;
333 	size_t byte_offset;
334 	ssize_t byte_count;
335 	ssize_t byte_count_wanted;
336 	struct timespec send_delay;
337 	int fd;
338 
339 	/* check our command line: */
340 	if ((_ndbootd_argv0 = strrchr(argv[0], '/')) == NULL)
341 		_ndbootd_argv0 = argv[0];
342 	else
343 		_ndbootd_argv0++;
344 	show_usage = FALSE;
345 #ifdef _NDBOOTD_DO_DEBUG
346 	_ndbootd_debug = FALSE;
347 #endif				/* _NDBOOTD_DO_DEBUG */
348 	boot1_file_name = NULL;
349 	boot2_x_name = NULL;
350 	interface_name = NULL;
351 	nd_window_size = NDBOOT_WINDOW_SIZE_DEFAULT;
352 	for (argv_i = 1; argv_i < argc; argv_i++) {
353 		if (argv[argv_i][0] != '-'
354 		    || argv[argv_i][1] == '\0') {
355 			break;
356 		} else if (!strcmp(argv[argv_i], "-s")
357 		    || !strcmp(argv[argv_i], "--boot2")) {
358 			if (++argv_i < argc) {
359 				boot2_x_name = argv[argv_i];
360 			} else {
361 				show_usage = TRUE;
362 				break;
363 			}
364 		} else if (!strcmp(argv[argv_i], "-i")
365 		    || !strcmp(argv[argv_i], "--interface")) {
366 			if (++argv_i < argc) {
367 				interface_name = argv[argv_i];
368 			} else {
369 				show_usage = TRUE;
370 				break;
371 			}
372 		} else if (!strcmp(argv[argv_i], "-w")
373 		    || !strcmp(argv[argv_i], "--window-size")) {
374 			if (++argv_i == argc || (nd_window_size = atoi(argv[argv_i])) <= 0) {
375 				show_usage = TRUE;
376 				break;
377 			}
378 		}
379 #ifdef _NDBOOTD_DO_DEBUG
380 		else if (!strcmp(argv[argv_i], "-d")
381 		    || !strcmp(argv[argv_i], "--debug")) {
382 			_ndbootd_debug = TRUE;
383 		}
384 #endif				/* _NDBOOTD_DO_DEBUG */
385 		else {
386 			if (strcmp(argv[argv_i], "-h")
387 			    && strcmp(argv[argv_i], "--help")) {
388 				fprintf(stderr, "%s error: unknown switch '%s'\n",
389 				    _ndbootd_argv0, argv[argv_i]);
390 			}
391 			show_usage = TRUE;
392 			break;
393 		}
394 	}
395 	if (argv_i + 1 == argc) {
396 		boot1_file_name = argv[argv_i];
397 	} else {
398 		show_usage = TRUE;
399 	}
400 
401 	if (show_usage) {
402 		fprintf(stderr, "\
403 usage: %s [OPTIONS] BOOT1-BIN\n\
404 where OPTIONS are:\n\
405   -s, --boot2 { BOOT2-BIN | DIR }\n\
406                           find a second-stage boot program in the file\n\
407                           BOOT2-BIN or in the directory DIR\n\
408   -i, --interface NAME    use interface NAME\n\
409   -w, --window-size COUNT \n\
410                           send at most COUNT unacknowledged packets [default=%d]\n",
411 		    _ndbootd_argv0,
412 		    NDBOOT_WINDOW_SIZE_DEFAULT);
413 #ifdef _NDBOOTD_DO_DEBUG
414 		fprintf(stderr, "\
415   -d, --debug             set debug mode\n");
416 #endif				/* _NDBOOTD_DO_DEBUG */
417 		exit(1);
418 	}
419 	/* if we have been given a name for the second-stage boot, see if it's
420 	 * a filename or a directory: */
421 	boot2_x_name_is_dir = FALSE;
422 	if (boot2_x_name != NULL) {
423 		if (stat(boot2_x_name, &stat_buffer) < 0) {
424 			fprintf(stderr, "%s error: could not stat %s: %s\n",
425 			    _ndbootd_argv0, boot2_x_name, strerror(errno));
426 			exit(1);
427 		}
428 		if (S_ISDIR(stat_buffer.st_mode)) {
429 			boot2_x_name_is_dir = TRUE;
430 		} else if (!S_ISREG(stat_buffer.st_mode)) {
431 			fprintf(stderr, "%s error: %s is neither a regular file nor a directory\n",
432 			    _ndbootd_argv0, boot2_x_name);
433 			exit(1);
434 		}
435 	}
436 	/* find the interface we will use: */
437 	if ((interface = _ndbootd_find_interface(interface_name)) == NULL) {
438 		fprintf(stderr, "%s error: could not find the interface to use: %s\n",
439 		    _ndbootd_argv0, strerror(errno));
440 		exit(1);
441 	}
442 	_NDBOOTD_DEBUG((fp, "opening interface %s", interface->ndbootd_interface_ifreq->ifr_name));
443 
444 	/* open the network interface: */
445 	if (ndbootd_raw_open(interface)) {
446 		fprintf(stderr, "%s error: could not open the %s interface: %s\n",
447 		    _ndbootd_argv0, interface->ndbootd_interface_ifreq->ifr_name, strerror(errno));
448 		exit(1);
449 	}
450 	_NDBOOTD_DEBUG((fp, "opened interface %s (ip %s ether %02x:%02x:%02x:%02x:%02x:%02x)",
451 		interface->ndbootd_interface_ifreq->ifr_name,
452 		inet_ntoa(((struct sockaddr_in *) & interface->ndbootd_interface_ifreq->ifr_addr)->sin_addr),
453 		((unsigned char *) interface->ndbootd_interface_ether)[0],
454 		((unsigned char *) interface->ndbootd_interface_ether)[1],
455 		((unsigned char *) interface->ndbootd_interface_ether)[2],
456 		((unsigned char *) interface->ndbootd_interface_ether)[3],
457 		((unsigned char *) interface->ndbootd_interface_ether)[4],
458 		((unsigned char *) interface->ndbootd_interface_ether)[5]));
459 
460 	/* become a daemon: */
461 #ifdef _NDBOOTD_DO_DEBUG
462 	if (!_ndbootd_debug)
463 #endif				/* _NDBOOTD_DO_DEBUG */
464 	{
465 
466 		/* fork and exit: */
467 		switch (fork()) {
468 		case 0:
469 			break;
470 		case -1:
471 			fprintf(stderr, "%s error: could not fork: %s\n",
472 			    _ndbootd_argv0, strerror(errno));
473 			exit(1);
474 		default:
475 			exit(0);
476 		}
477 
478 		/* close all file descriptors: */
479 #ifdef HAVE_GETDTABLESIZE
480 		fd = getdtablesize();
481 #else				/* !HAVE_GETDTABLESIZE */
482 		fd = -1;
483 #endif				/* !HAVE_GETDTABLESIZE */
484 		for (; fd >= 0; fd--) {
485 			if (fd != interface->ndbootd_interface_fd) {
486 				close(fd);
487 			}
488 		}
489 
490 #ifdef HAVE_SETSID
491 		/* become our own session: */
492 		setsid();
493 #endif				/* HAVE_SETSID */
494 	}
495 	/* write the pid file: */
496 	if ((fd = open(NDBOOTD_PID_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644)) >= 0) {
497 		sprintf(pid_buffer, "%u\n", getpid());
498 		write(fd, pid_buffer, strlen(pid_buffer));
499 		close(fd);
500 	}
501 #ifdef HAVE_STRICT_ALIGNMENT
502 	/* we will be dealing with all packet headers in separate buffers, to
503 	 * make sure everything is correctly aligned: */
504 	ether_packet = &ether_packet_buffer;
505 	ip_packet = (struct ip *) & ip_packet_buffer[0];
506 	nd_packet = &nd_packet_buffer;
507 #else				/* !HAVE_STRICT_ALIGNMENT */
508 	/* we will always find the Ethernet header and the IP packet at the
509 	 * front of the buffer: */
510 	ether_packet = (struct ether_header *) packet_buffer;
511 	ip_packet = (struct ip *) (ether_packet + 1);
512 #endif				/* !HAVE_STRICT_ALIGNMENT */
513 
514 	/* initialize our state: */
515 	last_rarp_time = 0;
516 	last_open_time = 0;
517 	boot1_fd = -1;
518 	boot2_file_name = NULL;
519 	boot2_fd = -1;
520 	boot1_block_count = 0;		/* XXXGCC -Wuninitialized */
521 	boot2_block_count = 0;		/* XXXGCC -Wuninitialized */
522 	boot1_byte_count = 0;		/* XXXGCC -Wuninitialized */
523 	boot2_byte_count = 0;		/* XXXGCC -Wuninitialized */
524 
525 	/* loop processing packets: */
526 	for (;;) {
527 
528 		/* receive another packet: */
529 		packet_length = ndbootd_raw_read(interface, packet_buffer, sizeof(packet_buffer));
530 		if (packet_length < 0) {
531 			_NDBOOTD_DEBUG((fp, "failed to receive packet: %s", strerror(errno)));
532 			exit(1);
533 			continue;
534 		}
535 		now = time(NULL);
536 
537 		/* check the Ethernet and IP parts of the packet: */
538 		if (packet_length
539 		    < (sizeof(struct ether_header)
540 			+ sizeof(struct ip)
541 			+ sizeof(struct ndboot_packet))) {
542 			_NDBOOTD_DEBUG((fp, "ignoring a too-short packet of length %ld", (long) packet_length));
543 			continue;
544 		}
545 #ifdef HAVE_STRICT_ALIGNMENT
546 		memcpy(ether_packet, packet_buffer, sizeof(struct ether_header));
547 		memcpy(ip_packet, packet_buffer + sizeof(struct ether_header),
548 		    (((struct ip *) (packet_buffer + sizeof(struct ether_header)))->ip_hl << 2));
549 #endif				/* !HAVE_STRICT_ALIGNMENT */
550 		if (ether_packet->ether_type != htons(ETHERTYPE_IP)
551 		    || ip_packet->ip_p != IPPROTO_ND) {
552 			_NDBOOTD_DEBUG((fp, "ignoring a packet with the wrong Ethernet or IP protocol"));
553 			continue;
554 		}
555 		_ndbootd_ip_cksum(ip_packet);
556 		if (ip_packet->ip_sum != 0) {
557 			_NDBOOTD_DEBUG((fp, "ignoring a packet with a bad IP checksum"));
558 			continue;
559 		}
560 		if (packet_length
561 		    != (sizeof(struct ether_header)
562 			+ (ip_packet->ip_hl << 2)
563 			+ sizeof(struct ndboot_packet))) {
564 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad total length %ld", (long) packet_length));
565 			continue;
566 		}
567 		/* if we need to, refresh our RARP cache: */
568 		if ((last_rarp_time + NDBOOTD_CLIENT_TTL_SECONDS) < now
569 		    || memcmp(last_client_ether, ether_packet->ether_shost, ETHER_ADDR_LEN)) {
570 
571 			/* turn the Ethernet address into a hostname: */
572 			if (ether_ntohost(hostname_buffer, (struct ether_addr *) ether_packet->ether_shost)) {
573 				_NDBOOTD_DEBUG((fp, "could not resolve %02x:%02x:%02x:%02x:%02x:%02x into a hostname: %s",
574 					((unsigned char *) ether_packet->ether_shost)[0],
575 					((unsigned char *) ether_packet->ether_shost)[1],
576 					((unsigned char *) ether_packet->ether_shost)[2],
577 					((unsigned char *) ether_packet->ether_shost)[3],
578 					((unsigned char *) ether_packet->ether_shost)[4],
579 					((unsigned char *) ether_packet->ether_shost)[5],
580 					strerror(errno)));
581 				continue;
582 			}
583 			/* turn the hostname into an IP address: */
584 			hostname_buffer[sizeof(hostname_buffer) - 1] = '\0';
585 			if ((the_hostent = gethostbyname(hostname_buffer)) == NULL
586 			    || the_hostent->h_addrtype != AF_INET) {
587 				_NDBOOTD_DEBUG((fp, "could not resolve %s into an IP address: %s",
588 					hostname_buffer,
589 					strerror(errno)));
590 				continue;
591 			}
592 			/* save these new results in our RARP cache: */
593 			last_rarp_time = now;
594 			memcpy(last_client_ether, ether_packet->ether_shost, ETHER_ADDR_LEN);
595 			memcpy(&last_client_ip, the_hostent->h_addr, sizeof(last_client_ip));
596 			_NDBOOTD_DEBUG((fp, "IP address for %02x:%02x:%02x:%02x:%02x:%02x is %s",
597 				((unsigned char *) last_client_ether)[0],
598 				((unsigned char *) last_client_ether)[1],
599 				((unsigned char *) last_client_ether)[2],
600 				((unsigned char *) last_client_ether)[3],
601 				((unsigned char *) last_client_ether)[4],
602 				((unsigned char *) last_client_ether)[5],
603 				inet_ntoa(last_client_ip)));
604 
605 			/* this will cause the file descriptor cache to be
606 			 * reloaded, the next time we make it that far: */
607 			last_open_time = 0;
608 		}
609 		/* if this IP packet was broadcast, rewrite the source IP
610 		 * address to be the client, else, check that the client is
611 		 * using the correct IP addresses: */
612 		if (ip_packet->ip_dst.s_addr == htonl(0)) {
613 			ip_packet->ip_src = last_client_ip;
614 		} else {
615 			if (ip_packet->ip_src.s_addr !=
616 			    last_client_ip.s_addr) {
617 				_NDBOOTD_DEBUG((fp, "machine %02x:%02x:%02x:%02x:%02x:%02x is using the wrong IP address\n",
618 					((unsigned char *) ether_packet->ether_shost)[0],
619 					((unsigned char *) ether_packet->ether_shost)[1],
620 					((unsigned char *) ether_packet->ether_shost)[2],
621 					((unsigned char *) ether_packet->ether_shost)[3],
622 					((unsigned char *) ether_packet->ether_shost)[4],
623 					((unsigned char *) ether_packet->ether_shost)[5]));
624 				continue;
625 			}
626 			if (ip_packet->ip_dst.s_addr
627 			    != ((struct sockaddr_in *) & interface->ndbootd_interface_ifreq->ifr_addr)->sin_addr.s_addr) {
628 				_NDBOOTD_DEBUG((fp, "machine %02x:%02x:%02x:%02x:%02x:%02x is sending to the wrong IP address\n",
629 					((unsigned char *) ether_packet->ether_shost)[0],
630 					((unsigned char *) ether_packet->ether_shost)[1],
631 					((unsigned char *) ether_packet->ether_shost)[2],
632 					((unsigned char *) ether_packet->ether_shost)[3],
633 					((unsigned char *) ether_packet->ether_shost)[4],
634 					((unsigned char *) ether_packet->ether_shost)[5]));
635 				continue;
636 			}
637 		}
638 
639 		/* if we need to, refresh our "cache" of file descriptors for
640 		 * the boot programs: */
641 		if ((last_open_time + NDBOOTD_CLIENT_TTL_SECONDS) < now) {
642 
643 			/* close any previously opened programs: */
644 			if (boot1_fd >= 0) {
645 				close(boot1_fd);
646 			}
647 			if (boot2_file_name != NULL) {
648 				free(boot2_file_name);
649 			}
650 			if (boot2_fd >= 0) {
651 				close(boot2_fd);
652 			}
653 			/* open the first-stage boot program: */
654 			if ((boot1_fd = open(boot1_file_name, O_RDONLY)) < 0) {
655 				_NDBOOTD_DEBUG((fp, "could not open %s: %s",
656 					boot1_file_name, strerror(errno)));
657 				continue;
658 			}
659 			if (fstat(boot1_fd, &stat_buffer) < 0) {
660 				_NDBOOTD_DEBUG((fp, "could not stat %s: %s",
661 					boot1_file_name, strerror(errno)));
662 				continue;
663 			}
664 			boot1_byte_count = stat_buffer.st_size;
665 			boot1_block_count = (boot1_byte_count + (NDBOOT_BSIZE - 1)) / NDBOOT_BSIZE;
666 			if (boot1_block_count > NDBOOTD_BOOT1_BLOCK_COUNT) {
667 				_NDBOOTD_DEBUG((fp, "first-stage boot program %s has too many blocks (%d, max is %d)",
668 					boot1_file_name, boot1_block_count, NDBOOTD_BOOT1_BLOCK_COUNT));
669 			}
670 			_NDBOOTD_DEBUG((fp, "first-stage boot program %s has %d blocks",
671 				boot1_file_name, boot1_block_count));
672 
673 			/* open any second-stage boot program: */
674 			if (boot2_x_name != NULL) {
675 
676 				/* determine what the name of the second-stage
677 				 * boot program will be: */
678 				if (boot2_x_name_is_dir) {
679 					if ((boot2_file_name = malloc(strlen(boot2_x_name) + strlen("/00000000.SUN2") + 1)) != NULL) {
680 						sprintf(boot2_file_name, "%s/%02X%02X%02X%02X.SUN2",
681 						    boot2_x_name,
682 						    ((unsigned char *) &last_client_ip)[0],
683 						    ((unsigned char *) &last_client_ip)[1],
684 						    ((unsigned char *) &last_client_ip)[2],
685 						    ((unsigned char *) &last_client_ip)[3]);
686 					}
687 				} else {
688 					boot2_file_name = strdup(boot2_x_name);
689 				}
690 				if (boot2_file_name == NULL) {
691 					abort();
692 				}
693 				/* open the second-stage boot program: */
694 				if ((boot2_fd = open(boot2_file_name, O_RDONLY)) < 0) {
695 					_NDBOOTD_DEBUG((fp, "could not open %s: %s",
696 						boot2_file_name, strerror(errno)));
697 					continue;
698 				}
699 				if (fstat(boot2_fd, &stat_buffer) < 0) {
700 					_NDBOOTD_DEBUG((fp, "could not stat %s: %s",
701 						boot2_file_name, strerror(errno)));
702 					continue;
703 				}
704 				boot2_byte_count = stat_buffer.st_size;
705 				boot2_block_count = (boot2_byte_count + (NDBOOT_BSIZE - 1)) / NDBOOT_BSIZE;
706 				_NDBOOTD_DEBUG((fp, "second-stage boot program %s has %d blocks",
707 					boot2_file_name, boot2_block_count));
708 			}
709 			/* success: */
710 			last_open_time = now;
711 		}
712 		/* check the nd packet: */
713 #ifdef HAVE_STRICT_ALIGNMENT
714 		memcpy(nd_packet, packet_buffer + sizeof(struct ether_header) + (ip_packet->ip_hl << 2), sizeof(struct ndboot_packet));
715 #else				/* !HAVE_STRICT_ALIGNMENT */
716 		nd_packet = (struct ndboot_packet *) (((char *) ip_packet) + (ip_packet->ip_hl << 2));
717 #endif				/* !HAVE_STRICT_ALIGNMENT */
718 
719 		/* dump a bunch of debug information: */
720 		_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 			nd_packet->ndboot_packet_op,
722 			nd_packet->ndboot_packet_minor,
723 			nd_packet->ndboot_packet_error,
724 			nd_packet->ndboot_packet_disk_version,
725 			(int) ntohl(nd_packet->ndboot_packet_sequence),
726 			(int) ntohl(nd_packet->ndboot_packet_block_number),
727 			(int) ntohl(nd_packet->ndboot_packet_byte_count),
728 			(int) ntohl(nd_packet->ndboot_packet_current_byte_offset),
729 			(int) ntohl(nd_packet->ndboot_packet_current_byte_count)));
730 
731 		/* ignore this packet if it has a bad opcode, a bad minor
732 		 * number, a bad disk version, a bad block number, a bad byte
733 		 * count, a bad current byte offset, or a bad current byte
734 		 * count: */
735 		/* FIXME - for some of these conditions, we probably should
736 		 * return an NDBOOT_OP_ERROR packet: */
737 		if ((nd_packet->ndboot_packet_op & NDBOOT_OP_MASK) != NDBOOT_OP_READ) {
738 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad op %d",
739 				nd_packet->ndboot_packet_op & NDBOOT_OP_MASK));
740 			continue;
741 		}
742 		if (nd_packet->ndboot_packet_minor != NDBOOT_MINOR_NDP0) {
743 			_NDBOOTD_DEBUG((fp, "ignoring a packet with device minor %d",
744 				nd_packet->ndboot_packet_minor));
745 			continue;
746 		}
747 		if (nd_packet->ndboot_packet_disk_version != 0) {
748 			_NDBOOTD_DEBUG((fp, "ignoring a packet with disk version %d",
749 				nd_packet->ndboot_packet_disk_version));
750 			continue;
751 		}
752 		if (ntohl(nd_packet->ndboot_packet_block_number) < 0) {
753 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad block number %d",
754 				(int) ntohl(nd_packet->ndboot_packet_block_number)));
755 			continue;
756 		}
757 		if (ntohl(nd_packet->ndboot_packet_byte_count) <= 0 ||
758 		    ntohl(nd_packet->ndboot_packet_byte_count) > NDBOOT_MAX_BYTE_COUNT) {
759 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad byte count %d",
760 				(int) ntohl(nd_packet->ndboot_packet_byte_count)));
761 			continue;
762 		}
763 		if (ntohl(nd_packet->ndboot_packet_current_byte_offset) < 0 ||
764 		    ntohl(nd_packet->ndboot_packet_current_byte_offset)
765 		    >= ntohl(nd_packet->ndboot_packet_byte_count)) {
766 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad current offset %d",
767 				(int) ntohl(nd_packet->ndboot_packet_current_byte_offset)));
768 			continue;
769 		}
770 		if (ntohl(nd_packet->ndboot_packet_current_byte_count) < 0 ||
771 		    ntohl(nd_packet->ndboot_packet_current_byte_count)
772 		    > (ntohl(nd_packet->ndboot_packet_byte_count)
773 			- ntohl(nd_packet->ndboot_packet_current_byte_offset))) {
774 			_NDBOOTD_DEBUG((fp, "ignoring a packet with bad current count %d",
775 				(int) ntohl(nd_packet->ndboot_packet_current_byte_count)));
776 			continue;
777 		}
778 		/* if we were given a current byte count of zero, rewrite it
779 		 * to be the maximum: */
780 		if (ntohl(nd_packet->ndboot_packet_current_byte_count) == 0) {
781 			nd_packet->ndboot_packet_current_byte_count =
782 			    htonl(ntohl(nd_packet->ndboot_packet_byte_count)
783 			    - ntohl(nd_packet->ndboot_packet_current_byte_offset));
784 		}
785 		/* read the data: */
786 		disk_buffer_offset = 0;
787 		block_number = ntohl(nd_packet->ndboot_packet_block_number);
788 		byte_offset = ntohl(nd_packet->ndboot_packet_current_byte_offset);
789 		byte_count = ntohl(nd_packet->ndboot_packet_current_byte_count);
790 		for (; byte_count > 0;) {
791 
792 			/* adjust the current block number and byte offset
793 			 * such that the byte offset is always < NDBOOT_BSIZE: */
794 			block_number += (byte_offset / NDBOOT_BSIZE);
795 			byte_offset = byte_offset % NDBOOT_BSIZE;
796 
797 			/* dispatch on the beginning block number: */
798 			byte_count_read = 0;
799 
800 			/* the (dummy) Sun disk label: */
801 			if (block_number >= NDBOOTD_SUNDK_BLOCK_FIRST
802 			    && block_number < (NDBOOTD_SUNDK_BLOCK_FIRST + NDBOOTD_SUNDK_BLOCK_COUNT)) {
803 				byte_count_read = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset,
804 					NDBOOTD_SUNDK_BLOCK_FIRST, NDBOOTD_SUNDK_BLOCK_COUNT),
805 				    byte_count);
806 			}
807 			/* the first-stage boot program: */
808 			else if (block_number >= NDBOOTD_BOOT1_BLOCK_FIRST
809 			    && block_number < (NDBOOTD_BOOT1_BLOCK_FIRST + NDBOOTD_BOOT1_BLOCK_COUNT)) {
810 
811 				/* if any real part of the first-stage boot
812 				 * program is needed to satisfy the request,
813 				 * read it (otherwise we return garbage as
814 				 * padding): */
815 				byte_count_wanted = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset,
816 					NDBOOTD_BOOT1_BLOCK_FIRST, boot1_block_count),
817 				    byte_count);
818 				if (byte_count_wanted > 0) {
819 
820 					file_offset = ((block_number - NDBOOTD_BOOT1_BLOCK_FIRST) * NDBOOT_BSIZE) + byte_offset;
821 					if (lseek(boot1_fd, file_offset, SEEK_SET) < 0) {
822 						_NDBOOTD_DEBUG((fp, "could not seek %s to block %ld offset %ld: %s",
823 							boot1_file_name,
824 							(long) (block_number - NDBOOTD_BOOT1_BLOCK_FIRST),
825 							(long) byte_offset,
826 							strerror(errno)));
827 						break;
828 					}
829 					byte_count_read = read(boot1_fd, disk_buffer + disk_buffer_offset, byte_count_wanted);
830 					/* pretend that the size of the
831 					 * first-stage boot program is a
832 					 * multiple of NDBOOT_BSIZE: */
833 					if (byte_count_read != byte_count_wanted
834 					    && byte_count_read > 0
835 					    && file_offset + byte_count_read == boot1_byte_count) {
836 						byte_count_read = byte_count_wanted;
837 					}
838 					if (byte_count_read != byte_count_wanted) {
839 						_NDBOOTD_DEBUG((fp, "could not read %ld bytes at block %ld offset %ld from %s: %s (read %ld bytes)",
840 							(long) byte_count_wanted,
841 							(long) (block_number - NDBOOTD_BOOT1_BLOCK_FIRST),
842 							(long) byte_offset,
843 							boot1_file_name,
844 							strerror(errno),
845 							(long) byte_count_read));
846 						break;
847 					}
848 				}
849 				/* the number of bytes we read, including any
850 				 * padding garbage: */
851 				byte_count_read = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset,
852 					NDBOOTD_BOOT1_BLOCK_FIRST, NDBOOTD_BOOT1_BLOCK_COUNT),
853 				    byte_count);
854 			}
855 			/* any second-stage boot program: */
856 			else if (block_number >= NDBOOTD_BOOT2_BLOCK_FIRST) {
857 
858 				/* if any real part of any first-stage boot
859 				 * program is needed to satisfy the request,
860 				 * read it (otherwise we return garbage as
861 				 * padding): */
862 				byte_count_wanted = MIN(NDBOOTD_BYTES_AVAIL(block_number, byte_offset,
863 					NDBOOTD_BOOT2_BLOCK_FIRST, boot2_block_count),
864 				    byte_count);
865 				if (boot2_fd >= 0
866 				    && byte_count_wanted > 0) {
867 
868 					file_offset = ((block_number - NDBOOTD_BOOT2_BLOCK_FIRST) * NDBOOT_BSIZE) + byte_offset;
869 					if (lseek(boot2_fd, file_offset, SEEK_SET) < 0) {
870 						_NDBOOTD_DEBUG((fp, "could not seek %s to block %ld offset %ld: %s",
871 							boot2_file_name,
872 							(long) (block_number - NDBOOTD_BOOT2_BLOCK_FIRST),
873 							(long) byte_offset,
874 							strerror(errno)));
875 						break;
876 					}
877 					byte_count_read = read(boot2_fd, disk_buffer + disk_buffer_offset, byte_count_wanted);
878 					/* pretend that the size of the
879 					 * second-stage boot program is a
880 					 * multiple of NDBOOT_BSIZE: */
881 					if (byte_count_read != byte_count_wanted
882 					    && byte_count_read > 0
883 					    && file_offset + byte_count_read == boot2_byte_count) {
884 						byte_count_read = byte_count_wanted;
885 					}
886 					if (byte_count_read != byte_count_wanted) {
887 						_NDBOOTD_DEBUG((fp, "could not read %ld bytes at block %ld offset %ld from %s: %s (read %ld bytes)",
888 							(long) byte_count_wanted,
889 							(long) (block_number - NDBOOTD_BOOT2_BLOCK_FIRST),
890 							(long) byte_offset,
891 							boot2_file_name,
892 							strerror(errno),
893 							(long) byte_count_read));
894 						break;
895 					}
896 				}
897 				/* the number of bytes we read, including any
898 				 * padding garbage: */
899 				byte_count_read = byte_count;
900 			}
901 			/* update for the amount that we read: */
902 			assert(byte_count_read > 0);
903 			disk_buffer_offset += byte_count_read;
904 			byte_offset += byte_count_read;
905 			byte_count -= byte_count_read;
906 		}
907 		if (byte_count > 0) {
908 			/* an error occurred: */
909 			continue;
910 		}
911 		/* set the Ethernet and IP destination and source addresses,
912 		 * and the IP TTL: */
913 		memcpy(ether_packet->ether_dhost, ether_packet->ether_shost, ETHER_ADDR_LEN);
914 		memcpy(ether_packet->ether_shost, interface->ndbootd_interface_ether, ETHER_ADDR_LEN);
915 #ifdef HAVE_STRICT_ALIGNMENT
916 		memcpy(packet_buffer, ether_packet, sizeof(struct ether_header));
917 #endif				/* !HAVE_STRICT_ALIGNMENT */
918 		ip_packet->ip_dst = ip_packet->ip_src;
919 		ip_packet->ip_src = ((struct sockaddr_in *) & interface->ndbootd_interface_ifreq->ifr_addr)->sin_addr;
920 		ip_packet->ip_ttl = 4;
921 
922 		/* return the data: */
923 		nd_window_filled = 0;
924 		disk_buffer_offset = 0;
925 		byte_count = ntohl(nd_packet->ndboot_packet_current_byte_count);
926 		for (;;) {
927 
928 			/* set the byte count on this packet: */
929 			nd_packet->ndboot_packet_current_byte_count = htonl(MIN(byte_count, NDBOOT_MAX_PACKET_DATA));
930 
931 			/* set our opcode.  the opcode is always
932 			 * NDBOOT_OP_READ, ORed with NDBOOT_OP_FLAG_DONE |
933 			 * NDBOOT_OP_FLAG_WAIT if this packet finishes the
934 			 * request, or ORed with NDBOOT_OP_FLAG_WAIT if this
935 			 * packet fills the window: */
936 			nd_window_filled++;
937 			nd_packet->ndboot_packet_op =
938 			    (NDBOOT_OP_READ
939 			    | ((ntohl(nd_packet->ndboot_packet_current_byte_offset)
940 				    + ntohl(nd_packet->ndboot_packet_current_byte_count))
941 				== ntohl(nd_packet->ndboot_packet_byte_count)
942 				? (NDBOOT_OP_FLAG_DONE
943 				    | NDBOOT_OP_FLAG_WAIT)
944 				: (nd_window_filled == nd_window_size
945 				    ? NDBOOT_OP_FLAG_WAIT
946 				    : 0)));
947 
948 			/* copy the data into the packet: */
949 			memcpy(packet_buffer +
950 			    sizeof(struct ether_header) + (ip_packet->ip_hl << 2) + sizeof(struct ndboot_packet),
951 			    disk_buffer + disk_buffer_offset,
952 			    ntohl(nd_packet->ndboot_packet_current_byte_count));
953 
954 			/* finish the IP packet and calculate the checksum: */
955 			ip_packet->ip_len = htons((ip_packet->ip_hl << 2)
956 			    + sizeof(struct ndboot_packet)
957 			    + ntohl(nd_packet->ndboot_packet_current_byte_count));
958 			ip_packet->ip_sum = 0;
959 			_ndbootd_ip_cksum(ip_packet);
960 
961 #ifdef HAVE_STRICT_ALIGNMENT
962 			memcpy(packet_buffer + sizeof(struct ether_header), ip_packet, ip_packet->ip_hl << 2);
963 			memcpy(packet_buffer + sizeof(struct ether_header) + (ip_packet->ip_hl << 2), nd_packet, sizeof(struct ndboot_packet));
964 #endif				/* !HAVE_STRICT_ALIGNMENT */
965 
966 			/* dump a bunch of debug information: */
967 			_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 				nd_packet->ndboot_packet_op,
969 				nd_packet->ndboot_packet_minor,
970 				nd_packet->ndboot_packet_error,
971 				nd_packet->ndboot_packet_disk_version,
972 				(int) ntohl(nd_packet->ndboot_packet_sequence),
973 				(int) ntohl(nd_packet->ndboot_packet_block_number),
974 				(int) ntohl(nd_packet->ndboot_packet_byte_count),
975 				(int) ntohl(nd_packet->ndboot_packet_current_byte_offset),
976 				(int) ntohl(nd_packet->ndboot_packet_current_byte_count),
977 				nd_window_filled - 1));
978 
979 			/* delay before sending the packet: */
980 			send_delay.tv_sec = 0;
981 			send_delay.tv_nsec = NDBOOTD_SEND_DELAY_NSECONDS;
982 			nanosleep(&send_delay, NULL);
983 
984 			/* transmit the packet: */
985 			if (ndbootd_raw_write(interface, packet_buffer,
986 				sizeof(struct ether_header) + (ip_packet->ip_hl << 2) + sizeof(struct ndboot_packet) + ntohl(nd_packet->ndboot_packet_current_byte_count)) < 0) {
987 				_NDBOOTD_DEBUG((fp, "could not write a packet: %s",
988 					strerror(errno)));
989 			}
990 			/* if we set NDBOOT_OP_FLAG_DONE or
991 			 * NDBOOT_OP_FLAG_WAIT in the packet we just sent,
992 			 * we're done sending: */
993 			if (nd_packet->ndboot_packet_op != NDBOOT_OP_READ) {
994 				break;
995 			}
996 			/* advance to the next packet: */
997 			byte_count -= ntohl(nd_packet->ndboot_packet_current_byte_count);
998 			disk_buffer_offset += ntohl(nd_packet->ndboot_packet_current_byte_count);
999 			nd_packet->ndboot_packet_current_byte_offset =
1000 			    htonl(ntohl(nd_packet->ndboot_packet_current_byte_offset)
1001 			    + ntohl(nd_packet->ndboot_packet_current_byte_count));
1002 		}
1003 	}
1004 	/* NOTREACHED */
1005 }
1006 /* the raw Ethernet access code: */
1007 #include "config/ndbootd-bpf.c"
1008