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
82static 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: */
131void *ndbootd_malloc _NDBOOTD_P((size_t, size_t));
132void *ndbootd_calloc _NDBOOTD_P((size_t, size_t));
133void *ndbootd_memdup _NDBOOTD_P((void *, size_t));
134
135/* globals: */
136const char *_ndbootd_argv0;
137#ifdef _NDBOOTD_DO_DEBUG
138int _ndbootd_debug;
139#endif				/* _NDBOOTD_DO_DEBUG */
140
141/* allocators: */
142void *
143ndbootd_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}
151void *
152ndbootd_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}
160void *
161ndbootd_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: */
174static void
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: */
204static struct ndbootd_interface *
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
290int
291main(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, "\
403usage: %s [OPTIONS] BOOT1-BIN\n\
404where 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