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