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