xref: /minix/minix/tests/test83.c (revision ebfedea0)
1 /*
2  * test83: test bad network packets
3  */
4 
5 #define DEBUG 0
6 
7 #if DEBUG
8 #define dbgprintf(...)	do {						\
9 				struct timeval time = { };		\
10 				gettimeofday(&time, NULL);		\
11 				fprintf(stderr, "[%2d:%.2d:%.2d.%.6d p%d %s:%d] ", \
12 					(int) ((time.tv_sec / 3600) % 24), \
13 					(int) ((time.tv_sec / 60) % 60), \
14 					(int) (time.tv_sec % 60),	\
15 					time.tv_usec,			\
16 					getpid(),			\
17 					__FUNCTION__,			\
18 					__LINE__);			\
19 				fprintf(stderr, __VA_ARGS__);		\
20 				fflush(stderr);				\
21 			} while (0)
22 #else
23 #define	dbgprintf(...)
24 #endif
25 
26 #include <arpa/inet.h>
27 #include <assert.h>
28 #include <fcntl.h>
29 #include <netinet/in.h>
30 #include <signal.h>
31 #include <stdarg.h>
32 #include <stdint.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
38 #include <sys/time.h>
39 #include <sys/wait.h>
40 
41 #include <net/gen/ether.h>
42 #include <net/gen/eth_io.h>
43 #include <net/gen/in.h>
44 #include <net/gen/ip_io.h>
45 
46 #include "common.h"
47 
48 int max_error = 100;
49 
50 /* https://tools.ietf.org/html/rfc791 */
51 struct header_ip {
52 	uint8_t  ver_ihl; /* Version (4 bits) + IHL (4 bits) */
53 	uint8_t  tos;     /* Type of Service */
54 	uint16_t len;     /* Total Length */
55 	uint16_t id;      /* Identification */
56 	uint16_t fl_fo;   /* Flags (3 bits) + Fragment Offset (13 bits) */
57 	uint8_t  ttl;     /* Time to Live */
58 	uint8_t  prot;    /* Protocol */
59 	uint16_t cs;      /* Header Checksum */
60 	uint32_t src;     /* Source Address */
61 	uint32_t dst;     /* Destination Address */
62 	uint8_t  opt[16]; /* Options  */
63 };
64 #define IP_FLAG_EVIL	(1 << 2)
65 #define IP_FLAG_DF	(1 << 1)
66 #define IP_FLAG_MF	(1 << 0)
67 
68 /* https://tools.ietf.org/html/rfc790 */
69 #define IP_PROT_ICMP	1
70 #define IP_PROT_TCP	6
71 #define IP_PROT_UDP	17
72 
73 /* https://tools.ietf.org/html/rfc768 */
74 struct header_udp {
75 	uint16_t src; /* Source Port */
76 	uint16_t dst; /* Destination Port */
77 	uint16_t len; /* Length */
78 	uint16_t cs;  /* Checksum */
79 };
80 
81 struct header_udp_pseudo {
82 	uint32_t src;
83 	uint32_t dst;
84 	uint8_t  zero;
85 	uint8_t  prot;
86 	uint16_t len;
87 };
88 
89 /* https://tools.ietf.org/html/rfc793 */
90 struct header_tcp {
91 	uint16_t src;     /* Source Port */
92 	uint16_t dst;     /* Destination Port */
93 	uint32_t seq;     /* Sequence Number */
94 	uint32_t ack;     /* Acknowledgment Number */
95 	uint8_t  doff;    /* Data Offset */
96 	uint8_t  fl;      /* Flags */
97 	uint16_t win;     /* Window */
98 	uint16_t cs;      /* Checksum */
99 	uint16_t uptr;    /* Urgent Pointer */
100 	uint8_t  opt[16]; /* Options  */
101 };
102 #define TCP_FLAG_URG	(1 << 5)
103 #define TCP_FLAG_ACK	(1 << 4)
104 #define TCP_FLAG_PSH	(1 << 3)
105 #define TCP_FLAG_RST	(1 << 2)
106 #define TCP_FLAG_SYN	(1 << 1)
107 #define TCP_FLAG_FIN	(1 << 0)
108 
109 #define PORT_BASE	12345
110 #define PORT_COUNT_TCP	4
111 #define PORT_COUNT_UDP	2
112 #define PORT_COUNT	(PORT_COUNT_TCP + PORT_COUNT_UDP)
113 
114 #define PORT_BASE_SRC	(PORT_BASE + PORT_COUNT)
115 #define PORT_COUNT_SRC	79
116 
117 #define PAYLOADSIZE_COUNT 6
118 static const size_t payloadsizes[] = {
119 	0,
120 	1,
121 	100,
122 	1024,
123 	2345,
124 	65535 - sizeof(struct header_ip) - sizeof(struct header_udp),
125 };
126 
127 #define ADDR_COUNT_MAX 10
128 static size_t addr_count;
129 static uint32_t addrsrc = 0xc0000201; /* 192.0.2.1 (TEST-NET) */
130 static uint32_t addrdst = 0x7f000001; /* 127.0.0.1 (localhost) */
131 static uint32_t addrs[ADDR_COUNT_MAX] = {
132 	0x00000000, /* 0.0.0.0 (INADDR_NONE) */
133 	0x7f000001, /* 127.0.0.1 (localhost) */
134 	0xc0000201, /* 192.0.2.1 (TEST-NET) */
135 	0xffffffff, /* 255.255.255.255 (broadcast) */
136 	/* local addresses will be added */
137 };
138 
139 #define CLOSE(fd) do { assert(fd >= 0); if (close((fd)) != 0) efmt("close failed"); } while (0);
140 enum server_action {
141 	sa_close,
142 	sa_read,
143 	sa_selectr,
144 	sa_selectrw,
145 	sa_write,
146 };
147 static int server_done;
148 
149 static void server_alarm(int seconds);
150 
151 static char *sigstr_cat(char *p, const char *s) {
152 	size_t slen = strlen(s);
153 	memcpy(p, s, slen);
154 	return p + slen;
155 }
156 
157 static char *sigstr_itoa(char *p, unsigned long n) {
158 	unsigned digit;
159 	unsigned long factor = 1000000000UL;
160 	int first = 1;
161 
162 	while (factor > 0) {
163 		digit = (n / factor) % 10;
164 		if (!first || digit || factor == 1) {
165 			*(p++) = digit + '0';
166 			first = 0;
167 		}
168 		factor /= 10;
169 	}
170 	return p;
171 }
172 
173 #if 0
174 static void dbgprintdata(const void *data, size_t size) {
175 	size_t addr;
176 	const unsigned char *p = data;
177 
178 	for (addr = 0; addr < size; addr++) {
179 		if (addr % 16 == 0) {
180 			if (addr > 0) fprintf(stderr, "\n");
181 			fprintf(stderr, "%.4zx", addr);
182 		}
183 		fprintf(stderr, " %.2x", p[addr]);
184 	}
185 	fprintf(stderr, "\n");
186 	fflush(stderr);
187 }
188 #endif
189 
190 static void dbgprint_sig(const char *name) {
191 #if DEBUG
192 	char buf[256];
193 	char *p = buf;
194 
195 	/* fprintf not used to be signal safe */
196 	p = sigstr_cat(p, "[");
197 	p = sigstr_itoa(p, getpid());
198 	p = sigstr_cat(p, "] ");
199 	p = sigstr_cat(p, name);
200 	p = sigstr_cat(p, "\n");
201 	write(STDERR_FILENO, buf, p - buf);
202 #endif
203 }
204 
205 #define SIGNAL(sig, handler) (signal_checked((sig), (handler), #sig, __FILE__, __FUNCTION__, __LINE__))
206 
207 static void signal_checked(int sig, void (* handler)(int), const char *signame,
208 	const char *file, const char *func, int line) {
209 	char buf[256];
210 	char *p = buf;
211 	struct sigaction sa = {
212 		.sa_handler = handler,
213 	};
214 
215 	if (sigaction(sig, &sa, NULL) == 0) return;
216 
217 	/* efmt not used to be signal safe */
218 	p = sigstr_cat(p, "[");
219 	p = sigstr_cat(p, file);
220 	p = sigstr_cat(p, ":");
221 	p = sigstr_itoa(p, line);
222 	p = sigstr_cat(p, "] error: sigaction(");
223 	p = sigstr_cat(p, signame);
224 	p = sigstr_cat(p, ") failed in function ");
225 	p = sigstr_cat(p, func);
226 	p = sigstr_cat(p, ": ");
227 	p = sigstr_itoa(p, errno);
228 	p = sigstr_cat(p, "\n");
229 	write(STDERR_FILENO, buf, p - buf);
230 	errct++;
231 }
232 
233 static void server_sigusr1(int signo) {
234 	dbgprint_sig("SIGUSR1");
235 
236 	/* terminate on the first opportunity */
237 	server_done = 1;
238 
239 	/* in case signal is caught before a blocking operation,
240 	 * keep interrupting
241 	 */
242 	server_alarm(1);
243 }
244 
245 static void server_stop(pid_t pid) {
246 
247 	if (pid < 0) return;
248 
249 	dbgprintf("sending SIGUSR1 to child %d\n", (int) pid);
250 	if (kill(pid, SIGUSR1) != 0) efmt("kill failed");
251 }
252 
253 static void server_wait(pid_t pid) {
254 	int exitcode, status;
255 	pid_t r;
256 
257 	if (pid < 0) return;
258 
259 	dbgprintf("waiting for child %d\n", (int) pid);
260 	r = waitpid(pid, &status, 0);
261 	if (r != pid) {
262 		efmt("waitpid failed");
263 		return;
264 	}
265 
266 	if (WIFEXITED(status)) {
267 		exitcode = WEXITSTATUS(status);
268 		if (exitcode < 0) {
269 			efmt("negative exit code from child %d\n", (int) pid);
270 		} else {
271 			dbgprintf("child exited exitcode=%d\n", exitcode);
272 			errct += exitcode;
273 		}
274 	} else if (WIFSIGNALED(status)) {
275 		efmt("child killed by signal %d", WTERMSIG(status));
276 	} else {
277 		efmt("child has unexpected exit status 0x%x", status);
278 	}
279 }
280 
281 static void server_sigalrm(int signum) {
282 	server_alarm(1);
283 }
284 
285 static void server_alarm(int seconds) {
286 	SIGNAL(SIGALRM, server_sigalrm);
287 	alarm(seconds);
288 }
289 
290 static void server_no_alarm(void) {
291 	int errno_old = errno;
292 	alarm(0);
293 	SIGNAL(SIGALRM, SIG_DFL);
294 	errno = errno_old;
295 }
296 
297 static int server_rw(int fd, int is_write, int *success) {
298 	char buf[4096];
299 	ssize_t r;
300 
301 	/* return 0 means close connection, *success=0 means stop server */
302 
303 	if (is_write) {
304 		/* ignore SIGPIPE */
305 		SIGNAL(SIGPIPE, SIG_IGN);
306 
307 		/* initialize buffer */
308 		memset(buf, -1, sizeof(buf));
309 	}
310 
311 	/* don't block for more than 1s */
312 	server_alarm(1);
313 
314 	/* perform read or write operation */
315 	dbgprintf("server_rw waiting is_write=%d\n", is_write);
316 	r = is_write ? write(fd, buf, sizeof(buf)) : read(fd, buf, sizeof(buf));
317 
318 	/* stop alarm (preserves errno) */
319 	server_no_alarm();
320 
321 	/* handle read/write result */
322 	if (r >= 0) {
323 		dbgprintf("server_rw done\n");
324 		*success = 1;
325 		return r > 0;
326 	}
327 
328 	switch (errno) {
329 	case EINTR:
330 		dbgprintf("server_rw interrupted\n");
331 		*success = 1;
332 		return 0;
333 	case ECONNRESET:
334 		dbgprintf("server_rw connection reset\n");
335 		*success = 1;
336 		return 0;
337 	case EPIPE:
338 		if (is_write) {
339 			dbgprintf("server_rw EPIPE\n");
340 			*success = 1;
341 			return 0;
342 		}
343 		/* fall through */
344 	default:
345 		efmt("%s failed", is_write ? "write" : "read");
346 		*success = 0;
347 		return 0;
348 	}
349 }
350 
351 static int server_select(int fd, int is_rw, int *success,
352 	enum server_action *actionnext) {
353 	int r;
354 	fd_set readfds, writefds;
355 	struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };
356 
357 	/* return 0 means close connection, *success=0 means stop server */
358 
359 	/* prepare fd sets */
360 	FD_ZERO(&readfds);
361 	FD_SET(fd, &readfds);
362 	FD_ZERO(&writefds);
363 	if (is_rw) FD_SET(fd, &writefds);
364 
365 	/* perform select */
366 	errno = 0;
367 	dbgprintf("server_select waiting\n");
368 	r = select(fd + 1, &readfds, &writefds, NULL, &timeout);
369 
370 	/* handle result */
371 	if (r < 0) {
372 		switch (errno) {
373 		case EINTR:
374 			dbgprintf("server_select interrupted\n");
375 			*success = 1;
376 			return 0;
377 		default:
378 			efmt("select failed");
379 			*success = 0;
380 			return 0;
381 		}
382 	}
383 	if (r == 0) {
384 		dbgprintf("server_select nothing available\n");
385 		*success = 1;
386 		return 0;
387 	}
388 
389 	if (FD_ISSET(fd, &readfds)) {
390 		dbgprintf("server_select read available\n");
391 		*actionnext = sa_read;
392 		*success = 1;
393 		return 1;
394 	} else if (FD_ISSET(fd, &writefds)) {
395 		dbgprintf("server_select write available\n");
396 		*actionnext = sa_write;
397 		*success = 1;
398 		return 1;
399 	}
400 
401 	*success = 0;
402 	efmt("select did not set fd");
403 	return 0;
404 }
405 
406 static int server_accept(int servfd, int type, enum server_action action) {
407 	enum server_action actionnext;
408 	struct sockaddr addr;
409 	socklen_t addrsize;
410 	int connfd;
411 	int success = 0;
412 
413 	/* if connection-oriented, accept a conmection */
414 	if (type == SOCK_DGRAM) {
415 		connfd = servfd;
416 	} else {
417 		dbgprintf("server_accept waiting for connection\n");
418 		addrsize = sizeof(addr);
419 		connfd = accept(servfd, &addr, &addrsize);
420 		if (connfd < 0) {
421 			switch (errno) {
422 			case EINTR:
423 				dbgprintf("server_accept interrupted\n");
424 				return 1;
425 			default:
426 				efmt("cannot accept connection");
427 				return 0;
428 			}
429 		}
430 		dbgprintf("server_accept new connection\n");
431 	}
432 
433 	/* perform requested action while the connection is open */
434 	actionnext = action;
435 	while (!server_done) {
436 		switch (actionnext) {
437 		case sa_close:
438 			success = 1;
439 			goto cleanup;
440 		case sa_read:
441 			if (!server_rw(connfd, 0, &success)) goto cleanup;
442 			actionnext = action;
443 			break;
444 		case sa_selectr:
445 		case sa_selectrw:
446 			if (!server_select(connfd, actionnext == sa_selectrw,
447 				&success, &actionnext)) {
448 				goto cleanup;
449 			}
450 			break;
451 		case sa_write:
452 			if (!server_rw(connfd, 1, &success)) goto cleanup;
453 			actionnext = action;
454 			break;
455 		default:
456 			efmt("bad server action");
457 			success = 0;
458 			goto cleanup;
459 		}
460 	}
461 
462 	/* socket connection socket */
463 cleanup:
464 	dbgprintf("server_accept done success=%d\n", success);
465 	if (connfd != servfd) CLOSE(connfd);
466 	return success;
467 }
468 
469 static pid_t server_start(int type, int port, enum server_action action) {
470 	struct sockaddr_in addr = {
471 		.sin_family = AF_INET,
472 		.sin_port = htons(port),
473 		.sin_addr = { htonl(INADDR_ANY) },
474 	};
475 	int fd;
476 	pid_t pid = -1;
477 
478 	dbgprintf("server_start port %d\n", port);
479 
480 	/* create socket */
481 	fd = socket(AF_INET, type, 0);
482 	if (fd < 0) {
483 		efmt("cannot create socket");
484 		goto cleanup;
485 	}
486 
487 	/* bind socket */
488 	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
489 		efmt("cannot bind socket");
490 		goto cleanup;
491 	}
492 
493 	/* make it a server socket if needed */
494 	if (type != SOCK_DGRAM) {
495 		if (listen(fd, 5) != 0) {
496 			efmt("cannot listen on socket");
497 			goto cleanup;
498 		}
499 	}
500 
501 	/* intercept SIGUSR1 in case parent wants the server to stop */
502 	SIGNAL(SIGUSR1, server_sigusr1);
503 
504 	/* fork; parent continues, child becomes server */
505 	pid = fork();
506 	if (pid < 0) {
507 		efmt("cannot create socket");
508 		goto cleanup;
509 	}
510 	if (pid) goto cleanup;
511 
512 	/* server loop */
513 	dbgprintf("server_start child\n");
514 	while (!server_done && server_accept(fd, type, action)) {}
515 	dbgprintf("server_start child returns\n");
516 
517 	CLOSE(fd);
518 	exit(errct);
519 
520 cleanup:
521 	dbgprintf("server_start parent returns pid=%d\n", (int) pid);
522 	if (fd >= 0) CLOSE(fd);
523 	return pid;
524 }
525 
526 static ssize_t send_packet_raw(int fd, const void *buf, size_t size) {
527 	return write(fd, buf, size);
528 }
529 
530 enum settings_ip {
531 	si_bad_version   = (1 <<  0),
532 	si_bad_ihl_small = (1 <<  1),
533 	si_bad_ihl_big   = (1 <<  2),
534 	si_bad_len_small = (1 <<  3),
535 	si_bad_len_big   = (1 <<  4),
536 	si_bad_len_huge  = (1 <<  5),
537 	si_bad_cs        = (1 <<  6),
538 	si_zero_cs       = (1 <<  7),
539 
540 	si_flag_evil     = (1 <<  8),
541 	si_flag_df       = (1 <<  9),
542 	si_flag_mf       = (1 << 10),
543 
544 	si_opt_end       = (1 << 11),
545 	si_opt_topsec    = (1 << 12),
546 	si_opt_nop       = (1 << 13),
547 	si_opt_badopt    = (1 << 14),
548 	si_opt_badpad    = (1 << 15),
549 };
550 
551 enum settings_udp {
552 	su_bad_len_small = (1 <<  0),
553 	su_bad_len_big   = (1 <<  1),
554 	su_bad_len_huge  = (1 <<  2),
555 	su_bad_cs        = (1 <<  3),
556 	su_zero_cs       = (1 <<  4),
557 };
558 
559 enum fragmode_ip {
560 	fi_as_needed,
561 	fi_one,
562 	fi_two,
563 	fi_frag_tiny,
564 	fi_frag_overlap,
565 	fi_frag_first,
566 	fi_frag_last,
567 	fi_frag_repeat,
568 	fi_fo_max,
569 };
570 
571 static uint16_t checksum_ip(const void *header, size_t headersize) {
572 	const uint16_t *p = header;
573 	uint32_t sum = 0;
574 
575 	while (headersize > 0) {
576 		assert(headersize >= sizeof(*p));
577 		sum += ntohs(*p);
578 		headersize -= sizeof(*p);
579 		p++;
580 	}
581 	sum += sum >> 16;
582 	return htons(~sum);
583 }
584 
585 static void send_packet_ip_base(
586 	int fd,
587 	enum settings_ip ipsettings,
588 	uint8_t  tos,
589 	uint16_t id,
590 	uint16_t fo,
591 	uint8_t  ttl,
592 	uint8_t  prot,
593 	uint32_t srcip,
594 	uint32_t dstip,
595 	const void *payload,
596 	size_t payloadsize) {
597 	uint8_t ver = (ipsettings & si_bad_version) ? 3 : 4;
598 	uint8_t ihl, ihl_fuzzed;
599 	uint16_t fl = ((ipsettings & si_flag_evil) ? IP_FLAG_EVIL : 0) |
600 	              ((ipsettings & si_flag_df)   ? IP_FLAG_DF   : 0) |
601 	              ((ipsettings & si_flag_mf)   ? IP_FLAG_MF   : 0);
602 	uint16_t len;
603 	int optlen;
604 	struct header_ip header = {
605 		.tos     = tos,
606 		.id      = htons(id),
607 		.fl_fo   = htons((fl << 13) | fo),
608 		.ttl     = ttl,
609 		.prot    = prot,
610 		.cs      = 0,
611 		.src     = htonl(srcip),
612 		.dst     = htonl(dstip),
613 	};
614 	char packet[6536];
615 	size_t packetsize;
616 	ssize_t r;
617 
618 	dbgprintf("sending IP packet src=%d.%d.%d.%d dst=%d.%d.%d.%d "
619 		"payloadsize=%zu id=0x%.4x fragoff=%d%s\n",
620 		(uint8_t) (srcip >> 24), (uint8_t) (srcip >> 16),
621 		(uint8_t) (srcip >> 8), (uint8_t) (srcip >> 0),
622 		(uint8_t) (dstip >> 24), (uint8_t) (dstip >> 16),
623 		(uint8_t) (dstip >> 8), (uint8_t) (dstip >> 0),
624 		payloadsize, id, fo, (ipsettings & si_flag_mf) ? " (MF)" : "");
625 
626 	optlen = 0;
627 	if (ipsettings & si_opt_badpad) memset(header.opt, -1, sizeof(header.opt));
628 	if (ipsettings & si_opt_nop) header.opt[optlen++] = 0x01;
629 	if (ipsettings & si_opt_topsec) {
630 		header.opt[optlen++] = 0x82;
631 		header.opt[optlen++] = 0x0b;
632 		header.opt[optlen++] = 0x6b; /* S: top secret */
633 		header.opt[optlen++] = 0xc5; /* S: top secret */
634 		header.opt[optlen++] = 0x00; /* C */
635 		header.opt[optlen++] = 0x00; /* C */
636 		header.opt[optlen++] = 'A'; /* H */
637 		header.opt[optlen++] = 'B'; /* H */
638 		header.opt[optlen++] = 'C'; /* TCC */
639 		header.opt[optlen++] = 'D'; /* TCC */
640 		header.opt[optlen++] = 'E'; /* TCC */
641 	}
642 	if (ipsettings & si_opt_badopt) header.opt[optlen++] = 0xff;
643 	if (ipsettings & si_opt_end) header.opt[optlen++] = 0x00;
644 	assert(optlen <= sizeof(header.opt));
645 
646 	ihl = ihl_fuzzed = (20 + optlen + 3) / 4;
647 	if (ipsettings & si_bad_ihl_small) ihl_fuzzed = 4;
648 	if (ipsettings & si_bad_ihl_big) ihl_fuzzed = 15;
649 	header.ver_ihl = (ver << 4) | ihl_fuzzed;
650 
651 	len = ihl * 4 + payloadsize;
652 	if (ipsettings & si_bad_len_small) len = ihl * 4 - 1;
653 	if (ipsettings & si_bad_len_big) len += 1;
654 	if (ipsettings & si_bad_len_huge) len = 0xffff;
655 	header.len = htons(len);
656 
657 	packetsize = ihl * 4 + payloadsize;
658 	if (packetsize > sizeof(packet)) {
659 		payloadsize = sizeof(packet) - ihl * 4;
660 		packetsize = sizeof(packet);
661 	}
662 
663 	header.cs = checksum_ip(&header, ihl * 4);
664 	if (ipsettings & si_zero_cs) header.cs = 0;
665 	if (ipsettings & si_bad_cs) header.cs += 1;
666 
667 	memset(packet, 0, sizeof(packet));
668 	memcpy(packet, &header, ihl * 4);
669 	memcpy(packet + ihl * 4, payload, payloadsize);
670 
671 	errno = 0;
672 	r = send_packet_raw(fd, packet, packetsize);
673 	if (r == -1 && errno == EPACKSIZE &&
674 		(packetsize < 60 || packetsize > 1514)) {
675 		return;
676 	}
677 	if (r != packetsize) {
678 		efmt("write to network interface failed");
679 	}
680 }
681 
682 static void send_packet_ip(
683 	int fd,
684 	enum settings_ip ipsettings,
685 	uint8_t tos,
686 	uint16_t id,
687 	uint8_t ttl,
688 	uint8_t prot,
689 	uint32_t srcip,
690 	uint32_t dstip,
691 	enum fragmode_ip fragmode,
692 	const void *payload,
693 	size_t payloadsize) {
694 	enum settings_ip flags;
695 	size_t fragcount = 1;
696 	size_t fragsize, fragsizecur;
697 	size_t fragstart = 0;
698 	size_t fragstep;
699 
700 	switch (fragmode) {
701 	case fi_as_needed:
702 		fragsize = fragstep = 1500;
703 		fragcount = (payloadsize + fragsize - 1) / fragsize;
704 		break;
705 	case fi_one:
706 	case fi_fo_max:
707 		fragsize = fragstep = payloadsize;
708 		break;
709 	case fi_two:
710 		fragcount = 2;
711 		fragsize = fragstep = (payloadsize + 1) / 2;
712 		break;
713 	case fi_frag_tiny:
714 		fragcount = (payloadsize >= 100) ? 100 :
715 			(payloadsize < 1) ? 1 : payloadsize;
716 		fragsize = fragstep = (payloadsize + fragcount - 1) / fragcount;
717 		break;
718 	case fi_frag_overlap:
719 		fragcount = 2;
720 		fragsize = (payloadsize * 2 + 2) / 3;
721 		fragstep = (payloadsize + 1) / 2;
722 		break;
723 	case fi_frag_first:
724 		fragcount = 1;
725 		fragsize = fragstep = (payloadsize + 1) / 2;
726 		break;
727 	case fi_frag_last:
728 		fragcount = 1;
729 		fragsize = fragstep = (payloadsize + 1) / 2;
730 		break;
731 	case fi_frag_repeat:
732 		fragcount = 2;
733 		fragsize = payloadsize;
734 		fragstep = 0;
735 		break;
736 	default:
737 		abort();
738 	}
739 
740 	while (fragcount > 0) {
741 		if (fragstart >= payloadsize) {
742 			fragsizecur = 0;
743 		} else if (payloadsize - fragstart < fragsize) {
744 			fragsizecur = payloadsize - fragstart;
745 		} else {
746 			fragsizecur = fragsize;
747 		}
748 
749 		flags = 0;
750 		if (fragstart + fragsizecur < payloadsize) flags |= si_flag_mf;
751 		send_packet_ip_base(
752 			fd,
753 			ipsettings | flags,
754 			tos,
755 			id,
756 			(fragmode == fi_fo_max) ? 0x1fff : fragstart,
757 			ttl,
758 			prot,
759 			srcip,
760 			dstip,
761 			(uint8_t *) payload + fragstart,
762 			fragsizecur);
763 
764 		fragcount--;
765 		fragstart += fragstep;
766 	}
767 }
768 
769 static uint32_t checksum_udp_sum(const void *buf, size_t size) {
770 	const uint16_t *p = buf;
771 	uint32_t sum = 0;
772 
773 	while (size > 0) {
774 		assert(size >= sizeof(*p));
775 		sum += ntohs(*p);
776 		size -= sizeof(*p);
777 		p++;
778 	}
779 	return sum;
780 }
781 
782 static uint16_t checksum_udp(
783 	uint32_t srcip,
784 	uint32_t dstip,
785 	uint8_t prot,
786 	const void *packet,
787 	size_t packetsize) {
788 	uint32_t sum = 0;
789 	struct header_udp_pseudo header = {
790 		.src = htonl(srcip),
791 		.dst = htonl(dstip),
792 		.zero = 0,
793 		.prot = prot,
794 		.len = htons(packetsize),
795 	};
796 
797 	sum = checksum_udp_sum(&header, sizeof(header)) +
798 		checksum_udp_sum(packet, packetsize + packetsize % 2);
799 	sum += sum >> 16;
800 	return ntohs(~sum);
801 }
802 
803 static void send_packet_udp(
804 	int fd,
805 	enum settings_ip ipsettings,
806 	uint8_t tos,
807 	uint16_t id,
808 	uint8_t ttl,
809 	uint8_t prot,
810 	uint32_t srcip,
811 	uint32_t dstip,
812 	enum fragmode_ip fragmode,
813 	enum settings_udp udpsettings,
814 	uint16_t srcport,
815 	uint16_t dstport,
816 	const void *payload,
817 	size_t payloadsize) {
818 	uint16_t len;
819 	struct header_udp header = {
820 		.src = htons(srcport),
821 		.dst = htons(dstport),
822 		.cs = 0,
823 	};
824 	char packet[65536];
825 	size_t packetsize;
826 
827 	dbgprintf("sending UDP packet srcport=%d dstport=%d payloadsize=%zu\n",
828 		srcport, dstport, payloadsize);
829 
830 	len = sizeof(struct header_udp) + payloadsize;
831 	if (udpsettings & su_bad_len_small) len = sizeof(struct header_udp) - 1;
832 	if (udpsettings & su_bad_len_big) len += 1;
833 	if (udpsettings & su_bad_len_huge) len = 65535 - sizeof(struct header_ip);
834 	header.len = htons(len);
835 
836 	packetsize = sizeof(header) + payloadsize;
837 	assert(packetsize <= sizeof(packet));
838 
839 	memcpy(packet, &header, sizeof(header));
840 	memcpy(packet + sizeof(header), payload, payloadsize);
841 	if (packetsize % 2) packet[packetsize] = 0;
842 
843 	header.cs = checksum_udp(srcip, dstip, prot, packet, packetsize);
844 	if (udpsettings & su_zero_cs) header.cs = 0;
845 	if (udpsettings & su_bad_cs) header.cs += 1;
846 
847 	memcpy(packet, &header, sizeof(header));
848 	send_packet_ip(
849 		fd,
850 		ipsettings,
851 		tos,
852 		id,
853 		ttl,
854 		prot,
855 		srcip,
856 		dstip,
857 		fragmode,
858 		packet,
859 		packetsize);
860 }
861 
862 struct send_packet_udp_simple_params {
863 	int fd;
864 	enum settings_ip ipsettings;
865 	uint8_t tos;
866 	uint16_t *id;
867 	uint8_t ttl;
868 	uint8_t prot;
869 	uint32_t srcip;
870 	uint32_t dstip;
871 	enum fragmode_ip fragmode;
872 	enum settings_udp udpsettings;
873 	uint16_t srcport;
874 	uint16_t dstport;
875 	size_t payloadsize;
876 };
877 
878 static void send_packet_udp_simple(
879 	const struct send_packet_udp_simple_params *params) {
880 	int i;
881 	char payload[65536];
882 
883 	assert(params->payloadsize <= sizeof(payload));
884 	for (i = 0; i < params->payloadsize; i++) {
885 		payload[i] = *params->id + i;
886 	}
887 
888 	send_packet_udp(
889 		params->fd,
890 		params->ipsettings,
891 		params->tos,
892 		*params->id,
893 		params->ttl,
894 		params->prot,
895 		params->srcip,
896 		params->dstip,
897 		params->fragmode,
898 		params->udpsettings,
899 		params->srcport,
900 		params->dstport,
901 		payload,
902 		params->payloadsize);
903 	*params->id += 5471;
904 }
905 
906 static void send_packets_ip_settings(
907 	const struct send_packet_udp_simple_params *paramsbase) {
908 	struct send_packet_udp_simple_params params;
909 	int i;
910 	enum settings_ip ipsettings[] = {
911 		0,
912 		si_bad_version,
913 		si_bad_ihl_small,
914 		si_bad_ihl_big,
915 		si_bad_len_small,
916 		si_bad_len_big,
917 		si_bad_len_huge,
918 		si_bad_cs,
919 		si_zero_cs,
920 		si_flag_evil,
921 		si_flag_df,
922 		si_flag_mf,
923 		si_opt_end,
924 		si_opt_topsec,
925 		si_opt_nop,
926 		si_opt_badopt,
927 		si_opt_nop | si_opt_end | si_opt_badpad,
928 	};
929 	uint8_t ttls[] = { 0, 1, 127, 128, 255 };
930 
931 	/* various types of flags/options/corruptions */
932 	params = *paramsbase;
933 	for (i = 0; i < 17; i++) {
934 		params.ipsettings = ipsettings[i];
935 		send_packet_udp_simple(&params);
936 	}
937 
938 	/* various TTL settings */
939 	params = *paramsbase;
940 	for (i = 0; i < 5; i++) {
941 		params.ttl = ttls[i];
942 		send_packet_udp_simple(&params);
943 	}
944 }
945 
946 static void send_packets_ip(int fd) {
947 	enum fragmode_ip fragmode;
948 	int i, j;
949 	uint16_t id = 0;
950 	struct send_packet_udp_simple_params params;
951 	const struct send_packet_udp_simple_params paramsbase = {
952 		.fd            = fd,
953 		.ipsettings    = 0,
954 		.tos           = 0,
955 		.id            = &id,
956 		.ttl           = 10,
957 		.prot          = IP_PROT_UDP,
958 		.srcip         = addrsrc,
959 		.dstip         = addrdst,
960 		.fragmode      = fi_as_needed,
961 		.udpsettings   = 0,
962 		.srcport       = PORT_BASE + 0,
963 		.dstport       = PORT_BASE + 1,
964 		.payloadsize   = 1234,
965 	};
966 
967 	/* send packets with various payload sizes and corruptions */
968 	params = paramsbase;
969 	for (i = 0; i < PAYLOADSIZE_COUNT; i++) {
970 		params.payloadsize = payloadsizes[i];
971 		send_packets_ip_settings(&params);
972 	}
973 
974 	/* send packets with various addresses and corruptions */
975 	params = paramsbase;
976 	for (i = 0; i < addr_count; i++) {
977 	for (j = 0; j < addr_count; j++) {
978 		params.srcip = addrs[i];
979 		params.dstip = addrs[j];
980 		send_packets_ip_settings(&params);
981 	}
982 	}
983 
984 	/* send valid packets with various fragmentation settings */
985 	params = paramsbase;
986 	for (i = 0; i < PAYLOADSIZE_COUNT; i++) {
987 	for (fragmode = fi_as_needed; fragmode <= fi_fo_max; fragmode++) {
988 		params.payloadsize = payloadsizes[i];
989 		params.fragmode = fragmode;
990 		send_packet_udp_simple(&params);
991 	}
992 	}
993 
994 	/* send a packet for each protocol */
995 	params = paramsbase;
996 	for (i = 0; i < 256; i++) {
997 		params.prot = i;
998 		send_packet_udp_simple(&params);
999 	}
1000 
1001 	/* send a packet for each tos */
1002 	params = paramsbase;
1003 	for (i = 0; i < 256; i++) {
1004 		params.tos = i;
1005 		send_packet_udp_simple(&params);
1006 	}
1007 }
1008 
1009 static void send_packets_udp(int fd) {
1010 	int i, j, k;
1011 	uint16_t id = 0;
1012 	struct send_packet_udp_simple_params params;
1013 	const struct send_packet_udp_simple_params paramsbase = {
1014 		.fd            = fd,
1015 		.ipsettings    = 0,
1016 		.tos           = 0,
1017 		.id            = &id,
1018 		.ttl           = 10,
1019 		.prot          = IP_PROT_UDP,
1020 		.srcip         = addrsrc,
1021 		.dstip         = addrdst,
1022 		.fragmode      = fi_as_needed,
1023 		.udpsettings   = 0,
1024 		.srcport       = PORT_BASE + 0,
1025 		.dstport       = PORT_BASE + 1,
1026 		.payloadsize   = 1234,
1027 	};
1028 	uint16_t ports[] = {
1029 		0,
1030 		PORT_BASE + 0,
1031 		PORT_BASE + 1,
1032 		32767,
1033 		65535,
1034 	};
1035 	enum settings_udp udpsettings[] = {
1036 		0,
1037 		su_bad_len_small,
1038 		su_bad_len_big,
1039 		su_bad_len_huge,
1040 		su_bad_cs,
1041 		su_zero_cs,
1042 	};
1043 
1044 	/* send packets with various corruptions */
1045 	params = paramsbase;
1046 	for (i = 0; i < 6; i++) {
1047 		params.udpsettings = udpsettings[i];
1048 		send_packet_udp_simple(&params);
1049 	}
1050 
1051 	/* send packets with various addresses and ports */
1052 	params = paramsbase;
1053 	for (i = 0; i < addr_count; i++) {
1054 	for (j = 0; j < addr_count; j++) {
1055 	for (k = 0; k < 5; k++) {
1056 		params.srcip = addrs[i];
1057 		params.dstip = addrs[j];
1058 		params.dstport = ports[k];
1059 		send_packet_udp_simple(&params);
1060 	}
1061 	}
1062 	}
1063 	params = paramsbase;
1064 	for (i = 0; i < addr_count; i++) {
1065 	for (j = 0; j < 5; j++) {
1066 	for (k = 0; k < 5; k++) {
1067 		params.dstip = addrs[i];
1068 		params.srcport = ports[j];
1069 		params.dstport = ports[k];
1070 		send_packet_udp_simple(&params);
1071 	}
1072 	}
1073 	}
1074 }
1075 
1076 enum settings_tcp {
1077 	st_bad_doff_small  = (1 <<  0),
1078 	st_bad_doff_big    = (1 <<  1),
1079 	st_bad_doff_huge   = (1 <<  2),
1080 	st_bad_cs          = (1 <<  3),
1081 	st_zero_cs         = (1 <<  4),
1082 	st_opt_end         = (1 <<  5),
1083 	st_opt_nop         = (1 <<  6),
1084 	st_opt_mss_small   = (1 <<  7),
1085 	st_opt_mss_big     = (1 <<  8),
1086 	st_opt_mss_huge    = (1 <<  9),
1087 	st_opt_badpad      = (1 << 10),
1088 };
1089 
1090 static void send_packet_tcp(
1091 	int fd,
1092 	enum settings_ip ipsettings,
1093 	uint8_t tos,
1094 	uint16_t id,
1095 	uint8_t ttl,
1096 	uint8_t prot,
1097 	uint32_t srcip,
1098 	uint32_t dstip,
1099 	enum fragmode_ip fragmode,
1100 	enum settings_tcp tcpsettings,
1101 	uint16_t srcport,
1102 	uint16_t dstport,
1103 	uint32_t seq,
1104 	uint32_t ack,
1105 	uint8_t fl,
1106 	uint16_t win,
1107 	uint16_t uptr,
1108 	const void *payload,
1109 	size_t payloadsize) {
1110 	uint8_t doff, doff_fuzzed;
1111 	int optlen;
1112 	struct header_tcp header = {
1113 		.src  = htons(srcport),
1114 		.dst  = htons(dstport),
1115 		.seq  = htonl(seq),
1116 		.ack  = htonl(ack),
1117 		.fl   = fl,
1118 		.win  = htons(win),
1119 		.cs   = 0,
1120 		.uptr = htons(uptr),
1121 	};
1122 	char packet[65536];
1123 	size_t packetsize;
1124 
1125 	dbgprintf("sending TCP packet srcport=%d dstport=%d fl=%s%s%s%s%s%s "
1126 		"payloadsize=%zu\n", srcport, dstport,
1127 		(fl & TCP_FLAG_URG) ? "  URG" : "",
1128 		(fl & TCP_FLAG_ACK) ? "  ACK" : "",
1129 		(fl & TCP_FLAG_PSH) ? "  PSH" : "",
1130 		(fl & TCP_FLAG_RST) ? "  RST" : "",
1131 		(fl & TCP_FLAG_SYN) ? "  SYN" : "",
1132 		(fl & TCP_FLAG_FIN) ? "  FIN" : "",
1133 		payloadsize);
1134 
1135 	optlen = 0;
1136 	if (tcpsettings & st_opt_badpad) memset(header.opt, -1, sizeof(header.opt));
1137 	if (tcpsettings & st_opt_nop) header.opt[optlen++] = 0x01;
1138 	if (tcpsettings & st_opt_mss_small) {
1139 		header.opt[optlen++] = 0x02;
1140 		header.opt[optlen++] = 0x04;
1141 		header.opt[optlen++] = 0x00;
1142 		header.opt[optlen++] = 0x00;
1143 	}
1144 	if (tcpsettings & st_opt_mss_big) {
1145 		header.opt[optlen++] = 0x02;
1146 		header.opt[optlen++] = 0x04;
1147 		header.opt[optlen++] = 0x10;
1148 		header.opt[optlen++] = 0x00;
1149 	}
1150 	if (tcpsettings & st_opt_mss_huge) {
1151 		header.opt[optlen++] = 0x02;
1152 		header.opt[optlen++] = 0x04;
1153 		header.opt[optlen++] = 0xff;
1154 		header.opt[optlen++] = 0xff;
1155 	}
1156 	if (tcpsettings & st_opt_end) header.opt[optlen++] = 0x00;
1157 
1158 	doff = doff_fuzzed = (20 + optlen + 3) / 4;
1159 	if (tcpsettings & su_bad_len_small) doff_fuzzed -= 1;
1160 	if (tcpsettings & su_bad_len_big) doff_fuzzed += 1;
1161 	if (tcpsettings & su_bad_len_huge) doff_fuzzed = 15;
1162 	header.doff = doff_fuzzed << 4;
1163 
1164 	packetsize = doff * 4 + payloadsize;
1165 	assert(packetsize <= sizeof(packet));
1166 
1167 	memcpy(packet, &header, sizeof(header));
1168 	memcpy(packet + sizeof(header), payload, payloadsize);
1169 	if (packetsize % 2) packet[packetsize] = 0;
1170 
1171 	header.cs = checksum_udp(srcip, dstip, prot, packet, packetsize);
1172 	if (tcpsettings & su_zero_cs) header.cs = 0;
1173 	if (tcpsettings & su_bad_cs) header.cs += 1;
1174 
1175 	memcpy(packet, &header, sizeof(header));
1176 	send_packet_ip(
1177 		fd,
1178 		ipsettings,
1179 		tos,
1180 		id,
1181 		ttl,
1182 		prot,
1183 		srcip,
1184 		dstip,
1185 		fragmode,
1186 		packet,
1187 		packetsize);
1188 }
1189 
1190 struct send_packet_tcp_simple_params {
1191 	int fd;
1192 	enum settings_ip ipsettings;
1193 	uint8_t tos;
1194 	uint16_t *id;
1195 	uint8_t ttl;
1196 	uint8_t prot;
1197 	uint32_t srcip;
1198 	uint32_t dstip;
1199 	enum fragmode_ip fragmode;
1200 	enum settings_tcp tcpsettings;
1201 	uint16_t srcport;
1202 	uint16_t dstport;
1203 	uint32_t seq;
1204 	uint32_t ack;
1205 	uint8_t fl;
1206 	uint16_t win;
1207 	uint16_t uptr;
1208 	size_t payloadsize;
1209 };
1210 
1211 static void send_packet_tcp_simple(
1212 	const struct send_packet_tcp_simple_params *params) {
1213 	int i;
1214 	char payload[65536];
1215 
1216 	if (!params->srcip || !params->dstip) return; /* crashes QEMU */
1217 
1218 	assert(params->payloadsize <= sizeof(payload));
1219 	for (i = 0; i < params->payloadsize; i++) {
1220 		payload[i] = *params->id + i;
1221 	}
1222 	send_packet_tcp(
1223 		params->fd,
1224 		params->ipsettings,
1225 		params->tos,
1226 		*params->id,
1227 		params->ttl,
1228 		params->prot,
1229 		params->srcip,
1230 		params->dstip,
1231 		params->fragmode,
1232 		params->tcpsettings,
1233 		params->srcport,
1234 		params->dstport,
1235 		params->seq,
1236 		params->ack,
1237 		params->fl,
1238 		params->win,
1239 		params->uptr,
1240 		payload,
1241 		params->payloadsize);
1242 	*params->id += 5471;
1243 }
1244 
1245 static void send_packets_tcp(int fd) {
1246 	int i, j, k;
1247 	uint16_t id = 0;
1248 	const struct send_packet_tcp_simple_params paramsbase = {
1249 		.fd          = fd,
1250 		.ipsettings  = 0,
1251 		.tos         = 0,
1252 		.id          = &id,
1253 		.ttl         = 10,
1254 		.prot        = IP_PROT_TCP,
1255 		.srcip       = addrsrc,
1256 		.dstip       = addrdst,
1257 		.fragmode    = fi_as_needed,
1258 		.tcpsettings = 0,
1259 		.srcport     = PORT_BASE + 0,
1260 		.dstport     = PORT_BASE + 1,
1261 		.seq         = 0x12345678,
1262 		.ack         = 0x87654321,
1263 		.fl          = TCP_FLAG_SYN,
1264 		.win         = 4096,
1265 		.uptr        = 0,
1266 		.payloadsize = 1234,
1267 	};
1268 	uint16_t payloadsizes[] = {
1269 		0,
1270 		1,
1271 		999,
1272 		1500,
1273 		1600,
1274 		9999,
1275 	};
1276 	uint16_t ports[] = {
1277 		0,
1278 		PORT_BASE + 0,
1279 		PORT_BASE + 1,
1280 		PORT_BASE + 2,
1281 		PORT_BASE + 3,
1282 		32767,
1283 		65535,
1284 	};
1285 	enum settings_tcp tcpsettings[] = {
1286 		0,
1287 		st_bad_doff_small,
1288 		st_bad_doff_big,
1289 		st_bad_doff_huge,
1290 		st_bad_cs,
1291 		st_zero_cs,
1292 		st_opt_end,
1293 		st_opt_nop,
1294 		st_opt_mss_small,
1295 		st_opt_mss_big,
1296 		st_opt_mss_huge,
1297 		st_opt_badpad,
1298 	};
1299 	struct send_packet_tcp_simple_params params;
1300 
1301 	/* send packets with various corruptions */
1302 	params = paramsbase;
1303 	for (i = 0; i < 12; i++) {
1304 		params.tcpsettings = tcpsettings[i];
1305 		send_packet_tcp_simple(&params);
1306 	}
1307 
1308 	/* send packets with various addresses and ports */
1309 	params = paramsbase;
1310 	for (i = 0; i < addr_count; i++) {
1311 	for (j = 0; j < addr_count; j++) {
1312 	for (k = 0; k < 7; k++) {
1313 		params.srcip = addrs[i];
1314 		params.dstip = addrs[j];
1315 		params.dstport = ports[k];
1316 		send_packet_tcp_simple(&params);
1317 	}
1318 	}
1319 	}
1320 	params = paramsbase;
1321 	for (i = 0; i < addr_count; i++) {
1322 	for (j = 0; j < 7; j++) {
1323 	for (k = 0; k < 7; k++) {
1324 		params.dstip = addrs[i];
1325 		params.srcport = ports[j];
1326 		params.dstport = ports[k];
1327 		send_packet_tcp_simple(&params);
1328 	}
1329 	}
1330 	}
1331 
1332 	/* send packets with different sequence numbers */
1333 	params = paramsbase;
1334 	for (i = 0; i < 16; i++) {
1335 		params.seq = 0x1fffffff;
1336 		send_packet_tcp_simple(&params);
1337 	}
1338 
1339 	/* send packets with all combinations of flags */
1340 	params = paramsbase;
1341 	for (i = 0; i < 256; i++) {
1342 		params.fl = i;
1343 		send_packet_tcp_simple(&params);
1344 	}
1345 
1346 	/* send packets with different window sizes */
1347 	params = paramsbase;
1348 	for (i = 0; i < 6; i++) {
1349 		params.win = payloadsizes[i];
1350 		send_packet_tcp_simple(&params);
1351 	}
1352 
1353 	/* send packets with different payload sizes */
1354 	params = paramsbase;
1355 	for (i = 0; i < 6; i++) {
1356 		params.payloadsize = payloadsizes[i];
1357 		send_packet_tcp_simple(&params);
1358 	}
1359 }
1360 
1361 static void recv_packets_nb(int fd) {
1362 	char buf[4096];
1363 	int flags;
1364 	ssize_t r;
1365 
1366 	flags = fcntl(fd, F_GETFL);
1367 	if (flags < 0) {
1368 		efmt("fcntl(F_GETFL) failed");
1369 		return;
1370 	}
1371 
1372 	if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
1373 		efmt("fcntl(F_SETFL) failed");
1374 		return;
1375 	}
1376 
1377 	for (;;) {
1378 		errno = 0;
1379 		r = read(fd, buf, sizeof(buf));
1380 		if (r <= 0) {
1381 			if (errno != EAGAIN) efmt("nb read failed");
1382 			dbgprintf("no more packets to receive\n");
1383 			break;
1384 		}
1385 		dbgprintf("received packet of size %zd\n", r);
1386 	}
1387 
1388 	if (fcntl(fd, F_SETFL, flags) == -1) {
1389 		efmt("fcntl(F_SETFL) failed");
1390 		return;
1391 	}
1392 }
1393 
1394 static struct timeval gettimeofday_checked(void) {
1395 	struct timeval time = {};
1396 
1397 	if (gettimeofday(&time, NULL) != 0) {
1398 		efmt("gettimeofday failed");
1399 	}
1400 	return time;
1401 }
1402 
1403 static int timeval_cmp(const struct timeval *x, const struct timeval *y) {
1404 	if (x->tv_sec < y->tv_sec) return -1;
1405 	if (x->tv_sec > y->tv_sec) return 1;
1406 	if (x->tv_usec < y->tv_usec) return -1;
1407 	if (x->tv_usec > y->tv_usec) return 1;
1408 	return 0;
1409 }
1410 
1411 static struct timeval timeval_sub(struct timeval x, struct timeval y) {
1412 	struct timeval z;
1413 
1414 	/* no negative result allowed */
1415 	if (timeval_cmp(&x, &y) < 0) {
1416 		memset(&z, 0, sizeof(z));
1417 	} else {
1418 		/* no negative tv_usec allowed */
1419 		if (x.tv_usec < y.tv_usec) {
1420 			x.tv_sec -= 1;
1421 			x.tv_usec += 1000000;
1422 		}
1423 
1424 		/* perform subtraction */
1425 		z.tv_sec = x.tv_sec - y.tv_sec;
1426 		z.tv_usec = x.tv_usec - y.tv_usec;
1427 	}
1428 	return z;
1429 }
1430 
1431 static size_t recv_packet_select(
1432 	int fd,
1433 	void *buf,
1434 	size_t size,
1435 	const struct timeval *deadline) {
1436 	int nfds;
1437 	ssize_t r;
1438 	fd_set readfds;
1439 	struct timeval timeout = timeval_sub(*deadline, gettimeofday_checked());
1440 
1441 	FD_ZERO(&readfds);
1442 	FD_SET(fd, &readfds);
1443 	errno = 0;
1444 	nfds = select(fd + 1, &readfds, NULL, NULL, &timeout);
1445 	if (nfds < 0 || nfds > 1) {
1446 		efmt("select failed");
1447 		return 0;
1448 	}
1449 
1450 	if (nfds == 0) {
1451 		if (FD_ISSET(fd, &readfds)) efmt("select spuriously set fd");
1452 		dbgprintf("no more packets to receive\n");
1453 		return 0;
1454 	}
1455 
1456 	if (!FD_ISSET(fd, &readfds)) {
1457 		efmt("select did not set fd");
1458 		return 0;
1459 	}
1460 
1461 	r = read(fd, buf, size);
1462 	if (r <= 0) {
1463 		efmt("read failed");
1464 		return 0;
1465 	}
1466 	dbgprintf("received packet of size %zd\n", r);
1467 
1468 	return r;
1469 }
1470 
1471 static void recv_packets_select(int fd) {
1472 	char buf[4096];
1473 	struct timeval deadline = gettimeofday_checked();
1474 
1475 	deadline.tv_sec++;
1476 	while (recv_packet_select(fd, buf, sizeof(buf), &deadline)) { }
1477 }
1478 
1479 static int open_raw_socket(int broadcast) {
1480 	int fd;
1481 	struct nwio_ethopt opt = { };
1482 	struct nwio_ethstat stat = { };
1483 
1484 	fd = open("/dev/eth", O_RDWR);
1485 	if (fd < 0) efmt("cannot open /dev/eth");
1486 
1487 	/* test NWIOGETHOPT */
1488 	if (ioctl(fd, NWIOGETHOPT, &opt) != 0) {
1489 		efmt("ioctl(NWIOGETHOPT) failed");
1490 	}
1491 
1492 	/* test NWIOGETHSTAT */
1493 	if (ioctl(fd, NWIOGETHSTAT, &stat) != 0) {
1494 		efmt("ioctl(NWIOGETHSTAT) failed");
1495 	}
1496 
1497 	/* test invalid NWIOSETHOPT input */
1498 	opt.nweo_flags = NWEO_COPY << 16;
1499 	if (ioctl(fd, NWIOSETHOPT, &opt) != -1 && errno != EBADMODE) {
1500 		efmt("ioctl(NWIOSETHOPT) should have returned EBADMODE");
1501 	}
1502 
1503 	opt.nweo_flags = NWEO_EN_LOC | NWEO_DI_LOC;
1504 	if (ioctl(fd, NWIOSETHOPT, &opt) != -1 && errno != EBADMODE) {
1505 		efmt("ioctl(NWIOSETHOPT) should have returned EBADMODE");
1506 	}
1507 
1508 	/* test NWIOSETHOPT with defaults */
1509 	opt.nweo_flags = 0;
1510 	if (ioctl(fd, NWIOSETHOPT, &opt) != 0) {
1511 		efmt("ioctl(NWIOSETHOPT) failed");
1512 	}
1513 
1514 	/* test NWIOGETHSTAT right after reconfiguring */
1515 	opt.nweo_flags = NWEO_EN_BROAD | NWEO_EN_MULTI | NWEO_EN_PROMISC;
1516 	if (ioctl(fd, NWIOSETHOPT, &opt) != 0) {
1517 		efmt("ioctl(NWIOSETHOPT) failed");
1518 	}
1519 
1520 	opt.nweo_flags = NWEO_DI_BROAD | NWEO_DI_MULTI | NWEO_DI_PROMISC;
1521 	if (ioctl(fd, NWIOSETHOPT, &opt) != 0) {
1522 		efmt("ioctl(NWIOSETHOPT) failed");
1523 	}
1524 
1525 	if (ioctl(fd, NWIOGETHSTAT, &stat) != 0) {
1526 		efmt("ioctl(NWIOGETHSTAT) failed");
1527 	}
1528 
1529 	/* configure /dev/eth the way we want it for the rest of the test */
1530 	opt.nweo_flags = NWEO_COPY | NWEO_EN_LOC | NWEO_EN_BROAD |
1531 		NWEO_EN_MULTI | NWEO_EN_PROMISC |
1532 		(broadcast ? NWEO_REMANY : NWEO_REMSPEC) |
1533 		NWEO_TYPESPEC | NWEO_RWDATONLY;
1534 	opt.nweo_type = htons(ETH_IP_PROTO);
1535 	memcpy(&opt.nweo_rem, &stat.nwes_addr, sizeof(opt.nweo_rem));
1536 	if (ioctl(fd, NWIOSETHOPT, &opt) != 0) {
1537 		efmt("ioctl(NWIOSETHOPT) failed");
1538 	}
1539 
1540 	return fd;
1541 }
1542 
1543 static void do_packets(void) {
1544 	int fd;
1545 
1546 	/* test IP and UDP with broadcast */
1547 	fd = open_raw_socket(1 /*broadcast*/);
1548 	if (fd < 0) return;
1549 
1550 	send_packets_ip(fd);
1551 	send_packets_udp(fd);
1552 	recv_packets_nb(fd);
1553 
1554 	CLOSE(fd);
1555 
1556 	/* test TCP locally to avoid crashing QEMU */
1557 	fd = open_raw_socket(0 /*broadcast*/);
1558 	if (fd < 0) return;
1559 
1560 	send_packets_tcp(fd);
1561 	recv_packets_select(fd);
1562 
1563 	CLOSE(fd);
1564 }
1565 
1566 static void add_local_ip(uint32_t ip) {
1567 	static int first = 1;
1568 	int i;
1569 
1570 	for (i = 0; i < addr_count; i++) {
1571 		if (addrs[i] == ip) return;
1572 	}
1573 	dbgprintf("found local IP: %d.%d.%d.%d\n",
1574 		(uint8_t) (ip >> 24), (uint8_t) (ip >> 16),
1575 		(uint8_t) (ip >> 8), (uint8_t) (ip >> 0));
1576 	if (addr_count < ADDR_COUNT_MAX) {
1577 		addrs[addr_count++] = ip;
1578 	}
1579 	if (first) {
1580 		addrdst = ip;
1581 		first = 0;
1582 	}
1583 }
1584 
1585 static void get_local_ip(void) {
1586 	char device[16];
1587 	int flags;
1588 	int ifno;
1589 	nwio_ipconf_t ipconf;
1590 	int ip_fd;
1591 
1592 	/* inspired by ifconfig */
1593 	for (ifno = 0; ifno < 32; ifno++) {
1594 		snprintf(device, sizeof(device), "/dev/ip%d", ifno);
1595 		ip_fd = open(device, O_RDWR);
1596 		if (ip_fd < 0) {
1597 			if (errno != ENOENT && errno != ENXIO) {
1598 				efmt("cannot open %s", device);
1599 			}
1600 			continue;
1601 		}
1602 
1603 		flags = fcntl(ip_fd, F_GETFL);
1604 		if (flags == -1) {
1605 			efmt("cannot get flags for %s", device);
1606 			goto next;
1607 		}
1608 		if (fcntl(ip_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
1609 			efmt("cannot set flags for %s", device);
1610 			goto next;
1611 		}
1612 
1613 		if (ioctl(ip_fd, NWIOGIPCONF, &ipconf) == -1) {
1614 			if (errno != EAGAIN) {
1615 				efmt("cannot get IP address for %s", device);
1616 			}
1617 			goto next;
1618 		}
1619 
1620 		if (fcntl(ip_fd, F_SETFL, flags) == -1) {
1621 			efmt("cannot restore flags for %s", device);
1622 		}
1623 
1624 		add_local_ip(ntohl(ipconf.nwic_ipaddr));
1625 
1626 next:
1627 		CLOSE(ip_fd);
1628 	}
1629 }
1630 
1631 int main(int argc, char **argv)
1632 {
1633 	int i;
1634 	pid_t pids[PORT_COUNT];
1635 
1636 	start(83);
1637 
1638 	/* start servers so we have someone to talk to */
1639 	pids[0] = server_start(SOCK_STREAM, PORT_BASE + 0, sa_close);
1640 	pids[1] = server_start(SOCK_STREAM, PORT_BASE + 1, sa_read);
1641 	pids[2] = server_start(SOCK_STREAM, PORT_BASE + 2, sa_selectrw);
1642 	pids[3] = server_start(SOCK_STREAM, PORT_BASE + 3, sa_write);
1643 	pids[4] = server_start(SOCK_DGRAM,  PORT_BASE + 0, sa_read);
1644 	pids[5] = server_start(SOCK_DGRAM,  PORT_BASE + 1, sa_selectr);
1645 
1646 	/* send some bogus packets */
1647 	get_local_ip();
1648 	if (get_setting_use_network()) do_packets();
1649 
1650 	/* stop the servers */
1651 	for (i = 0; i < PORT_COUNT; i++) server_stop(pids[i]);
1652 	for (i = 0; i < PORT_COUNT; i++) server_wait(pids[i]);
1653 
1654 	quit();
1655 	return 0;
1656 }
1657